aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorRavi Bangoria <ravi.bangoria@linux.vnet.ibm.com>2016-08-09 02:23:25 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-08-09 11:14:29 -0400
commit99e608b5954c9e1ebadbf9660b74697d9dfd9f20 (patch)
treed3e90cf32de461417ca4a962094bff0daa717b43 /tools
parentd820456dc70b231d62171ba46b43db0045e9bd57 (diff)
perf probe ppc64le: Fix probe location when using DWARF
Powerpc has Global Entry Point and Local Entry Point for functions. LEP catches call from both the GEP and the LEP. Symbol table of ELF contains GEP and Offset from which we can calculate LEP, but debuginfo does not have LEP info. Currently, perf prioritize symbol table over dwarf to probe on LEP for ppc64le. But when user tries to probe with function parameter, we fall back to using dwarf(i.e. GEP) and when function called via LEP, probe will never hit. For example: $ objdump -d vmlinux ... do_sys_open(): c0000000002eb4a0: e8 00 4c 3c addis r2,r12,232 c0000000002eb4a4: 60 00 42 38 addi r2,r2,96 c0000000002eb4a8: a6 02 08 7c mflr r0 c0000000002eb4ac: d0 ff 41 fb std r26,-48(r1) $ sudo ./perf probe do_sys_open $ sudo cat /sys/kernel/debug/tracing/kprobe_events p:probe/do_sys_open _text+3060904 $ sudo ./perf probe 'do_sys_open filename:string' $ sudo cat /sys/kernel/debug/tracing/kprobe_events p:probe/do_sys_open _text+3060896 filename_string=+0(%gpr4):string For second case, perf probed on GEP. So when function will be called via LEP, probe won't hit. $ sudo ./perf record -a -e probe:do_sys_open ls [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.195 MB perf.data ] To resolve this issue, let's not prioritize symbol table, let perf decide what it wants to use. Perf is already converting GEP to LEP when it uses symbol table. When perf uses debuginfo, let it find LEP offset form symbol table. This way we fall back to probe on LEP for all cases. After patch: $ sudo ./perf probe 'do_sys_open filename:string' $ sudo cat /sys/kernel/debug/tracing/kprobe_events p:probe/do_sys_open _text+3060904 filename_string=+0(%gpr4):string $ sudo ./perf record -a -e probe:do_sys_open ls [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.197 MB perf.data (11 samples) ] Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Balbir Singh <bsingharora@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Wang Nan <wangnan0@huawei.com> Link: http://lkml.kernel.org/r/1470723805-5081-2-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c27
-rw-r--r--tools/perf/util/probe-event.c37
-rw-r--r--tools/perf/util/probe-event.h6
3 files changed, 49 insertions, 21 deletions
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index c6d0f91731a1..8d4dc97d80ba 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -54,10 +54,6 @@ int arch__compare_symbol_names(const char *namea, const char *nameb)
54#endif 54#endif
55 55
56#if defined(_CALL_ELF) && _CALL_ELF == 2 56#if defined(_CALL_ELF) && _CALL_ELF == 2
57bool arch__prefers_symtab(void)
58{
59 return true;
60}
61 57
62#ifdef HAVE_LIBELF_SUPPORT 58#ifdef HAVE_LIBELF_SUPPORT
63void arch__sym_update(struct symbol *s, GElf_Sym *sym) 59void arch__sym_update(struct symbol *s, GElf_Sym *sym)
@@ -100,4 +96,27 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
100 tev->point.offset += lep_offset; 96 tev->point.offset += lep_offset;
101 } 97 }
102} 98}
99
100void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
101 int ntevs)
102{
103 struct probe_trace_event *tev;
104 struct map *map;
105 struct symbol *sym = NULL;
106 struct rb_node *tmp;
107 int i = 0;
108
109 map = get_target_map(pev->target, pev->uprobes);
110 if (!map || map__load(map, NULL) < 0)
111 return;
112
113 for (i = 0; i < ntevs; i++) {
114 tev = &pev->tevs[i];
115 map__for_each_symbol(map, sym, tmp) {
116 if (map->unmap_ip(map, sym->start) == tev->point.address)
117 arch__fix_tev_from_maps(pev, tev, map, sym);
118 }
119 }
120}
121
103#endif 122#endif
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 234fbfb5c2ed..28733962cd80 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -180,7 +180,7 @@ static struct map *kernel_get_module_map(const char *module)
180 return NULL; 180 return NULL;
181} 181}
182 182
183static struct map *get_target_map(const char *target, bool user) 183struct map *get_target_map(const char *target, bool user)
184{ 184{
185 /* Init maps of given executable or kernel */ 185 /* Init maps of given executable or kernel */
186 if (user) 186 if (user)
@@ -705,19 +705,32 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
705 return skipped; 705 return skipped;
706} 706}
707 707
708void __weak
709arch__post_process_probe_trace_events(struct perf_probe_event *pev __maybe_unused,
710 int ntevs __maybe_unused)
711{
712}
713
708/* Post processing the probe events */ 714/* Post processing the probe events */
709static int post_process_probe_trace_events(struct probe_trace_event *tevs, 715static int post_process_probe_trace_events(struct perf_probe_event *pev,
716 struct probe_trace_event *tevs,
710 int ntevs, const char *module, 717 int ntevs, const char *module,
711 bool uprobe) 718 bool uprobe)
712{ 719{
713 if (uprobe) 720 int ret;
714 return add_exec_to_probe_trace_events(tevs, ntevs, module);
715 721
716 if (module) 722 if (uprobe)
723 ret = add_exec_to_probe_trace_events(tevs, ntevs, module);
724 else if (module)
717 /* Currently ref_reloc_sym based probe is not for drivers */ 725 /* Currently ref_reloc_sym based probe is not for drivers */
718 return add_module_to_probe_trace_events(tevs, ntevs, module); 726 ret = add_module_to_probe_trace_events(tevs, ntevs, module);
727 else
728 ret = post_process_kernel_probe_trace_events(tevs, ntevs);
719 729
720 return post_process_kernel_probe_trace_events(tevs, ntevs); 730 if (ret >= 0)
731 arch__post_process_probe_trace_events(pev, ntevs);
732
733 return ret;
721} 734}
722 735
723/* Try to find perf_probe_event with debuginfo */ 736/* Try to find perf_probe_event with debuginfo */
@@ -758,7 +771,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
758 771
759 if (ntevs > 0) { /* Succeeded to find trace events */ 772 if (ntevs > 0) { /* Succeeded to find trace events */
760 pr_debug("Found %d probe_trace_events.\n", ntevs); 773 pr_debug("Found %d probe_trace_events.\n", ntevs);
761 ret = post_process_probe_trace_events(*tevs, ntevs, 774 ret = post_process_probe_trace_events(pev, *tevs, ntevs,
762 pev->target, pev->uprobes); 775 pev->target, pev->uprobes);
763 if (ret < 0 || ret == ntevs) { 776 if (ret < 0 || ret == ntevs) {
764 clear_probe_trace_events(*tevs, ntevs); 777 clear_probe_trace_events(*tevs, ntevs);
@@ -2945,8 +2958,6 @@ errout:
2945 return err; 2958 return err;
2946} 2959}
2947 2960
2948bool __weak arch__prefers_symtab(void) { return false; }
2949
2950/* Concatinate two arrays */ 2961/* Concatinate two arrays */
2951static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b) 2962static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b)
2952{ 2963{
@@ -3167,12 +3178,6 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
3167 if (ret > 0 || pev->sdt) /* SDT can be found only in the cache */ 3178 if (ret > 0 || pev->sdt) /* SDT can be found only in the cache */
3168 return ret == 0 ? -ENOENT : ret; /* Found in probe cache */ 3179 return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
3169 3180
3170 if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
3171 ret = find_probe_trace_events_from_map(pev, tevs);
3172 if (ret > 0)
3173 return ret; /* Found in symbol table */
3174 }
3175
3176 /* Convert perf_probe_event with debuginfo */ 3181 /* Convert perf_probe_event with debuginfo */
3177 ret = try_to_find_probe_trace_events(pev, tevs); 3182 ret = try_to_find_probe_trace_events(pev, tevs);
3178 if (ret != 0) 3183 if (ret != 0)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e18ea9fe6385..f4f45db77c1c 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -158,7 +158,6 @@ int show_line_range(struct line_range *lr, const char *module, bool user);
158int show_available_vars(struct perf_probe_event *pevs, int npevs, 158int show_available_vars(struct perf_probe_event *pevs, int npevs,
159 struct strfilter *filter); 159 struct strfilter *filter);
160int show_available_funcs(const char *module, struct strfilter *filter, bool user); 160int show_available_funcs(const char *module, struct strfilter *filter, bool user);
161bool arch__prefers_symtab(void);
162void arch__fix_tev_from_maps(struct perf_probe_event *pev, 161void arch__fix_tev_from_maps(struct perf_probe_event *pev,
163 struct probe_trace_event *tev, struct map *map, 162 struct probe_trace_event *tev, struct map *map,
164 struct symbol *sym); 163 struct symbol *sym);
@@ -173,4 +172,9 @@ int e_snprintf(char *str, size_t size, const char *format, ...)
173int copy_to_probe_trace_arg(struct probe_trace_arg *tvar, 172int copy_to_probe_trace_arg(struct probe_trace_arg *tvar,
174 struct perf_probe_arg *pvar); 173 struct perf_probe_arg *pvar);
175 174
175struct map *get_target_map(const char *target, bool user);
176
177void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
178 int ntevs);
179
176#endif /*_PROBE_EVENT_H */ 180#endif /*_PROBE_EVENT_H */