aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2014-02-06 00:32:18 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-02-18 07:34:51 -0500
commitf90acac75713cc6f18a4b2f1b9162bc1cd893c20 (patch)
tree5a845a8cac58ed20e28fa7c00e2cb798b52bf7ee /tools
parentdfef99cd0b2c8abafb571e5992ce954135be5f40 (diff)
perf probe: Find given address from offline dwarf
Find the given address from offline dwarfs instead of online kernel dwarfs. On the KASLR enabled kernel, the kernel text section is loaded with random offset, and the debuginfo__new_online_kernel can't handle it. So let's move to the offline dwarf loader instead of using the online dwarf loader. As a result, since we don't need debuginfo__new_online_kernel any more, this also removes the functions related to that. Without this change; # ./perf probe -l probe:t_show (on _stext+901288 with m v) probe:t_show_1 (on _stext+939624 with m v t) probe:t_show_2 (on _stext+980296 with m v fmt) probe:t_show_3 (on _stext+1014392 with m v file) With this change; # ./perf probe -l probe:t_show (on t_show@linux-3/kernel/trace/ftrace.c with m v) probe:t_show_1 (on t_show@linux-3/kernel/trace/trace.c with m v t) probe:t_show_2 (on t_show@kernel/trace/trace_printk.c with m v fmt) probe:t_show_3 (on t_show@kernel/trace/trace_events.c with m v file) Changes from v2: - Instead of retrying, directly opens offline dwarf. - Remove debuginfo__new_online_kernel and related functions. - Refer map->reloc to get the correct address of a symbol. - Add a special case for handling ref_reloc_sym based address. Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: David Ahern <dsahern@gmail.com> Cc: "David A. Long" <dave.long@linaro.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: yrl.pp-manager.tt@hitachi.com Link: http://lkml.kernel.org/r/20140206053218.29635.74821.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/probe-event.c40
-rw-r--r--tools/perf/util/probe-finder.c86
-rw-r--r--tools/perf/util/probe-finder.h1
3 files changed, 26 insertions, 101 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1ce2cb9845b6..8e34c8d47813 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -248,6 +248,18 @@ static struct debuginfo *open_debuginfo(const char *module)
248 return debuginfo__new(path); 248 return debuginfo__new(path);
249} 249}
250 250
251static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
252{
253 /* kmap->ref_reloc_sym should be set if host_machine is initialized */
254 struct kmap *kmap;
255
256 if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
257 return NULL;
258
259 kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
260 return kmap->ref_reloc_sym;
261}
262
251/* 263/*
252 * Convert trace point to probe point with debuginfo 264 * Convert trace point to probe point with debuginfo
253 * Currently only handles kprobes. 265 * Currently only handles kprobes.
@@ -256,18 +268,27 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
256 struct perf_probe_point *pp) 268 struct perf_probe_point *pp)
257{ 269{
258 struct symbol *sym; 270 struct symbol *sym;
271 struct ref_reloc_sym *reloc_sym;
259 struct map *map; 272 struct map *map;
260 u64 addr; 273 u64 addr = 0;
261 int ret = -ENOENT; 274 int ret = -ENOENT;
262 struct debuginfo *dinfo; 275 struct debuginfo *dinfo;
263 276
264 sym = __find_kernel_function_by_name(tp->symbol, &map); 277 /* ref_reloc_sym is just a label. Need a special fix*/
265 if (sym) { 278 reloc_sym = __kernel_get_ref_reloc_sym();
266 addr = map->unmap_ip(map, sym->start + tp->offset); 279 if (reloc_sym && strcmp(tp->symbol, reloc_sym->name) == 0)
280 addr = reloc_sym->unrelocated_addr + tp->offset;
281 else {
282 sym = __find_kernel_function_by_name(tp->symbol, &map);
283 if (sym)
284 addr = map->unmap_ip(map, sym->start + tp->offset) -
285 map->reloc;
286 }
287 if (addr) {
267 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, 288 pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
268 tp->offset, addr); 289 tp->offset, addr);
269 290
270 dinfo = debuginfo__new_online_kernel(addr); 291 dinfo = open_debuginfo(tp->module);
271 if (dinfo) { 292 if (dinfo) {
272 ret = debuginfo__find_probe_point(dinfo, 293 ret = debuginfo__find_probe_point(dinfo,
273 (unsigned long)addr, pp); 294 (unsigned long)addr, pp);
@@ -383,15 +404,6 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
383 return ret; 404 return ret;
384} 405}
385 406
386static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
387{
388 /* kmap->ref_reloc_sym should be set if host_machine is initialized */
389 struct kmap *kmap;
390
391 kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
392 return kmap->ref_reloc_sym;
393}
394
395/* Post processing the probe events */ 407/* Post processing the probe events */
396static int post_process_probe_trace_events(struct probe_trace_event *tevs, 408static int post_process_probe_trace_events(struct probe_trace_event *tevs,
397 int ntevs, const char *module, 409 int ntevs, const char *module,
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e5e589fdef9b..4f6e277c457c 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -89,79 +89,6 @@ error:
89 return -ENOENT; 89 return -ENOENT;
90} 90}
91 91
92#if _ELFUTILS_PREREQ(0, 148)
93/* This method is buggy if elfutils is older than 0.148 */
94static int __linux_kernel_find_elf(Dwfl_Module *mod,
95 void **userdata,
96 const char *module_name,
97 Dwarf_Addr base,
98 char **file_name, Elf **elfp)
99{
100 int fd;
101 const char *path = kernel_get_module_path(module_name);
102
103 pr_debug2("Use file %s for %s\n", path, module_name);
104 if (path) {
105 fd = open(path, O_RDONLY);
106 if (fd >= 0) {
107 *file_name = strdup(path);
108 return fd;
109 }
110 }
111 /* If failed, try to call standard method */
112 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
113 file_name, elfp);
114}
115
116static const Dwfl_Callbacks kernel_callbacks = {
117 .find_debuginfo = dwfl_standard_find_debuginfo,
118 .debuginfo_path = &debuginfo_path,
119
120 .find_elf = __linux_kernel_find_elf,
121 .section_address = dwfl_linux_kernel_module_section_address,
122};
123
124/* Get a Dwarf from live kernel image */
125static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
126 Dwarf_Addr addr)
127{
128 dbg->dwfl = dwfl_begin(&kernel_callbacks);
129 if (!dbg->dwfl)
130 return -EINVAL;
131
132 /* Load the kernel dwarves: Don't care the result here */
133 dwfl_linux_kernel_report_kernel(dbg->dwfl);
134 dwfl_linux_kernel_report_modules(dbg->dwfl);
135
136 dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
137 /* Here, check whether we could get a real dwarf */
138 if (!dbg->dbg) {
139 pr_debug("Failed to find kernel dwarf at %lx\n",
140 (unsigned long)addr);
141 dwfl_end(dbg->dwfl);
142 memset(dbg, 0, sizeof(*dbg));
143 return -ENOENT;
144 }
145
146 return 0;
147}
148#else
149/* With older elfutils, this just support kernel module... */
150static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
151 Dwarf_Addr addr __maybe_unused)
152{
153 const char *path = kernel_get_module_path("kernel");
154
155 if (!path) {
156 pr_err("Failed to find vmlinux path\n");
157 return -ENOENT;
158 }
159
160 pr_debug2("Use file %s for debuginfo\n", path);
161 return debuginfo__init_offline_dwarf(dbg, path);
162}
163#endif
164
165struct debuginfo *debuginfo__new(const char *path) 92struct debuginfo *debuginfo__new(const char *path)
166{ 93{
167 struct debuginfo *dbg = zalloc(sizeof(*dbg)); 94 struct debuginfo *dbg = zalloc(sizeof(*dbg));
@@ -174,19 +101,6 @@ struct debuginfo *debuginfo__new(const char *path)
174 return dbg; 101 return dbg;
175} 102}
176 103
177struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
178{
179 struct debuginfo *dbg = zalloc(sizeof(*dbg));
180
181 if (!dbg)
182 return NULL;
183
184 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
185 zfree(&dbg);
186
187 return dbg;
188}
189
190void debuginfo__delete(struct debuginfo *dbg) 104void debuginfo__delete(struct debuginfo *dbg)
191{ 105{
192 if (dbg) { 106 if (dbg) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 592c4dac3be9..3fc597365ce6 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -31,7 +31,6 @@ struct debuginfo {
31}; 31};
32 32
33extern struct debuginfo *debuginfo__new(const char *path); 33extern struct debuginfo *debuginfo__new(const char *path);
34extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
35extern void debuginfo__delete(struct debuginfo *dbg); 34extern void debuginfo__delete(struct debuginfo *dbg);
36 35
37/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 36/* Find probe_trace_events specified by perf_probe_event from debuginfo */