Commit 6da80ce8 authored by Dave Martin's avatar Dave Martin Committed by Arnaldo Carvalho de Melo

perf symbols: Improve debug image search when loading symbols

Changes:
	* Simplification of the main search loop on dso__load()
	* Replace the search with a 2-pass search:
		* First, try to find an image with a proper symtab.
		* Second, repeat the search, accepting dynsym.

A second scan should only ever happen when needed debug images are
missing from the buildid cache or stale, i.e., when the cache is out of
sync.

Currently, the second scan also happens when using separated debug
images, since the caching logic doesn't currently know how to cache
those.  Improvements to the cache behaviour ought to solve that.
Signed-off-by: default avatarDave Martin <dave.martin@linaro.org>
LKML-Reference: <new-submission>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 8b1389ef
...@@ -966,7 +966,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) ...@@ -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, 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 kmap *kmap = self->kernel ? map__kmap(map) : NULL;
struct map *curr_map = map; struct map *curr_map = map;
...@@ -995,6 +996,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, ...@@ -995,6 +996,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
goto out_elf_end; goto out_elf_end;
} }
/* Always reject images with a mismatched build-id: */
if (self->has_build_id) { if (self->has_build_id) {
u8 build_id[BUILD_ID_SIZE]; u8 build_id[BUILD_ID_SIZE];
...@@ -1008,6 +1010,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, ...@@ -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); sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
if (sec == NULL) { if (sec == NULL) {
if (want_symtab)
goto out_elf_end;
sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
if (sec == NULL) if (sec == NULL)
goto out_elf_end; goto out_elf_end;
...@@ -1365,6 +1370,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) ...@@ -1365,6 +1370,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
int fd; int fd;
struct machine *machine; struct machine *machine;
const char *root_dir; const char *root_dir;
int want_symtab;
dso__set_loaded(self, map->type); dso__set_loaded(self, map->type);
...@@ -1391,13 +1397,18 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) ...@@ -1391,13 +1397,18 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
return ret; return ret;
} }
self->origin = DSO__ORIG_BUILD_ID_CACHE; /* Iterate over candidate debug images.
if (dso__build_id_filename(self, name, size) != NULL) * On the first pass, only load images if they have a full symtab.
goto open_file; * Failing that, do a second pass where we accept .dynsym also
more: */
do { for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
self->origin++; self->origin != DSO__ORIG_NOT_FOUND;
self->origin++) {
switch (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: case DSO__ORIG_FEDORA:
snprintf(name, size, "/usr/lib/debug%s.debug", snprintf(name, size, "/usr/lib/debug%s.debug",
self->long_name); self->long_name);
...@@ -1406,19 +1417,20 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) ...@@ -1406,19 +1417,20 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
snprintf(name, size, "/usr/lib/debug%s", snprintf(name, size, "/usr/lib/debug%s",
self->long_name); self->long_name);
break; break;
case DSO__ORIG_BUILDID: case DSO__ORIG_BUILDID: {
if (self->has_build_id) { char build_id_hex[BUILD_ID_SIZE * 2 + 1];
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
build_id__sprintf(self->build_id, if (!self->has_build_id)
sizeof(self->build_id), continue;
build_id_hex);
snprintf(name, size, build_id__sprintf(self->build_id,
"/usr/lib/debug/.build-id/%.2s/%s.debug", sizeof(self->build_id),
build_id_hex, build_id_hex + 2); build_id_hex);
break; snprintf(name, size,
"/usr/lib/debug/.build-id/%.2s/%s.debug",
build_id_hex, build_id_hex + 2);
} }
self->origin++; break;
/* Fall thru */
case DSO__ORIG_DSO: case DSO__ORIG_DSO:
snprintf(name, size, "%s", self->long_name); snprintf(name, size, "%s", self->long_name);
break; break;
...@@ -1431,27 +1443,41 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) ...@@ -1431,27 +1443,41 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
break; break;
default: 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); fd = open(name, O_RDONLY);
} while (fd < 0); if (fd < 0)
continue;
ret = dso__load_sym(self, map, name, fd, filter, 0); ret = dso__load_sym(self, map, name, fd, filter, 0,
close(fd); want_symtab);
close(fd);
/* /*
* Some people seem to have debuginfo files _WITHOUT_ debug info!?!? * Some people seem to have debuginfo files _WITHOUT_ debug
*/ * info!?!?
if (!ret) */
goto more; if (!ret)
continue;
if (ret > 0) { if (ret > 0) {
int nr_plt = dso__synthesize_plt_symbols(self, map, filter); int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
if (nr_plt > 0) if (nr_plt > 0)
ret += nr_plt; ret += nr_plt;
break;
}
} }
out:
free(name); free(name);
if (ret < 0 && strstr(self->name, " (deleted)") != NULL) if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
return 0; return 0;
...@@ -1715,7 +1741,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, ...@@ -1715,7 +1741,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
return -1; return -1;
dso__set_loaded(self, map->type); 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); close(fd);
if (err > 0) if (err > 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment