From 9685aac7ef885a0549119c4ddc240744b86dc824 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Tue, 27 Jul 2010 16:40:02 +0100 Subject: perf report: Don't abbreviate file paths relative to the cwd This avoids around some problems where the full path is executables and DSOs it needed for finding debug symbols on platforms with separated debug symbol files such as Ubuntu. This is simpler than tracking an extra name for each image. The only impact should be that paths in verbose output from the perf tools become absolute, instead of relative to . LKML-Reference: Signed-off-by: Dave Martin Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Will Deacon --- tools/perf/util/event.c | 2 +- tools/perf/util/map.c | 22 +--------------------- tools/perf/util/map.h | 2 +- 3 files changed, 3 insertions(+), 23 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2fbf6a463c8..a83c166f57f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -517,7 +517,7 @@ int event__process_mmap(event_t *self, struct perf_session *session) map = map__new(&machine->user_dsos, self->mmap.start, self->mmap.len, self->mmap.pgoff, self->mmap.pid, self->mmap.filename, - MAP__FUNCTION, session->cwd, session->cwdlen); + MAP__FUNCTION); if (thread == NULL || map == NULL) goto out_problem; diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index e672f2fef65..37cab903853 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -17,16 +17,6 @@ static inline int is_anon_memory(const char *filename) return strcmp(filename, "//anon") == 0; } -static int strcommon(const char *pathname, char *cwd, int cwdlen) -{ - int n = 0; - - while (n < cwdlen && pathname[n] == cwd[n]) - ++n; - - return n; -} - void map__init(struct map *self, enum map_type type, u64 start, u64 end, u64 pgoff, struct dso *dso) { @@ -43,7 +33,7 @@ void map__init(struct map *self, enum map_type type, struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, u64 pgoff, u32 pid, char *filename, - enum map_type type, char *cwd, int cwdlen) + enum map_type type) { struct map *self = malloc(sizeof(*self)); @@ -52,16 +42,6 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, struct dso *dso; int anon; - if (cwd) { - int n = strcommon(filename, cwd, cwdlen); - - if (n == cwdlen) { - snprintf(newfilename, sizeof(newfilename), - ".%s", filename + n); - filename = newfilename; - } - } - anon = is_anon_memory(filename); if (anon) { diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index f3913451282..3b2f706c0ba 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -106,7 +106,7 @@ void map__init(struct map *self, enum map_type type, u64 start, u64 end, u64 pgoff, struct dso *dso); struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, u64 pgoff, u32 pid, char *filename, - enum map_type type, char *cwd, int cwdlen); + enum map_type type); void map__delete(struct map *self); struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); -- cgit v1.2.3 From dedb1f683618d7b1cf3c5f07681d0c73bcdd64f3 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Tue, 27 Jul 2010 11:46:12 -0300 Subject: perf tools: Remove unneeded code for tracking the cwd in perf sessions Tidy-up patch to remove some code and struct perf_session data members which are no longer needed due to the previous patch: "perf tools: Don't abbreviate file paths relative to the cwd". LKML-Reference: Signed-off-by: Dave Martin Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Will Deacon --- tools/perf/builtin-buildid-list.c | 4 +--- tools/perf/builtin-diff.c | 2 -- tools/perf/builtin-report.c | 2 -- tools/perf/util/session.c | 22 +--------------------- tools/perf/util/symbol.h | 1 - 5 files changed, 2 insertions(+), 29 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 99890728409..44a47e13bd6 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -43,10 +43,8 @@ static int __cmd_buildid_list(void) if (session == NULL) return -1; - if (with_hits) { - symbol_conf.full_paths = true; + if (with_hits) perf_session__process_events(session, &build_id__mark_dso_hit_ops); - } perf_session__fprintf_dsos_buildid(session, stdout, with_hits); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index a6e2fdc7a04..33730c8211d 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -185,8 +185,6 @@ static const struct option options[] = { OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), - OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, - "Don't shorten the pathnames taking into account the cwd"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fd7407c7205..47e304e21cf 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -464,8 +464,6 @@ static const struct option options[] = { "pretty printing style key: normal raw"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), - OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, - "Don't shorten the pathnames taking into account the cwd"), OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, "Show sample percentage for different cpu modes"), OPT_STRING('p', "parent", &parent_pattern, "regex", diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c422cd67631..c777c25af65 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -94,8 +94,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc self->hists_tree = RB_ROOT; self->last_match = NULL; self->mmap_window = 32; - self->cwd = NULL; - self->cwdlen = 0; self->machines = RB_ROOT; self->repipe = repipe; INIT_LIST_HEAD(&self->ordered_samples.samples_head); @@ -128,7 +126,6 @@ void perf_session__delete(struct perf_session *self) { perf_header__exit(&self->header); close(self->fd); - free(self->cwd); free(self); } @@ -830,23 +827,6 @@ int perf_session__process_events(struct perf_session *self, if (perf_session__register_idle_thread(self) == NULL) return -ENOMEM; - if (!symbol_conf.full_paths) { - char bf[PATH_MAX]; - - if (getcwd(bf, sizeof(bf)) == NULL) { - err = -errno; -out_getcwd_err: - pr_err("failed to get the current directory\n"); - goto out_err; - } - self->cwd = strdup(bf); - if (self->cwd == NULL) { - err = -ENOMEM; - goto out_getcwd_err; - } - self->cwdlen = strlen(self->cwd); - } - if (!self->fd_pipe) err = __perf_session__process_events(self, self->header.data_offset, @@ -854,7 +834,7 @@ out_getcwd_err: self->size, ops); else err = __perf_session__process_pipe_events(self, ops); -out_err: + return err; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 5e02d2c1715..5ce2ee16fca 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -70,7 +70,6 @@ struct symbol_conf { show_nr_samples, use_callchain, exclude_other, - full_paths, show_cpu_utilization; const char *vmlinux_name, *field_sep; -- cgit v1.2.3 From 6c6823674c1deaa0e0c0a0f2256d1c553fe29115 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Fri, 30 Jul 2010 09:08:08 -0300 Subject: perf tools: Factor out buildid reading and make it implicit in dso__load If we have a buildid, then we never want to load an image which has no buildid, or which has a different buildid, so it makes sense for the check to be built into dso__load and not done separately. This is fine for old distros which don't use buildid at all since we do no check in that case. This refactoring also alleviates some subtle race condition issues by not opening ELF images twice to check the buildid and then load the symbols, which could lead to weirdness if an image is replaced under our feet. Signed-off-by: Dave Martin LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Will Deacon --- tools/perf/util/symbol.c | 80 ++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 33 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 5b276833e2b..4be5a0216d7 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -25,6 +25,8 @@ #define NT_GNU_BUILD_ID 3 #endif +static bool dso__build_id_equal(const struct dso *self, u8 *build_id); +static int elf_read_build_id(Elf *elf, void *bf, size_t size); static void dsos__add(struct list_head *head, struct dso *dso); static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); static int dso__load_kernel_sym(struct dso *self, struct map *map, @@ -962,6 +964,17 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, goto out_elf_end; } + if (self->has_build_id) { + u8 build_id[BUILD_ID_SIZE]; + + if (elf_read_build_id(elf, build_id, + BUILD_ID_SIZE) != BUILD_ID_SIZE) + goto out_elf_end; + + if (!dso__build_id_equal(self, build_id)) + goto out_elf_end; + } + sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); if (sec == NULL) { sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); @@ -1151,37 +1164,26 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) */ #define NOTE_ALIGN(n) (((n) + 3) & -4U) -int filename__read_build_id(const char *filename, void *bf, size_t size) +static int elf_read_build_id(Elf *elf, void *bf, size_t size) { - int fd, err = -1; + int err = -1; GElf_Ehdr ehdr; GElf_Shdr shdr; Elf_Data *data; Elf_Scn *sec; Elf_Kind ek; void *ptr; - Elf *elf; if (size < BUILD_ID_SIZE) goto out; - fd = open(filename, O_RDONLY); - if (fd < 0) - goto out; - - elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf == NULL) { - pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); - goto out_close; - } - ek = elf_kind(elf); if (ek != ELF_K_ELF) - goto out_elf_end; + goto out; if (gelf_getehdr(elf, &ehdr) == NULL) { pr_err("%s: cannot get elf header.\n", __func__); - goto out_elf_end; + goto out; } sec = elf_section_by_name(elf, &ehdr, &shdr, @@ -1190,12 +1192,12 @@ int filename__read_build_id(const char *filename, void *bf, size_t size) sec = elf_section_by_name(elf, &ehdr, &shdr, ".notes", NULL); if (sec == NULL) - goto out_elf_end; + goto out; } data = elf_getdata(sec, NULL); if (data == NULL) - goto out_elf_end; + goto out; ptr = data->d_buf; while (ptr < (data->d_buf + data->d_size)) { @@ -1217,7 +1219,31 @@ int filename__read_build_id(const char *filename, void *bf, size_t size) } ptr += descsz; } -out_elf_end: + +out: + return err; +} + +int filename__read_build_id(const char *filename, void *bf, size_t size) +{ + int fd, err = -1; + Elf *elf; + + if (size < BUILD_ID_SIZE) + goto out; + + fd = open(filename, O_RDONLY); + if (fd < 0) + goto out; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) { + pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); + goto out_close; + } + + err = elf_read_build_id(elf, bf, size); + elf_end(elf); out_close: close(fd); @@ -1293,7 +1319,6 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) { int size = PATH_MAX; char *name; - u8 build_id[BUILD_ID_SIZE]; int ret = -1; int fd; struct machine *machine; @@ -1340,16 +1365,14 @@ more: self->long_name); break; case DSO__ORIG_BUILDID: - if (filename__read_build_id(self->long_name, build_id, - sizeof(build_id))) { + if (self->has_build_id) { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; - build_id__sprintf(build_id, sizeof(build_id), + 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); - if (self->has_build_id) - goto compare_build_id; break; } self->origin++; @@ -1368,15 +1391,6 @@ more: default: goto out; } - - if (self->has_build_id) { - if (filename__read_build_id(name, build_id, - sizeof(build_id)) < 0) - goto more; -compare_build_id: - if (!dso__build_id_equal(self, build_id)) - goto more; - } open_file: fd = open(name, O_RDONLY); } while (fd < 0); -- cgit v1.2.3 From 6d947886bbf3562e793220ed5b2822dd19f43d0c Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Fri, 30 Jul 2010 09:36:08 -0300 Subject: perf tools: remove extra build-id check factored into dso__load Signed-off-by: Dave Martin LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Will Deacon --- tools/perf/util/symbol.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4be5a0216d7..1386b3db173 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -955,12 +955,12 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); if (elf == NULL) { - pr_err("%s: cannot read %s ELF file.\n", __func__, name); + pr_debug("%s: cannot read %s ELF file.\n", __func__, name); goto out_close; } if (gelf_getehdr(elf, &ehdr) == NULL) { - pr_err("%s: cannot get elf header.\n", __func__); + pr_debug("%s: cannot get elf header.\n", __func__); goto out_elf_end; } @@ -1670,30 +1670,6 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, { int err = -1, fd; - if (self->has_build_id) { - u8 build_id[BUILD_ID_SIZE]; - - if (filename__read_build_id(vmlinux, build_id, - sizeof(build_id)) < 0) { - pr_debug("No build_id in %s, ignoring it\n", vmlinux); - return -1; - } - if (!dso__build_id_equal(self, build_id)) { - char expected_build_id[BUILD_ID_SIZE * 2 + 1], - vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; - - build_id__sprintf(self->build_id, - sizeof(self->build_id), - expected_build_id); - build_id__sprintf(build_id, sizeof(build_id), - vmlinux_build_id); - pr_debug("build_id in %s is %s while expected is %s, " - "ignoring it\n", vmlinux, vmlinux_build_id, - expected_build_id); - return -1; - } - } - fd = open(vmlinux, O_RDONLY); if (fd < 0) return -1; -- cgit v1.2.3 From f90a18613ee399d4db595688da337b6c3a43ab13 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Fri, 30 Jul 2010 09:50:09 -0300 Subject: 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: Dave Martin LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Will Deacon --- tools/perf/util/symbol.c | 96 ++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 35 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 1386b3db173..d80346d0d05 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -936,7 +936,8 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type } 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; @@ -964,6 +965,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]; @@ -977,6 +979,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; @@ -1323,6 +1328,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); @@ -1349,13 +1355,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); @@ -1364,19 +1375,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; @@ -1389,27 +1401,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; @@ -1675,7 +1701,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) -- cgit v1.2.3 From 17c507ba926e4272d9ef077b6bfa256b7a85324a Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Tue, 3 Aug 2010 11:48:13 +0100 Subject: perf events: Fix mmap offset determination Fix buggy-looking code which unnecessarily adjusts the file offset fields read from /proc/*/maps. This may have gone unnoticed since the offset is usually 0 (and the logic in util/symbol.c may work incorrectly for other offset values). I make assumptions about the intended design here. The cover note accompanying this patch contains a more detailed explanation. Signed-off-by: Dave Martin Signed-off-by: Will Deacon --- tools/perf/util/event.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index a83c166f57f..2e5352565eb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -151,7 +151,6 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, continue; pbf += n + 3; if (*pbf == 'x') { /* vm_exec */ - u64 vm_pgoff; char *execname = strchr(bf, '/'); /* Catch VDSO */ @@ -162,12 +161,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, continue; pbf += 3; - n = hex2u64(pbf, &vm_pgoff); - /* pgoff is in bytes, not pages */ - if (n >= 0) - ev.mmap.pgoff = vm_pgoff << getpagesize(); - else - ev.mmap.pgoff = 0; + n = hex2u64(pbf, &ev.mmap.pgoff); size = strlen(execname); execname[size - 1] = '\0'; /* Remove \n */ -- cgit v1.2.3 From 224a2106f63943b3194b2080bdf938ea94fe8d22 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Tue, 3 Aug 2010 11:49:01 +0100 Subject: perf symbols: work around incorrect ET_EXEC symbol adjustment Workaround to adjust .text symbols from ET_EXEC images correctly. This is not a complete fix, but addresses the common case and does not create additional assumptions beyond those which perf already makes. ELF images with a weird link map may still be processed incorrectly (as at present) -- that will require a separate fix. The workaround allows correct symbol offsets to be generated for ET_EXEC executables on systems with separated debug info (where section sh_offset fields from the debug image may bear no relation to the layout of the executable image). The cover note accompanying this patch contains a more detailed explanation. Signed-off-by: Dave Martin Signed-off-by: Will Deacon --- tools/perf/util/symbol.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index d80346d0d05..c991525908b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1093,7 +1093,15 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); - sym.st_value -= shdr.sh_addr - shdr.sh_offset; + /* Assumptions: + * a) shdr.sh_addr - shdr.sh_offset == + * map->start - map->pgoff + * b) map->pgoff == 0 + * These are true iff we are looking at a function + * symbol in the main executable segment _and_ + * the main executable segment starts at the start of + * the ELF image (normally true). */ + sym.st_value -= map->start; } /* * We need to figure out if the object was created from C++ sources -- cgit v1.2.3