|
@@ -966,7 +966,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
|
|
|
}
|
|
|
|
|
|
static int dso__load_sym(struct dso *self, struct map *map, const char *name,
|
|
|
- int fd, symbol_filter_t filter, int kmodule)
|
|
|
+ int fd, symbol_filter_t filter, int kmodule,
|
|
|
+ int want_symtab)
|
|
|
{
|
|
|
struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
|
|
|
struct map *curr_map = map;
|
|
@@ -995,6 +996,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
|
|
|
goto out_elf_end;
|
|
|
}
|
|
|
|
|
|
+ /* Always reject images with a mismatched build-id: */
|
|
|
if (self->has_build_id) {
|
|
|
u8 build_id[BUILD_ID_SIZE];
|
|
|
|
|
@@ -1008,6 +1010,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
|
|
|
|
|
|
sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
|
|
|
if (sec == NULL) {
|
|
|
+ if (want_symtab)
|
|
|
+ goto out_elf_end;
|
|
|
+
|
|
|
sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
|
|
|
if (sec == NULL)
|
|
|
goto out_elf_end;
|
|
@@ -1365,6 +1370,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
|
|
int fd;
|
|
|
struct machine *machine;
|
|
|
const char *root_dir;
|
|
|
+ int want_symtab;
|
|
|
|
|
|
dso__set_loaded(self, map->type);
|
|
|
|
|
@@ -1391,13 +1397,18 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- self->origin = DSO__ORIG_BUILD_ID_CACHE;
|
|
|
- if (dso__build_id_filename(self, name, size) != NULL)
|
|
|
- goto open_file;
|
|
|
-more:
|
|
|
- do {
|
|
|
- self->origin++;
|
|
|
+ /* Iterate over candidate debug images.
|
|
|
+ * On the first pass, only load images if they have a full symtab.
|
|
|
+ * Failing that, do a second pass where we accept .dynsym also
|
|
|
+ */
|
|
|
+ for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
|
|
|
+ self->origin != DSO__ORIG_NOT_FOUND;
|
|
|
+ self->origin++) {
|
|
|
switch (self->origin) {
|
|
|
+ case DSO__ORIG_BUILD_ID_CACHE:
|
|
|
+ if (dso__build_id_filename(self, name, size) == NULL)
|
|
|
+ continue;
|
|
|
+ break;
|
|
|
case DSO__ORIG_FEDORA:
|
|
|
snprintf(name, size, "/usr/lib/debug%s.debug",
|
|
|
self->long_name);
|
|
@@ -1406,19 +1417,20 @@ more:
|
|
|
snprintf(name, size, "/usr/lib/debug%s",
|
|
|
self->long_name);
|
|
|
break;
|
|
|
- case DSO__ORIG_BUILDID:
|
|
|
- if (self->has_build_id) {
|
|
|
- char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
|
|
- build_id__sprintf(self->build_id,
|
|
|
- sizeof(self->build_id),
|
|
|
- build_id_hex);
|
|
|
- snprintf(name, size,
|
|
|
- "/usr/lib/debug/.build-id/%.2s/%s.debug",
|
|
|
- build_id_hex, build_id_hex + 2);
|
|
|
- break;
|
|
|
+ case DSO__ORIG_BUILDID: {
|
|
|
+ char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
|
|
+
|
|
|
+ if (!self->has_build_id)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ build_id__sprintf(self->build_id,
|
|
|
+ sizeof(self->build_id),
|
|
|
+ build_id_hex);
|
|
|
+ snprintf(name, size,
|
|
|
+ "/usr/lib/debug/.build-id/%.2s/%s.debug",
|
|
|
+ build_id_hex, build_id_hex + 2);
|
|
|
}
|
|
|
- self->origin++;
|
|
|
- /* Fall thru */
|
|
|
+ break;
|
|
|
case DSO__ORIG_DSO:
|
|
|
snprintf(name, size, "%s", self->long_name);
|
|
|
break;
|
|
@@ -1431,27 +1443,41 @@ more:
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- goto out;
|
|
|
+ /*
|
|
|
+ * If we wanted a full symtab but no image had one,
|
|
|
+ * relax our requirements and repeat the search.
|
|
|
+ */
|
|
|
+ if (want_symtab) {
|
|
|
+ want_symtab = 0;
|
|
|
+ self->origin = DSO__ORIG_BUILD_ID_CACHE;
|
|
|
+ } else
|
|
|
+ continue;
|
|
|
}
|
|
|
-open_file:
|
|
|
+
|
|
|
+ /* Name is now the name of the next image to try */
|
|
|
fd = open(name, O_RDONLY);
|
|
|
- } while (fd < 0);
|
|
|
+ if (fd < 0)
|
|
|
+ continue;
|
|
|
|
|
|
- ret = dso__load_sym(self, map, name, fd, filter, 0);
|
|
|
- close(fd);
|
|
|
+ ret = dso__load_sym(self, map, name, fd, filter, 0,
|
|
|
+ want_symtab);
|
|
|
+ close(fd);
|
|
|
|
|
|
- /*
|
|
|
- * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
|
|
|
- */
|
|
|
- if (!ret)
|
|
|
- goto more;
|
|
|
+ /*
|
|
|
+ * Some people seem to have debuginfo files _WITHOUT_ debug
|
|
|
+ * info!?!?
|
|
|
+ */
|
|
|
+ if (!ret)
|
|
|
+ continue;
|
|
|
|
|
|
- if (ret > 0) {
|
|
|
- int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
|
|
|
- if (nr_plt > 0)
|
|
|
- ret += nr_plt;
|
|
|
+ if (ret > 0) {
|
|
|
+ int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
|
|
|
+ if (nr_plt > 0)
|
|
|
+ ret += nr_plt;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
-out:
|
|
|
+
|
|
|
free(name);
|
|
|
if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
|
|
|
return 0;
|
|
@@ -1715,7 +1741,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
|
|
|
return -1;
|
|
|
|
|
|
dso__set_loaded(self, map->type);
|
|
|
- err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
|
|
|
+ err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
|
|
|
close(fd);
|
|
|
|
|
|
if (err > 0)
|