Commit 1f2ed153 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Arnaldo Carvalho de Melo

perf probe: Fix to get correct modname from elf header

Since 'perf probe' supports cross-arch probes, it is possible to analyze
different arch kernel image which has different bits-per-long.

In that case, it fails to get the module name because it uses the
MOD_NAME_OFFSET macro based on the host machine bits-per-long, instead
of the target arch bits-per-long.

This fixes above issue by changing modname-offset based on the target
archs bit width. This is ok because linux kernel uses LP64 model on
64bit arch.

E.g. without this (on x86_64, and target module is arm32):

  $ perf probe -m build-arm/fs/configfs/configfs.ko -D configfs_lookup
  p:probe/configfs_lookup :configfs_lookup+0
                          ^-Here is an empty module name.

With this fix, you can see correct module name:

  $ perf probe -m build-arm/fs/configfs/configfs.ko -D configfs_lookup
  p:probe/configfs_lookup configfs:configfs_lookup+0
Signed-off-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/148337043836.6752.383495516397005695.stgit@devboxSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent b6f4c667
...@@ -267,21 +267,6 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address) ...@@ -267,21 +267,6 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
return true; 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, * @module can be module name of module file path. In case of path,
* inspect elf and find out what is actual module name. * inspect elf and find out what is actual module name.
...@@ -296,6 +281,7 @@ static char *find_module_name(const char *module) ...@@ -296,6 +281,7 @@ static char *find_module_name(const char *module)
Elf_Data *data; Elf_Data *data;
Elf_Scn *sec; Elf_Scn *sec;
char *mod_name = NULL; char *mod_name = NULL;
int name_offset;
fd = open(module, O_RDONLY); fd = open(module, O_RDONLY);
if (fd < 0) if (fd < 0)
...@@ -317,7 +303,21 @@ static char *find_module_name(const char *module) ...@@ -317,7 +303,21 @@ static char *find_module_name(const char *module)
if (!data || !data->d_buf) if (!data || !data->d_buf)
goto ret_err; goto ret_err;
mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET); /*
* 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.
*/
if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
name_offset = 12;
else /* expect ELFCLASS64 by default */
name_offset = 24;
mod_name = strdup((char *)data->d_buf + name_offset);
ret_err: ret_err:
elf_end(elf); elf_end(elf);
......
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