about summary refs log tree commit diff
path: root/pkgs/os-specific
diff options
context:
space:
mode:
authorTim Steinbach <tim@nequissimus.com>2017-07-14 20:02:15 -0400
committerTim Steinbach <tim@nequissimus.com>2017-07-14 20:07:16 -0400
commit954c66983df36e50ec569dce6350b8a8344d99c2 (patch)
treef329a3bea18393c2525a976217f09772bbe60846 /pkgs/os-specific
parent3ef073e9f14e55defa2cb688ed389bc6fe1d5553 (diff)
downloadnixlib-954c66983df36e50ec569dce6350b8a8344d99c2.tar
nixlib-954c66983df36e50ec569dce6350b8a8344d99c2.tar.gz
nixlib-954c66983df36e50ec569dce6350b8a8344d99c2.tar.bz2
nixlib-954c66983df36e50ec569dce6350b8a8344d99c2.tar.lz
nixlib-954c66983df36e50ec569dce6350b8a8344d99c2.tar.xz
nixlib-954c66983df36e50ec569dce6350b8a8344d99c2.tar.zst
nixlib-954c66983df36e50ec569dce6350b8a8344d99c2.zip
perf: Apply patch for offline kernels
As per https://lkml.org/lkml/2017/7/13/314, perf is broken in 4.9.36 and 4.9.37
Patches in this commit are taken from
https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git/commit/?id=39f4f2c018bd831c325e11983f8893caf72fd9eb

