From 04e11960aa9a5edbe612dd8623190e341aedab35 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 24 Aug 2016 14:57:58 +0900 Subject: perf probe: Remove unused tracing_dir variable Remove unused tracing_dir variable from open_probe_events(). Signed-off-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/147201827792.5713.4165387506020511920.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-file.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 697ef66bff91..6f931e442f14 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -73,11 +73,10 @@ static void print_both_open_warning(int kerr, int uerr) static int open_probe_events(const char *trace_file, bool readwrite) { char buf[PATH_MAX]; - const char *tracing_dir = ""; int ret; - ret = e_snprintf(buf, PATH_MAX, "%s/%s%s", - tracing_path, tracing_dir, trace_file); + ret = e_snprintf(buf, PATH_MAX, "%s/%s", + tracing_path, trace_file); if (ret >= 0) { pr_debug("Opening %s write=%d\n", buf, readwrite); if (readwrite && !probe_event_dry_run) -- cgit v1.2.3 From ffe67c2fabf128122b30fbf0ac498928e171b0b3 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sun, 21 Aug 2016 15:57:33 +0800 Subject: perf tools: Fix error handling of lzma decompression lzma_decompress_to_file() never actually closes the file pointer, let's fix it. Signed-off-by: Shawn Lin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1471766253-1964-1-git-send-email-shawn.lin@rock-chips.com [ Make err = -1, the common case, set it to 0 before the error label ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/lzma.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c index 95a1acb61245..9ddea5cecd94 100644 --- a/tools/perf/util/lzma.c +++ b/tools/perf/util/lzma.c @@ -29,6 +29,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) lzma_action action = LZMA_RUN; lzma_stream strm = LZMA_STREAM_INIT; lzma_ret ret; + int err = -1; u8 buf_in[BUFSIZE]; u8 buf_out[BUFSIZE]; @@ -45,7 +46,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (ret != LZMA_OK) { pr_err("lzma: lzma_stream_decoder failed %s (%d)\n", lzma_strerror(ret), ret); - return -1; + goto err_fclose; } strm.next_in = NULL; @@ -60,7 +61,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (ferror(infile)) { pr_err("lzma: read error: %s\n", strerror(errno)); - return -1; + goto err_fclose; } if (feof(infile)) @@ -74,7 +75,7 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (writen(output_fd, buf_out, write_size) != write_size) { pr_err("lzma: write error: %s\n", strerror(errno)); - return -1; + goto err_fclose; } strm.next_out = buf_out; @@ -83,13 +84,15 @@ int lzma_decompress_to_file(const char *input, int output_fd) if (ret != LZMA_OK) { if (ret == LZMA_STREAM_END) - return 0; + break; pr_err("lzma: failed %s\n", lzma_strerror(ret)); - return -1; + goto err_fclose; } } + err = 0; +err_fclose: fclose(infile); - return 0; + return err; } -- cgit v1.2.3 From b01141f4f59ce56e5ed177a1fc70b3ba4d676aca Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 25 Aug 2016 16:09:21 -0300 Subject: perf annotate: Initialize the priv are in symbol__new() We need to initializa some fields (right now just a mutex) when we allocate the per symbol annotation struct, so do it at the symbol constructor instead of (ab)using the filter mechanism for that. This way we remove one of the few cases we have for that symbol filter, which will eventually led to removing it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-cvz34avlz1lez888lob95390@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 7 ++++--- tools/perf/builtin-report.c | 6 +++--- tools/perf/builtin-top.c | 4 +++- tools/perf/util/annotate.c | 7 ------- tools/perf/util/annotate.h | 1 - tools/perf/util/symbol.c | 25 ++++++++++++++++++++++++- tools/perf/util/symbol.h | 3 +++ 7 files changed, 37 insertions(+), 16 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 9c1034d81b4f..f07b23011b22 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -204,8 +204,6 @@ static int __cmd_annotate(struct perf_annotate *ann) struct perf_evsel *pos; u64 total_nr_samples; - machines__set_symbol_filter(&session->machines, symbol__annotate_init); - if (ann->cpu_list) { ret = perf_session__cpu_bitmap(session, ann->cpu_list, ann->cpu_bitmap); @@ -367,7 +365,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) if (annotate.session == NULL) return -1; - symbol_conf.priv_size = sizeof(struct annotation); + ret = symbol__annotation_init(); + if (ret < 0) + goto out_delete; + symbol_conf.try_vmlinux_path = true; ret = symbol__init(&annotate.session->header.env); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b9e046baa5fc..1a07c4cdf6ed 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -984,9 +984,9 @@ repeat: * implementation. */ if (ui__has_annotation()) { - symbol_conf.priv_size = sizeof(struct annotation); - machines__set_symbol_filter(&session->machines, - symbol__annotate_init); + ret = symbol__annotation_init(); + if (ret < 0) + goto error; /* * For searching by name on the "Browse map details". * providing it only in verbose mode not to bloat too diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a3223aa22213..e8ca8dc88af9 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1324,7 +1324,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (symbol_conf.cumulate_callchain && !callchain_param.order_set) callchain_param.order = ORDER_CALLER; - symbol_conf.priv_size = sizeof(struct annotation); + status = symbol__annotation_init(); + if (status < 0) + goto out_delete_evlist; symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init(NULL) < 0) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 25a9259a6a6e..1b59e3129216 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -491,13 +491,6 @@ static struct ins *ins__find(const char *name) return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); } -int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) -{ - struct annotation *notes = symbol__annotation(sym); - pthread_mutex_init(¬es->lock, NULL); - return 0; -} - int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index f67ccb027561..e96f4daed9b9 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -177,7 +177,6 @@ enum symbol_disassemble_errno { int symbol__strerror_disassemble(struct symbol *sym, struct map *map, int errnum, char *buf, size_t buflen); -int symbol__annotate_init(struct map *map, struct symbol *sym); int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool full_paths, int min_pcnt, int max_lines, int context); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 37e8d20ae03e..863d69c45b8a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -9,6 +9,7 @@ #include #include #include +#include "annotate.h" #include "build-id.h" #include "util.h" #include "debug.h" @@ -235,8 +236,13 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) if (sym == NULL) return NULL; - if (symbol_conf.priv_size) + if (symbol_conf.priv_size) { + if (symbol_conf.init_annotation) { + struct annotation *notes = (void *)sym; + pthread_mutex_init(¬es->lock, NULL); + } sym = ((void *)sym) + symbol_conf.priv_size; + } sym->start = start; sym->end = len ? start + len : start; @@ -1948,6 +1954,23 @@ static bool symbol__read_kptr_restrict(void) return value; } +int symbol__annotation_init(void) +{ + if (symbol_conf.initialized) { + pr_err("Annotation needs to be init before symbol__init()\n"); + return -1; + } + + if (symbol_conf.init_annotation) { + pr_warning("Annotation being initialized multiple times\n"); + return 0; + } + + symbol_conf.priv_size += sizeof(struct annotation); + symbol_conf.init_annotation = true; + return 0; +} + int symbol__init(struct perf_env *env) { const char *symfs; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 699f7cbcfe72..f6c54d3756da 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -88,6 +88,7 @@ struct symbol_conf { unsigned short priv_size; unsigned short nr_events; bool try_vmlinux_path, + init_annotation, force, ignore_vmlinux, ignore_vmlinux_buildid, @@ -277,6 +278,8 @@ struct perf_env; int symbol__init(struct perf_env *env); void symbol__exit(void); void symbol__elf_init(void); +int symbol__annotation_init(void); + struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); size_t __symbol__fprintf_symname_offs(const struct symbol *sym, const struct addr_location *al, -- cgit v1.2.3 From b55cc4ed202175777690860c482ca2ae5184458e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 30 Aug 2016 11:15:59 -0300 Subject: perf symbols: Rename ->ignore to ->idle Since this is the only use thus far, and this mechanism is in place for a long time. To clarify why symbols should be skipped or treated differently, name it for the only use it has. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-oqpf82x2svir611ry15paufd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 ++-- tools/perf/util/evsel_fprintf.c | 4 ++-- tools/perf/util/symbol.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e8ca8dc88af9..e0919006fcba 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -680,7 +680,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) return 1; if (symbol__is_idle(sym)) - sym->ignore = true; + sym->idle = 1; return 0; } @@ -783,7 +783,7 @@ static void perf_event__process_sample(struct perf_tool *tool, } } - if (al.sym == NULL || !al.sym->ignore) { + if (al.sym == NULL || !al.sym->idle) { struct hists *hists = evsel__hists(evsel); struct hist_entry_iter iter = { .evsel = evsel, diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 3674e77ad640..9111e0666950 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -122,7 +122,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, if (!node) break; - if (node->sym && node->sym->ignore) + if (node->sym && node->sym->idle) goto next; printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); @@ -181,7 +181,7 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, if (cursor != NULL) { printed += sample__fprintf_callchain(sample, left_alignment, print_opts, cursor, fp); - } else if (!(al->sym && al->sym->ignore)) { + } else if (!(al->sym && al->sym->idle)) { printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); if (print_ip) diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index f6c54d3756da..e54ee7c78ca3 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -57,7 +57,7 @@ struct symbol { u64 end; u16 namelen; u8 binding; - bool ignore; + u8 idle:1; u8 arch_sym; char name[0]; }; -- cgit v1.2.3 From fd2275984d6e29c6737646ff39dd3de87a03f300 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 31 Aug 2016 10:04:27 -0300 Subject: perf probe: Do not use map_load filters for function It is simpler to just do the loop, no need for globals and the last user of such facility disappears. Testing: # perf probe -F [a-z]*recvmsg aead_recvmsg compat_SyS_recvmsg compat_sys_recvmsg hash_recvmsg inet_recvmsg kernel_recvmsg netlink_recvmsg packet_recvmsg ping_recvmsg raw_recvmsg rawv6_recvmsg rng_recvmsg security_socket_recvmsg selinux_socket_recvmsg skcipher_recvmsg sock_common_recvmsg sock_no_recvmsg sock_recvmsg sys_recvmsg tcp_recvmsg udp_recvmsg udpv6_recvmsg unix_dgram_recvmsg unix_seqpacket_recvmsg unix_stream_recvmsg # Without filters: # perf probe -F | tail -5 zswap_pool_create zswap_pool_current zswap_update_total_size zswap_writeback_entry zswap_zpool_param_set # # perf probe -F | wc -l 33311 # Acked-by: Masami Hiramatsu Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20160831130427.GA13095@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 28733962cd80..0bed2ee16292 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -3289,24 +3289,10 @@ out: return ret; } -/* TODO: don't use a global variable for filter ... */ -static struct strfilter *available_func_filter; - -/* - * If a symbol corresponds to a function with global binding and - * matches filter return 0. For all others return 1. - */ -static int filter_available_functions(struct map *map __maybe_unused, - struct symbol *sym) -{ - if (strfilter__compare(available_func_filter, sym->name)) - return 0; - return 1; -} - int show_available_funcs(const char *target, struct strfilter *_filter, bool user) { + struct rb_node *nd; struct map *map; int ret; @@ -3324,9 +3310,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, return -EINVAL; } - /* Load symbols with given filter */ - available_func_filter = _filter; - ret = map__load(map, filter_available_functions); + ret = map__load(map, NULL); if (ret) { if (ret == -2) { char *str = strfilter__string(_filter); @@ -3343,7 +3327,14 @@ int show_available_funcs(const char *target, struct strfilter *_filter, /* Show all (filtered) symbols */ setup_pager(); - dso__fprintf_symbols_by_name(map->dso, map->type, stdout); + + for (nd = rb_first(&map->dso->symbol_names[map->type]); nd; nd = rb_next(nd)) { + struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); + + if (strfilter__compare(_filter, pos->sym.name)) + printf("%s\n", pos->sym.name); + } + end: if (user) { map__put(map); -- cgit v1.2.3 From 2a8d41b46540f224d77c255b5cc042d145e81b83 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 30 Aug 2016 13:41:02 +0200 Subject: perf symbols: Demangle symbols for synthesized @plt entries. The symbols in the synthesized @plt entries where not demangled before, i.e. we could end up with entries such as: $ perf report Samples: 7K of event 'cycles:ppp', Event count (approx.): 6223833141 Children Self Command Shared Object Symbol - 93.63% 28.89% lab_mandelbrot lab_mandelbrot [.] main - 73.81% main - 33.57% hypot 27.76% __hypot_finite 15.97% __muldc3 2.90% __muldc3@plt 2.40% _ZNK6QImage6heightEv@plt + 2.14% QColor::rgb 1.94% _ZNK6QImage5widthEv@plt 1.92% cabs@plt This patch remedies this issue by also applying demangling to the synthesized symbols. The output for the above is now: $ perf report Samples: 7K of event 'cycles:ppp', Event count (approx.): 6223833141 Children Self Command Shared Object Symbol - 93.63% 28.89% lab_mandelbrot lab_mandelbrot [.] main - 73.81% main - 33.57% hypot 27.76% __hypot_finite 15.97% __muldc3 2.90% __muldc3@plt 2.40% QImage::height() const@plt + 2.14% QColor::rgb 1.94% QImage::width() const@plt 1.92% cabs@plt Signed-off-by: Milian Wolff LPU-Reference: 20160830114102.30863-1-milian.wolff@kdab.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 81 ++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index a811c13a74d6..fbe31eff1beb 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -206,6 +206,37 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, return NULL; } +static bool want_demangle(bool is_kernel_sym) +{ + return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; +} + +static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name) +{ + int demangle_flags = verbose ? (DMGL_PARAMS | DMGL_ANSI) : DMGL_NO_OPTS; + char *demangled = NULL; + + /* + * We need to figure out if the object was created from C++ sources + * DWARF DW_compile_unit has this, but we don't always have access + * to it... + */ + if (!want_demangle(dso->kernel || kmodule)) + return demangled; + + demangled = bfd_demangle(NULL, elf_name, demangle_flags); + if (demangled == NULL) + demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET); + else if (rust_is_mangled(demangled)) + /* + * Input to Rust demangling is the BFD-demangled + * name which it Rust-demangles in place. + */ + rust_demangle_sym(demangled); + + return demangled; +} + #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ idx < nr_entries; \ @@ -301,11 +332,19 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map * elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_rel_entries) { + const char *elf_name = NULL; + char *demangled = NULL; symidx = GELF_R_SYM(pos->r_info); plt_offset += shdr_plt.sh_entsize; gelf_getsym(syms, symidx, &sym); + + elf_name = elf_sym__name(&sym, symstrs); + demangled = demangle_sym(dso, 0, elf_name); + if (demangled != NULL) + elf_name = demangled; snprintf(sympltname, sizeof(sympltname), - "%s@plt", elf_sym__name(&sym, symstrs)); + "%s@plt", elf_name); + free(demangled); f = symbol__new(plt_offset, shdr_plt.sh_entsize, STB_GLOBAL, sympltname); @@ -323,11 +362,19 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map * GElf_Rel pos_mem, *pos; elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_rel_entries) { + const char *elf_name = NULL; + char *demangled = NULL; symidx = GELF_R_SYM(pos->r_info); plt_offset += shdr_plt.sh_entsize; gelf_getsym(syms, symidx, &sym); + + elf_name = elf_sym__name(&sym, symstrs); + demangled = demangle_sym(dso, 0, elf_name); + if (demangled != NULL) + elf_name = demangled; snprintf(sympltname, sizeof(sympltname), - "%s@plt", elf_sym__name(&sym, symstrs)); + "%s@plt", elf_name); + free(demangled); f = symbol__new(plt_offset, shdr_plt.sh_entsize, STB_GLOBAL, sympltname); @@ -775,11 +822,6 @@ static u64 ref_reloc(struct kmap *kmap) return 0; } -static bool want_demangle(bool is_kernel_sym) -{ - return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; -} - void __weak arch__sym_update(struct symbol *s __maybe_unused, GElf_Sym *sym __maybe_unused) { } @@ -1070,29 +1112,10 @@ int dso__load_sym(struct dso *dso, struct map *map, sym.st_value -= shdr.sh_addr - shdr.sh_offset; } new_symbol: - /* - * We need to figure out if the object was created from C++ sources - * DWARF DW_compile_unit has this, but we don't always have access - * to it... - */ - if (want_demangle(dso->kernel || kmodule)) { - int demangle_flags = DMGL_NO_OPTS; - if (verbose) - demangle_flags = DMGL_PARAMS | DMGL_ANSI; - - demangled = bfd_demangle(NULL, elf_name, demangle_flags); - if (demangled == NULL) - demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET); - else if (rust_is_mangled(demangled)) - /* - * Input to Rust demangling is the BFD-demangled - * name which it Rust-demangles in place. - */ - rust_demangle_sym(demangled); + demangled = demangle_sym(dso, kmodule, elf_name); + if (demangled != NULL) + elf_name = demangled; - if (demangled != NULL) - elf_name = demangled; - } f = symbol__new(sym.st_value, sym.st_size, GELF_ST_BIND(sym.st_info), elf_name); free(demangled); -- cgit v1.2.3 From 893c5c798be99bcff5b235402dbd21e5aa03d76e Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 30 Aug 2016 15:41:06 +0200 Subject: perf config: Show default report configuration in example and docs Signed-off-by: Milian Wolff LPU-Reference: 20160830134106.21240-2-milian.wolff@kdab.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-config.txt | 8 ++++++++ tools/perf/Documentation/perfconfig.example | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 68c89190e79c..cb081ac59fd1 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -110,6 +110,14 @@ Given a $HOME/.perfconfig like this: order = caller sort-key = function + [report] + # Defaults + sort-order = comm,dso,symbol + percent-limit = 0 + queue-size = 0 + children = true + group = true + Variables ~~~~~~~~~ diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example index 1d8d5bc4cd2d..2b477c1d1efe 100644 --- a/tools/perf/Documentation/perfconfig.example +++ b/tools/perf/Documentation/perfconfig.example @@ -27,3 +27,12 @@ use_offset = true jump_arrows = true show_nr_jumps = false + +[report] + + # Defaults + sort-order = comm,dso,symbol + percent-limit = 0 + queue-size = 0 + children = true + group = true -- cgit v1.2.3 From 1c20b1d15473a91e2fccecbcd2809d80ff4b4924 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 26 Aug 2016 01:24:27 +0900 Subject: perf probe: Show trace event definition Add --definition/-D option for showing the trace-event definition in stdout. This can be useful in debugging or combined with a shell script. e.g. ---- # perf probe --definition 'do_sys_open $params' p:probe/do_sys_open _text+2261728 dfd=%di:s32 filename=%si:u64 flags=%dx:s32 mode=%cx:u16 ---- Suggested-and-Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/147214226712.23638.2240534040014013658.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-probe.txt | 7 +++++ tools/perf/builtin-probe.c | 26 ++++++++++++++----- tools/perf/util/probe-event.c | 46 +++++++++++++++++++++++++++++++++ tools/perf/util/probe-event.h | 1 + 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index f37d123d5dac..56db4d40d27e 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -21,6 +21,8 @@ or 'perf probe' [options] --vars='PROBEPOINT' or 'perf probe' [options] --funcs +or +'perf probe' [options] --definition='PROBE' [...] DESCRIPTION ----------- @@ -96,6 +98,11 @@ OPTIONS can also list functions in a user space executable / shared library. This also can accept a FILTER rule argument. +-D:: +--definition=:: + Show trace-event definition converted from given probe-event instead + of write it into tracing/[k,u]probe_events. + --filter=FILTER:: (Only for --vars and --funcs) Set filter. FILTER is a combination of glob pattern, see FILTER PATTERN for detail. diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index ee5b42173ba3..7a3d8c47ed29 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -326,6 +326,11 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs) if (ret < 0) goto out_cleanup; + if (params.command == 'D') { /* it shows definition */ + ret = show_probe_trace_events(pevs, npevs); + goto out_cleanup; + } + ret = apply_perf_probe_events(pevs, npevs); if (ret < 0) goto out_cleanup; @@ -454,6 +459,14 @@ out: return ret; } +#ifdef HAVE_DWARF_SUPPORT +#define PROBEDEF_STR \ + "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]" +#else +#define PROBEDEF_STR "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]" +#endif + + static int __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) { @@ -479,13 +492,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) opt_set_filter_with_command, DEFAULT_LIST_FILTER), OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", opt_set_filter_with_command), - OPT_CALLBACK('a', "add", NULL, -#ifdef HAVE_DWARF_SUPPORT - "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" - " [[NAME=]ARG ...]", -#else - "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]", -#endif + OPT_CALLBACK('a', "add", NULL, PROBEDEF_STR, "probe point definition, where\n" "\t\tGROUP:\tGroup name (optional)\n" "\t\tEVENT:\tEvent name\n" @@ -503,6 +510,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n", #endif opt_add_probe_event), + OPT_CALLBACK('D', "definition", NULL, PROBEDEF_STR, + "Show trace event definition of given traceevent for k/uprobe_events.", + opt_add_probe_event), OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events" " with existing name"), OPT_CALLBACK('L', "line", NULL, @@ -548,6 +558,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE); + set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE); #ifdef HAVE_DWARF_SUPPORT set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); @@ -644,6 +655,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) } break; case 'a': + case 'D': /* Ensure the last given target is used */ if (params.target && !params.target_used) { pr_err(" Error: -x/-m must follow the probe definitions.\n"); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 0bed2ee16292..4a49cb8ce7ab 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -3207,6 +3207,52 @@ int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs) return 0; } +static int show_probe_trace_event(struct probe_trace_event *tev) +{ + char *buf = synthesize_probe_trace_command(tev); + + if (!buf) { + pr_debug("Failed to synthesize probe trace event.\n"); + return -EINVAL; + } + + /* Showing definition always go stdout */ + printf("%s\n", buf); + free(buf); + + return 0; +} + +int show_probe_trace_events(struct perf_probe_event *pevs, int npevs) +{ + struct strlist *namelist = strlist__new(NULL, NULL); + struct probe_trace_event *tev; + struct perf_probe_event *pev; + int i, j, ret = 0; + + if (!namelist) + return -ENOMEM; + + for (j = 0; j < npevs && !ret; j++) { + pev = &pevs[j]; + for (i = 0; i < pev->ntevs && !ret; i++) { + tev = &pev->tevs[i]; + /* Skip if the symbol is out of .text or blacklisted */ + if (!tev->point.symbol && !pev->uprobes) + continue; + + /* Set new name for tev (and update namelist) */ + ret = probe_trace_event__set_name(tev, pev, + namelist, true); + if (!ret) + ret = show_probe_trace_event(tev); + } + } + strlist__delete(namelist); + + return ret; +} + int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int i, ret = 0; diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index f4f45db77c1c..62094082d940 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -147,6 +147,7 @@ int line_range__init(struct line_range *lr); int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); +int show_probe_trace_events(struct perf_probe_event *pevs, int npevs); void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); int del_perf_probe_events(struct strfilter *filter); -- cgit v1.2.3 From 428aff82e92a29da0e4276623180f9a98f2d5b16 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 26 Aug 2016 01:24:42 +0900 Subject: perf probe: Ignore vmlinux buildid if offline kernel is given Ignore the buildid of running kernel when both of --definition and --vmlinux is given because that kernel should be off-line. This also skips post-processing of kprobe event for relocating symbol and checking blacklist, because it can not be done on off-line kernel. E.g. without this fix perf shows an error as below ---- $ perf probe --vmlinux=./vmlinux-arm --definition do_sys_open ./vmlinux-arm with build id 7a1f76dd56e9c4da707cd3d6333f50748141434b not found, continuing without symbols Failed to find symbol do_sys_open in kernel Error: Failed to add events. ---- with this fix, we can get the definition ---- $ perf probe --vmlinux=./vmlinux-arm --definition do_sys_open p:probe/do_sys_open do_sys_open+0 ---- Signed-off-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/147214228193.23638.12581984840822162131.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-probe.txt | 2 ++ tools/perf/builtin-probe.c | 10 +++++++++- tools/perf/util/probe-event.c | 4 ++++ tools/perf/util/symbol-elf.c | 2 +- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 56db4d40d27e..e6c9902c6d82 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -36,6 +36,8 @@ OPTIONS -k:: --vmlinux=PATH:: Specify vmlinux path which has debuginfo (Dwarf binary). + Only when using this with --definition, you can give an offline + vmlinux file. -m:: --module=MODNAME|PATH:: diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 7a3d8c47ed29..b4220cd4acd8 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -654,8 +654,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) return ret; } break; - case 'a': case 'D': + /* + * If user gives offline vmlinux, ignore buildid, since + * --definition doesn't change running kernel. + */ + if (symbol_conf.vmlinux_name) + symbol_conf.ignore_vmlinux_buildid = true; + /* fall through */ + case 'a': + /* Ensure the last given target is used */ if (params.target && !params.target_used) { pr_err(" Error: -x/-m must follow the probe definitions.\n"); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 4a49cb8ce7ab..8a1e9e67614f 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -674,6 +674,10 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs, char *tmp; int i, skipped = 0; + /* Skip post process if the target is an offline kernel */ + if (symbol_conf.ignore_vmlinux_buildid) + return 0; + reloc_sym = kernel_get_ref_reloc_sym(); if (!reloc_sym) { pr_warning("Relocated base symbol is not found!\n"); diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index fbe31eff1beb..e680371bd5c9 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -732,7 +732,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, } /* Always reject images with a mismatched build-id: */ - if (dso->has_build_id) { + if (dso->has_build_id && !symbol_conf.ignore_vmlinux_buildid) { u8 build_id[BUILD_ID_SIZE]; if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) { -- cgit v1.2.3 From 293d5b43948309434568f4dcbb36cce4c3c51bd5 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 26 Aug 2016 01:24:57 +0900 Subject: perf probe: Support probing on offline cross-arch binary Support probing on offline cross-architecture binary by adding getting the target machine arch from ELF and choose correct register string for the machine. Here is an example: ----- $ perf probe --vmlinux=./vmlinux-arm --definition 'do_sys_open $params' p:probe/do_sys_open do_sys_open+0 dfd=%r5:s32 filename=%r1:u32 flags=%r6:s32 mode=%r3:u16 ----- Here, we can get probe/do_sys_open from above and append it to to the target machine's tracing/kprobe_events file in the tracefs mountput, usually /sys/kernel/debug/tracing/kprobe_events (or /sys/kernel/tracing/kprobe_events). Signed-off-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/147214229717.23638.6440579792548044658.stgit@devbox [ Add definition for EM_AARCH64 to fix the build on at least centos 6, debian 7 & ubuntu 12.04.5 ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/include/dwarf-regs-table.h | 9 ++++ tools/perf/arch/arm64/include/dwarf-regs-table.h | 13 +++++ tools/perf/arch/powerpc/include/dwarf-regs-table.h | 27 ++++++++++ tools/perf/arch/s390/include/dwarf-regs-table.h | 8 +++ tools/perf/arch/sh/include/dwarf-regs-table.h | 25 +++++++++ tools/perf/arch/sparc/include/dwarf-regs-table.h | 18 +++++++ tools/perf/arch/x86/include/dwarf-regs-table.h | 14 +++++ tools/perf/arch/xtensa/include/dwarf-regs-table.h | 8 +++ tools/perf/util/Build | 1 + tools/perf/util/dwarf-regs.c | 59 ++++++++++++++++++++++ tools/perf/util/include/dwarf-regs.h | 6 +++ tools/perf/util/probe-finder.c | 27 ++++++---- tools/perf/util/probe-finder.h | 1 + 13 files changed, 205 insertions(+), 11 deletions(-) create mode 100644 tools/perf/arch/arm/include/dwarf-regs-table.h create mode 100644 tools/perf/arch/arm64/include/dwarf-regs-table.h create mode 100644 tools/perf/arch/powerpc/include/dwarf-regs-table.h create mode 100644 tools/perf/arch/s390/include/dwarf-regs-table.h create mode 100644 tools/perf/arch/sh/include/dwarf-regs-table.h create mode 100644 tools/perf/arch/sparc/include/dwarf-regs-table.h create mode 100644 tools/perf/arch/x86/include/dwarf-regs-table.h create mode 100644 tools/perf/arch/xtensa/include/dwarf-regs-table.h create mode 100644 tools/perf/util/dwarf-regs.c diff --git a/tools/perf/arch/arm/include/dwarf-regs-table.h b/tools/perf/arch/arm/include/dwarf-regs-table.h new file mode 100644 index 000000000000..f298d034c37b --- /dev/null +++ b/tools/perf/arch/arm/include/dwarf-regs-table.h @@ -0,0 +1,9 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const arm_regstr_tbl[] = { + "%r0", "%r1", "%r2", "%r3", "%r4", + "%r5", "%r6", "%r7", "%r8", "%r9", "%r10", + "%fp", "%ip", "%sp", "%lr", "%pc", +}; +#endif diff --git a/tools/perf/arch/arm64/include/dwarf-regs-table.h b/tools/perf/arch/arm64/include/dwarf-regs-table.h new file mode 100644 index 000000000000..26759363f921 --- /dev/null +++ b/tools/perf/arch/arm64/include/dwarf-regs-table.h @@ -0,0 +1,13 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const aarch64_regstr_tbl[] = { + "%r0", "%r1", "%r2", "%r3", "%r4", + "%r5", "%r6", "%r7", "%r8", "%r9", + "%r10", "%r11", "%r12", "%r13", "%r14", + "%r15", "%r16", "%r17", "%r18", "%r19", + "%r20", "%r21", "%r22", "%r23", "%r24", + "%r25", "%r26", "%r27", "%r28", "%r29", + "%lr", "%sp", +}; +#endif diff --git a/tools/perf/arch/powerpc/include/dwarf-regs-table.h b/tools/perf/arch/powerpc/include/dwarf-regs-table.h new file mode 100644 index 000000000000..db4730f5585c --- /dev/null +++ b/tools/perf/arch/powerpc/include/dwarf-regs-table.h @@ -0,0 +1,27 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +/* + * Reference: + * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html + * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf + */ +#define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg + +static const char * const powerpc_regstr_tbl[] = { + "%gpr0", "%gpr1", "%gpr2", "%gpr3", "%gpr4", + "%gpr5", "%gpr6", "%gpr7", "%gpr8", "%gpr9", + "%gpr10", "%gpr11", "%gpr12", "%gpr13", "%gpr14", + "%gpr15", "%gpr16", "%gpr17", "%gpr18", "%gpr19", + "%gpr20", "%gpr21", "%gpr22", "%gpr23", "%gpr24", + "%gpr25", "%gpr26", "%gpr27", "%gpr28", "%gpr29", + "%gpr30", "%gpr31", + REG_DWARFNUM_NAME(msr, 66), + REG_DWARFNUM_NAME(ctr, 109), + REG_DWARFNUM_NAME(link, 108), + REG_DWARFNUM_NAME(xer, 101), + REG_DWARFNUM_NAME(dar, 119), + REG_DWARFNUM_NAME(dsisr, 118), +}; + +#endif diff --git a/tools/perf/arch/s390/include/dwarf-regs-table.h b/tools/perf/arch/s390/include/dwarf-regs-table.h new file mode 100644 index 000000000000..9da74a933bd6 --- /dev/null +++ b/tools/perf/arch/s390/include/dwarf-regs-table.h @@ -0,0 +1,8 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const s390_regstr_tbl[] = { + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", +}; +#endif diff --git a/tools/perf/arch/sh/include/dwarf-regs-table.h b/tools/perf/arch/sh/include/dwarf-regs-table.h new file mode 100644 index 000000000000..3a2deaf3dab4 --- /dev/null +++ b/tools/perf/arch/sh/include/dwarf-regs-table.h @@ -0,0 +1,25 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +const char * const sh_regstr_tbl[] = { + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "pc", + "pr", +}; + +#endif diff --git a/tools/perf/arch/sparc/include/dwarf-regs-table.h b/tools/perf/arch/sparc/include/dwarf-regs-table.h new file mode 100644 index 000000000000..12c07619002c --- /dev/null +++ b/tools/perf/arch/sparc/include/dwarf-regs-table.h @@ -0,0 +1,18 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const sparc_regstr_tbl[] = { + "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", + "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", + "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", + "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39", + "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47", + "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55", + "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63", +}; +#endif diff --git a/tools/perf/arch/x86/include/dwarf-regs-table.h b/tools/perf/arch/x86/include/dwarf-regs-table.h new file mode 100644 index 000000000000..39ac7cbb525b --- /dev/null +++ b/tools/perf/arch/x86/include/dwarf-regs-table.h @@ -0,0 +1,14 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const x86_32_regstr_tbl[] = { + "%ax", "%cx", "%dx", "%bx", "$stack",/* Stack address instead of %sp */ + "%bp", "%si", "%di", +}; + +static const char * const x86_64_regstr_tbl[] = { + "%ax", "dx", "%cx", "%bx", "%si", "%di", + "%bp", "%sp", "%r8", "%r9", "%r10", "%r11", + "%r12", "%r13", "%r14", "%r15", +}; +#endif diff --git a/tools/perf/arch/xtensa/include/dwarf-regs-table.h b/tools/perf/arch/xtensa/include/dwarf-regs-table.h new file mode 100644 index 000000000000..aa0444a33fe6 --- /dev/null +++ b/tools/perf/arch/xtensa/include/dwarf-regs-table.h @@ -0,0 +1,8 @@ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +static const char * const xtensa_regstr_tbl[] = { + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15", +}; +#endif diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 91c5f6e1af59..f1a6d17c5a37 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -98,6 +98,7 @@ endif libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o +libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c new file mode 100644 index 000000000000..62bc4a86a970 --- /dev/null +++ b/tools/perf/util/dwarf-regs.c @@ -0,0 +1,59 @@ +/* + * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. + * + * Written by: Masami Hiramatsu + */ + +#include +#include +#include +#include + +#ifndef EM_AARCH64 +#define EM_AARCH64 183 /* ARM 64 bit */ +#endif + +/* Define const char * {arch}_register_tbl[] */ +#define DEFINE_DWARF_REGSTR_TABLE +#include "../arch/x86/include/dwarf-regs-table.h" +#include "../arch/arm/include/dwarf-regs-table.h" +#include "../arch/arm64/include/dwarf-regs-table.h" +#include "../arch/sh/include/dwarf-regs-table.h" +#include "../arch/powerpc/include/dwarf-regs-table.h" +#include "../arch/s390/include/dwarf-regs-table.h" +#include "../arch/sparc/include/dwarf-regs-table.h" +#include "../arch/xtensa/include/dwarf-regs-table.h" + +#define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL) + +/* Return architecture dependent register string (for kprobe-tracer) */ +const char *get_dwarf_regstr(unsigned int n, unsigned int machine) +{ + switch (machine) { + case EM_NONE: /* Generic arch - use host arch */ + return get_arch_regstr(n); + case EM_386: + return __get_dwarf_regstr(x86_32_regstr_tbl, n); + case EM_X86_64: + return __get_dwarf_regstr(x86_64_regstr_tbl, n); + case EM_ARM: + return __get_dwarf_regstr(arm_regstr_tbl, n); + case EM_AARCH64: + return __get_dwarf_regstr(aarch64_regstr_tbl, n); + case EM_SH: + return __get_dwarf_regstr(sh_regstr_tbl, n); + case EM_S390: + return __get_dwarf_regstr(s390_regstr_tbl, n); + case EM_PPC: + case EM_PPC64: + return __get_dwarf_regstr(powerpc_regstr_tbl, n); + case EM_SPARC: + case EM_SPARCV9: + return __get_dwarf_regstr(sparc_regstr_tbl, n); + case EM_XTENSA: + return __get_dwarf_regstr(xtensa_regstr_tbl, n); + default: + pr_err("ELF MACHINE %x is not supported.\n", machine); + } + return NULL; +} diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h index 07c644ed64c4..43bfd8da7919 100644 --- a/tools/perf/util/include/dwarf-regs.h +++ b/tools/perf/util/include/dwarf-regs.h @@ -3,6 +3,12 @@ #ifdef HAVE_DWARF_SUPPORT const char *get_arch_regstr(unsigned int n); +/* + * get_dwarf_regstr - Returns ftrace register string from DWARF regnum + * n: DWARF register number + * machine: ELF machine signature (EM_*) + */ +const char *get_dwarf_regstr(unsigned int n, unsigned int machine); #endif #ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ac4740f8ee3a..508b61c6e5fb 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -171,6 +171,7 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) */ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, Dwarf_Op *fb_ops, Dwarf_Die *sp_die, + unsigned int machine, struct probe_trace_arg *tvar) { Dwarf_Attribute attr; @@ -266,7 +267,7 @@ static_var: if (!tvar) return ret2; - regs = get_arch_regstr(regn); + regs = get_dwarf_regstr(regn, machine); if (!regs) { /* This should be a bug in DWARF or this tool */ pr_warning("Mapping for the register number %u " @@ -543,7 +544,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) dwarf_diename(vr_die)); ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, - &pf->sp_die, pf->tvar); + &pf->sp_die, pf->machine, pf->tvar); if (ret == -ENOENT || ret == -EINVAL) { pr_err("Failed to find the location of the '%s' variable at this address.\n" " Perhaps it has been optimized out.\n" @@ -1106,11 +1107,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg, struct probe_finder *pf) { int ret = 0; - -#if _ELFUTILS_PREREQ(0, 142) Elf *elf; GElf_Ehdr ehdr; - GElf_Shdr shdr; if (pf->cfi_eh || pf->cfi_dbg) return debuginfo__find_probe_location(dbg, pf); @@ -1123,11 +1121,18 @@ static int debuginfo__find_probes(struct debuginfo *dbg, if (gelf_getehdr(elf, &ehdr) == NULL) return -EINVAL; - if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && - shdr.sh_type == SHT_PROGBITS) - pf->cfi_eh = dwarf_getcfi_elf(elf); + pf->machine = ehdr.e_machine; + +#if _ELFUTILS_PREREQ(0, 142) + do { + GElf_Shdr shdr; + + if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && + shdr.sh_type == SHT_PROGBITS) + pf->cfi_eh = dwarf_getcfi_elf(elf); - pf->cfi_dbg = dwarf_getcfi(dbg->dbg); + pf->cfi_dbg = dwarf_getcfi(dbg->dbg); + } while (0); #endif ret = debuginfo__find_probe_location(dbg, pf); @@ -1155,7 +1160,7 @@ static int copy_variables_cb(Dwarf_Die *die_mem, void *data) (tag == DW_TAG_variable && vf->vars)) { if (convert_variable_location(die_mem, vf->pf->addr, vf->pf->fb_ops, &pf->sp_die, - NULL) == 0) { + pf->machine, NULL) == 0) { vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); if (vf->args[vf->nargs].var == NULL) { vf->ret = -ENOMEM; @@ -1318,7 +1323,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) tag == DW_TAG_variable) { ret = convert_variable_location(die_mem, af->pf.addr, af->pf.fb_ops, &af->pf.sp_die, - NULL); + af->pf.machine, NULL); if (ret == 0 || ret == -ERANGE) { int ret2; bool externs = !af->child; diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 51137fccb9c8..f1d8558f498e 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -80,6 +80,7 @@ struct probe_finder { Dwarf_CFI *cfi_dbg; #endif Dwarf_Op *fb_ops; /* Frame base attribute */ + unsigned int machine; /* Target machine arch */ struct perf_probe_arg *pvar; /* Current target variable */ struct probe_trace_arg *tvar; /* Current result variable */ }; -- cgit v1.2.3 From e50243bbeb528e92e31e03e560b557737c9def3c Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 26 Aug 2016 23:57:58 +0900 Subject: perf probe: Ignore vmlinux Build-id when offline vmlinux given Ignore vmlinux build-id when user gives offline vmlinux if the command does not affect running kernel. perf-probe has several actions some of them does not change the running kernel, like --lines, --vars, and --funcs. e.g. ----- $ ./perf probe -k ./vmlinux-arm -V do_sys_open:14 Available variables at do_sys_open:14 @ char* filename int dfd int fd int flags struct filename* tmp struct open_flags op umode_t mode ----- Signed-off-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/147222347320.5088.2582658035296667520.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index b4220cd4acd8..f87996b0cb29 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -611,6 +611,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) */ symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); + /* + * Except for --list, --del and --add, other command doesn't depend + * nor change running kernel. So if user gives offline vmlinux, + * ignore its buildid. + */ + if (!strchr("lda", params.command) && symbol_conf.vmlinux_name) + symbol_conf.ignore_vmlinux_buildid = true; + switch (params.command) { case 'l': if (params.uprobes) { @@ -655,13 +663,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) } break; case 'D': - /* - * If user gives offline vmlinux, ignore buildid, since - * --definition doesn't change running kernel. - */ - if (symbol_conf.vmlinux_name) - symbol_conf.ignore_vmlinux_buildid = true; - /* fall through */ case 'a': /* Ensure the last given target is used */ -- cgit v1.2.3 From e267769ed4d22144d317d934cbce382cc7a8cca0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 10:26:49 -0300 Subject: perf test vmlinux: Clarify which -v lines are errors or warning When the 'perf test -v vmlinux' test fails, it is not clear which of the lines are errors or warnings, clarify that adding ERR/WARN prefixes: # perf test -F -v 1 1: vmlinux symtab matches kallsyms : --- start --- Looking at the vmlinux_path (8 entries long) Using /lib/modules/4.8.0-rc4+/build/vmlinux for symbols ERR : 0xffffffffb7001000: diff name v: xen_hypercall_set_trap_table k: hypercall_page WARN: 0xffffffffb7077970: diff end addr for aesni_gcm_dec v: 0xffffffffb707a2f2 k: 0xffffffffb7077a02 WARN: 0xffffffffb707a300: diff end addr for aesni_gcm_enc v: 0xffffffffb707cc03 k: 0xffffffffb707a392 WARN: 0xffffffffb707f950: diff end addr for aesni_gcm_enc_avx_gen2 v: 0xffffffffb7084ef6 k: 0xffffffffb707f9c3 WARN: 0xffffffffb7084f00: diff end addr for aesni_gcm_dec_avx_gen2 v: 0xffffffffb708a691 k: 0xffffffffb7084f73 WARN: 0xffffffffb708aa10: diff end addr for aesni_gcm_enc_avx_gen4 v: 0xffffffffb708f844 k: 0xffffffffb708aa83 WARN: 0xffffffffb708f850: diff end addr for aesni_gcm_dec_avx_gen4 v: 0xffffffffb709486f k: 0xffffffffb708f8c3 ERR : 0xffffffffb71a6e50: diff name v: perf_pmu_commit_txn.part.98 k: perf_pmu_cancel_txn.part.97 ERR : 0xffffffffb752e480: diff name v: wakeup_expire_count_show.part.5 k: wakeup_active_count_show.part.7 ERR : 0xffffffffb76e8d00: diff name v: phys_switch_id_show.part.11 k: phys_port_name_show.part.12 WARN: Maps only in vmlinux: ffffffffb7d7d000-ffffffffb7eeaac8 117d000 [kernel].init.text ffffffffb7eeaac8-ffffffffc03ad000 12eaac8 [kernel].exit.text WARN: Maps in vmlinux with a different name in kallsyms: WARN: Maps only in kallsyms: ---- end ---- vmlinux symtab matches kallsyms: FAILED! # Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-n5ml8m7y9x8kzvxt09ipku88@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/vmlinux-kallsyms.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index e63abab7d5a1..6bd5bf980de2 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -143,7 +143,7 @@ next_pair: */ s64 skew = mem_end - UM(pair->end); if (llabs(skew) >= page_size) - pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", + pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", mem_start, sym->name, mem_end, UM(pair->end)); @@ -161,15 +161,15 @@ next_pair: if (UM(pair->start) == mem_start) goto next_pair; - pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", + pr_debug("ERR : %#" PRIx64 ": diff name v: %s k: %s\n", mem_start, sym->name, pair->name); } else { - pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", + pr_debug("ERR : %#" PRIx64 ": diff name v: %s k: %s\n", mem_start, sym->name, first_pair->name); } } } else - pr_debug("%#" PRIx64 ": %s not on kallsyms\n", + pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n", mem_start, sym->name); err = -1; @@ -178,7 +178,7 @@ next_pair: if (!verbose) goto out; - pr_info("Maps only in vmlinux:\n"); + pr_info("WARN: Maps only in vmlinux:\n"); for (map = maps__first(maps); map; map = map__next(map)) { struct map * @@ -198,7 +198,7 @@ next_pair: map__fprintf(map, stderr); } - pr_info("Maps in vmlinux with a different name in kallsyms:\n"); + pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); for (map = maps__first(maps); map; map = map__next(map)) { struct map *pair; @@ -212,17 +212,17 @@ next_pair: if (pair->start == mem_start) { pair->priv = 1; - pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", + pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", map->start, map->end, map->pgoff, map->dso->name); if (mem_end != pair->end) - pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64, + pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, pair->start, pair->end, pair->pgoff); pr_info(" %s\n", pair->dso->name); pair->priv = 1; } } - pr_info("Maps only in kallsyms:\n"); + pr_info("WARN: Maps only in kallsyms:\n"); maps = &kallsyms.kmaps.maps[type]; -- cgit v1.2.3 From 54da07695a0c11b342815be0d8f1796c88765bde Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 10:40:57 -0300 Subject: perf test vmlinux: Avoid printing headers for empty lists Before: # perf test -F -v 1 1: vmlinux symtab matches kallsyms: --- start --- WARN: Maps only in vmlinux: ffffffffb7d7d000-ffffffffb7eeaac8 117d000 [kernel].init.text ffffffffb7eeaac8-ffffffffc03ad000 12eaac8 [kernel].exit.text WARN: Maps in vmlinux with a different name in kallsyms: WARN: Maps only in kallsyms: ---- end ---- vmlinux symtab matches kallsyms: Ok # The two last WARN lines are now suppressed, since there are no such cases detected. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-9ww8uvzl682ykaw8ht1tozlr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/vmlinux-kallsyms.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 6bd5bf980de2..450f69960931 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -28,6 +28,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) enum map_type type = MAP__FUNCTION; struct maps *maps = &vmlinux.kmaps.maps[type]; u64 mem_start, mem_end; + bool header_printed; /* * Step 1: @@ -178,7 +179,7 @@ next_pair: if (!verbose) goto out; - pr_info("WARN: Maps only in vmlinux:\n"); + header_printed = false; for (map = maps__first(maps); map; map = map__next(map)) { struct map * @@ -192,13 +193,18 @@ next_pair: (map->dso->kernel ? map->dso->short_name : map->dso->name)); - if (pair) + if (pair) { pair->priv = 1; - else + } else { + if (!header_printed) { + pr_info("WARN: Maps only in vmlinux:\n"); + header_printed = true; + } map__fprintf(map, stderr); + } } - pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); + header_printed = false; for (map = maps__first(maps); map; map = map__next(map)) { struct map *pair; @@ -211,7 +217,11 @@ next_pair: continue; if (pair->start == mem_start) { - pair->priv = 1; + if (!header_printed) { + pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); + header_printed = true; + } + pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", map->start, map->end, map->pgoff, map->dso->name); if (mem_end != pair->end) @@ -222,13 +232,18 @@ next_pair: } } - pr_info("WARN: Maps only in kallsyms:\n"); + header_printed = false; maps = &kallsyms.kmaps.maps[type]; for (map = maps__first(maps); map; map = map__next(map)) { - if (!map->priv) + if (!map->priv) { + if (!header_printed) { + pr_info("WARN: Maps only in kallsyms:\n"); + header_printed = true; + } map__fprintf(map, stderr); + } } out: machine__exit(&kallsyms); -- cgit v1.2.3 From 7e1b659545b37ed629ee43d4daf72a02dc06e195 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 10:40:57 -0300 Subject: perf test vmlinux: Tolerate symbol aliases The algorithms used to prune aliases in symbols__fixup_duplicate() uses information available on ELF symtabs that are not present on /proc/kallsyms, so it picks different aliases as "best" for vmlinux and kallsyms. We could probably improve a bit this by having a list of aliases for the "best" symbols picked, instead of throwing this info, but that is left for when we find a real need. With this, 'perf test vmlinux' passes: # perf test -F 1 1: vmlinux symtab matches kallsyms: Ok # When we ask for verbose mode, we can see those warning: # perf test -F -v 1 1: vmlinux symtab matches kallsyms: --- start --- Looking at the vmlinux_path (8 entries long) Using /lib/modules/4.8.0-rc4+/build/vmlinux for symbols WARN: 0xffffffffb7001000: diff name v: xen_hypercall_set_trap_table k: hypercall_page WARN: 0xffffffffb7077970: diff end addr for aesni_gcm_dec v: 0xffffffffb707a2f2 k: 0xffffffffb7077a02 WARN: 0xffffffffb707a300: diff end addr for aesni_gcm_enc v: 0xffffffffb707cc03 k: 0xffffffffb707a392 WARN: 0xffffffffb707f950: diff end addr for aesni_gcm_enc_avx_gen2 v: 0xffffffffb7084ef6 k: 0xffffffffb707f9c3 WARN: 0xffffffffb7084f00: diff end addr for aesni_gcm_dec_avx_gen2 v: 0xffffffffb708a691 k: 0xffffffffb7084f73 WARN: 0xffffffffb708aa10: diff end addr for aesni_gcm_enc_avx_gen4 v: 0xffffffffb708f844 k: 0xffffffffb708aa83 WARN: 0xffffffffb708f850: diff end addr for aesni_gcm_dec_avx_gen4 v: 0xffffffffb709486f k: 0xffffffffb708f8c3 WARN: 0xffffffffb71a6e50: diff name v: perf_pmu_commit_txn.part.98 k: perf_pmu_cancel_txn.part.97 WARN: 0xffffffffb752e480: diff name v: wakeup_expire_count_show.part.5 k: wakeup_active_count_show.part.7 WARN: 0xffffffffb76e8d00: diff name v: phys_switch_id_show.part.11 k: phys_port_name_show.part.12 WARN: Maps only in vmlinux: ffffffffb7d7d000-ffffffffb7eeaac8 117d000 [kernel].init.text ffffffffb7eeaac8-ffffffffc03ad000 12eaac8 [kernel].exit.text ---- end ---- vmlinux symtab matches kallsyms: Ok # Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-6v5w1k8rpx4ggczlkw730vt0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/vmlinux-kallsyms.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 450f69960931..77513bf99d1b 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -155,19 +155,20 @@ next_pair: * kallsyms. */ continue; - } else { pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL); if (pair) { if (UM(pair->start) == mem_start) goto next_pair; - pr_debug("ERR : %#" PRIx64 ": diff name v: %s k: %s\n", + pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n", mem_start, sym->name, pair->name); } else { - pr_debug("ERR : %#" PRIx64 ": diff name v: %s k: %s\n", + pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n", mem_start, sym->name, first_pair->name); } + + continue; } } else pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n", -- cgit v1.2.3 From c97b40e4d15f13a36cd037d598e45cbe9e1e5757 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 10:56:06 -0300 Subject: perf symbols: Check symbol_conf.allow_aliases for kallsyms loading too We can allow aliases to be kept, but we were checking this just when loading vmlinux files, be consistent, do it for any symbol table loading code that calls symbol__fixup_duplicate() by making this function check .allow_aliases instead. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Fixes: 680d926a8cb0 ("perf symbols: Allow symbol alias when loading map for symbol name") Link: http://lkml.kernel.org/n/tip-z0avp0s6cfjckc4xj3pdfjdz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 3 +-- tools/perf/util/symbol.c | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index e680371bd5c9..9ba6e49ead62 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1136,8 +1136,7 @@ new_symbol: * For misannotated, zeroed, ASM function sizes. */ if (nr > 0) { - if (!symbol_conf.allow_aliases) - symbols__fixup_duplicate(&dso->symbols[map->type]); + symbols__fixup_duplicate(&dso->symbols[map->type]); symbols__fixup_end(&dso->symbols[map->type]); if (kmap) { /* diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 863d69c45b8a..ef2f913de662 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -153,6 +153,9 @@ void symbols__fixup_duplicate(struct rb_root *symbols) struct rb_node *nd; struct symbol *curr, *next; + if (symbol_conf.allow_aliases) + return; + nd = rb_first(symbols); while (nd) { -- cgit v1.2.3 From 432746f8e0b6a82ba832b771afe31abd51af6752 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 11:00:23 -0300 Subject: perf symbols: Fixup symbol sizes before picking best ones When we call symbol__fixup_duplicate() we use algorithms to pick the "best" symbols for cases where there are various functions/aliases to an address, and those check zero size symbols, which, before calling symbol__fixup_end() are _all_ symbols in a just parsed kallsyms file. So first fixup the end, then fixup the duplicates. Found while trying to figure out why 'perf test vmlinux' failed, see the output of 'perf test -v vmlinux' to see cases where the symbols picked as best for vmlinux don't match the ones picked for kallsyms. Cc: Anton Blanchard Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Fixes: 694bf407b061 ("perf symbols: Add some heuristics for choosing the best duplicate symbol") Link: http://lkml.kernel.org/n/tip-rxqvdgr0mqjdxee0kf8i2ufn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/symbol.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 9ba6e49ead62..295d3147a803 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1136,8 +1136,8 @@ new_symbol: * For misannotated, zeroed, ASM function sizes. */ if (nr > 0) { - symbols__fixup_duplicate(&dso->symbols[map->type]); symbols__fixup_end(&dso->symbols[map->type]); + symbols__fixup_duplicate(&dso->symbols[map->type]); if (kmap) { /* * We need to fixup this here too because we create new diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ef2f913de662..98cd50384c32 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1243,8 +1243,8 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename, if (kallsyms__delta(map, filename, &delta)) return -1; - symbols__fixup_duplicate(&dso->symbols[map->type]); symbols__fixup_end(&dso->symbols[map->type]); + symbols__fixup_duplicate(&dso->symbols[map->type]); if (dso->kernel == DSO_TYPE_GUEST_KERNEL) dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; -- cgit v1.2.3 From b3f33f930606a55b547ac4ef5a32df2c23a44ec1 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Wed, 3 Aug 2016 14:28:44 +0530 Subject: perf probe: Add helper function to check if probe with variable Introduce helper function instead of inline code and replace hardcoded strings "$vars" and "$params" with their corresponding macros. perf_probe_with_var() is not declared as static since it will be called from different file in subsequent patch. Signed-off-by: Ravi Bangoria Acked-by: Masami Hiramatsu Cc: Alexander Shishkin Cc: Hemant Kumar Cc: Naveen N. Rao Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1470214725-5023-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 22 +++++++++++++++------- tools/perf/util/probe-event.h | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8a1e9e67614f..a543e9ca581c 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1618,19 +1618,27 @@ out: return ret; } +/* Returns true if *any* ARG is either C variable, $params or $vars. */ +bool perf_probe_with_var(struct perf_probe_event *pev) +{ + int i = 0; + + for (i = 0; i < pev->nargs; i++) + if (is_c_varname(pev->args[i].var) || + !strcmp(pev->args[i].var, PROBE_ARG_PARAMS) || + !strcmp(pev->args[i].var, PROBE_ARG_VARS)) + return true; + return false; +} + /* Return true if this perf_probe_event requires debuginfo */ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) { - int i; - if (pev->point.file || pev->point.line || pev->point.lazy_line) return true; - for (i = 0; i < pev->nargs; i++) - if (is_c_varname(pev->args[i].var) || - !strcmp(pev->args[i].var, "$params") || - !strcmp(pev->args[i].var, "$vars")) - return true; + if (perf_probe_with_var(pev)) + return true; return false; } diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 62094082d940..8091d15113f7 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -128,6 +128,8 @@ char *synthesize_perf_probe_point(struct perf_probe_point *pp); int perf_probe_event__copy(struct perf_probe_event *dst, struct perf_probe_event *src); +bool perf_probe_with_var(struct perf_probe_event *pev); + /* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); -- cgit v1.2.3 From e47392bf9c0613a058cd20ee89d8ce9d957d4b24 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Wed, 3 Aug 2016 14:28:45 +0530 Subject: perf uprobe: Skip prologue if program compiled without optimization The function prologue prepares stack and registers before executing function logic. When target program is compiled without optimization, function parameter information is only valid after the prologue. When we probe entrypc of the function, and try to record a function parameter, it contains a garbage value. For example: $ vim test.c #include void foo(int i) { printf("i: %d\n", i); } int main() { foo(42); return 0; } $ gcc -g test.c -o test $ objdump -dl test | less foo(): /home/ravi/test.c:4 400536: 55 push %rbp 400537: 48 89 e5 mov %rsp,%rbp 40053a: 48 83 ec 10 sub -bashx10,%rsp 40053e: 89 7d fc mov %edi,-0x4(%rbp) /home/ravi/test.c:5 400541: 8b 45 fc mov -0x4(%rbp),%eax ... ... main(): /home/ravi/test.c:9 400558: 55 push %rbp 400559: 48 89 e5 mov %rsp,%rbp /home/ravi/test.c:10 40055c: bf 2a 00 00 00 mov -bashx2a,%edi 400561: e8 d0 ff ff ff callq 400536 $ perf probe -x ./test 'foo i' $ cat /sys/kernel/debug/tracing/uprobe_events p:probe_test/foo /home/ravi/test:0x0000000000000536 i=-12(%sp):s32 $ perf record -e probe_test:foo ./test $ perf script test 5778 [001] 4918.562027: probe_test:foo: (400536) i=0 Here variable 'i' is passed via stack which is pushed on stack at 0x40053e. But we are probing at 0x400536. To resolve this issues, we need to probe on next instruction after prologue. gdb and systemtap also does same thing. I've implemented this patch based on approach systemtap has used. After applying patch: $ perf probe -x ./test 'foo i' $ cat /sys/kernel/debug/tracing/uprobe_events p:probe_test/foo /home/ravi/test:0x0000000000000541 i=-4(%bp):s32 $ perf record -e probe_test:foo ./test $ perf script test 6300 [001] 5877.879327: probe_test:foo: (400541) i=42 No need to skip prologue for optimized case since debug info is correct for each instructions for -O2 -g. For more details please visit: https://bugzilla.redhat.com/show_bug.cgi?id=612253#c6 Changes in v2: - Skipping prologue only when any ARG is either C variable, $params or $vars. - Probe on line(:1) may not be always possible. Recommend only address to force probe on function entry. Committer notes: Testing it with 'perf trace': # perf probe -x ./test foo i Added new event: probe_test:foo (on foo in /home/acme/c/test with i) You can now use it in all perf tools, such as: perf record -e probe_test:foo -aR sleep 1 # cat /sys/kernel/debug/tracing/uprobe_events p:probe_test/foo /home/acme/c/test:0x0000000000000526 i=-12(%sp):s32 # trace --no-sys --event probe_*:* ./test i: 42 0.000 probe_test:foo:(400526) i=0) # After the patch: # perf probe -d *:* Removed event: probe_test:foo # perf probe -x ./test foo i Target program is compiled without optimization. Skipping prologue. Probe on address 0x400526 to force probing at the function entry. Added new event: probe_test:foo (on foo in /home/acme/c/test with i) You can now use it in all perf tools, such as: perf record -e probe_test:foo -aR sleep 1 # cat /sys/kernel/debug/tracing/uprobe_events p:probe_test/foo /home/acme/c/test:0x0000000000000531 i=-4(%bp):s32 # trace --no-sys --event probe_*:* ./test i: 42 0.000 probe_test:foo:(400531) i=42) # Reported-by: Michael Petlan Report-Link: https://www.mail-archive.com/linux-perf-users@vger.kernel.org/msg02348.html Signed-off-by: Ravi Bangoria Tested-by: Arnaldo Carvalho de Melo Tested-by: Jiri Olsa Acked-by: Masami Hiramatsu Acked-by: Naveen N. Rao Cc: Alexander Shishkin Cc: Hemant Kumar Cc: Peter Zijlstra Cc: Wang Nan Cc: Yauheni Kaliuta Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1299021 Link: http://lkml.kernel.org/r/1470214725-5023-2-git-send-email-ravi.bangoria@linux.vnet.ibm.com [ Rename 'die' to 'cu_die' to avoid shadowing a die() definition on at least centos 5, Debian 7 and ubuntu:12.04.5] [ Use PRIx64 instead of lx to format a Dwarf_Addr, aka long long unsigned int, fixing the build on 32-bit systems ] [ dwarf_getsrclines() expects a size_t * argument ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 165 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 508b61c6e5fb..003ecadae35d 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -907,6 +907,170 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) return die_walk_lines(sp_die, probe_point_lazy_walker, pf); } +static bool var_has_loclist(Dwarf_Die *cu_die) +{ + Dwarf_Attribute loc; + int tag = dwarf_tag(cu_die); + + if (tag != DW_TAG_formal_parameter && + tag != DW_TAG_variable) + return false; + + return (dwarf_attr_integrate(cu_die, DW_AT_location, &loc) && + dwarf_whatform(&loc) == DW_FORM_sec_offset); +} + +/* + * For any object in given CU whose DW_AT_location is a location list, + * target program is compiled with optimization. + */ +static bool optimized_target(Dwarf_Die *cu_die) +{ + Dwarf_Die tmp_die; + + if (var_has_loclist(cu_die)) + return true; + + if (!dwarf_child(cu_die, &tmp_die) && optimized_target(&tmp_die)) + return true; + + if (!dwarf_siblingof(cu_die, &tmp_die) && optimized_target(&tmp_die)) + return true; + + return false; +} + +static bool get_entrypc_idx(Dwarf_Lines *lines, unsigned long nr_lines, + Dwarf_Addr pf_addr, unsigned long *entrypc_idx) +{ + unsigned long i; + Dwarf_Addr addr; + + for (i = 0; i < nr_lines; i++) { + if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &addr)) + return false; + + if (addr == pf_addr) { + *entrypc_idx = i; + return true; + } + } + return false; +} + +static bool get_postprologue_addr(unsigned long entrypc_idx, + Dwarf_Lines *lines, + unsigned long nr_lines, + Dwarf_Addr highpc, + Dwarf_Addr *postprologue_addr) +{ + unsigned long i; + int entrypc_lno, lno; + Dwarf_Line *line; + Dwarf_Addr addr; + bool p_end; + + /* entrypc_lno is actual source line number */ + line = dwarf_onesrcline(lines, entrypc_idx); + if (dwarf_lineno(line, &entrypc_lno)) + return false; + + for (i = entrypc_idx; i < nr_lines; i++) { + line = dwarf_onesrcline(lines, i); + + if (dwarf_lineaddr(line, &addr) || + dwarf_lineno(line, &lno) || + dwarf_lineprologueend(line, &p_end)) + return false; + + /* highpc is exclusive. [entrypc,highpc) */ + if (addr >= highpc) + break; + + /* clang supports prologue-end marker */ + if (p_end) + break; + + /* Actual next line in source */ + if (lno != entrypc_lno) + break; + + /* + * Single source line can have multiple line records. + * For Example, + * void foo() { printf("hello\n"); } + * contains two line records. One points to declaration and + * other points to printf() line. Variable 'lno' won't get + * incremented in this case but 'i' will. + */ + if (i != entrypc_idx) + break; + } + + dwarf_lineaddr(line, postprologue_addr); + if (*postprologue_addr >= highpc) + dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), + postprologue_addr); + + return true; +} + +static void __skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) +{ + size_t nr_lines = 0; + unsigned long entrypc_idx = 0; + Dwarf_Lines *lines = NULL; + Dwarf_Addr postprologue_addr; + Dwarf_Addr highpc; + + if (dwarf_highpc(sp_die, &highpc)) + return; + + if (dwarf_getsrclines(&pf->cu_die, &lines, &nr_lines)) + return; + + if (!get_entrypc_idx(lines, nr_lines, pf->addr, &entrypc_idx)) + return; + + if (!get_postprologue_addr(entrypc_idx, lines, nr_lines, + highpc, &postprologue_addr)) + return; + + pf->addr = postprologue_addr; +} + +static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) +{ + struct perf_probe_point *pp = &pf->pev->point; + + /* Not uprobe? */ + if (!pf->pev->uprobes) + return; + + /* Compiled with optimization? */ + if (optimized_target(&pf->cu_die)) + return; + + /* Don't know entrypc? */ + if (!pf->addr) + return; + + /* Only FUNC and FUNC@SRC are eligible. */ + if (!pp->function || pp->line || pp->retprobe || pp->lazy_line || + pp->offset || pp->abs_address) + return; + + /* Not interested in func parameter? */ + if (!perf_probe_with_var(pf->pev)) + return; + + pr_info("Target program is compiled without optimization. Skipping prologue.\n" + "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", + pf->addr); + + __skip_prologue(sp_die, pf); +} + static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) { struct probe_finder *pf = data; @@ -969,6 +1133,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) if (pp->lazy_line) param->retval = find_probe_point_lazy(sp_die, pf); else { + skip_prologue(sp_die, pf); pf->addr += pp->offset; /* TODO: Check the address in this function */ param->retval = call_probe_finder(sp_die, pf); -- cgit v1.2.3 From 6243b9dc4c991fe8bdc53a0e029908aef3ddb101 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Tue, 30 Aug 2016 14:09:37 +0530 Subject: perf probe: Move dwarf specific functions to dwarf-aux.c Move generic dwarf related functions from util/probe-finder.c to util/dwarf-aux.c. Functions name and their prototype are also changed accordingly. No functionality changes. Suggested-and-Acked-by: Masami Hiramatsu Signed-off-by: Ravi Bangoria Cc: Alexander Shishkin Cc: Hemant Kumar Cc: Naveen N. Rao Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1472546377-25612-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 179 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.h | 8 ++ tools/perf/util/probe-finder.c | 136 +------------------------------ 3 files changed, 189 insertions(+), 134 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index a347b19c961a..faec899435f2 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, return -ENOTSUP; } #endif + +/* + * die_has_loclist - Check if DW_AT_location of @vr_die is a location list + * @vr_die: a variable DIE + */ +static bool die_has_loclist(Dwarf_Die *vr_die) +{ + Dwarf_Attribute loc; + int tag = dwarf_tag(vr_die); + + if (tag != DW_TAG_formal_parameter && + tag != DW_TAG_variable) + return false; + + return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) && + dwarf_whatform(&loc) == DW_FORM_sec_offset); +} + +/* + * die_is_optimized_target - Check if target program is compiled with + * optimization + * @cu_die: a CU DIE + * + * For any object in given CU whose DW_AT_location is a location list, + * target program is compiled with optimization. This is applicable to + * clang as well. + */ +bool die_is_optimized_target(Dwarf_Die *cu_die) +{ + Dwarf_Die tmp_die; + + if (die_has_loclist(cu_die)) + return true; + + if (!dwarf_child(cu_die, &tmp_die) && + die_is_optimized_target(&tmp_die)) + return true; + + if (!dwarf_siblingof(cu_die, &tmp_die) && + die_is_optimized_target(&tmp_die)) + return true; + + return false; +} + +/* + * die_search_idx - Search index of given line address + * @lines: Line records of single CU + * @nr_lines: Number of @lines + * @addr: address we are looking for + * @idx: index to be set by this function (return value) + * + * Search for @addr by looping over every lines of CU. If address + * matches, set index of that line in @idx. Note that single source + * line can have multiple line records. i.e. single source line can + * have multiple index. + */ +static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines, + Dwarf_Addr addr, unsigned long *idx) +{ + unsigned long i; + Dwarf_Addr tmp; + + for (i = 0; i < nr_lines; i++) { + if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp)) + return false; + + if (tmp == addr) { + *idx = i; + return true; + } + } + return false; +} + +/* + * die_get_postprologue_addr - Search next address after function prologue + * @entrypc_idx: entrypc index + * @lines: Line records of single CU + * @nr_lines: Number of @lines + * @hignpc: high PC address of function + * @postprologue_addr: Next address after function prologue (return value) + * + * Look for prologue-end marker. If there is no explicit marker, return + * address of next line record or next source line. + */ +static bool die_get_postprologue_addr(unsigned long entrypc_idx, + Dwarf_Lines *lines, + unsigned long nr_lines, + Dwarf_Addr highpc, + Dwarf_Addr *postprologue_addr) +{ + unsigned long i; + int entrypc_lno, lno; + Dwarf_Line *line; + Dwarf_Addr addr; + bool p_end; + + /* entrypc_lno is actual source line number */ + line = dwarf_onesrcline(lines, entrypc_idx); + if (dwarf_lineno(line, &entrypc_lno)) + return false; + + for (i = entrypc_idx; i < nr_lines; i++) { + line = dwarf_onesrcline(lines, i); + + if (dwarf_lineaddr(line, &addr) || + dwarf_lineno(line, &lno) || + dwarf_lineprologueend(line, &p_end)) + return false; + + /* highpc is exclusive. [entrypc,highpc) */ + if (addr >= highpc) + break; + + /* clang supports prologue-end marker */ + if (p_end) + break; + + /* Actual next line in source */ + if (lno != entrypc_lno) + break; + + /* + * Single source line can have multiple line records. + * For Example, + * void foo() { printf("hello\n"); } + * contains two line records. One points to declaration and + * other points to printf() line. Variable 'lno' won't get + * incremented in this case but 'i' will. + */ + if (i != entrypc_idx) + break; + } + + dwarf_lineaddr(line, postprologue_addr); + if (*postprologue_addr >= highpc) + dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), + postprologue_addr); + + return true; +} + +/* + * die_skip_prologue - Use next address after prologue as probe location + * @sp_die: a subprogram DIE + * @cu_die: a CU DIE + * @entrypc: entrypc of the function + * + * Function prologue prepares stack and registers before executing function + * logic. When target program is compiled without optimization, function + * parameter information is only valid after prologue. When we probe entrypc + * of the function, and try to record function parameter, it contains + * garbage value. + */ +void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, + Dwarf_Addr *entrypc) +{ + size_t nr_lines = 0; + unsigned long entrypc_idx = 0; + Dwarf_Lines *lines = NULL; + Dwarf_Addr postprologue_addr; + Dwarf_Addr highpc; + + if (dwarf_highpc(sp_die, &highpc)) + return; + + if (dwarf_getsrclines(cu_die, &lines, &nr_lines)) + return; + + if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx)) + return; + + if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines, + highpc, &postprologue_addr)) + return; + + *entrypc = postprologue_addr; +} diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index dc0ce1adb075..8b6d2f83af02 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -125,4 +125,12 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf); /* Get the name and type of given variable DIE, stored as "type\tname" */ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); + +/* Check if target program is compiled with optimization */ +bool die_is_optimized_target(Dwarf_Die *cu_die); + +/* Use next address after prologue as probe location */ +void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, + Dwarf_Addr *entrypc); + #endif diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 003ecadae35d..8daca4fc1f8d 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -907,138 +907,6 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) return die_walk_lines(sp_die, probe_point_lazy_walker, pf); } -static bool var_has_loclist(Dwarf_Die *cu_die) -{ - Dwarf_Attribute loc; - int tag = dwarf_tag(cu_die); - - if (tag != DW_TAG_formal_parameter && - tag != DW_TAG_variable) - return false; - - return (dwarf_attr_integrate(cu_die, DW_AT_location, &loc) && - dwarf_whatform(&loc) == DW_FORM_sec_offset); -} - -/* - * For any object in given CU whose DW_AT_location is a location list, - * target program is compiled with optimization. - */ -static bool optimized_target(Dwarf_Die *cu_die) -{ - Dwarf_Die tmp_die; - - if (var_has_loclist(cu_die)) - return true; - - if (!dwarf_child(cu_die, &tmp_die) && optimized_target(&tmp_die)) - return true; - - if (!dwarf_siblingof(cu_die, &tmp_die) && optimized_target(&tmp_die)) - return true; - - return false; -} - -static bool get_entrypc_idx(Dwarf_Lines *lines, unsigned long nr_lines, - Dwarf_Addr pf_addr, unsigned long *entrypc_idx) -{ - unsigned long i; - Dwarf_Addr addr; - - for (i = 0; i < nr_lines; i++) { - if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &addr)) - return false; - - if (addr == pf_addr) { - *entrypc_idx = i; - return true; - } - } - return false; -} - -static bool get_postprologue_addr(unsigned long entrypc_idx, - Dwarf_Lines *lines, - unsigned long nr_lines, - Dwarf_Addr highpc, - Dwarf_Addr *postprologue_addr) -{ - unsigned long i; - int entrypc_lno, lno; - Dwarf_Line *line; - Dwarf_Addr addr; - bool p_end; - - /* entrypc_lno is actual source line number */ - line = dwarf_onesrcline(lines, entrypc_idx); - if (dwarf_lineno(line, &entrypc_lno)) - return false; - - for (i = entrypc_idx; i < nr_lines; i++) { - line = dwarf_onesrcline(lines, i); - - if (dwarf_lineaddr(line, &addr) || - dwarf_lineno(line, &lno) || - dwarf_lineprologueend(line, &p_end)) - return false; - - /* highpc is exclusive. [entrypc,highpc) */ - if (addr >= highpc) - break; - - /* clang supports prologue-end marker */ - if (p_end) - break; - - /* Actual next line in source */ - if (lno != entrypc_lno) - break; - - /* - * Single source line can have multiple line records. - * For Example, - * void foo() { printf("hello\n"); } - * contains two line records. One points to declaration and - * other points to printf() line. Variable 'lno' won't get - * incremented in this case but 'i' will. - */ - if (i != entrypc_idx) - break; - } - - dwarf_lineaddr(line, postprologue_addr); - if (*postprologue_addr >= highpc) - dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), - postprologue_addr); - - return true; -} - -static void __skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) -{ - size_t nr_lines = 0; - unsigned long entrypc_idx = 0; - Dwarf_Lines *lines = NULL; - Dwarf_Addr postprologue_addr; - Dwarf_Addr highpc; - - if (dwarf_highpc(sp_die, &highpc)) - return; - - if (dwarf_getsrclines(&pf->cu_die, &lines, &nr_lines)) - return; - - if (!get_entrypc_idx(lines, nr_lines, pf->addr, &entrypc_idx)) - return; - - if (!get_postprologue_addr(entrypc_idx, lines, nr_lines, - highpc, &postprologue_addr)) - return; - - pf->addr = postprologue_addr; -} - static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) { struct perf_probe_point *pp = &pf->pev->point; @@ -1048,7 +916,7 @@ static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) return; /* Compiled with optimization? */ - if (optimized_target(&pf->cu_die)) + if (die_is_optimized_target(&pf->cu_die)) return; /* Don't know entrypc? */ @@ -1068,7 +936,7 @@ static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", pf->addr); - __skip_prologue(sp_die, pf); + die_skip_prologue(sp_die, &pf->cu_die, &pf->addr); } static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) -- cgit v1.2.3