diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2011-06-27 03:27:39 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-07-15 16:14:19 -0400 |
commit | ff741783506c340035659a71be68ddb4068760d1 (patch) | |
tree | 90ccff5203ae54e738ab98d6a73f88fa5bc5a5b1 /tools | |
parent | e0d153c69040bb37cbdf09deb52fee3013c07742 (diff) |
perf probe: Introduce debuginfo to encapsulate dwarf information
Introduce debuginfo to encapsulate dwarf information.
This new object allows us to reuse and expand debuginfo easily.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Link: http://lkml.kernel.org/r/20110627072739.6528.12438.stgit@fedora15
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/probe-event.c | 78 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 201 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 39 |
3 files changed, 182 insertions, 136 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index f0223166e761..920c1957d6d3 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -170,16 +170,17 @@ const char *kernel_get_module_path(const char *module) | |||
170 | } | 170 | } |
171 | 171 | ||
172 | #ifdef DWARF_SUPPORT | 172 | #ifdef DWARF_SUPPORT |
173 | static int open_vmlinux(const char *module) | 173 | /* Open new debuginfo of given module */ |
174 | static struct debuginfo *open_debuginfo(const char *module) | ||
174 | { | 175 | { |
175 | const char *path = kernel_get_module_path(module); | 176 | const char *path = kernel_get_module_path(module); |
177 | |||
176 | if (!path) { | 178 | if (!path) { |
177 | pr_err("Failed to find path of %s module.\n", | 179 | pr_err("Failed to find path of %s module.\n", |
178 | module ?: "kernel"); | 180 | module ?: "kernel"); |
179 | return -ENOENT; | 181 | return NULL; |
180 | } | 182 | } |
181 | pr_debug("Try to open %s\n", path); | 183 | return debuginfo__new(path); |
182 | return open(path, O_RDONLY); | ||
183 | } | 184 | } |
184 | 185 | ||
185 | /* | 186 | /* |
@@ -193,13 +194,24 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
193 | struct map *map; | 194 | struct map *map; |
194 | u64 addr; | 195 | u64 addr; |
195 | int ret = -ENOENT; | 196 | int ret = -ENOENT; |
197 | struct debuginfo *dinfo; | ||
196 | 198 | ||
197 | sym = __find_kernel_function_by_name(tp->symbol, &map); | 199 | sym = __find_kernel_function_by_name(tp->symbol, &map); |
198 | if (sym) { | 200 | if (sym) { |
199 | addr = map->unmap_ip(map, sym->start + tp->offset); | 201 | addr = map->unmap_ip(map, sym->start + tp->offset); |
200 | pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, | 202 | pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, |
201 | tp->offset, addr); | 203 | tp->offset, addr); |
202 | ret = find_perf_probe_point((unsigned long)addr, pp); | 204 | |
205 | dinfo = debuginfo__new_online_kernel(addr); | ||
206 | if (dinfo) { | ||
207 | ret = debuginfo__find_probe_point(dinfo, | ||
208 | (unsigned long)addr, pp); | ||
209 | debuginfo__delete(dinfo); | ||
210 | } else { | ||
211 | pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", | ||
212 | addr); | ||
213 | ret = -ENOENT; | ||
214 | } | ||
203 | } | 215 | } |
204 | if (ret <= 0) { | 216 | if (ret <= 0) { |
205 | pr_debug("Failed to find corresponding probes from " | 217 | pr_debug("Failed to find corresponding probes from " |
@@ -220,20 +232,22 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
220 | int max_tevs, const char *module) | 232 | int max_tevs, const char *module) |
221 | { | 233 | { |
222 | bool need_dwarf = perf_probe_event_need_dwarf(pev); | 234 | bool need_dwarf = perf_probe_event_need_dwarf(pev); |
223 | int fd, ntevs; | 235 | struct debuginfo *dinfo = open_debuginfo(module); |
236 | int ntevs; | ||
224 | 237 | ||
225 | fd = open_vmlinux(module); | 238 | if (!dinfo) { |
226 | if (fd < 0) { | ||
227 | if (need_dwarf) { | 239 | if (need_dwarf) { |
228 | pr_warning("Failed to open debuginfo file.\n"); | 240 | pr_warning("Failed to open debuginfo file.\n"); |
229 | return fd; | 241 | return -ENOENT; |
230 | } | 242 | } |
231 | pr_debug("Could not open vmlinux. Try to use symbols.\n"); | 243 | pr_debug("Could not open debuginfo. Try to use symbols.\n"); |
232 | return 0; | 244 | return 0; |
233 | } | 245 | } |
234 | 246 | ||
235 | /* Searching trace events corresponding to probe event */ | 247 | /* Searching trace events corresponding to a probe event */ |
236 | ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); | 248 | ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); |
249 | |||
250 | debuginfo__delete(dinfo); | ||
237 | 251 | ||
238 | if (ntevs > 0) { /* Succeeded to find trace events */ | 252 | if (ntevs > 0) { /* Succeeded to find trace events */ |
239 | pr_debug("find %d probe_trace_events.\n", ntevs); | 253 | pr_debug("find %d probe_trace_events.\n", ntevs); |
@@ -371,8 +385,9 @@ int show_line_range(struct line_range *lr, const char *module) | |||
371 | { | 385 | { |
372 | int l = 1; | 386 | int l = 1; |
373 | struct line_node *ln; | 387 | struct line_node *ln; |
388 | struct debuginfo *dinfo; | ||
374 | FILE *fp; | 389 | FILE *fp; |
375 | int fd, ret; | 390 | int ret; |
376 | char *tmp; | 391 | char *tmp; |
377 | 392 | ||
378 | /* Search a line range */ | 393 | /* Search a line range */ |
@@ -380,13 +395,14 @@ int show_line_range(struct line_range *lr, const char *module) | |||
380 | if (ret < 0) | 395 | if (ret < 0) |
381 | return ret; | 396 | return ret; |
382 | 397 | ||
383 | fd = open_vmlinux(module); | 398 | dinfo = open_debuginfo(module); |
384 | if (fd < 0) { | 399 | if (!dinfo) { |
385 | pr_warning("Failed to open debuginfo file.\n"); | 400 | pr_warning("Failed to open debuginfo file.\n"); |
386 | return fd; | 401 | return -ENOENT; |
387 | } | 402 | } |
388 | 403 | ||
389 | ret = find_line_range(fd, lr); | 404 | ret = debuginfo__find_line_range(dinfo, lr); |
405 | debuginfo__delete(dinfo); | ||
390 | if (ret == 0) { | 406 | if (ret == 0) { |
391 | pr_warning("Specified source line is not found.\n"); | 407 | pr_warning("Specified source line is not found.\n"); |
392 | return -ENOENT; | 408 | return -ENOENT; |
@@ -448,7 +464,8 @@ end: | |||
448 | return ret; | 464 | return ret; |
449 | } | 465 | } |
450 | 466 | ||
451 | static int show_available_vars_at(int fd, struct perf_probe_event *pev, | 467 | static int show_available_vars_at(struct debuginfo *dinfo, |
468 | struct perf_probe_event *pev, | ||
452 | int max_vls, struct strfilter *_filter, | 469 | int max_vls, struct strfilter *_filter, |
453 | bool externs) | 470 | bool externs) |
454 | { | 471 | { |
@@ -463,7 +480,8 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev, | |||
463 | return -EINVAL; | 480 | return -EINVAL; |
464 | pr_debug("Searching variables at %s\n", buf); | 481 | pr_debug("Searching variables at %s\n", buf); |
465 | 482 | ||
466 | ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); | 483 | ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, |
484 | max_vls, externs); | ||
467 | if (ret <= 0) { | 485 | if (ret <= 0) { |
468 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); | 486 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); |
469 | goto end; | 487 | goto end; |
@@ -504,24 +522,26 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
504 | int max_vls, const char *module, | 522 | int max_vls, const char *module, |
505 | struct strfilter *_filter, bool externs) | 523 | struct strfilter *_filter, bool externs) |
506 | { | 524 | { |
507 | int i, fd, ret = 0; | 525 | int i, ret = 0; |
526 | struct debuginfo *dinfo; | ||
508 | 527 | ||
509 | ret = init_vmlinux(); | 528 | ret = init_vmlinux(); |
510 | if (ret < 0) | 529 | if (ret < 0) |
511 | return ret; | 530 | return ret; |
512 | 531 | ||
532 | dinfo = open_debuginfo(module); | ||
533 | if (!dinfo) { | ||
534 | pr_warning("Failed to open debuginfo file.\n"); | ||
535 | return -ENOENT; | ||
536 | } | ||
537 | |||
513 | setup_pager(); | 538 | setup_pager(); |
514 | 539 | ||
515 | for (i = 0; i < npevs && ret >= 0; i++) { | 540 | for (i = 0; i < npevs && ret >= 0; i++) |
516 | fd = open_vmlinux(module); | 541 | ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, |
517 | if (fd < 0) { | ||
518 | pr_warning("Failed to open debug information file.\n"); | ||
519 | ret = fd; | ||
520 | break; | ||
521 | } | ||
522 | ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, | ||
523 | externs); | 542 | externs); |
524 | } | 543 | |
544 | debuginfo__delete(dinfo); | ||
525 | return ret; | 545 | return ret; |
526 | } | 546 | } |
527 | 547 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 53d219bddb48..3e44a3e36519 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -116,29 +116,37 @@ static const Dwfl_Callbacks offline_callbacks = { | |||
116 | }; | 116 | }; |
117 | 117 | ||
118 | /* Get a Dwarf from offline image */ | 118 | /* Get a Dwarf from offline image */ |
119 | static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) | 119 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, |
120 | const char *path) | ||
120 | { | 121 | { |
121 | Dwfl_Module *mod; | 122 | Dwfl_Module *mod; |
122 | Dwarf *dbg = NULL; | 123 | int fd; |
123 | 124 | ||
124 | if (!dwflp) | 125 | fd = open(path, O_RDONLY); |
125 | return NULL; | 126 | if (fd < 0) |
127 | return fd; | ||
126 | 128 | ||
127 | *dwflp = dwfl_begin(&offline_callbacks); | 129 | self->dwfl = dwfl_begin(&offline_callbacks); |
128 | if (!*dwflp) | 130 | if (!self->dwfl) |
129 | return NULL; | 131 | goto error; |
130 | 132 | ||
131 | mod = dwfl_report_offline(*dwflp, "", "", fd); | 133 | mod = dwfl_report_offline(self->dwfl, "", "", fd); |
132 | if (!mod) | 134 | if (!mod) |
133 | goto error; | 135 | goto error; |
134 | 136 | ||
135 | dbg = dwfl_module_getdwarf(mod, bias); | 137 | self->dbg = dwfl_module_getdwarf(mod, &self->bias); |
136 | if (!dbg) { | 138 | if (!self->dbg) |
139 | goto error; | ||
140 | |||
141 | return 0; | ||
137 | error: | 142 | error: |
138 | dwfl_end(*dwflp); | 143 | if (self->dwfl) |
139 | *dwflp = NULL; | 144 | dwfl_end(self->dwfl); |
140 | } | 145 | else |
141 | return dbg; | 146 | close(fd); |
147 | memset(self, 0, sizeof(*self)); | ||
148 | |||
149 | return -ENOENT; | ||
142 | } | 150 | } |
143 | 151 | ||
144 | #if _ELFUTILS_PREREQ(0, 148) | 152 | #if _ELFUTILS_PREREQ(0, 148) |
@@ -174,53 +182,82 @@ static const Dwfl_Callbacks kernel_callbacks = { | |||
174 | }; | 182 | }; |
175 | 183 | ||
176 | /* Get a Dwarf from live kernel image */ | 184 | /* Get a Dwarf from live kernel image */ |
177 | static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, | 185 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, |
178 | Dwarf_Addr *bias) | 186 | Dwarf_Addr addr) |
179 | { | 187 | { |
180 | Dwarf *dbg; | 188 | self->dwfl = dwfl_begin(&kernel_callbacks); |
181 | 189 | if (!self->dwfl) | |
182 | if (!dwflp) | 190 | return -EINVAL; |
183 | return NULL; | ||
184 | |||
185 | *dwflp = dwfl_begin(&kernel_callbacks); | ||
186 | if (!*dwflp) | ||
187 | return NULL; | ||
188 | 191 | ||
189 | /* Load the kernel dwarves: Don't care the result here */ | 192 | /* Load the kernel dwarves: Don't care the result here */ |
190 | dwfl_linux_kernel_report_kernel(*dwflp); | 193 | dwfl_linux_kernel_report_kernel(self->dwfl); |
191 | dwfl_linux_kernel_report_modules(*dwflp); | 194 | dwfl_linux_kernel_report_modules(self->dwfl); |
192 | 195 | ||
193 | dbg = dwfl_addrdwarf(*dwflp, addr, bias); | 196 | self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); |
194 | /* Here, check whether we could get a real dwarf */ | 197 | /* Here, check whether we could get a real dwarf */ |
195 | if (!dbg) { | 198 | if (!self->dbg) { |
196 | pr_debug("Failed to find kernel dwarf at %lx\n", | 199 | pr_debug("Failed to find kernel dwarf at %lx\n", |
197 | (unsigned long)addr); | 200 | (unsigned long)addr); |
198 | dwfl_end(*dwflp); | 201 | dwfl_end(self->dwfl); |
199 | *dwflp = NULL; | 202 | memset(self, 0, sizeof(*self)); |
203 | return -ENOENT; | ||
200 | } | 204 | } |
201 | return dbg; | 205 | |
206 | return 0; | ||
202 | } | 207 | } |
203 | #else | 208 | #else |
204 | /* With older elfutils, this just support kernel module... */ | 209 | /* With older elfutils, this just support kernel module... */ |
205 | static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp, | 210 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, |
206 | Dwarf_Addr *bias) | 211 | Dwarf_Addr addr __used) |
207 | { | 212 | { |
208 | int fd; | ||
209 | const char *path = kernel_get_module_path("kernel"); | 213 | const char *path = kernel_get_module_path("kernel"); |
210 | 214 | ||
211 | if (!path) { | 215 | if (!path) { |
212 | pr_err("Failed to find vmlinux path\n"); | 216 | pr_err("Failed to find vmlinux path\n"); |
213 | return NULL; | 217 | return -ENOENT; |
214 | } | 218 | } |
215 | 219 | ||
216 | pr_debug2("Use file %s for debuginfo\n", path); | 220 | pr_debug2("Use file %s for debuginfo\n", path); |
217 | fd = open(path, O_RDONLY); | 221 | return debuginfo__init_offline_dwarf(self, path); |
218 | if (fd < 0) | 222 | } |
223 | #endif | ||
224 | |||
225 | struct debuginfo *debuginfo__new(const char *path) | ||
226 | { | ||
227 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); | ||
228 | if (!self) | ||
219 | return NULL; | 229 | return NULL; |
220 | 230 | ||
221 | return dwfl_init_offline_dwarf(fd, dwflp, bias); | 231 | if (debuginfo__init_offline_dwarf(self, path) < 0) { |
232 | free(self); | ||
233 | self = NULL; | ||
234 | } | ||
235 | |||
236 | return self; | ||
237 | } | ||
238 | |||
239 | struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) | ||
240 | { | ||
241 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); | ||
242 | if (!self) | ||
243 | return NULL; | ||
244 | |||
245 | if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { | ||
246 | free(self); | ||
247 | self = NULL; | ||
248 | } | ||
249 | |||
250 | return self; | ||
251 | } | ||
252 | |||
253 | void debuginfo__delete(struct debuginfo *self) | ||
254 | { | ||
255 | if (self) { | ||
256 | if (self->dwfl) | ||
257 | dwfl_end(self->dwfl); | ||
258 | free(self); | ||
259 | } | ||
222 | } | 260 | } |
223 | #endif | ||
224 | 261 | ||
225 | /* | 262 | /* |
226 | * Probe finder related functions | 263 | * Probe finder related functions |
@@ -949,28 +986,18 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) | |||
949 | } | 986 | } |
950 | 987 | ||
951 | /* Find probe points from debuginfo */ | 988 | /* Find probe points from debuginfo */ |
952 | static int find_probes(int fd, struct probe_finder *pf) | 989 | static int debuginfo__find_probes(struct debuginfo *self, |
990 | struct probe_finder *pf) | ||
953 | { | 991 | { |
954 | struct perf_probe_point *pp = &pf->pev->point; | 992 | struct perf_probe_point *pp = &pf->pev->point; |
955 | Dwarf_Off off, noff; | 993 | Dwarf_Off off, noff; |
956 | size_t cuhl; | 994 | size_t cuhl; |
957 | Dwarf_Die *diep; | 995 | Dwarf_Die *diep; |
958 | Dwarf *dbg = NULL; | ||
959 | Dwfl *dwfl; | ||
960 | Dwarf_Addr bias; /* Currently ignored */ | ||
961 | int ret = 0; | 996 | int ret = 0; |
962 | 997 | ||
963 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); | ||
964 | if (!dbg) { | ||
965 | pr_warning("No debug information found in the vmlinux - " | ||
966 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
967 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
968 | return -EBADF; | ||
969 | } | ||
970 | |||
971 | #if _ELFUTILS_PREREQ(0, 142) | 998 | #if _ELFUTILS_PREREQ(0, 142) |
972 | /* Get the call frame information from this dwarf */ | 999 | /* Get the call frame information from this dwarf */ |
973 | pf->cfi = dwarf_getcfi(dbg); | 1000 | pf->cfi = dwarf_getcfi(self->dbg); |
974 | #endif | 1001 | #endif |
975 | 1002 | ||
976 | off = 0; | 1003 | off = 0; |
@@ -989,7 +1016,8 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
989 | .data = pf, | 1016 | .data = pf, |
990 | }; | 1017 | }; |
991 | 1018 | ||
992 | dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); | 1019 | dwarf_getpubnames(self->dbg, pubname_search_cb, |
1020 | &pubname_param, 0); | ||
993 | if (pubname_param.found) { | 1021 | if (pubname_param.found) { |
994 | ret = probe_point_search_cb(&pf->sp_die, &probe_param); | 1022 | ret = probe_point_search_cb(&pf->sp_die, &probe_param); |
995 | if (ret) | 1023 | if (ret) |
@@ -998,9 +1026,9 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
998 | } | 1026 | } |
999 | 1027 | ||
1000 | /* Loop on CUs (Compilation Unit) */ | 1028 | /* Loop on CUs (Compilation Unit) */ |
1001 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | 1029 | while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { |
1002 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1030 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1003 | diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); | 1031 | diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); |
1004 | if (!diep) | 1032 | if (!diep) |
1005 | continue; | 1033 | continue; |
1006 | 1034 | ||
@@ -1027,8 +1055,6 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1027 | 1055 | ||
1028 | found: | 1056 | found: |
1029 | line_list__free(&pf->lcache); | 1057 | line_list__free(&pf->lcache); |
1030 | if (dwfl) | ||
1031 | dwfl_end(dwfl); | ||
1032 | 1058 | ||
1033 | return ret; | 1059 | return ret; |
1034 | } | 1060 | } |
@@ -1074,8 +1100,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1074 | } | 1100 | } |
1075 | 1101 | ||
1076 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | 1102 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
1077 | int find_probe_trace_events(int fd, struct perf_probe_event *pev, | 1103 | int debuginfo__find_trace_events(struct debuginfo *self, |
1078 | struct probe_trace_event **tevs, int max_tevs) | 1104 | struct perf_probe_event *pev, |
1105 | struct probe_trace_event **tevs, int max_tevs) | ||
1079 | { | 1106 | { |
1080 | struct trace_event_finder tf = { | 1107 | struct trace_event_finder tf = { |
1081 | .pf = {.pev = pev, .callback = add_probe_trace_event}, | 1108 | .pf = {.pev = pev, .callback = add_probe_trace_event}, |
@@ -1090,7 +1117,7 @@ int find_probe_trace_events(int fd, struct perf_probe_event *pev, | |||
1090 | tf.tevs = *tevs; | 1117 | tf.tevs = *tevs; |
1091 | tf.ntevs = 0; | 1118 | tf.ntevs = 0; |
1092 | 1119 | ||
1093 | ret = find_probes(fd, &tf.pf); | 1120 | ret = debuginfo__find_probes(self, &tf.pf); |
1094 | if (ret < 0) { | 1121 | if (ret < 0) { |
1095 | free(*tevs); | 1122 | free(*tevs); |
1096 | *tevs = NULL; | 1123 | *tevs = NULL; |
@@ -1184,9 +1211,10 @@ out: | |||
1184 | } | 1211 | } |
1185 | 1212 | ||
1186 | /* Find available variables at given probe point */ | 1213 | /* Find available variables at given probe point */ |
1187 | int find_available_vars_at(int fd, struct perf_probe_event *pev, | 1214 | int debuginfo__find_available_vars_at(struct debuginfo *self, |
1188 | struct variable_list **vls, int max_vls, | 1215 | struct perf_probe_event *pev, |
1189 | bool externs) | 1216 | struct variable_list **vls, |
1217 | int max_vls, bool externs) | ||
1190 | { | 1218 | { |
1191 | struct available_var_finder af = { | 1219 | struct available_var_finder af = { |
1192 | .pf = {.pev = pev, .callback = add_available_vars}, | 1220 | .pf = {.pev = pev, .callback = add_available_vars}, |
@@ -1201,7 +1229,7 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev, | |||
1201 | af.vls = *vls; | 1229 | af.vls = *vls; |
1202 | af.nvls = 0; | 1230 | af.nvls = 0; |
1203 | 1231 | ||
1204 | ret = find_probes(fd, &af.pf); | 1232 | ret = debuginfo__find_probes(self, &af.pf); |
1205 | if (ret < 0) { | 1233 | if (ret < 0) { |
1206 | /* Free vlist for error */ | 1234 | /* Free vlist for error */ |
1207 | while (af.nvls--) { | 1235 | while (af.nvls--) { |
@@ -1219,28 +1247,19 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev, | |||
1219 | } | 1247 | } |
1220 | 1248 | ||
1221 | /* Reverse search */ | 1249 | /* Reverse search */ |
1222 | int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | 1250 | int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, |
1251 | struct perf_probe_point *ppt) | ||
1223 | { | 1252 | { |
1224 | Dwarf_Die cudie, spdie, indie; | 1253 | Dwarf_Die cudie, spdie, indie; |
1225 | Dwarf *dbg = NULL; | 1254 | Dwarf_Addr _addr, baseaddr; |
1226 | Dwfl *dwfl = NULL; | ||
1227 | Dwarf_Addr _addr, baseaddr, bias = 0; | ||
1228 | const char *fname = NULL, *func = NULL, *tmp; | 1255 | const char *fname = NULL, *func = NULL, *tmp; |
1229 | int baseline = 0, lineno = 0, ret = 0; | 1256 | int baseline = 0, lineno = 0, ret = 0; |
1230 | 1257 | ||
1231 | /* Open the live linux kernel */ | ||
1232 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); | ||
1233 | if (!dbg) { | ||
1234 | pr_warning("No debug information found in the vmlinux - " | ||
1235 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1236 | ret = -EINVAL; | ||
1237 | goto end; | ||
1238 | } | ||
1239 | |||
1240 | /* Adjust address with bias */ | 1258 | /* Adjust address with bias */ |
1241 | addr += bias; | 1259 | addr += self->bias; |
1260 | |||
1242 | /* Find cu die */ | 1261 | /* Find cu die */ |
1243 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { | 1262 | if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { |
1244 | pr_warning("Failed to find debug information for address %lx\n", | 1263 | pr_warning("Failed to find debug information for address %lx\n", |
1245 | addr); | 1264 | addr); |
1246 | ret = -EINVAL; | 1265 | ret = -EINVAL; |
@@ -1316,8 +1335,6 @@ post: | |||
1316 | } | 1335 | } |
1317 | } | 1336 | } |
1318 | end: | 1337 | end: |
1319 | if (dwfl) | ||
1320 | dwfl_end(dwfl); | ||
1321 | if (ret == 0 && (fname || func)) | 1338 | if (ret == 0 && (fname || func)) |
1322 | ret = 1; /* Found a point */ | 1339 | ret = 1; /* Found a point */ |
1323 | return ret; | 1340 | return ret; |
@@ -1427,26 +1444,15 @@ static int find_line_range_by_func(struct line_finder *lf) | |||
1427 | return param.retval; | 1444 | return param.retval; |
1428 | } | 1445 | } |
1429 | 1446 | ||
1430 | int find_line_range(int fd, struct line_range *lr) | 1447 | int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) |
1431 | { | 1448 | { |
1432 | struct line_finder lf = {.lr = lr, .found = 0}; | 1449 | struct line_finder lf = {.lr = lr, .found = 0}; |
1433 | int ret = 0; | 1450 | int ret = 0; |
1434 | Dwarf_Off off = 0, noff; | 1451 | Dwarf_Off off = 0, noff; |
1435 | size_t cuhl; | 1452 | size_t cuhl; |
1436 | Dwarf_Die *diep; | 1453 | Dwarf_Die *diep; |
1437 | Dwarf *dbg = NULL; | ||
1438 | Dwfl *dwfl; | ||
1439 | Dwarf_Addr bias; /* Currently ignored */ | ||
1440 | const char *comp_dir; | 1454 | const char *comp_dir; |
1441 | 1455 | ||
1442 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); | ||
1443 | if (!dbg) { | ||
1444 | pr_warning("No debug information found in the vmlinux - " | ||
1445 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1446 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
1447 | return -EBADF; | ||
1448 | } | ||
1449 | |||
1450 | /* Fastpath: lookup by function name from .debug_pubnames section */ | 1456 | /* Fastpath: lookup by function name from .debug_pubnames section */ |
1451 | if (lr->function) { | 1457 | if (lr->function) { |
1452 | struct pubname_callback_param pubname_param = { | 1458 | struct pubname_callback_param pubname_param = { |
@@ -1455,7 +1461,8 @@ int find_line_range(int fd, struct line_range *lr) | |||
1455 | struct dwarf_callback_param line_range_param = { | 1461 | struct dwarf_callback_param line_range_param = { |
1456 | .data = (void *)&lf, .retval = 0}; | 1462 | .data = (void *)&lf, .retval = 0}; |
1457 | 1463 | ||
1458 | dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); | 1464 | dwarf_getpubnames(self->dbg, pubname_search_cb, |
1465 | &pubname_param, 0); | ||
1459 | if (pubname_param.found) { | 1466 | if (pubname_param.found) { |
1460 | line_range_search_cb(&lf.sp_die, &line_range_param); | 1467 | line_range_search_cb(&lf.sp_die, &line_range_param); |
1461 | if (lf.found) | 1468 | if (lf.found) |
@@ -1465,11 +1472,12 @@ int find_line_range(int fd, struct line_range *lr) | |||
1465 | 1472 | ||
1466 | /* Loop on CUs (Compilation Unit) */ | 1473 | /* Loop on CUs (Compilation Unit) */ |
1467 | while (!lf.found && ret >= 0) { | 1474 | while (!lf.found && ret >= 0) { |
1468 | if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) | 1475 | if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, |
1476 | NULL, NULL, NULL) != 0) | ||
1469 | break; | 1477 | break; |
1470 | 1478 | ||
1471 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1479 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1472 | diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); | 1480 | diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); |
1473 | if (!diep) | 1481 | if (!diep) |
1474 | continue; | 1482 | continue; |
1475 | 1483 | ||
@@ -1503,7 +1511,6 @@ found: | |||
1503 | } | 1511 | } |
1504 | 1512 | ||
1505 | pr_debug("path: %s\n", lr->path); | 1513 | pr_debug("path: %s\n", lr->path); |
1506 | dwfl_end(dwfl); | ||
1507 | return (ret < 0) ? ret : lf.found; | 1514 | return (ret < 0) ? ret : lf.found; |
1508 | } | 1515 | } |
1509 | 1516 | ||
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 0f1ed3d25a20..c478b42a2473 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -16,23 +16,42 @@ static inline int is_c_varname(const char *name) | |||
16 | } | 16 | } |
17 | 17 | ||
18 | #ifdef DWARF_SUPPORT | 18 | #ifdef DWARF_SUPPORT |
19 | |||
20 | #include "dwarf-aux.h" | ||
21 | |||
22 | /* TODO: export debuginfo data structure even if no dwarf support */ | ||
23 | |||
24 | /* debug information structure */ | ||
25 | struct debuginfo { | ||
26 | Dwarf *dbg; | ||
27 | Dwfl *dwfl; | ||
28 | Dwarf_Addr bias; | ||
29 | }; | ||
30 | |||
31 | extern struct debuginfo *debuginfo__new(const char *path); | ||
32 | extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr); | ||
33 | extern void debuginfo__delete(struct debuginfo *self); | ||
34 | |||
19 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | 35 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
20 | extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, | 36 | extern int debuginfo__find_trace_events(struct debuginfo *self, |
21 | struct probe_trace_event **tevs, | 37 | struct perf_probe_event *pev, |
22 | int max_tevs); | 38 | struct probe_trace_event **tevs, |
39 | int max_tevs); | ||
23 | 40 | ||
24 | /* Find a perf_probe_point from debuginfo */ | 41 | /* Find a perf_probe_point from debuginfo */ |
25 | extern int find_perf_probe_point(unsigned long addr, | 42 | extern int debuginfo__find_probe_point(struct debuginfo *self, |
26 | struct perf_probe_point *ppt); | 43 | unsigned long addr, |
44 | struct perf_probe_point *ppt); | ||
27 | 45 | ||
28 | /* Find a line range */ | 46 | /* Find a line range */ |
29 | extern int find_line_range(int fd, struct line_range *lr); | 47 | extern int debuginfo__find_line_range(struct debuginfo *self, |
48 | struct line_range *lr); | ||
30 | 49 | ||
31 | /* Find available variables */ | 50 | /* Find available variables */ |
32 | extern int find_available_vars_at(int fd, struct perf_probe_event *pev, | 51 | extern int debuginfo__find_available_vars_at(struct debuginfo *self, |
33 | struct variable_list **vls, int max_points, | 52 | struct perf_probe_event *pev, |
34 | bool externs); | 53 | struct variable_list **vls, |
35 | #include "dwarf-aux.h" | 54 | int max_points, bool externs); |
36 | 55 | ||
37 | struct probe_finder { | 56 | struct probe_finder { |
38 | struct perf_probe_event *pev; /* Target probe event */ | 57 | struct perf_probe_event *pev; /* Target probe event */ |