Skip to contentSkip to conversation

perf-probe: Fix to get correct modname from elf header

PATCH In review Masami Hiramatsu 3 participants 3 messages Jan 2, 2017 – Jan 5, 2017 perf events

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 perf-probe: Fix to get correct modname from elf header

Since perf-probe supports cross-arch probe, it is possible to analyze different arch kernel image which has different bits-per-long. In that case, it fails to get module name because perf probe uses MOD_NAME_OFFSET macro based on host machines bits-per-long, instead of the target archs bits-per-long.

This fixes above issue by changing modname-offset based on the target archs bitwidth. 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
  -----
---
 tools/perf/util/probe-event.c |   32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)
tools/perf/util/probe-event.c +16 -16
index d281ae2..8f81096 100644
@@ -268,21 +268,6 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
 }
 
 /*
- * 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.
@@ -296,6 +281,7 @@ static char *find_module_name(const char *module)
 	Elf_Data *data;
 	Elf_Scn *sec;
 	char *mod_name = NULL;
+	int name_offset;
 
 	fd = open(module, O_RDONLY);
 	if (fd < 0)
@@ -317,7 +303,21 @@ static char *find_module_name(const char *module)
 	if (!data || !data->d_buf)
 		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:
 	elf_end(elf);
#1 lore raw

Em Tue, Jan 03, 2017 at 12:20:49AM +0900, Masami Hiramatsu escreveu:

Quoted 10 lines

Since perf-probe supports cross-arch probe, it is possible to analyze different arch kernel image which has different bits-per-long. In that case, it fails to get module name because perf probe uses MOD_NAME_OFFSET macro based on host machines bits-per-long, instead of the target archs bits-per-long.

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

Seems simple enough, thanks, applied.

- Arnaldo

#2 lore raw

[tip:perf/urgent] perf probe: Fix to get correct modname from elf header

In reply to Masami Hiramatsu
perf probe: Fix to get correct modname from elf header
Commit-ID:  1f2ed153b916c95a49a1ca9d7107738664224b7f
Gitweb:     http://git.kernel.org/tip/1f2ed153b916c95a49a1ca9d7107738664224b7f
Author:     Masami Hiramatsu <[email protected]>
AuthorDate: Tue, 3 Jan 2017 00:20:49 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 2 Jan 2017 14:09:17 -0300

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
---
 tools/perf/util/probe-event.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)
tools/perf/util/probe-event.c +16 -16
index d281ae2..8f81096 100644
@@ -268,21 +268,6 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
 }
 
 /*
- * 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.
@@ -296,6 +281,7 @@ static char *find_module_name(const char *module)
 	Elf_Data *data;
 	Elf_Scn *sec;
 	char *mod_name = NULL;
+	int name_offset;
 
 	fd = open(module, O_RDONLY);
 	if (fd < 0)
@@ -317,7 +303,21 @@ static char *find_module_name(const char *module)
 	if (!data || !data->d_buf)
 		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:
 	elf_end(elf);