aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorRavi Bangoria <ravi.bangoria@linux.vnet.ibm.com>2016-04-26 10:25:40 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-04-26 12:15:01 -0400
commitc61fb959df898b994382d586046d7704476ff503 (patch)
tree3f160494f84c3facbc315eb77193f16302f04466 /tools/perf
parent63a29613d7c69f17b6a3266bfc338986698b2546 (diff)
perf probe: Fix module probe issue if no dwarf support
Perf is not able to register probe in kernel module when dwarf supprt is not there(and so it goes for symtab). Perf passes full path of module where only module name is required which is causing the problem. This patch fixes this issue. Before applying patch: $ dpkg -s libdw-dev dpkg-query: package 'libdw-dev' is not installed and no information is... $ sudo ./perf probe -m /linux/samples/kprobes/kprobe_example.ko kprobe_init Added new event: probe:kprobe_init (on kprobe_init in /linux/samples/kprobes/kprobe_example.ko) You can now use it in all perf tools, such as: perf record -e probe:kprobe_init -aR sleep 1 $ sudo cat /sys/kernel/debug/tracing/kprobe_events p:probe/kprobe_init /linux/samples/kprobes/kprobe_example.ko:kprobe_init $ sudo ./perf record -a -e probe:kprobe_init [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.105 MB perf.data ] $ sudo ./perf script # No output here After applying patch: $ sudo ./perf probe -m /linux/samples/kprobes/kprobe_example.ko kprobe_init Added new event: probe:kprobe_init (on kprobe_init in kprobe_example) You can now use it in all perf tools, such as: perf record -e probe:kprobe_init -aR sleep 1 $ sudo cat /sys/kernel/debug/tracing/kprobe_events p:probe/kprobe_init kprobe_example:kprobe_init $ sudo ./perf record -a -e probe:kprobe_init [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.105 MB perf.data (2 samples) ] $ sudo ./perf script insmod 13990 [002] 5961.216833: probe:kprobe_init: ... insmod 13995 [002] 5962.889384: probe:kprobe_init: ... 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: Namhyung Kim <namhyung@kernel.org> Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Wang Nan <wangnan0@huawei.com> Link: http://lkml.kernel.org/r/1461680741-12517-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/probe-event.c76
1 files changed, 73 insertions, 3 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index bc2eb7cda2d1..a9774628c6f6 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -265,6 +265,65 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
265 return true; 265 return true;
266} 266}
267 267
268/*
269 * NOTE:
270 * '.gnu.linkonce.this_module' section of kernel module elf directly
271 * maps to 'struct module' from linux/module.h. This section contains
272 * actual module name which will be used by kernel after loading it.
273 * But, we cannot use 'struct module' here since linux/module.h is not
274 * exposed to user-space. Offset of 'name' has remained same from long
275 * time, so hardcoding it here.
276 */
277#ifdef __LP64__
278#define MOD_NAME_OFFSET 24
279#else
280#define MOD_NAME_OFFSET 12
281#endif
282
283/*
284 * @module can be module name of module file path. In case of path,
285 * inspect elf and find out what is actual module name.
286 * Caller has to free mod_name after using it.
287 */
288static char *find_module_name(const char *module)
289{
290 int fd;
291 Elf *elf;
292 GElf_Ehdr ehdr;
293 GElf_Shdr shdr;
294 Elf_Data *data;
295 Elf_Scn *sec;
296 char *mod_name = NULL;
297
298 fd = open(module, O_RDONLY);
299 if (fd < 0)
300 return NULL;
301
302 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
303 if (elf == NULL)
304 goto elf_err;
305
306 if (gelf_getehdr(elf, &ehdr) == NULL)
307 goto ret_err;
308
309 sec = elf_section_by_name(elf, &ehdr, &shdr,
310 ".gnu.linkonce.this_module", NULL);
311 if (!sec)
312 goto ret_err;
313
314 data = elf_getdata(sec, NULL);
315 if (!data || !data->d_buf)
316 goto ret_err;
317
318 mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET);
319
320ret_err:
321 elf_end(elf);
322elf_err:
323 close(fd);
324 return mod_name;
325}
326
268#ifdef HAVE_DWARF_SUPPORT 327#ifdef HAVE_DWARF_SUPPORT
269 328
270static int kernel_get_module_dso(const char *module, struct dso **pdso) 329static int kernel_get_module_dso(const char *module, struct dso **pdso)
@@ -2512,6 +2571,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2512 struct probe_trace_point *tp; 2571 struct probe_trace_point *tp;
2513 int num_matched_functions; 2572 int num_matched_functions;
2514 int ret, i, j, skipped = 0; 2573 int ret, i, j, skipped = 0;
2574 char *mod_name;
2515 2575
2516 map = get_target_map(pev->target, pev->uprobes); 2576 map = get_target_map(pev->target, pev->uprobes);
2517 if (!map) { 2577 if (!map) {
@@ -2596,9 +2656,19 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2596 tp->realname = strdup_or_goto(sym->name, nomem_out); 2656 tp->realname = strdup_or_goto(sym->name, nomem_out);
2597 2657
2598 tp->retprobe = pp->retprobe; 2658 tp->retprobe = pp->retprobe;
2599 if (pev->target) 2659 if (pev->target) {
2600 tev->point.module = strdup_or_goto(pev->target, 2660 if (pev->uprobes) {
2601 nomem_out); 2661 tev->point.module = strdup_or_goto(pev->target,
2662 nomem_out);
2663 } else {
2664 mod_name = find_module_name(pev->target);
2665 tev->point.module =
2666 strdup(mod_name ? mod_name : pev->target);
2667 free(mod_name);
2668 if (!tev->point.module)
2669 goto nomem_out;
2670 }
2671 }
2602 tev->uprobes = pev->uprobes; 2672 tev->uprobes = pev->uprobes;
2603 tev->nargs = pev->nargs; 2673 tev->nargs = pev->nargs;
2604 if (tev->nargs) { 2674 if (tev->nargs) {