Commit c61fb959 authored by Ravi Bangoria's avatar Ravi Bangoria Committed by Arnaldo Carvalho de Melo

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: default avatarRavi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Acked-by: default avatarMasami 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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 63a29613
......@@ -265,6 +265,65 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
return true;
}
/*
* NOTE:
* '.gnu.linkonce.this_module' section of kernel module elf directly
* maps to 'struct module' from linux/module.h. This section contains
* actual module name which will be used by kernel after loading it.
* But, we cannot use 'struct module' here since linux/module.h is not
* exposed to user-space. Offset of 'name' has remained same from long
* time, so hardcoding it here.
*/
#ifdef __LP64__
#define MOD_NAME_OFFSET 24
#else
#define MOD_NAME_OFFSET 12
#endif
/*
* @module can be module name of module file path. In case of path,
* inspect elf and find out what is actual module name.
* Caller has to free mod_name after using it.
*/
static char *find_module_name(const char *module)
{
int fd;
Elf *elf;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
Elf_Data *data;
Elf_Scn *sec;
char *mod_name = NULL;
fd = open(module, O_RDONLY);
if (fd < 0)
return NULL;
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL)
goto elf_err;
if (gelf_getehdr(elf, &ehdr) == NULL)
goto ret_err;
sec = elf_section_by_name(elf, &ehdr, &shdr,
".gnu.linkonce.this_module", NULL);
if (!sec)
goto ret_err;
data = elf_getdata(sec, NULL);
if (!data || !data->d_buf)
goto ret_err;
mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET);
ret_err:
elf_end(elf);
elf_err:
close(fd);
return mod_name;
}
#ifdef HAVE_DWARF_SUPPORT
static 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,
struct probe_trace_point *tp;
int num_matched_functions;
int ret, i, j, skipped = 0;
char *mod_name;
map = get_target_map(pev->target, pev->uprobes);
if (!map) {
......@@ -2596,9 +2656,19 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
tp->realname = strdup_or_goto(sym->name, nomem_out);
tp->retprobe = pp->retprobe;
if (pev->target)
tev->point.module = strdup_or_goto(pev->target,
nomem_out);
if (pev->target) {
if (pev->uprobes) {
tev->point.module = strdup_or_goto(pev->target,
nomem_out);
} else {
mod_name = find_module_name(pev->target);
tev->point.module =
strdup(mod_name ? mod_name : pev->target);
free(mod_name);
if (!tev->point.module)
goto nomem_out;
}
}
tev->uprobes = pev->uprobes;
tev->nargs = pev->nargs;
if (tev->nargs) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment