Skip to contentSkip to conversation

perf tools: Set proper module name when build-id event found

PATCH Applied Namhyung Kim 4 participants 9 messages May 31, 2017 – Jun 7, 2017 perf events

lore
Share & tools
lore

Namhyung Kim

author maintainer
#0 lore raw

PATCH 1/3 perf tools: Set proper module name when build-id event found

When perf processes build-id event, it creates DSOs with the build-id. But it didn't set the module short name (like '[module-name]') so when processing a kernel mmap event of the module, it cannot found the DSO as it only checks the short names.

That leads for perf to create a same DSO without the build-id info and it'll lookup the system path even if the DSO is already in the build-id cache. After kernel was updated, perf cannot find the DSO and cannot show symbols in it anymore.

You can see this if you have an old data file (w/ old kernel version):

  $ perf report -i perf.data.old -v |& grep scsi_mod
  build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz : cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1
  Failed to open /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz, continuing without symbols
  ...

The second message didn't show the build-id. With this patch:

  $ perf report -i perf.data.old -v |& grep scsi_mod
  build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz: cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1
  /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz with build id cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1 not found, continuing without symbols
  ...

Now it shows the build-id but still cannot load the symbol table. This is a different problem which will be fixed in the next patch.

---
 tools/perf/util/header.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
tools/perf/util/header.c +10 -2
index 314a07151fb7..56b8a479223b 100644
@@ -1469,8 +1469,16 @@ static int __event_process_build_id(struct build_id_event *bev,
 
 		dso__set_build_id(dso, &bev->build_id);
 
-		if (!is_kernel_module(filename, cpumode))
-			dso->kernel = dso_type;
+		if (dso_type != DSO_TYPE_USER) {
+			struct kmod_path m = {};
+
+			if (!kmod_path__parse_name(&m, filename) && m.kmod)
+				dso__set_short_name(dso, strdup(m.name), true);
+			else
+				dso->kernel = dso_type;
+
+			free(m.name);
+		}
 
 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
 				  sbuild_id);
Signature · 1 line
2.13.0
author maintainer
#1 lore raw

PATCH 2/3 perf tools: Set module info when build-id event found

Like machine__findnew_module_dso(), it should set necessary info for kernel modules to find symbol info from the file. Factor out dso__set_module_info() to do it.

This is needed for dso__needs_decompress() to detect such DSOs.

---
 tools/perf/util/dso.c     | 15 +++++++++++++++
 tools/perf/util/dso.h     |  3 +++
 tools/perf/util/header.c  |  2 +-
 tools/perf/util/machine.c | 11 +----------
 4 files changed, 20 insertions(+), 11 deletions(-)
tools/perf/util/dso.c +15 -0
index a96a99d2369f..b27d127cdf68 100644
@@ -335,6 +335,21 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
 	return 0;
 }
 
+void dso__set_module_info(struct dso *dso, struct kmod_path *m,
+			  struct machine *machine)
+{
+	if (machine__is_host(machine))
+		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
+	else
+		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+	/* _KMODULE_COMP should be next to _KMODULE */
+	if (m->kmod && m->comp)
+		dso->symtab_type++;
+
+	dso__set_short_name(dso, strdup(m->name), true);
+}
+
 /*
  * Global list of open DSOs and the counter.
  */
tools/perf/util/dso.h +3 -0
index 12350b171727..5fe2ab5877bd 100644
@@ -259,6 +259,9 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
 #define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false)
 #define kmod_path__parse_ext(__m, __p)  __kmod_path__parse(__m, __p, false, true)
 
+void dso__set_module_info(struct dso *dso, struct kmod_path *m,
+			  struct machine *machine);
+
 /*
  * The dso__data_* external interface provides following functions:
  *   dso__data_get_fd
tools/perf/util/header.c +1 -1
index 56b8a479223b..8b3dd430c63c 100644
@@ -1473,7 +1473,7 @@ static int __event_process_build_id(struct build_id_event *bev,
 			struct kmod_path m = {};
 
 			if (!kmod_path__parse_name(&m, filename) && m.kmod)
-				dso__set_short_name(dso, strdup(m.name), true);
+				dso__set_module_info(dso, &m, machine);
 			else
 				dso->kernel = dso_type;
 
tools/perf/util/machine.c +1 -10
index d97e014c3df3..d7f31cb0a4cb 100644
@@ -572,16 +572,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine,
 		if (dso == NULL)
 			goto out_unlock;
 
-		if (machine__is_host(machine))
-			dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
-		else
-			dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
-
-		/* _KMODULE_COMP should be next to _KMODULE */
-		if (m->kmod && m->comp)
-			dso->symtab_type++;
-
-		dso__set_short_name(dso, strdup(m->name), true);
+		dso__set_module_info(dso, m, machine);
 		dso__set_long_name(dso, strdup(filename), true);
 	}
 
Signature · 1 line
2.13.0
#2 lore raw

[tip:perf/urgent] perf symbols: Set module info when build-id event found

perf symbols: Set module info when build-id event found
Commit-ID:  6b335e8f545591c07df0f34231bd7ff7506c98c1
Gitweb:     http://git.kernel.org/tip/6b335e8f545591c07df0f34231bd7ff7506c98c1
Author:     Namhyung Kim <[email protected]>
AuthorDate: Wed, 31 May 2017 21:01:04 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 5 Jun 2017 14:17:58 -0300

perf symbols: Set module info when build-id event found

Like machine__findnew_module_dso(), it should set necessary info for kernel modules to find symbol info from the file. Factor out dso__set_module_info() to do it.

This is needed for dso__needs_decompress() to detect such DSOs.

---
 tools/perf/util/dso.c     | 15 +++++++++++++++
 tools/perf/util/dso.h     |  3 +++
 tools/perf/util/header.c  |  2 +-
 tools/perf/util/machine.c | 11 +----------
 4 files changed, 20 insertions(+), 11 deletions(-)
tools/perf/util/dso.c +15 -0
index a96a99d..b27d127 100644
@@ -335,6 +335,21 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
 	return 0;
 }
 
+void dso__set_module_info(struct dso *dso, struct kmod_path *m,
+			  struct machine *machine)
+{
+	if (machine__is_host(machine))
+		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
+	else
+		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+	/* _KMODULE_COMP should be next to _KMODULE */
+	if (m->kmod && m->comp)
+		dso->symtab_type++;
+
+	dso__set_short_name(dso, strdup(m->name), true);
+}
+
 /*
  * Global list of open DSOs and the counter.
  */
tools/perf/util/dso.h +3 -0
index 12350b1..5fe2ab5 100644
@@ -259,6 +259,9 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
 #define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false)
 #define kmod_path__parse_ext(__m, __p)  __kmod_path__parse(__m, __p, false, true)
 
+void dso__set_module_info(struct dso *dso, struct kmod_path *m,
+			  struct machine *machine);
+
 /*
  * The dso__data_* external interface provides following functions:
  *   dso__data_get_fd
tools/perf/util/header.c +1 -1
index c40a4d8..5cac8d5 100644
@@ -1473,7 +1473,7 @@ static int __event_process_build_id(struct build_id_event *bev,
 			struct kmod_path m = { .name = NULL, };
 
 			if (!kmod_path__parse_name(&m, filename) && m.kmod)
-				dso__set_short_name(dso, strdup(m.name), true);
+				dso__set_module_info(dso, &m, machine);
 			else
 				dso->kernel = dso_type;
 
tools/perf/util/machine.c +1 -10
index d97e014..d7f31cb 100644
@@ -572,16 +572,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine,
 		if (dso == NULL)
 			goto out_unlock;
 
-		if (machine__is_host(machine))
-			dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
-		else
-			dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
-
-		/* _KMODULE_COMP should be next to _KMODULE */
-		if (m->kmod && m->comp)
-			dso->symtab_type++;
-
-		dso__set_short_name(dso, strdup(m->name), true);
+		dso__set_module_info(dso, m, machine);
 		dso__set_long_name(dso, strdup(filename), true);
 	}
 
author maintainer
#3 lore raw

PATCH 3/3 perf tools: Use correct filename for compressed modules in build-id cache

In reply to Namhyung Kim

The decompress_kmodule() is to decompress kernel module in order to load symbols from it. In DSO_BINARY_TYPE__BUILD_ID_CACHE case, it needs full file path to extract the file extension to determine decompress method. But overwriting 'name' will fail to decompress since it might point to a non-existing old file.

Instead, use dso->long_name for extension and use real filename to decompress. In DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP case, both name should be same. This can show symbols in the old modules.

Before:

  $ perf report -i perf.data.old | grep scsi_mod
     0.00%  cc1      [scsi_mod]    [k] 0x0000000000004aa6
     0.00%  as       [scsi_mod]    [k] 0x00000000000099e1
     0.00%  cc1      [scsi_mod]    [k] 0x0000000000009830
     0.00%  cc1      [scsi_mod]    [k] 0x0000000000001b8f

