diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index a04187582d5241..8d2fe1fd31e96d 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -134,6 +134,7 @@ enum perf_output_field { PERF_OUTPUT_CGROUP = 1ULL << 39, PERF_OUTPUT_RETIRE_LAT = 1ULL << 40, PERF_OUTPUT_DSOFF = 1ULL << 41, + PERF_OUTPUT_SYMLINE = 1ULL << 42, }; struct perf_script { @@ -178,6 +179,7 @@ struct output_option { {.str = "dsoff", .field = PERF_OUTPUT_DSOFF}, {.str = "addr", .field = PERF_OUTPUT_ADDR}, {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, + {.str = "symline", .field = PERF_OUTPUT_SYMLINE}, {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, {.str = "period", .field = PERF_OUTPUT_PERIOD}, {.str = "iregs", .field = PERF_OUTPUT_IREGS}, @@ -497,6 +499,11 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session) "selected.\n"); return -EINVAL; } + if (PRINT_FIELD(SYMLINE) && !PRINT_FIELD(SYM)) { + pr_err("Display of line offsets requested but symbol is not" + "selected.\n"); + return -EINVAL; + } if (PRINT_FIELD(DSO) && !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) { pr_err("Display of DSO requested but no address to convert.\n"); @@ -582,6 +589,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr) if (PRINT_FIELD(SYMOFFSET)) output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET; + if (PRINT_FIELD(SYMLINE)) + output[type].print_ip_opts |= EVSEL__PRINT_SYMLINE; + if (PRINT_FIELD(SRCLINE)) output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE; } diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 8719b3cb564661..464ace5b532033 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -119,6 +119,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, int print_dso = print_opts & EVSEL__PRINT_DSO; int print_dsoff = print_opts & EVSEL__PRINT_DSOFF; int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; + int print_symline = print_opts & EVSEL__PRINT_SYMLINE; int print_oneline = print_opts & EVSEL__PRINT_ONELINE; int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; @@ -167,7 +168,9 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, node_al.addr = addr; node_al.map = map__get(map); - if (print_symoffset) { + if (print_symline) { + printed += symbol__fprintf_symline_offs(sym, &node_al, fp); + } else if (print_symoffset) { printed += __symbol__fprintf_symname_offs(sym, &node_al, print_unknown_as_addr, true, fp); diff --git a/tools/perf/util/evsel_fprintf.h b/tools/perf/util/evsel_fprintf.h index c8a9fac2f2ddc0..9db9c46ff9dff7 100644 --- a/tools/perf/util/evsel_fprintf.h +++ b/tools/perf/util/evsel_fprintf.h @@ -27,6 +27,7 @@ int evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE #define EVSEL__PRINT_CALLCHAIN_ARROW (1<<7) #define EVSEL__PRINT_SKIP_IGNORED (1<<8) #define EVSEL__PRINT_DSOFF (1<<9) +#define EVSEL__PRINT_SYMLINE (1<<10) struct addr_location; struct perf_event_attr; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index af87c46b3f89e5..ff0834328fa46c 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -156,6 +156,10 @@ void symbol__elf_init(void); int symbol__annotation_init(void); struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name); +size_t __symbol__fprintf_sym_offs(const struct symbol *sym, + const struct addr_location *al, + bool unknown_as_addr, bool print_offsets, + bool print_line, FILE *fp); size_t __symbol__fprintf_symname_offs(const struct symbol *sym, const struct addr_location *al, bool unknown_as_addr, @@ -171,6 +175,8 @@ bool symbol__restricted_filename(const char *filename, const char *restricted_filename); int symbol__config_symfs(const struct option *opt __maybe_unused, const char *dir, int unset __maybe_unused); +size_t symbol__fprintf_symline_offs(const struct symbol *sym, + const struct addr_location *al, FILE *fp); struct symsrc; diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c index 088f4abf230fe7..e2165c898bd214 100644 --- a/tools/perf/util/symbol_fprintf.c +++ b/tools/perf/util/symbol_fprintf.c @@ -6,6 +6,7 @@ #include "dso.h" #include "map.h" #include "symbol.h" +#include "srcline.h" size_t symbol__fprintf(struct symbol *sym, FILE *fp) { @@ -16,22 +17,40 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp) sym->name); } -size_t __symbol__fprintf_symname_offs(const struct symbol *sym, - const struct addr_location *al, - bool unknown_as_addr, - bool print_offsets, FILE *fp) +size_t __symbol__fprintf_sym_offs(const struct symbol *sym, + const struct addr_location *al, + bool unknown_as_addr, bool print_offsets, + bool print_line, FILE *fp) { unsigned long offset; size_t length; if (sym) { length = fprintf(fp, "%s", sym->name); - if (al && print_offsets) { - if (al->addr < sym->end) - offset = al->addr - sym->start; - else - offset = al->addr - map__start(al->map) - sym->start; - length += fprintf(fp, "+0x%lx", offset); + if (al && (print_offsets || print_line)) { + if (print_line) { + int ret = 0; + char *srcline = map__srcline(al->map, al->addr, NULL); + if (srcline != SRCLINE_UNKNOWN) { + ret = fprintf(fp, "+%s", srcline); + if (ret > 0) + length += (size_t)ret; + } + zfree_srcline(&srcline); + srcline = map__srcline(al->map, sym->start, NULL); + if (srcline != SRCLINE_UNKNOWN) { + ret = fprintf(fp, "+%s", srcline); + if (ret > 0) + length += (size_t)ret; + } + zfree_srcline(&srcline); + } else { + if (al->addr < sym->end) + offset = al->addr - sym->start; + else + offset = al->addr - map__start(al->map) - sym->start; + length += fprintf(fp, "+0x%lx", offset); + } } return length; } else if (al && unknown_as_addr) @@ -40,6 +59,15 @@ size_t __symbol__fprintf_symname_offs(const struct symbol *sym, return fprintf(fp, "[unknown]"); } +size_t __symbol__fprintf_symname_offs(const struct symbol *sym, + const struct addr_location *al, + bool unknown_as_addr, bool print_offsets, + FILE *fp) +{ + return __symbol__fprintf_sym_offs(sym, al, unknown_as_addr, + print_offsets, false, fp); +} + size_t symbol__fprintf_symname_offs(const struct symbol *sym, const struct addr_location *al, FILE *fp) @@ -71,3 +99,9 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, } return ret; } + +size_t symbol__fprintf_symline_offs(const struct symbol *sym, + const struct addr_location *al, FILE *fp) +{ + return __symbol__fprintf_sym_offs(sym, al, false, false, true, fp); +} \ No newline at end of file