This will allow perf to build again and should be included in a future 4.9.x release,
allowing the custom patching to be removed again
Diffstat (limited to 'pkgs/os-specific')
-rw-r--r--pkgs/os-specific/linux/kernel/perf-offline-probe.patch224
-rw-r--r--pkgs/os-specific/linux/kernel/perf.nix2
2 files changed, 225 insertions, 1 deletions
diff --git a/pkgs/os-specific/linux/kernel/perf-offline-probe.patch b/pkgs/os-specific/linux/kernel/perf-offline-probe.patch
new file mode 100644
index 000000000000..7334a339c858
--- /dev/null
+++ b/pkgs/os-specific/linux/kernel/perf-offline-probe.patch
@@ -0,0 +1,224 @@
+From 8a937a25a7e3c19d5fb3f9d92f605cf5fda219d8 Mon Sep 17 00:00:00 2001
+From: Masami Hiramatsu <mhiramat@kernel.org>
+Date: Wed, 4 Jan 2017 12:30:19 +0900
+Subject: perf probe: Fix to probe on gcc generated symbols for offline kernel
+
+From: Masami Hiramatsu <mhiramat@kernel.org>
+
+commit 8a937a25a7e3c19d5fb3f9d92f605cf5fda219d8 upstream.
+
+Fix perf-probe to show probe definition on gcc generated symbols for
+offline kernel (including cross-arch kernel image).
+
+gcc sometimes optimizes functions and generate new symbols with suffixes
+such as ".constprop.N" or ".isra.N" etc. Since those symbol names are
+not recorded in DWARF, we have to find correct generated symbols from
+offline ELF binary to probe on it (kallsyms doesn't correct it).  For
+online kernel or uprobes we don't need it because those are rebased on
+_text, or a section relative address.
+
+E.g. Without this:
+
+  $ perf probe -k build-arm/vmlinux -F __slab_alloc*
+  __slab_alloc.constprop.9
+  $ perf probe -k build-arm/vmlinux -D __slab_alloc
+  p:probe/__slab_alloc __slab_alloc+0
+
+If you put above definition on target machine, it should fail
+because there is no __slab_alloc in kallsyms.
+
+With this fix, perf probe shows correct probe definition on
+__slab_alloc.constprop.9:
+
+  $ perf probe -k build-arm/vmlinux -D __slab_alloc
+  p:probe/__slab_alloc __slab_alloc.constprop.9+0
+
+Signed-off-by: Masami 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/148350060434.19001.11864836288580083501.stgit@devbox
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: Krister Johansen <kjlx@templeofstupid.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/perf/util/probe-event.c |   48 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 47 insertions(+), 1 deletion(-)
+
+--- a/tools/perf/util/probe-event.c
++++ b/tools/perf/util/probe-event.c
+@@ -618,6 +618,51 @@ error:
+	return ret ? : -ENOENT;
+ }
+
++/*
++ * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
++ * and generate new symbols with suffixes such as .constprop.N or .isra.N
++ * etc. Since those symbols are not recorded in DWARF, we have to find
++ * correct generated symbols from offline ELF binary.
++ * For online kernel or uprobes we don't need this because those are
++ * rebased on _text, or already a section relative address.
++ */
++static int
++post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
++					int ntevs, const char *pathname)
++{
++	struct symbol *sym;
++	struct map *map;
++	unsigned long stext = 0;
++	u64 addr;
++	int i;
++
++	/* Prepare a map for offline binary */
++	map = dso__new_map(pathname);
++	if (!map || get_text_start_address(pathname, &stext) < 0) {
++		pr_warning("Failed to get ELF symbols for %s\n", pathname);
++		return -EINVAL;
++	}
++
++	for (i = 0; i < ntevs; i++) {
++		addr = tevs[i].point.address + tevs[i].point.offset - stext;
++		sym = map__find_symbol(map, addr);
++		if (!sym)
++			continue;
++		if (!strcmp(sym->name, tevs[i].point.symbol))
++			continue;
++		/* If we have no realname, use symbol for it */
++		if (!tevs[i].point.realname)
++			tevs[i].point.realname = tevs[i].point.symbol;
++		else
++			free(tevs[i].point.symbol);
++		tevs[i].point.symbol = strdup(sym->name);
++		tevs[i].point.offset = addr - sym->start;
++	}
++	map__put(map);
++
++	return 0;
++}
++
+ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
+					  int ntevs, const char *exec)
+ {
+@@ -694,7 +739,8 @@ post_process_kernel_probe_trace_events(s
+
+	/* Skip post process if the target is an offline kernel */
+	if (symbol_conf.ignore_vmlinux_buildid)
+-		return 0;
++		return post_process_offline_probe_trace_events(tevs, ntevs,
++						symbol_conf.vmlinux_name);
+
+	reloc_sym = kernel_get_ref_reloc_sym();
+	if (!reloc_sym) {
+
+---
+
+From 3e96dac7c956089d3f23aca98c4dfca57b6aaf8a Mon Sep 17 00:00:00 2001
+From: Masami Hiramatsu <mhiramat@kernel.org>
+Date: Wed, 11 Jan 2017 15:00:47 +0900
+Subject: perf probe: Add error checks to offline probe post-processing
+
+From: Masami Hiramatsu <mhiramat@kernel.org>
+
+commit 3e96dac7c956089d3f23aca98c4dfca57b6aaf8a upstream.
+
+Add error check codes on post processing and improve it for offline
+probe events as:
+
+ - post processing fails if no matched symbol found in map(-ENOENT)
+   or strdup() failed(-ENOMEM).
+
+ - Even if the symbol name is the same, it updates symbol address
+   and offset.
+
+Signed-off-by: Masami 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/148411443738.9978.4617979132625405545.stgit@devbox
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: Krister Johansen <kjlx@templeofstupid.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/perf/util/probe-event.c |   50 +++++++++++++++++++++++++++---------------
+ 1 file changed, 33 insertions(+), 17 deletions(-)
+
+--- a/tools/perf/util/probe-event.c
++++ b/tools/perf/util/probe-event.c
+@@ -618,6 +618,33 @@ error:
+	return ret ? : -ENOENT;
+ }
+
++/* Adjust symbol name and address */
++static int post_process_probe_trace_point(struct probe_trace_point *tp,
++					   struct map *map, unsigned long offs)
++{
++	struct symbol *sym;
++	u64 addr = tp->address + tp->offset - offs;
++
++	sym = map__find_symbol(map, addr);
++	if (!sym)
++		return -ENOENT;
++
++	if (strcmp(sym->name, tp->symbol)) {
++		/* If we have no realname, use symbol for it */
++		if (!tp->realname)
++			tp->realname = tp->symbol;
++		else
++			free(tp->symbol);
++		tp->symbol = strdup(sym->name);
++		if (!tp->symbol)
++			return -ENOMEM;
++	}
++	tp->offset = addr - sym->start;
++	tp->address -= offs;
++
++	return 0;
++}
++
+ /*
+  * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
+  * and generate new symbols with suffixes such as .constprop.N or .isra.N
+@@ -630,11 +657,9 @@ static int
+ post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
+					int ntevs, const char *pathname)
+ {
+-	struct symbol *sym;
+	struct map *map;
+	unsigned long stext = 0;
+-	u64 addr;
+-	int i;
++	int i, ret = 0;
+
+	/* Prepare a map for offline binary */
+	map = dso__new_map(pathname);
+@@ -644,23 +669,14 @@ post_process_offline_probe_trace_events(
+	}
+
+	for (i = 0; i < ntevs; i++) {
+-		addr = tevs[i].point.address + tevs[i].point.offset - stext;
+-		sym = map__find_symbol(map, addr);
+-		if (!sym)
+-			continue;
+-		if (!strcmp(sym->name, tevs[i].point.symbol))
+-			continue;
+-		/* If we have no realname, use symbol for it */
+-		if (!tevs[i].point.realname)
+-			tevs[i].point.realname = tevs[i].point.symbol;
+-		else
+-			free(tevs[i].point.symbol);
+-		tevs[i].point.symbol = strdup(sym->name);
+-		tevs[i].point.offset = addr - sym->start;
++		ret = post_process_probe_trace_point(&tevs[i].point,
++						     map, stext);
++		if (ret < 0)
++			break;
+	}
+	map__put(map);
+
+-	return 0;
++	return ret;
+ }
+
+ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
diff --git a/pkgs/os-specific/linux/kernel/perf.nix b/pkgs/os-specific/linux/kernel/perf.nix
index 3fbad924568f..cb13167eebc5 100644
--- a/pkgs/os-specific/linux/kernel/perf.nix
+++ b/pkgs/os-specific/linux/kernel/perf.nix
@@ -13,7 +13,7 @@ stdenv.mkDerivation {
 
   inherit (kernel) src;
 
-  patches = kernel.patches ++ [ ./perf-binutils-path.patch ];
+  patches = kernel.patches ++ [ ./perf-binutils-path.patch ./perf-offline-probe.patch ];
 
   preConfigure = ''
     cd tools/perf