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 */ |
