diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d2c6cdd9d42b..28d41e709128 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -9,6 +9,13 @@ #include "debug.h" #include "vdso.h" +static const char * const debuglink_paths[] = { + "%.0s%s", + "%s/%s", + "%s/.debug/%s", + "/usr/lib/debug%s/%s" +}; + char dso__symtab_origin(const struct dso *dso) { static const char origin[] = { @@ -44,24 +51,43 @@ int dso__read_binary_type_filename(const struct dso *dso, size_t len; switch (type) { - case DSO_BINARY_TYPE__DEBUGLINK: { - char *debuglink; + case DSO_BINARY_TYPE__DEBUGLINK: + { + const char *last_slash; + char dso_dir[PATH_MAX]; + char symfile[PATH_MAX]; + unsigned int i; len = __symbol__join_symfs(filename, size, dso->long_name); - debuglink = filename + len; - while (debuglink != filename && *debuglink != '/') - debuglink--; - if (*debuglink == '/') - debuglink++; + last_slash = filename + len; + while (last_slash != filename && *last_slash != '/') + last_slash--; - ret = -1; - if (!is_regular_file(filename)) + strncpy(dso_dir, filename, last_slash - filename); + dso_dir[last_slash-filename] = '\0'; + + if (!is_regular_file(filename)) { + ret = -1; + break; + } + + ret = filename__read_debuglink(filename, symfile, PATH_MAX); + if (ret) break; - ret = filename__read_debuglink(filename, debuglink, - size - (debuglink - filename)); + /* Check predefined locations where debug file might reside */ + ret = -1; + for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) { + snprintf(filename, size, + debuglink_paths[i], dso_dir, symfile); + if (is_regular_file(filename)) { + ret = 0; + break; + } } + break; + } case DSO_BINARY_TYPE__BUILD_ID_CACHE: if (dso__build_id_filename(dso, filename, size) == NULL) ret = -1; diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 6fec84dff3f7..bfb9b7987692 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -35,6 +35,7 @@ #include "util.h" #include "debug.h" #include "asm/bug.h" +#include "dso.h" extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, @@ -297,15 +298,58 @@ static int read_unwind_spec_debug_frame(struct dso *dso, int fd; u64 ofs = dso->data.debug_frame_offset; + /* debug_frame can reside in: + * - dso + * - debug pointed by symsrc_filename + * - gnu_debuglink, which doesn't necessary + * has to be pointed by symsrc_filename + */ if (ofs == 0) { fd = dso__data_get_fd(dso, machine); - if (fd < 0) - return -EINVAL; + if (fd >= 0) { + ofs = elf_section_offset(fd, ".debug_frame"); + dso__data_put_fd(dso); + } + + if (ofs <= 0) { + fd = open(dso->symsrc_filename, O_RDONLY); + if (fd >= 0) { + ofs = elf_section_offset(fd, ".debug_frame"); + close(fd); + } + } + + if (ofs <= 0) { + char *debuglink = malloc(PATH_MAX); + int ret = 0; + + ret = dso__read_binary_type_filename( + dso, DSO_BINARY_TYPE__DEBUGLINK, + machine->root_dir, debuglink, PATH_MAX); + if (!ret) { + fd = open(debuglink, O_RDONLY); + if (fd >= 0) { + ofs = elf_section_offset(fd, + ".debug_frame"); + close(fd); + } + } + if (ofs > 0) { + if (dso->symsrc_filename != NULL) { + pr_warning( + "%s: overwrite symsrc(%s,%s)\n", + __func__, + dso->symsrc_filename, + debuglink); + free(dso->symsrc_filename); + } + dso->symsrc_filename = debuglink; + } else { + free(debuglink); + } + } - /* Check the .debug_frame section for unwinding info */ - ofs = elf_section_offset(fd, ".debug_frame"); dso->data.debug_frame_offset = ofs; - dso__data_put_fd(dso); } *offset = ofs;