aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2014-02-06 00:32:16 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-02-18 07:34:51 -0500
commitdfef99cd0b2c8abafb571e5992ce954135be5f40 (patch)
treee5a75cb41129bb12e307913a1c46548cf297cbea /tools
parentfb226ccd2a6f77be13009edc196da2077800066b (diff)
perf probe: Use ref_reloc_sym based address instead of the symbol name
Since several local symbols can have same name (e.g. t_show), we need to use the relative address from the symbol referred by kmap->ref_reloc_sym instead of the target symbol name itself. Because the kernel address space layout randomize (kASLR) changes the absolute address of kernel symbols, we can't rely on the absolute address. Note that this works only with debuginfo. E.g. without this change; ---- # ./perf probe -a "t_show \$vars" Added new events: probe:t_show (on t_show with $vars) probe:t_show_1 (on t_show with $vars) probe:t_show_2 (on t_show with $vars) probe:t_show_3 (on t_show with $vars) You can now use it in all perf tools, such as: perf record -e probe:t_show_3 -aR sleep 1 ---- OK, we have 4 different t_show()s. All functions have different arguments as below; ---- # cat /sys/kernel/debug/tracing/kprobe_events p:probe/t_show t_show m=%di:u64 v=%si:u64 p:probe/t_show_1 t_show m=%di:u64 v=%si:u64 t=%si:u64 p:probe/t_show_2 t_show m=%di:u64 v=%si:u64 fmt=%si:u64 p:probe/t_show_3 t_show m=%di:u64 v=%si:u64 file=%si:u64 ---- However, all of them have been put on the *same* address. ---- # cat /sys/kernel/debug/kprobes/list ffffffff810d9720 k t_show+0x0 [DISABLED] ffffffff810d9720 k t_show+0x0 [DISABLED] ffffffff810d9720 k t_show+0x0 [DISABLED] ffffffff810d9720 k t_show+0x0 [DISABLED] ---- With this change; ---- # ./perf probe -a "t_show \$vars" Added new events: probe:t_show (on t_show with $vars) probe:t_show_1 (on t_show with $vars) probe:t_show_2 (on t_show with $vars) probe:t_show_3 (on t_show with $vars) You can now use it in all perf tools, such as: perf record -e probe:t_show_3 -aR sleep 1 # cat /sys/kernel/debug/tracing/kprobe_events p:probe/t_show _stext+889880 m=%di:u64 v=%si:u64 p:probe/t_show_1 _stext+928568 m=%di:u64 v=%si:u64 t=%si:u64 p:probe/t_show_2 _stext+969512 m=%di:u64 v=%si:u64 fmt=%si:u64 p:probe/t_show_3 _stext+1001416 m=%di:u64 v=%si:u64 file=%si:u64 # cat /sys/kernel/debug/kprobes/list ffffffffb50d95e0 k t_show+0x0 [DISABLED] ffffffffb50e2d00 k t_show+0x0 [DISABLED] ffffffffb50f4990 k t_show+0x0 [DISABLED] ffffffffb50eccf0 k t_show+0x0 [DISABLED] ---- This time, each event is put in different address correctly. Note that currently this doesn't support address-based probe on modules (thus the probes on modules are symbol based), since it requires relative address probe syntax for kprobe-tracer, and it isn't implemented yet. One more note, this allows us to put events on correct address, but --list option should be updated to show correct corresponding source code. Changes from v2: - Refer kmap->ref_reloc_sym instead of "_stext". - Refer map->reloc to catch up the kASLR perf fix. Changes from v1: - Use _stext relative address instead of actual absolute address recorded in debuginfo. Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: David Ahern <dsahern@gmail.com> Cc: "David A. Long" <dave.long@linaro.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: yrl.pp-manager.tt@hitachi.com Link: http://lkml.kernel.org/r/20140206053216.29635.22584.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/probe-event.c58
1 files changed, 49 insertions, 9 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index de9fe906f3be..1ce2cb9845b6 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -383,6 +383,51 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
383 return ret; 383 return ret;
384} 384}
385 385
386static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
387{
388 /* kmap->ref_reloc_sym should be set if host_machine is initialized */
389 struct kmap *kmap;
390
391 kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
392 return kmap->ref_reloc_sym;
393}
394
395/* Post processing the probe events */
396static int post_process_probe_trace_events(struct probe_trace_event *tevs,
397 int ntevs, const char *module,
398 bool uprobe)
399{
400 struct ref_reloc_sym *reloc_sym;
401 char *tmp;
402 int i;
403
404 if (uprobe)
405 return add_exec_to_probe_trace_events(tevs, ntevs, module);
406
407 /* Note that currently ref_reloc_sym based probe is not for drivers */
408 if (module)
409 return add_module_to_probe_trace_events(tevs, ntevs, module);
410
411 reloc_sym = __kernel_get_ref_reloc_sym();
412 if (!reloc_sym) {
413 pr_warning("Relocated base symbol is not found!\n");
414 return -EINVAL;
415 }
416
417 for (i = 0; i < ntevs; i++) {
418 if (tevs[i].point.address) {
419 tmp = strdup(reloc_sym->name);
420 if (!tmp)
421 return -ENOMEM;
422 free(tevs[i].point.symbol);
423 tevs[i].point.symbol = tmp;
424 tevs[i].point.offset = tevs[i].point.address -
425 reloc_sym->unrelocated_addr;
426 }
427 }
428 return 0;
429}
430
386static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) 431static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
387{ 432{
388 int i; 433 int i;
@@ -411,21 +456,16 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
411 return 0; 456 return 0;
412 } 457 }
413 458
459 pr_debug("Try to find probe point from debuginfo.\n");
414 /* Searching trace events corresponding to a probe event */ 460 /* Searching trace events corresponding to a probe event */
415 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 461 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
416 462
417 debuginfo__delete(dinfo); 463 debuginfo__delete(dinfo);
418 464
419 if (ntevs > 0) { /* Succeeded to find trace events */ 465 if (ntevs > 0) { /* Succeeded to find trace events */
420 pr_debug("find %d probe_trace_events.\n", ntevs); 466 pr_debug("Found %d probe_trace_events.\n", ntevs);
421 if (target) { 467 ret = post_process_probe_trace_events(*tevs, ntevs,
422 if (pev->uprobes) 468 target, pev->uprobes);
423 ret = add_exec_to_probe_trace_events(*tevs,
424 ntevs, target);
425 else
426 ret = add_module_to_probe_trace_events(*tevs,
427 ntevs, target);
428 }
429 if (ret < 0) { 469 if (ret < 0) {
430 clear_probe_trace_events(*tevs, ntevs); 470 clear_probe_trace_events(*tevs, ntevs);
431 zfree(tevs); 471 zfree(tevs);