diff options
| author | Ian Rogers <irogers@google.com> | 2026-01-11 07:13:35 +0300 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2026-01-13 22:09:14 +0300 |
| commit | a2297e74a07d21eb498d8549ae6fddc35cf26ec6 (patch) | |
| tree | 1859528628f9a99e0dd02734d93cff91353e0260 /tools | |
| parent | ec9426655dcee3e337735935dcc2dea7684a5bf8 (diff) | |
| download | linux-a2297e74a07d21eb498d8549ae6fddc35cf26ec6.tar.xz | |
perf srcline: Add configuration support for the addr2line style
Allow the addr2line style to be specified on the `perf report` command
line or in the .perfconfig file.
Committer testing:
The methods:
# perf probe -x ~/bin/perf -F *__addr2line
cmd__addr2line
libbfd__addr2line
libdw__addr2line
llvm__addr2line
#
So if we configure one of them, say 'addr2line':
# perf config addr2line.style=addr2line
# perf config addr2line.style
addr2line.style=addr2line
#
And have probes on all of them:
# perf probe -x ~/bin/perf *__addr2line
Added new events:
probe_perf:cmd__addr2line (on *__addr2line in /home/acme/bin/perf)
probe_perf:llvm__addr2line (on *__addr2line in /home/acme/bin/perf)
probe_perf:libbfd__addr2line (on *__addr2line in /home/acme/bin/perf)
probe_perf:libdw__addr2line (on *__addr2line in /home/acme/bin/perf)
You can now use it in all perf tools, such as:
perf record -e probe_perf:libdw__addr2line -aR sleep 1
#
Only the selected method should be used:
# perf stat -e probe_perf:*_addr2line perf report -f --dso perf --stdio -s srcfile,srcline
# Total Lost Samples: 0
#
# Samples: 4K of event 'cpu/cycles/Pu'
# Event count (approx.): 5535180842
#
# Overhead Source File Source:Line
# ........ ............ ...............
#
99.04% inlineloop.c inlineloop.c:21
0.46% inlineloop.c inlineloop.c:20
#
# (Tip: For hierarchical output, try: perf report --hierarchy)
#
Performance counter stats for 'perf report -f --dso perf --stdio -s srcfile,srcline':
44 probe_perf:cmd__addr2line
0 probe_perf:llvm__addr2line
0 probe_perf:libbfd__addr2line
0 probe_perf:libdw__addr2line
0.035915611 seconds time elapsed
0.028008000 seconds user
0.009051000 seconds sys
#
I checked and that is the case for the other methods.
Also when using:
# perf config addr2line.style=libdw,llvm
Performance counter stats for 'perf report -f --dso perf --stdio -s srcfile,srcline':
0 probe_perf:cmd__addr2line
23 probe_perf:llvm__addr2line
0 probe_perf:libbfd__addr2line
44 probe_perf:libdw__addr2line
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephen Brennan <stephen.s.brennan@oracle.com>
Cc: Tony Jones <tonyj@suse.de>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/builtin-report.c | 10 | ||||
| -rw-r--r-- | tools/perf/util/config.c | 4 | ||||
| -rw-r--r-- | tools/perf/util/srcline.c | 98 | ||||
| -rw-r--r-- | tools/perf/util/srcline.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/symbol_conf.h | 10 |
5 files changed, 113 insertions, 11 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6c2b4f93ec78..2e936928e8c0 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1271,6 +1271,13 @@ parse_percent_limit(const struct option *opt, const char *str, return 0; } +static int +report_parse_addr2line_config(const struct option *opt __maybe_unused, + const char *arg, int unset __maybe_unused) +{ + return addr2line_configure("addr2line.style", arg, NULL); +} + static int process_attr(const struct perf_tool *tool __maybe_unused, union perf_event *event, struct evlist **pevlist) @@ -1447,6 +1454,9 @@ int cmd_report(int argc, const char **argv) "objdump binary to use for disassembly and annotations"), OPT_STRING(0, "addr2line", &addr2line_path, "path", "addr2line binary to use for line numbers"), + OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style", + "addr2line styles (libdw,llvm,libbfd,addr2line)", + report_parse_addr2line_config), OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, "Symbol demangling. Enabled by default, use --no-demangle to disable."), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index e0219bc6330a..0452fbc6c085 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -20,6 +20,7 @@ #include "util/stat.h" /* perf_stat__set_big_num */ #include "util/evsel.h" /* evsel__hw_names, evsel__use_bpf_counters */ #include "util/addr2line.h" /* addr2line_timeout_ms */ +#include "srcline.h" #include "build-id.h" #include "debug.h" #include "config.h" @@ -519,6 +520,9 @@ int perf_default_config(const char *var, const char *value, if (strstarts(var, "stat.")) return perf_stat_config(var, value); + if (strstarts(var, "addr2line.")) + return addr2line_configure(var, value, dummy); + /* Add other config variables here. */ return 0; } diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index e2d280678b02..28fa1abd1fd3 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -7,9 +7,11 @@ #include "llvm.h" #include "symbol.h" #include "libdw.h" +#include "debug.h" #include <inttypes.h> #include <string.h> +#include <linux/string.h> bool srcline_full_filename; @@ -138,21 +140,95 @@ static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int * struct dso *dso, bool unwind_inlines, struct inline_node *node, struct symbol *sym) { - int ret; + int ret = 0; + + if (symbol_conf.addr2line_style[0] == A2L_STYLE_UNKNOWN) { + int i = 0; + + /* Default addr2line fallback order. */ +#ifdef HAVE_LIBDW_SUPPORT + symbol_conf.addr2line_style[i++] = A2L_STYLE_LIBDW; +#endif +#ifdef HAVE_LIBLLVM_SUPPORT + symbol_conf.addr2line_style[i++] = A2L_STYLE_LLVM; +#endif +#ifdef HAVE_LIBBFD_SUPPORT + symbol_conf.addr2line_style[i++] = A2L_STYLE_LIBBFD; +#endif + symbol_conf.addr2line_style[i++] = A2L_STYLE_CMD; + } + + for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.addr2line_style); i++) { + switch (symbol_conf.addr2line_style[i]) { + case A2L_STYLE_LIBDW: + ret = libdw__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, + node, sym); + break; + case A2L_STYLE_LLVM: + ret = llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, + node, sym); + break; + case A2L_STYLE_LIBBFD: + ret = libbfd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, + node, sym); + break; + case A2L_STYLE_CMD: + ret = cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, + node, sym); + break; + case A2L_STYLE_UNKNOWN: + default: + break; + } + if (ret > 0) + return ret; + } + + return 0; +} + +int addr2line_configure(const char *var, const char *value, void *cb __maybe_unused) +{ + static const char * const a2l_style_names[] = { + [A2L_STYLE_LIBDW] = "libdw", + [A2L_STYLE_LLVM] = "llvm", + [A2L_STYLE_LIBBFD] = "libbfd", + [A2L_STYLE_CMD] = "addr2line", + NULL + }; + + char *s, *p, *saveptr; + size_t i = 0; - ret = libdw__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym); - if (ret > 0) - return ret; + if (strcmp(var, "addr2line.style")) + return 0; + + if (!value) + return -1; - ret = llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym); - if (ret > 0) - return ret; + s = strdup(value); + if (!s) + return -1; - ret = libbfd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym); - if (ret > 0) - return ret; + p = strtok_r(s, ",", &saveptr); + while (p && i < ARRAY_SIZE(symbol_conf.addr2line_style)) { + bool found = false; + char *q = strim(p); + + for (size_t j = A2L_STYLE_LIBDW; j < MAX_A2L_STYLE; j++) { + if (!strcasecmp(q, a2l_style_names[j])) { + symbol_conf.addr2line_style[i++] = j; + found = true; + break; + } + } + if (!found) + pr_warning("Unknown addr2line style: %s\n", q); + p = strtok_r(NULL, ",", &saveptr); + } - return cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym); + free(s); + return 0; } static struct inline_node *addr2inlines(const char *dso_name, u64 addr, diff --git a/tools/perf/util/srcline.h b/tools/perf/util/srcline.h index be9f002bf234..7c37b3bf9ce7 100644 --- a/tools/perf/util/srcline.h +++ b/tools/perf/util/srcline.h @@ -63,4 +63,6 @@ struct symbol *new_inline_sym(struct dso *dso, struct symbol *base_sym, const char *funcname); +int addr2line_configure(const char *var, const char *value, void *cb); + #endif /* PERF_SRCLINE_H */ diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h index 7a80d2c14d9b..71bb17372a6c 100644 --- a/tools/perf/util/symbol_conf.h +++ b/tools/perf/util/symbol_conf.h @@ -9,6 +9,15 @@ struct strlist; struct intlist; +enum a2l_style { + A2L_STYLE_UNKNOWN = 0, + A2L_STYLE_LIBDW, + A2L_STYLE_LLVM, + A2L_STYLE_LIBBFD, + A2L_STYLE_CMD, +}; +#define MAX_A2L_STYLE (A2L_STYLE_CMD + 1) + struct symbol_conf { bool nanosecs; unsigned short priv_size; @@ -70,6 +79,7 @@ struct symbol_conf { *col_width_list_str, *bt_stop_list_str; const char *addr2line_path; + enum a2l_style addr2line_style[MAX_A2L_STYLE]; unsigned long time_quantum; struct strlist *dso_list, *comm_list, |