After:

     0.00%  cc1      [scsi_mod]    [k] scsi_handle_queue_ramp_up
     0.00%  as       [scsi_mod]    [k] scsi_sg_alloc
     0.00%  cc1      [scsi_mod]    [k] scsi_setup_cmnd
     0.00%  cc1      [scsi_mod]    [k] scsi_get_command
---
 tools/perf/util/symbol-elf.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
tools/perf/util/symbol-elf.c +1 -4
index e7ee47f7377a..1fb2efae4f02 100644
@@ -649,10 +649,7 @@ static int decompress_kmodule(struct dso *dso, const char *name,
 	    type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
 		return -1;
 
-	if (type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
-		name = dso->long_name;
-
-	if (kmod_path__parse_ext(&m, name) || !m.comp)
+	if (kmod_path__parse_ext(&m, dso->long_name) || !m.comp)
 		return -1;
 
 	fd = mkstemp(tmpbuf);
Signature · 1 line
2.13.0
#4 lore raw

[tip:perf/urgent] perf symbols: Use correct filename for compressed modules in build-id cache

perf symbols: Use correct filename for compressed modules in build-id cache
Commit-ID:  a09935b878dc8efd4b030ed1ffa0553fc9011fb8
Gitweb:     http://git.kernel.org/tip/a09935b878dc8efd4b030ed1ffa0553fc9011fb8
Author:     Namhyung Kim <[email protected]>
AuthorDate: Wed, 31 May 2017 21:01:05 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 5 Jun 2017 14:17:59 -0300

perf symbols: Use correct filename for compressed modules in build-id cache

The decompress_kmodule() decompresses kernel modules in order to load symbols from it. In the DSO_BINARY_TYPE__BUILD_ID_CACHE case, it needs the full file path to extract the file extension to determine the decompression method. But overwriting 'name' will fail the decompression since it might point to a non-existing old file.

Instead, use dso->long_name for having the correct extension and use the real filename to decompress.

In the DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP case, both names should be the same. This allows resolving symbols in the old modules.

Before:

  $ perf report -i perf.data.old | grep scsi_mod
     0.00%  cc1      [scsi_mod]    [k] 0x0000000000004aa6
     0.00%  as       [scsi_mod]    [k] 0x00000000000099e1
     0.00%  cc1      [scsi_mod]    [k] 0x0000000000009830
     0.00%  cc1      [scsi_mod]    [k] 0x0000000000001b8f

After:

     0.00%  cc1      [scsi_mod]    [k] scsi_handle_queue_ramp_up
     0.00%  as       [scsi_mod]    [k] scsi_sg_alloc
     0.00%  cc1      [scsi_mod]    [k] scsi_setup_cmnd
     0.00%  cc1      [scsi_mod]    [k] scsi_get_command
---
 tools/perf/util/symbol-elf.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
tools/perf/util/symbol-elf.c +1 -4
index e7ee47f..1fb2efa 100644
@@ -649,10 +649,7 @@ static int decompress_kmodule(struct dso *dso, const char *name,
 	    type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
 		return -1;
 
-	if (type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
-		name = dso->long_name;
-
-	if (kmod_path__parse_ext(&m, name) || !m.comp)
+	if (kmod_path__parse_ext(&m, dso->long_name) || !m.comp)
 		return -1;
 
 	fd = mkstemp(tmpbuf);
Acked-by on v1 1/3
#5 lore raw
In reply to Namhyung Kim
Quoted 24 lines · Namhyung Kim

When perf processes build-id event, it creates DSOs with the build-id. But it didn't set the module short name (like '[module-name]') so when processing a kernel mmap event of the module, it cannot found the DSO as it only checks the short names.

That leads for perf to create a same DSO without the build-id info and it'll lookup the system path even if the DSO is already in the build-id cache. After kernel was updated, perf cannot find the DSO and cannot show symbols in it anymore.

You can see this if you have an old data file (w/ old kernel version):

  $ perf report -i perf.data.old -v |& grep scsi_mod
  build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz : cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1
  Failed to open /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz, continuing without symbols
  ...

The second message didn't show the build-id. With this patch:

  $ perf report -i perf.data.old -v |& grep scsi_mod
  build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz: cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1
  /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz with build id cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1 not found, continuing without symbols
  ...
Quoted 4 lines

Now it shows the build-id but still cannot load the symbol table. This is a different problem which will be fixed in the next patch.

for all 3:

thanks,
jirka

#7 lore raw
In reply to Namhyung Kim

Em Wed, May 31, 2017 at 09:01:03PM +0900, Namhyung Kim escreveu:

tools/perf/util/header.c static int __event_process_build_id(struct build_id_event *bev, · line 1474

Quoted 10 lines

+++ b/tools/perf/util/header.c

tools/perf/util/header.c +3 -2
@@ -1469,8 +1469,16 @@ static int __event_process_build_id(struct build_id_event *bev,
 
 		dso__set_build_id(dso, &bev->build_id);
 
-		if (!is_kernel_module(filename, cpumode))
-			dso->kernel = dso_type;
+		if (dso_type != DSO_TYPE_USER) {
+			struct kmod_path m = {};
+

This fails in several distros, among them centos:7, debian:8

CC /tmp/build/perf/util/header.o
util/header.c: In function '__event_process_build_id':
util/header.c:1473:11: error: missing initializer for field 'name' of 'struct kmod_path' [-Werror=missing-field-initializers]

    struct kmod_path m = {};
           ^
In file included from util/symbol.h:24:0,
                 from util/evsel.h:10,
                 from util/evlist.h:11,
                 from util/header.c:19:
util/dso.h:249:8: note: 'name' declared here
  char *name;
        ^

cc1: all warnings being treated as errors
mv: cannot stat '/tmp/build/perf/util/.header.o.tmp': No such file or directory make[4]: *** [/tmp/build/perf/util/header.o] Error 1
make[3]: *** [util] Error 2
make[3]: *** Waiting for unfinished jobs....

centos:5, centos:6, debian:7 have a slightly different message:

CC /tmp/build/perf/util/callchain.o
cc1: warnings being treated as errors
util/header.c: In function '__event_process_build_id':
util/header.c:1473: warning: missing initializer util/header.c:1473: warning: (near initialization for 'm.name')
MKDIR /tmp/build/perf/util/
CC /tmp/build/perf/util/values.o
mv: cannot stat `/tmp/build/perf/util/.header.o.tmp': No such file or directory

I'll fix this.

- Arnaldo

#8 lore raw

[tip:perf/urgent] perf header: Set proper module name when build-id event found

In reply to Namhyung Kim
perf header: Set proper module name when build-id event found
Commit-ID:  1deec1bd96ccd8beb04d2112a6d12fe20505c3a6
Gitweb:     http://git.kernel.org/tip/1deec1bd96ccd8beb04d2112a6d12fe20505c3a6
Author:     Namhyung Kim <[email protected]>
AuthorDate: Wed, 31 May 2017 21:01:03 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 5 Jun 2017 14:16:49 -0300

perf header: Set proper module name when build-id event found

When perf processes build-id event, it creates DSOs with the build-id. But it didn't set the module short name (like '[module-name]') so when processing a kernel mmap event of the module, it cannot found the DSO as it only checks the short names.

That leads for perf to create a same DSO without the build-id info and it'll lookup the system path even if the DSO is already in the build-id cache. After kernel was updated, perf cannot find the DSO and cannot show symbols in it anymore.

You can see this if you have an old data file (w/ old kernel version):

  $ perf report -i perf.data.old -v |& grep scsi_mod
  build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz : cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1
  Failed to open /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz, continuing without symbols
  ...

The second message didn't show the build-id. With this patch:

  $ perf report -i perf.data.old -v |& grep scsi_mod
  build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz: cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1
  /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz with build id cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1 not found, continuing without symbols
  ...

Now it shows the build-id but still cannot load the symbol table. This is a different problem which will be fixed in the next patch.

Cc Andi Kleen <[email protected]>
Cc David Ahern <[email protected]>
Cc Peter Zijlstra <[email protected]>
[ Fix the build on older compilers (debian <= 8, fedora <= 21, etc) wrt kmod_path var init ]
---
 tools/perf/util/header.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
tools/perf/util/header.c +10 -2
index 314a071..c40a4d8 100644
@@ -1469,8 +1469,16 @@ static int __event_process_build_id(struct build_id_event *bev,
 
 		dso__set_build_id(dso, &bev->build_id);
 
-		if (!is_kernel_module(filename, cpumode))
-			dso->kernel = dso_type;
+		if (dso_type != DSO_TYPE_USER) {
+			struct kmod_path m = { .name = NULL, };
+
+			if (!kmod_path__parse_name(&m, filename) && m.kmod)
+				dso__set_short_name(dso, strdup(m.name), true);
+			else
+				dso->kernel = dso_type;
+
+			free(m.name);
+		}
 
 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
 				  sbuild_id);