|
| 1 | +From 8a937a25a7e3c19d5fb3f9d92f605cf5fda219d8 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Masami Hiramatsu <mhiramat@kernel.org> |
| 3 | +Date: Wed, 4 Jan 2017 12:30:19 +0900 |
| 4 | +Subject: perf probe: Fix to probe on gcc generated symbols for offline kernel |
| 5 | + |
| 6 | +From: Masami Hiramatsu <mhiramat@kernel.org> |
| 7 | + |
| 8 | +commit 8a937a25a7e3c19d5fb3f9d92f605cf5fda219d8 upstream. |
| 9 | + |
| 10 | +Fix perf-probe to show probe definition on gcc generated symbols for |
| 11 | +offline kernel (including cross-arch kernel image). |
| 12 | + |
| 13 | +gcc sometimes optimizes functions and generate new symbols with suffixes |
| 14 | +such as ".constprop.N" or ".isra.N" etc. Since those symbol names are |
| 15 | +not recorded in DWARF, we have to find correct generated symbols from |
| 16 | +offline ELF binary to probe on it (kallsyms doesn't correct it). For |
| 17 | +online kernel or uprobes we don't need it because those are rebased on |
| 18 | +_text, or a section relative address. |
| 19 | + |
| 20 | +E.g. Without this: |
| 21 | + |
| 22 | + $ perf probe -k build-arm/vmlinux -F __slab_alloc* |
| 23 | + __slab_alloc.constprop.9 |
| 24 | + $ perf probe -k build-arm/vmlinux -D __slab_alloc |
| 25 | + p:probe/__slab_alloc __slab_alloc+0 |
| 26 | + |
| 27 | +If you put above definition on target machine, it should fail |
| 28 | +because there is no __slab_alloc in kallsyms. |
| 29 | + |
| 30 | +With this fix, perf probe shows correct probe definition on |
| 31 | +__slab_alloc.constprop.9: |
| 32 | + |
| 33 | + $ perf probe -k build-arm/vmlinux -D __slab_alloc |
| 34 | + p:probe/__slab_alloc __slab_alloc.constprop.9+0 |
| 35 | + |
| 36 | +Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> |
| 37 | +Cc: Jiri Olsa <jolsa@redhat.com> |
| 38 | +Cc: Namhyung Kim <namhyung@kernel.org> |
| 39 | +Cc: Peter Zijlstra <peterz@infradead.org> |
| 40 | +Link: http://lkml.kernel.org/r/148350060434.19001.11864836288580083501.stgit@devbox |
| 41 | +Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| 42 | +Cc: Krister Johansen <kjlx@templeofstupid.com> |
| 43 | +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| 44 | + |
| 45 | +--- |
| 46 | + tools/perf/util/probe-event.c | 48 +++++++++++++++++++++++++++++++++++++++++- |
| 47 | + 1 file changed, 47 insertions(+), 1 deletion(-) |
| 48 | + |
| 49 | +--- a/tools/perf/util/probe-event.c |
| 50 | ++++ b/tools/perf/util/probe-event.c |
| 51 | +@@ -618,6 +618,51 @@ error: |
| 52 | + return ret ? : -ENOENT; |
| 53 | + } |
| 54 | + |
| 55 | ++/* |
| 56 | ++ * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions |
| 57 | ++ * and generate new symbols with suffixes such as .constprop.N or .isra.N |
| 58 | ++ * etc. Since those symbols are not recorded in DWARF, we have to find |
| 59 | ++ * correct generated symbols from offline ELF binary. |
| 60 | ++ * For online kernel or uprobes we don't need this because those are |
| 61 | ++ * rebased on _text, or already a section relative address. |
| 62 | ++ */ |
| 63 | ++static int |
| 64 | ++post_process_offline_probe_trace_events(struct probe_trace_event *tevs, |
| 65 | ++ int ntevs, const char *pathname) |
| 66 | ++{ |
| 67 | ++ struct symbol *sym; |
| 68 | ++ struct map *map; |
| 69 | ++ unsigned long stext = 0; |
| 70 | ++ u64 addr; |
| 71 | ++ int i; |
| 72 | ++ |
| 73 | ++ /* Prepare a map for offline binary */ |
| 74 | ++ map = dso__new_map(pathname); |
| 75 | ++ if (!map || get_text_start_address(pathname, &stext) < 0) { |
| 76 | ++ pr_warning("Failed to get ELF symbols for %s\n", pathname); |
| 77 | ++ return -EINVAL; |
| 78 | ++ } |
| 79 | ++ |
| 80 | ++ for (i = 0; i < ntevs; i++) { |
| 81 | ++ addr = tevs[i].point.address + tevs[i].point.offset - stext; |
| 82 | ++ sym = map__find_symbol(map, addr); |
| 83 | ++ if (!sym) |
| 84 | ++ continue; |
| 85 | ++ if (!strcmp(sym->name, tevs[i].point.symbol)) |
| 86 | ++ continue; |
| 87 | ++ /* If we have no realname, use symbol for it */ |
| 88 | ++ if (!tevs[i].point.realname) |
| 89 | ++ tevs[i].point.realname = tevs[i].point.symbol; |
| 90 | ++ else |
| 91 | ++ free(tevs[i].point.symbol); |
| 92 | ++ tevs[i].point.symbol = strdup(sym->name); |
| 93 | ++ tevs[i].point.offset = addr - sym->start; |
| 94 | ++ } |
| 95 | ++ map__put(map); |
| 96 | ++ |
| 97 | ++ return 0; |
| 98 | ++} |
| 99 | ++ |
| 100 | + static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, |
| 101 | + int ntevs, const char *exec) |
| 102 | + { |
| 103 | +@@ -694,7 +739,8 @@ post_process_kernel_probe_trace_events(s |
| 104 | + |
| 105 | + /* Skip post process if the target is an offline kernel */ |
| 106 | + if (symbol_conf.ignore_vmlinux_buildid) |
| 107 | +- return 0; |
| 108 | ++ return post_process_offline_probe_trace_events(tevs, ntevs, |
| 109 | ++ symbol_conf.vmlinux_name); |
| 110 | + |
| 111 | + reloc_sym = kernel_get_ref_reloc_sym(); |
| 112 | + if (!reloc_sym) { |
| 113 | + |
| 114 | +--- |
| 115 | + |
| 116 | +From 3e96dac7c956089d3f23aca98c4dfca57b6aaf8a Mon Sep 17 00:00:00 2001 |
| 117 | +From: Masami Hiramatsu <mhiramat@kernel.org> |
| 118 | +Date: Wed, 11 Jan 2017 15:00:47 +0900 |
| 119 | +Subject: perf probe: Add error checks to offline probe post-processing |
| 120 | + |
| 121 | +From: Masami Hiramatsu <mhiramat@kernel.org> |
| 122 | + |
| 123 | +commit 3e96dac7c956089d3f23aca98c4dfca57b6aaf8a upstream. |
| 124 | + |
| 125 | +Add error check codes on post processing and improve it for offline |
| 126 | +probe events as: |
| 127 | + |
| 128 | + - post processing fails if no matched symbol found in map(-ENOENT) |
| 129 | + or strdup() failed(-ENOMEM). |
| 130 | + |
| 131 | + - Even if the symbol name is the same, it updates symbol address |
| 132 | + and offset. |
| 133 | + |
| 134 | +Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> |
| 135 | +Cc: Jiri Olsa <jolsa@redhat.com> |
| 136 | +Cc: Namhyung Kim <namhyung@kernel.org> |
| 137 | +Cc: Peter Zijlstra <peterz@infradead.org> |
| 138 | +Link: http://lkml.kernel.org/r/148411443738.9978.4617979132625405545.stgit@devbox |
| 139 | +Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| 140 | +Cc: Krister Johansen <kjlx@templeofstupid.com> |
| 141 | +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| 142 | + |
| 143 | +--- |
| 144 | + tools/perf/util/probe-event.c | 50 +++++++++++++++++++++++++++--------------- |
| 145 | + 1 file changed, 33 insertions(+), 17 deletions(-) |
| 146 | + |
| 147 | +--- a/tools/perf/util/probe-event.c |
| 148 | ++++ b/tools/perf/util/probe-event.c |
| 149 | +@@ -618,6 +618,33 @@ error: |
| 150 | + return ret ? : -ENOENT; |
| 151 | + } |
| 152 | + |
| 153 | ++/* Adjust symbol name and address */ |
| 154 | ++static int post_process_probe_trace_point(struct probe_trace_point *tp, |
| 155 | ++ struct map *map, unsigned long offs) |
| 156 | ++{ |
| 157 | ++ struct symbol *sym; |
| 158 | ++ u64 addr = tp->address + tp->offset - offs; |
| 159 | ++ |
| 160 | ++ sym = map__find_symbol(map, addr); |
| 161 | ++ if (!sym) |
| 162 | ++ return -ENOENT; |
| 163 | ++ |
| 164 | ++ if (strcmp(sym->name, tp->symbol)) { |
| 165 | ++ /* If we have no realname, use symbol for it */ |
| 166 | ++ if (!tp->realname) |
| 167 | ++ tp->realname = tp->symbol; |
| 168 | ++ else |
| 169 | ++ free(tp->symbol); |
| 170 | ++ tp->symbol = strdup(sym->name); |
| 171 | ++ if (!tp->symbol) |
| 172 | ++ return -ENOMEM; |
| 173 | ++ } |
| 174 | ++ tp->offset = addr - sym->start; |
| 175 | ++ tp->address -= offs; |
| 176 | ++ |
| 177 | ++ return 0; |
| 178 | ++} |
| 179 | ++ |
| 180 | + /* |
| 181 | + * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions |
| 182 | + * and generate new symbols with suffixes such as .constprop.N or .isra.N |
| 183 | +@@ -630,11 +657,9 @@ static int |
| 184 | + post_process_offline_probe_trace_events(struct probe_trace_event *tevs, |
| 185 | + int ntevs, const char *pathname) |
| 186 | + { |
| 187 | +- struct symbol *sym; |
| 188 | + struct map *map; |
| 189 | + unsigned long stext = 0; |
| 190 | +- u64 addr; |
| 191 | +- int i; |
| 192 | ++ int i, ret = 0; |
| 193 | + |
| 194 | + /* Prepare a map for offline binary */ |
| 195 | + map = dso__new_map(pathname); |
| 196 | +@@ -644,23 +669,14 @@ post_process_offline_probe_trace_events( |
| 197 | + } |
| 198 | + |
| 199 | + for (i = 0; i < ntevs; i++) { |
| 200 | +- addr = tevs[i].point.address + tevs[i].point.offset - stext; |
| 201 | +- sym = map__find_symbol(map, addr); |
| 202 | +- if (!sym) |
| 203 | +- continue; |
| 204 | +- if (!strcmp(sym->name, tevs[i].point.symbol)) |
| 205 | +- continue; |
| 206 | +- /* If we have no realname, use symbol for it */ |
| 207 | +- if (!tevs[i].point.realname) |
| 208 | +- tevs[i].point.realname = tevs[i].point.symbol; |
| 209 | +- else |
| 210 | +- free(tevs[i].point.symbol); |
| 211 | +- tevs[i].point.symbol = strdup(sym->name); |
| 212 | +- tevs[i].point.offset = addr - sym->start; |
| 213 | ++ ret = post_process_probe_trace_point(&tevs[i].point, |
| 214 | ++ map, stext); |
| 215 | ++ if (ret < 0) |
| 216 | ++ break; |
| 217 | + } |
| 218 | + map__put(map); |
| 219 | + |
| 220 | +- return 0; |
| 221 | ++ return ret; |
| 222 | + } |
| 223 | + |
| 224 | + static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, |
0 commit comments