perf unwind: Fix separate debug info files when using elfutils' libdw's unwinder
[linux-2.6-microblaze.git] / tools / perf / util / unwind-libdw.c
index 7a3dbc2..0ada907 100644 (file)
 
 static char *debuginfo_path;
 
+static int __find_debuginfo(Dwfl_Module *mod __maybe_unused, void **userdata,
+                           const char *modname __maybe_unused, Dwarf_Addr base __maybe_unused,
+                           const char *file_name, const char *debuglink_file __maybe_unused,
+                           GElf_Word debuglink_crc __maybe_unused, char **debuginfo_file_name)
+{
+       const struct dso *dso = *userdata;
+
+       assert(dso);
+       if (dso->symsrc_filename && strcmp (file_name, dso->symsrc_filename))
+               *debuginfo_file_name = strdup(dso->symsrc_filename);
+       return -1;
+}
+
 static const Dwfl_Callbacks offline_callbacks = {
-       .find_debuginfo         = dwfl_standard_find_debuginfo,
+       .find_debuginfo         = __find_debuginfo,
        .debuginfo_path         = &debuginfo_path,
        .section_address        = dwfl_offline_section_address,
+       // .find_elf is not set as we use dwfl_report_elf() instead.
 };
 
 static int __report_module(struct addr_location *al, u64 ip,
@@ -46,16 +60,24 @@ static int __report_module(struct addr_location *al, u64 ip,
        mod = dwfl_addrmodule(ui->dwfl, ip);
        if (mod) {
                Dwarf_Addr s;
+               void **userdatap;
 
-               dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
+               dwfl_module_info(mod, &userdatap, &s, NULL, NULL, NULL, NULL, NULL);
+               *userdatap = dso;
                if (s != al->map->start - al->map->pgoff)
                        mod = 0;
        }
 
        if (!mod)
-               mod = dwfl_report_elf(ui->dwfl, dso->short_name,
-                                     (dso->symsrc_filename ? dso->symsrc_filename : dso->long_name), -1, al->map->start - al->map->pgoff,
-                                     false);
+               mod = dwfl_report_elf(ui->dwfl, dso->short_name, dso->long_name, -1,
+                                     al->map->start - al->map->pgoff, false);
+       if (!mod) {
+               char filename[PATH_MAX];
+
+               if (dso__build_id_filename(dso, filename, sizeof(filename), false))
+                       mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
+                                             al->map->start - al->map->pgoff, false);
+       }
 
        return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
 }