Commit 57594454 authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo

perf symbol: Add command line support for addr2line path

Allow addr2line to be set either on the command line or via the
perfconfig file. This doesn't currently work with llvm-addr2line as
the addr2line code emits two things:
1) the address to decode,
2) a bogus ',' value.
The expectation is the bogus value will generate:
??
??:0
that terminates the addr2line reading. However, the output from
llvm-addr2line is a single line with just the input ',' locking up the
addr2line reading that is expecting a second line.
Signed-off-by: default avatarIan Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Andres Freund <andres@anarazel.de>
Cc: German Gomez <german.gomez@arm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Tom Rix <trix@redhat.com>
Cc: llvm@lists.linux.dev
Link: https://lore.kernel.org/r/20230328235543.1082207-2-irogers@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 0b02b47e
...@@ -116,6 +116,9 @@ include::itrace.txt[] ...@@ -116,6 +116,9 @@ include::itrace.txt[]
-M:: -M::
--disassembler-style=:: Set disassembler style for objdump. --disassembler-style=:: Set disassembler style for objdump.
--addr2line=<path>::
Path to addr2line binary.
--objdump=<path>:: --objdump=<path>::
Path to objdump binary. Path to objdump binary.
......
...@@ -250,6 +250,9 @@ annotate.*:: ...@@ -250,6 +250,9 @@ annotate.*::
These are in control of addresses, jump function, source code These are in control of addresses, jump function, source code
in lines of assembly code from a specific program. in lines of assembly code from a specific program.
annotate.addr2line::
addr2line binary to use for file names and line numbers.
annotate.objdump:: annotate.objdump::
objdump binary to use for disassembly and annotations. objdump binary to use for disassembly and annotations.
......
...@@ -381,6 +381,9 @@ OPTIONS ...@@ -381,6 +381,9 @@ OPTIONS
This allows to examine the path the program took to each sample. This allows to examine the path the program took to each sample.
The data collection must have used -b (or -j) and -g. The data collection must have used -b (or -j) and -g.
--addr2line=<path>::
Path to addr2line binary.
--objdump=<path>:: --objdump=<path>::
Path to objdump binary. Path to objdump binary.
......
...@@ -161,6 +161,12 @@ Default is to monitor all CPUS. ...@@ -161,6 +161,12 @@ Default is to monitor all CPUS.
-M:: -M::
--disassembler-style=:: Set disassembler style for objdump. --disassembler-style=:: Set disassembler style for objdump.
--addr2line=<path>::
Path to addr2line binary.
--objdump=<path>::
Path to objdump binary.
--prefix=PREFIX:: --prefix=PREFIX::
--prefix-strip=N:: --prefix-strip=N::
Remove first N entries from source file path names in executables Remove first N entries from source file path names in executables
......
...@@ -517,7 +517,7 @@ int cmd_annotate(int argc, const char **argv) ...@@ -517,7 +517,7 @@ int cmd_annotate(int argc, const char **argv)
struct itrace_synth_opts itrace_synth_opts = { struct itrace_synth_opts itrace_synth_opts = {
.set = 0, .set = 0,
}; };
const char *disassembler_style = NULL, *objdump_path = NULL; const char *disassembler_style = NULL, *objdump_path = NULL, *addr2line_path = NULL;
struct option options[] = { struct option options[] = {
OPT_STRING('i', "input", &input_name, "file", OPT_STRING('i', "input", &input_name, "file",
"input file name"), "input file name"),
...@@ -570,6 +570,8 @@ int cmd_annotate(int argc, const char **argv) ...@@ -570,6 +570,8 @@ int cmd_annotate(int argc, const char **argv)
"Strip first N entries of source file path name in programs (with --prefix)"), "Strip first N entries of source file path name in programs (with --prefix)"),
OPT_STRING(0, "objdump", &objdump_path, "path", OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"), "objdump binary to use for disassembly and annotations"),
OPT_STRING(0, "addr2line", &addr2line_path, "path",
"addr2line binary to use for line numbers"),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Enable symbol demangling"), "Enable symbol demangling"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
...@@ -629,6 +631,11 @@ int cmd_annotate(int argc, const char **argv) ...@@ -629,6 +631,11 @@ int cmd_annotate(int argc, const char **argv)
if (!annotate.opts.objdump_path) if (!annotate.opts.objdump_path)
return -ENOMEM; return -ENOMEM;
} }
if (addr2line_path) {
symbol_conf.addr2line_path = strdup(addr2line_path);
if (!symbol_conf.addr2line_path)
return -ENOMEM;
}
if (annotate_check_args(&annotate.opts) < 0) if (annotate_check_args(&annotate.opts) < 0)
return -EINVAL; return -EINVAL;
......
...@@ -1226,7 +1226,7 @@ int cmd_report(int argc, const char **argv) ...@@ -1226,7 +1226,7 @@ int cmd_report(int argc, const char **argv)
}; };
char *sort_order_help = sort_help("sort by key(s):"); char *sort_order_help = sort_help("sort by key(s):");
char *field_order_help = sort_help("output field(s): overhead period sample "); char *field_order_help = sort_help("output field(s): overhead period sample ");
const char *disassembler_style = NULL, *objdump_path = NULL; const char *disassembler_style = NULL, *objdump_path = NULL, *addr2line_path = NULL;
const struct option options[] = { const struct option options[] = {
OPT_STRING('i', "input", &input_name, "file", OPT_STRING('i', "input", &input_name, "file",
"input file name"), "input file name"),
...@@ -1344,6 +1344,8 @@ int cmd_report(int argc, const char **argv) ...@@ -1344,6 +1344,8 @@ int cmd_report(int argc, const char **argv)
"add last branch records to call history"), "add last branch records to call history"),
OPT_STRING(0, "objdump", &objdump_path, "path", OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"), "objdump binary to use for disassembly and annotations"),
OPT_STRING(0, "addr2line", &addr2line_path, "path",
"addr2line binary to use for line numbers"),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Disable symbol demangling"), "Disable symbol demangling"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
...@@ -1430,6 +1432,11 @@ int cmd_report(int argc, const char **argv) ...@@ -1430,6 +1432,11 @@ int cmd_report(int argc, const char **argv)
if (!report.annotation_opts.objdump_path) if (!report.annotation_opts.objdump_path)
return -ENOMEM; return -ENOMEM;
} }
if (addr2line_path) {
symbol_conf.addr2line_path = strdup(addr2line_path);
if (!symbol_conf.addr2line_path)
return -ENOMEM;
}
if (annotate_check_args(&report.annotation_opts) < 0) { if (annotate_check_args(&report.annotation_opts) < 0) {
ret = -EINVAL; ret = -EINVAL;
......
...@@ -1439,7 +1439,7 @@ int cmd_top(int argc, const char **argv) ...@@ -1439,7 +1439,7 @@ int cmd_top(int argc, const char **argv)
}; };
struct record_opts *opts = &top.record_opts; struct record_opts *opts = &top.record_opts;
struct target *target = &opts->target; struct target *target = &opts->target;
const char *disassembler_style = NULL, *objdump_path = NULL; const char *disassembler_style = NULL, *objdump_path = NULL, *addr2line_path = NULL;
const struct option options[] = { const struct option options[] = {
OPT_CALLBACK('e', "event", &top.evlist, "event", OPT_CALLBACK('e', "event", &top.evlist, "event",
"event selector. use 'perf list' to list available events", "event selector. use 'perf list' to list available events",
...@@ -1527,6 +1527,8 @@ int cmd_top(int argc, const char **argv) ...@@ -1527,6 +1527,8 @@ int cmd_top(int argc, const char **argv)
OPT_BOOLEAN(0, "no-bpf-event", &top.record_opts.no_bpf_event, "do not record bpf events"), OPT_BOOLEAN(0, "no-bpf-event", &top.record_opts.no_bpf_event, "do not record bpf events"),
OPT_STRING(0, "objdump", &objdump_path, "path", OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"), "objdump binary to use for disassembly and annotations"),
OPT_STRING(0, "addr2line", &addr2line_path, "path",
"addr2line binary to use for line numbers"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING(0, "prefix", &top.annotation_opts.prefix, "prefix", OPT_STRING(0, "prefix", &top.annotation_opts.prefix, "prefix",
...@@ -1629,7 +1631,11 @@ int cmd_top(int argc, const char **argv) ...@@ -1629,7 +1631,11 @@ int cmd_top(int argc, const char **argv)
if (!top.annotation_opts.objdump_path) if (!top.annotation_opts.objdump_path)
return -ENOMEM; return -ENOMEM;
} }
if (addr2line_path) {
symbol_conf.addr2line_path = strdup(addr2line_path);
if (!symbol_conf.addr2line_path)
return -ENOMEM;
}
status = symbol__validate_sym_arguments(); status = symbol__validate_sym_arguments();
if (status) if (status)
......
...@@ -3217,6 +3217,12 @@ static int annotation__config(const char *var, const char *value, void *data) ...@@ -3217,6 +3217,12 @@ static int annotation__config(const char *var, const char *value, void *data)
pr_err("Not enough memory for annotate.objdump\n"); pr_err("Not enough memory for annotate.objdump\n");
return -1; return -1;
} }
} else if (!strcmp(var, "annotate.addr2line")) {
symbol_conf.addr2line_path = strdup(value);
if (!symbol_conf.addr2line_path) {
pr_err("Not enough memory for annotate.addr2line\n");
return -1;
}
} else if (!strcmp(var, "annotate.demangle")) { } else if (!strcmp(var, "annotate.demangle")) {
symbol_conf.demangle = perf_config_bool("demangle", value); symbol_conf.demangle = perf_config_bool("demangle", value);
} else if (!strcmp(var, "annotate.demangle_kernel")) { } else if (!strcmp(var, "annotate.demangle_kernel")) {
......
...@@ -414,9 +414,14 @@ static void addr2line_subprocess_cleanup(struct a2l_subprocess *a2l) ...@@ -414,9 +414,14 @@ static void addr2line_subprocess_cleanup(struct a2l_subprocess *a2l)
free(a2l); free(a2l);
} }
static struct a2l_subprocess *addr2line_subprocess_init(const char *path) static struct a2l_subprocess *addr2line_subprocess_init(const char *addr2line_path,
{ const char *binary_path)
const char *argv[] = { "addr2line", "-e", path, "-i", "-f", NULL }; {
const char *argv[] = {
addr2line_path ?: "addr2line",
"-e", binary_path,
"-i", "-f", NULL
};
struct a2l_subprocess *a2l = zalloc(sizeof(*a2l)); struct a2l_subprocess *a2l = zalloc(sizeof(*a2l));
int start_command_status = 0; int start_command_status = 0;
...@@ -436,21 +441,22 @@ static struct a2l_subprocess *addr2line_subprocess_init(const char *path) ...@@ -436,21 +441,22 @@ static struct a2l_subprocess *addr2line_subprocess_init(const char *path)
a2l->addr2line.argv = NULL; /* it's not used after start_command; avoid dangling pointers */ a2l->addr2line.argv = NULL; /* it's not used after start_command; avoid dangling pointers */
if (start_command_status != 0) { if (start_command_status != 0) {
pr_warning("could not start addr2line for %s: start_command return code %d\n", pr_warning("could not start addr2line (%s) for %s: start_command return code %d\n",
path, addr2line_path, binary_path, start_command_status);
start_command_status);
goto out; goto out;
} }
a2l->to_child = fdopen(a2l->addr2line.in, "w"); a2l->to_child = fdopen(a2l->addr2line.in, "w");
if (a2l->to_child == NULL) { if (a2l->to_child == NULL) {
pr_warning("could not open write-stream to addr2line of %s\n", path); pr_warning("could not open write-stream to addr2line (%s) of %s\n",
addr2line_path, binary_path);
goto out; goto out;
} }
a2l->from_child = fdopen(a2l->addr2line.out, "r"); a2l->from_child = fdopen(a2l->addr2line.out, "r");
if (a2l->from_child == NULL) { if (a2l->from_child == NULL) {
pr_warning("could not open read-stream from addr2line of %s\n", path); pr_warning("could not open read-stream from addr2line (%s) of %s\n",
addr2line_path, binary_path);
goto out; goto out;
} }
...@@ -490,7 +496,6 @@ static int read_addr2line_record(struct a2l_subprocess *a2l, ...@@ -490,7 +496,6 @@ static int read_addr2line_record(struct a2l_subprocess *a2l,
if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len) if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len)
goto error; goto error;
if (function != NULL) if (function != NULL)
*function = strdup(strim(line)); *function = strdup(strim(line));
...@@ -553,7 +558,8 @@ static int addr2line(const char *dso_name, u64 addr, ...@@ -553,7 +558,8 @@ static int addr2line(const char *dso_name, u64 addr,
if (!filename__has_section(dso_name, ".debug_line")) if (!filename__has_section(dso_name, ".debug_line"))
goto out; goto out;
dso->a2l = addr2line_subprocess_init(dso_name); dso->a2l = addr2line_subprocess_init(symbol_conf.addr2line_path,
dso_name);
a2l = dso->a2l; a2l = dso->a2l;
} }
......
...@@ -61,6 +61,7 @@ struct symbol_conf { ...@@ -61,6 +61,7 @@ struct symbol_conf {
*sym_list_str, *sym_list_str,
*col_width_list_str, *col_width_list_str,
*bt_stop_list_str; *bt_stop_list_str;
char *addr2line_path;
unsigned long time_quantum; unsigned long time_quantum;
struct strlist *dso_list, struct strlist *dso_list,
*comm_list, *comm_list,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment