From 90f18e63fbd005133624bf18a5e8b75c92e90f4d Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 25 Aug 2010 19:13:29 +0530 Subject: perf symbols: List symbols in a dso in ascending name order Given a dso, list the symbols in ascending name order. Needed for listing available symbols from perf probe. Cc: Ananth N Mavinakayanahalli Cc: Andrew Morton Cc: Christoph Hellwig Cc: "Frank Ch. Eigler" Cc: Frederic Weisbecker Cc: Jim Keniston Cc: Mark Wielaard Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Cc: Naren A Devaiah Cc: Oleg Nesterov Cc: "Paul E. McKenney" Cc: Randy Dunlap Cc: Srikar Dronamraju Cc: Steven Rostedt LKML-Reference: <20100825134329.5447.92261.sendpatchset@localhost6.localdomain6> Signed-off-by: Srikar Dronamraju Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 1a367734e016..a08e1cbcbbbd 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -388,6 +388,20 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp) return fprintf(fp, "%s", sbuild_id); } +size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp) +{ + size_t ret = 0; + struct rb_node *nd; + struct symbol_name_rb_node *pos; + + for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); + fprintf(fp, "%s\n", pos->sym.name); + } + + return ret; +} + size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) { struct rb_node *nd; -- cgit v1.2.2 From 02a9d03772aa1ff33a26180a2da0bfb191240eda Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 23 Nov 2010 22:08:18 +0530 Subject: perf symbols: Remove incorrect open-coded container_of() At least on ARM, padding is inserted between rb_node and sym in struct symbol_name_rb_node, causing "((void *)sym) - sizeof(struct rb_node)" to point inside rb_node rather than to the symbol_name_rb_node. Fix this by converting the code to use container_of(). Cc: Ian Munsie Cc: Ingo Molnar Cc: Ming Lei Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tom Zanussi LKML-Reference: <20101123163106.GA25677@debian> Signed-off-by: Rabin Vincent Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b39f499e575a..0500895a45af 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -295,7 +295,9 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) { struct rb_node **p = &self->rb_node; struct rb_node *parent = NULL; - struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; + struct symbol_name_rb_node *symn, *s; + + symn = container_of(sym, struct symbol_name_rb_node, sym); while (*p != NULL) { parent = *p; -- cgit v1.2.2 From 9d1faba5fe410558099f13cfada2eab03186769d Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Thu, 25 Nov 2010 15:12:53 +1100 Subject: perf symbols: Correct final kernel map guesses If a 32bit userspace perf is running on a 64bit kernel, the end of the final map in the kernel would incorrectly be set to 2^32-1 rather than 2^64-1. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1290658375-10342-1-git-send-email-imunsie@au1.ibm.com> Signed-off-by: Ian Munsie Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 0500895a45af..a348906b587d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -121,7 +121,7 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) * We still haven't the actual symbols, so guess the * last map final address. */ - curr->end = ~0UL; + curr->end = ~0ULL; } static void map_groups__fixup_end(struct map_groups *self) -- cgit v1.2.2 From 8a9533123f43f2cdb3eb601c17ff2ad336882eff Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 29 Nov 2010 12:44:15 -0200 Subject: perf symbols: Fix kallsyms kernel/module map splitting On ARM, module addresss space is ahead of kernel space, so the module symbols are handled before kernel symbol in dso__split_kallsyms, then was causing one map to be created for each kernel symbol. Reported-by: Ming Lei Tested-by: Ming Lei Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Ming Lei Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: <20101124144540.GB15875@ghostprotocols.net> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 0500895a45af..2af4d7d22373 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -532,7 +532,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct machine *machine = kmaps->machine; struct map *curr_map = map; struct symbol *pos; - int count = 0; + int count = 0, moved = 0; struct rb_root *root = &self->symbols[map->type]; struct rb_node *next = rb_first(root); int kernel_range = 0; @@ -590,6 +590,11 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, char dso_name[PATH_MAX]; struct dso *dso; + if (count == 0) { + curr_map = map; + goto filter_symbol; + } + if (self->kernel == DSO_TYPE_GUEST_KERNEL) snprintf(dso_name, sizeof(dso_name), "[guest.kernel].%d", @@ -615,7 +620,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, map_groups__insert(kmaps, curr_map); ++kernel_range; } - +filter_symbol: if (filter && filter(curr_map, pos)) { discard_symbol: rb_erase(&pos->rb_node, root); symbol__delete(pos); @@ -623,8 +628,9 @@ discard_symbol: rb_erase(&pos->rb_node, root); if (curr_map != map) { rb_erase(&pos->rb_node, root); symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); - } - count++; + ++moved; + } else + ++count; } } @@ -634,7 +640,7 @@ discard_symbol: rb_erase(&pos->rb_node, root); dso__set_loaded(curr_map->dso, curr_map->type); } - return count; + return count + moved; } int dso__load_kallsyms(struct dso *self, const char *filename, -- cgit v1.2.2 From d214afbd81405d4da2c5745fe867e6b313fd4178 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 25 Nov 2010 19:27:25 +0800 Subject: perf symbols: Figure out start address of kernel map from kallsyms On ARM, module symbol start address is ahead of kernel symbol start address, so we can't suppose that the start address of kernel map always is zero, otherwise may cause incorrect .start and .end of kernel map (caused by fixup) when there are modules loaded, then map_groups__find may return incorrect map for symbol query. This patch always figures out the start address of kernel map from /proc/kallsyms if the file is available, so fix the issues on ARM for module loaded case. This patch fixes the following issues on ARM when modules are loaded: - vmlinux symbol can't be found by kallsyms maps doing 'perf test' - module symbols are parsed mistakenlly when doing 'perf top'/'perf report' Cc: Ian Munsie Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tom Zanussi LKML-Reference: <20101125192725.62d31b42@tom-lei> Signed-off-by: Ming Lei Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 2af4d7d22373..d628c8d1cf5e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2131,14 +2131,55 @@ static struct dso *machine__create_kernel(struct machine *self) return kernel; } +struct process_args { + u64 start; +}; + +static int symbol__in_kernel(void *arg, const char *name, + char type __used, u64 start) +{ + struct process_args *args = arg; + + if (strchr(name, '[')) + return 0; + + args->start = start; + return 1; +} + +/* Figure out the start address of kernel map from /proc/kallsyms */ +static u64 machine__get_kernel_start_addr(struct machine *machine) +{ + const char *filename; + char path[PATH_MAX]; + struct process_args args; + + if (machine__is_host(machine)) { + filename = "/proc/kallsyms"; + } else { + if (machine__is_default_guest(machine)) + filename = (char *)symbol_conf.default_guest_kallsyms; + else { + sprintf(path, "%s/proc/kallsyms", machine->root_dir); + filename = path; + } + } + + if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) + return 0; + + return args.start; +} + int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) { enum map_type type; + u64 start = machine__get_kernel_start_addr(self); for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; - self->vmlinux_maps[type] = map__new2(0, kernel, type); + self->vmlinux_maps[type] = map__new2(start, kernel, type); if (self->vmlinux_maps[type] == NULL) return -1; -- cgit v1.2.2 From b226a5a72901bc9c73d639ea2e53e6c304bf3b74 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 7 Dec 2010 19:39:46 -0700 Subject: perf report: Allow user to specify path to kallsyms file This is useful for analyzing a perf data file on a different system than the one data was collected on and still include symbols from loaded kernel modules in the output. Commiter note: Updated the man page accordingly. LKML-Reference: <1291775986-16475-1-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a348906b587d..f40c076aeb7b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1830,8 +1830,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, const char *kallsyms_filename = NULL; char *kallsyms_allocated_filename = NULL; /* - * Step 1: if the user specified a vmlinux filename, use it and only - * it, reporting errors to the user if it cannot be used. + * Step 1: if the user specified a kallsyms or vmlinux filename, use + * it and only it, reporting errors to the user if it cannot be used. * * For instance, try to analyse an ARM perf.data file _without_ a * build-id, or if the user specifies the wrong path to the right @@ -1844,6 +1844,11 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, * validation in dso__load_vmlinux and will bail out if they don't * match. */ + if (symbol_conf.kallsyms_name != NULL) { + kallsyms_filename = symbol_conf.kallsyms_name; + goto do_kallsyms; + } + if (symbol_conf.vmlinux_name != NULL) { err = dso__load_vmlinux(self, map, symbol_conf.vmlinux_name, filter); -- cgit v1.2.2 From fd930ff91e7fda18f7790984a98489a85edb7c71 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Fri, 10 Dec 2010 14:06:03 +0100 Subject: perf probe: Fix use of kernel image path given by 'k' option Users were not being able to have the explicitely specified vmlinux pathname used, instead a search on the vmlinux path was always being made. Reported-by: Francis Moreau Acked-by: Masami Hiramatsu Cc: 2nddept-manager@sdl.hitachi.co.jp Cc: Francis Moreau Cc: Franck Bui-Huu Cc: Masami Hiramatsu LPU-Reference: Signed-off-by: Franck Bui-Huu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index d628c8d1cf5e..439ab947daf4 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1780,8 +1780,8 @@ out_failure: return -1; } -static int dso__load_vmlinux(struct dso *self, struct map *map, - const char *vmlinux, symbol_filter_t filter) +int dso__load_vmlinux(struct dso *self, struct map *map, + const char *vmlinux, symbol_filter_t filter) { int err = -1, fd; -- cgit v1.2.2 From ec5761eab318e50e69fcf8e63e9edaef5949c067 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 9 Dec 2010 13:27:07 -0700 Subject: perf symbols: Add symfs option for off-box analysis using specified tree The symfs argument allows analysis of perf.data file using a locally accessible filesystem tree with debug symbols - e.g., tree created during image builds, sshfs mount, loop mounted KVM disk images, USB keys, initrds, etc. Anything with an OS tree can be analyzed from anywhere without the need to populate a local data store with build-ids. Commiter notes: o Fixed up symfs="/" variants handling. o prefixed DSO__ORIG_GUEST_KMODULE case with symfs too, avoiding use of files outside the symfs directory. LKML-Reference: <1291926427-28846-1-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 72 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 16 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ceefa6568def..561db6361f57 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -41,6 +41,7 @@ struct symbol_conf symbol_conf = { .exclude_other = true, .use_modules = true, .try_vmlinux_path = true, + .symfs = "", }; int dso__name_len(const struct dso *self) @@ -839,8 +840,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, char sympltname[1024]; Elf *elf; int nr = 0, symidx, fd, err = 0; + char name[PATH_MAX]; - fd = open(self->long_name, O_RDONLY); + snprintf(name, sizeof(name), "%s%s", + symbol_conf.symfs, self->long_name); + fd = open(name, O_RDONLY); if (fd < 0) goto out; @@ -1452,16 +1456,19 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) self->origin++) { switch (self->origin) { case DSO__ORIG_BUILD_ID_CACHE: - if (dso__build_id_filename(self, name, size) == NULL) + /* skip the locally configured cache if a symfs is given */ + if (symbol_conf.symfs[0] || + (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); + snprintf(name, size, "%s/usr/lib/debug%s.debug", + symbol_conf.symfs, self->long_name); break; case DSO__ORIG_UBUNTU: - snprintf(name, size, "/usr/lib/debug%s", - self->long_name); + snprintf(name, size, "%s/usr/lib/debug%s", + symbol_conf.symfs, self->long_name); break; case DSO__ORIG_BUILDID: { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; @@ -1473,19 +1480,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 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); + "%s/usr/lib/debug/.build-id/%.2s/%s.debug", + symbol_conf.symfs, build_id_hex, build_id_hex + 2); } break; case DSO__ORIG_DSO: - snprintf(name, size, "%s", self->long_name); + snprintf(name, size, "%s%s", + symbol_conf.symfs, self->long_name); break; case DSO__ORIG_GUEST_KMODULE: if (map->groups && map->groups->machine) root_dir = map->groups->machine->root_dir; else root_dir = ""; - snprintf(name, size, "%s%s", root_dir, self->long_name); + snprintf(name, size, "%s%s%s", symbol_conf.symfs, + root_dir, self->long_name); + break; + + case DSO__ORIG_KMODULE: + snprintf(name, size, "%s%s", symbol_conf.symfs, + self->long_name); break; default: @@ -1784,17 +1798,20 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, const char *vmlinux, symbol_filter_t filter) { int err = -1, fd; + char symfs_vmlinux[PATH_MAX]; - fd = open(vmlinux, O_RDONLY); + snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", + symbol_conf.symfs, vmlinux); + fd = open(symfs_vmlinux, O_RDONLY); if (fd < 0) return -1; dso__set_loaded(self, map->type); - err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); + err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); close(fd); if (err > 0) - pr_debug("Using %s for symbols\n", vmlinux); + pr_debug("Using %s for symbols\n", symfs_vmlinux); return err; } @@ -1872,6 +1889,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, goto out_fixup; } + /* do not try local files if a symfs was given */ + if (symbol_conf.symfs[0] != 0) + return -1; + /* * Say the kernel DSO was created when processing the build-id header table, * we have a build-id, so check if it is the same as the running kernel, @@ -2262,9 +2283,6 @@ static int vmlinux_path__init(void) struct utsname uts; char bf[PATH_MAX]; - if (uname(&uts) < 0) - return -1; - vmlinux_path = malloc(sizeof(char *) * 5); if (vmlinux_path == NULL) return -1; @@ -2277,6 +2295,14 @@ static int vmlinux_path__init(void) if (vmlinux_path[vmlinux_path__nr_entries] == NULL) goto out_fail; ++vmlinux_path__nr_entries; + + /* only try running kernel version if no symfs was given */ + if (symbol_conf.symfs[0] != 0) + return 0; + + if (uname(&uts) < 0) + return -1; + snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); if (vmlinux_path[vmlinux_path__nr_entries] == NULL) @@ -2336,6 +2362,8 @@ static int setup_list(struct strlist **list, const char *list_str, int symbol__init(void) { + const char *symfs; + if (symbol_conf.initialized) return 0; @@ -2364,6 +2392,18 @@ int symbol__init(void) symbol_conf.sym_list_str, "symbol") < 0) goto out_free_comm_list; + /* + * A path to symbols of "/" is identical to "" + * reset here for simplicity. + */ + symfs = realpath(symbol_conf.symfs, NULL); + if (symfs == NULL) + symfs = symbol_conf.symfs; + if (strcmp(symfs, "/") == 0) + symbol_conf.symfs = ""; + if (symfs != symbol_conf.symfs) + free((void *)symfs); + symbol_conf.initialized = true; return 0; -- cgit v1.2.2 From 3b01a413c196c91040d41c86e5b56f76bb369f74 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 22 Dec 2010 01:08:36 -0200 Subject: perf symbols: Improve kallsyms symbol end addr calculation For kallsyms we don't have the symbol address end, so we do an extra pass and set the symbol end addr as being the start of the next minus one. But this was being done just after we filtered the symbols of a particular type (functions, variables), so the symbol end was sometimes after what it really is. Fixing up symbol end also was falling apart when we have symbol aliases, then the end address of all but the last alias was being set to be before its start. Fix it up by checking for symbol aliases and making the kallsyms__parse routine use the next symbol, whatever its type, as the limit for the previous symbol, passing that end address to the callback. This was detected by the 'perf test' synthetic paranoid regression tests, fix it up so that even that case doesn't mislead us. Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Stephane Eranian LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 56 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 14 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 561db6361f57..2ea1a2e4c0c2 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -22,6 +22,10 @@ #include #include +#ifndef KSYM_NAME_LEN +#define KSYM_NAME_LEN 128 +#endif + #ifndef NT_GNU_BUILD_ID #define NT_GNU_BUILD_ID 3 #endif @@ -93,7 +97,7 @@ static void symbols__fixup_end(struct rb_root *self) prev = curr; curr = rb_entry(nd, struct symbol, rb_node); - if (prev->end == prev->start) + if (prev->end == prev->start && prev->end != curr->start) prev->end = curr->start - 1; } @@ -426,16 +430,25 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, - char type, u64 start)) + char type, u64 start, u64 end)) { char *line = NULL; size_t n; - int err = 0; + int err = -1; + u64 prev_start = 0; + char prev_symbol_type = 0; + char *prev_symbol_name; FILE *file = fopen(filename, "r"); if (file == NULL) goto out_failure; + prev_symbol_name = malloc(KSYM_NAME_LEN); + if (prev_symbol_name == NULL) + goto out_close; + + err = 0; + while (!feof(file)) { u64 start; int line_len, len; @@ -455,14 +468,33 @@ int kallsyms__parse(const char *filename, void *arg, continue; symbol_type = toupper(line[len]); - symbol_name = line + len + 2; + len += 2; + symbol_name = line + len; + len = line_len - len; - err = process_symbol(arg, symbol_name, symbol_type, start); - if (err) + if (len >= KSYM_NAME_LEN) { + err = -1; break; + } + + if (prev_symbol_type) { + u64 end = start; + if (end != prev_start) + --end; + err = process_symbol(arg, prev_symbol_name, + prev_symbol_type, prev_start, end); + if (err) + break; + } + + memcpy(prev_symbol_name, symbol_name, len + 1); + prev_symbol_type = symbol_type; + prev_start = start; } + free(prev_symbol_name); free(line); +out_close: fclose(file); return err; @@ -484,7 +516,7 @@ static u8 kallsyms2elf_type(char type) } static int map__process_kallsym_symbol(void *arg, const char *name, - char type, u64 start) + char type, u64 start, u64 end) { struct symbol *sym; struct process_kallsyms_args *a = arg; @@ -493,11 +525,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name, if (!symbol_type__is_a(type, a->map->type)) return 0; - /* - * Will fix up the end later, when we have all symbols sorted. - */ - sym = symbol__new(start, 0, kallsyms2elf_type(type), name); - + sym = symbol__new(start, end - start + 1, + kallsyms2elf_type(type), name); if (sym == NULL) return -ENOMEM; /* @@ -650,7 +679,6 @@ int dso__load_kallsyms(struct dso *self, const char *filename, if (dso__load_all_kallsyms(self, filename, map) < 0) return -1; - symbols__fixup_end(&self->symbols[map->type]); if (self->kernel == DSO_TYPE_GUEST_KERNEL) self->origin = DSO__ORIG_GUEST_KERNEL; else @@ -2162,7 +2190,7 @@ struct process_args { }; static int symbol__in_kernel(void *arg, const char *name, - char type __used, u64 start) + char type __used, u64 start, u64 end __used) { struct process_args *args = arg; -- cgit v1.2.2 From b2f8fb237e9cc407a02aca401369c15babae35dd Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 21 Jan 2011 16:40:19 +0000 Subject: perf symbols: Fix annotation of thumb code In ARM's Thumb mode the bottom bit of the symbol address is set to mark the function as Thumb; the instructions are in reality 2 or 4 byte on 2 byte alignments, and when the +1 address is used in annotate it causes objdump to disassemble invalid instructions. The patch removes that bottom bit during symbol loading. Many thinks to Dave Martin for comments on an initial version of the patch. (For reference this corresponds to this bug https://bugs.launchpad.net/linux-linaro/+bug/677547 ) Cc: Ingo Molnar Cc: Dave Martin LKML-Reference: <20110121163922.GA31398@davesworkthinkpad> Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 15ccfba8cdf8..e32478effed8 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1161,6 +1161,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, section_name = elf_sec__name(&shdr, secstrs); + /* On ARM, symbols for thumb functions have 1 added to + * the symbol address as a flag - remove it */ + if ((ehdr.e_machine == EM_ARM) && + (map->type == MAP__FUNCTION) && + (sym.st_value & 1)) + --sym.st_value; + if (self->kernel != DSO_TYPE_USER || kmodule) { char dso_name[PATH_MAX]; -- cgit v1.2.2 From 9486aa38771661e96fbb51c549b9901b5df609d8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 22 Jan 2011 20:37:02 -0200 Subject: perf tools: Fix 64 bit integer format strings Using %L[uxd] has issues in some architectures, like on ppc64. Fix it by making our 64 bit integers typedefs of stdint.h types and using PRI[ux]64 like, for instance, git does. Reported by Denis Kirjanov that provided a patch for one case, I went and changed all cases. Reported-by: Denis Kirjanov Tested-by: Denis Kirjanov LKML-Reference: <20110120093246.GA8031@hera.kernel.org> Cc: Denis Kirjanov Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Pingtian Han Cc: Stephane Eranian Cc: Tom Zanussi Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e32478effed8..7821d0e6866f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "build-id.h" #include "debug.h" #include "symbol.h" @@ -153,7 +154,7 @@ static struct symbol *symbol__new(u64 start, u64 len, u8 binding, self->binding = binding; self->namelen = namelen - 1; - pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); + pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end); memcpy(self->name, name, namelen); @@ -167,7 +168,7 @@ void symbol__delete(struct symbol *self) static size_t symbol__fprintf(struct symbol *self, FILE *fp) { - return fprintf(fp, " %llx-%llx %c %s\n", + return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", self->start, self->end, self->binding == STB_GLOBAL ? 'g' : self->binding == STB_LOCAL ? 'l' : 'w', @@ -1215,8 +1216,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } if (curr_dso->adjust_symbols) { - pr_debug4("%s: adjusting symbol: st_value: %#Lx " - "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, + pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " + "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); sym.st_value -= shdr.sh_addr - shdr.sh_offset; -- cgit v1.2.2 From fb7d0b3cefb80a105f7fd26bbc62e0cbf9192822 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 24 Jan 2011 11:13:04 -0500 Subject: perf tool: Fix gcc 4.6.0 issues GCC 4.6.0 in Fedora rawhide turned up some compile errors in tools/perf due to the -Werror=unused-but-set-variable flag. I've gone through and annotated some of the assignments that had side effects (ie: return value from a function) with the __used annotation, and in some cases, just removed unused code. In a few cases, we were assigning something useful, but not using it in later parts of the function. kyle@dreadnought:~/src% gcc --version gcc (GCC) 4.6.0 20110122 (Red Hat 4.6.0-0.3) Cc: Ingo Molnar LKML-Reference: <20110124161304.GK27353@bombadil.infradead.org> Signed-off-by: Kyle McMartin [ committer note: Fixed up the annotation fixes, as that code moved recently ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 7821d0e6866f..3e193f8e3061 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1525,8 +1525,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) symbol_conf.symfs, self->long_name); break; case DSO__ORIG_GUEST_KMODULE: - if (map->groups && map->groups->machine) - root_dir = map->groups->machine->root_dir; + if (map->groups && machine) + root_dir = machine->root_dir; else root_dir = ""; snprintf(name, size, "%s%s%s", symbol_conf.symfs, -- cgit v1.2.2 From a639dc64e52183a361c260e562e73b0800b89072 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Feb 2011 13:54:38 -0300 Subject: perf symbols: Fix vmlinux path when not using --symfs The ec5761e cset introduced the symfs feature with a bug for loading vmlinux files that ended up causing this failure: [root@emilia v2.6.38-rc5+]# strace -e trace=open perf top --vmlinux ./vmlinux 2>&1 | tail -3 open("/./vmlinux", O_RDONLY) = -1 ENOENT (No such file or directory) ./vmlinux with build id b9266bf40e98dadb5d43a2f3e95d3c5d4aff46dc not found, continuing without symbols The ./vmlinux file can't be used [root@emilia v2.6.38-rc5+]# Remove the extra slash, just like is done in the DSO__ORIG_DSO handling in dso__load() and other parts of the ec5761e cset. Reported-by: Ingo Molnar Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 7821d0e6866f..b1bf490aff88 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1836,7 +1836,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map, int err = -1, fd; char symfs_vmlinux[PATH_MAX]; - snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", + snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", symbol_conf.symfs, vmlinux); fd = open(symfs_vmlinux, O_RDONLY); if (fd < 0) -- cgit v1.2.2 From d7603d5122d9700fb8f36fa08b04f4e900fef059 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Mar 2011 14:51:33 -0300 Subject: perf hists: Remove needless global col lenght calcs To support multiple events we need to do these calcs per 'struct hists' instance, and it turns out we already do that at: __hists__add_entry hists__inc_nr_entries hists__calc_col_len for all the unfiltered hist_entry instances we stash in the rb tree, so trow away the dead code. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ba6d48949092..00014e32c288 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -207,7 +207,6 @@ struct dso *dso__new(const char *name) dso__set_short_name(self, self->name); for (i = 0; i < MAP__NR_TYPES; ++i) self->symbols[i] = self->symbol_names[i] = RB_ROOT; - self->slen_calculated = 0; self->origin = DSO__ORIG_NOT_FOUND; self->loaded = 0; self->sorted_by_name = 0; -- cgit v1.2.2 From 878b439dccd064d6908800fab0b47bd3c3a87ebb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 13:13:36 -0300 Subject: perf symbols: Rename dso->origin to dso->symtab_type And the DSO__ORIG_ enum to SYMTAB__, to clarify that this is about from where the symtab was obtained. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 00014e32c288..651dbfe7f4f3 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -207,7 +207,7 @@ struct dso *dso__new(const char *name) dso__set_short_name(self, self->name); for (i = 0; i < MAP__NR_TYPES; ++i) self->symbols[i] = self->symbol_names[i] = RB_ROOT; - self->origin = DSO__ORIG_NOT_FOUND; + self->symtab_type = SYMTAB__NOT_FOUND; self->loaded = 0; self->sorted_by_name = 0; self->has_build_id = 0; @@ -680,9 +680,9 @@ int dso__load_kallsyms(struct dso *self, const char *filename, return -1; if (self->kernel == DSO_TYPE_GUEST_KERNEL) - self->origin = DSO__ORIG_GUEST_KERNEL; + self->symtab_type = SYMTAB__GUEST_KALLSYMS; else - self->origin = DSO__ORIG_KERNEL; + self->symtab_type = SYMTAB__KALLSYMS; return dso__split_kallsyms(self, map, filter); } @@ -1204,7 +1204,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } curr_map->map_ip = identity__map_ip; curr_map->unmap_ip = identity__map_ip; - curr_dso->origin = self->origin; + curr_dso->symtab_type = self->symtab_type; map_groups__insert(kmap->kmaps, curr_map); dsos__add(&self->node, curr_dso); dso__set_loaded(curr_dso, map->type); @@ -1430,21 +1430,21 @@ out: char dso__symtab_origin(const struct dso *self) { static const char origin[] = { - [DSO__ORIG_KERNEL] = 'k', - [DSO__ORIG_JAVA_JIT] = 'j', - [DSO__ORIG_BUILD_ID_CACHE] = 'B', - [DSO__ORIG_FEDORA] = 'f', - [DSO__ORIG_UBUNTU] = 'u', - [DSO__ORIG_BUILDID] = 'b', - [DSO__ORIG_DSO] = 'd', - [DSO__ORIG_KMODULE] = 'K', - [DSO__ORIG_GUEST_KERNEL] = 'g', - [DSO__ORIG_GUEST_KMODULE] = 'G', + [SYMTAB__KALLSYMS] = 'k', + [SYMTAB__JAVA_JIT] = 'j', + [SYMTAB__BUILD_ID_CACHE] = 'B', + [SYMTAB__FEDORA_DEBUGINFO] = 'f', + [SYMTAB__UBUNTU_DEBUGINFO] = 'u', + [SYMTAB__BUILDID_DEBUGINFO] = 'b', + [SYMTAB__SYSTEM_PATH_DSO] = 'd', + [SYMTAB__SYSTEM_PATH_KMODULE] = 'K', + [SYMTAB__GUEST_KALLSYMS] = 'g', + [SYMTAB__GUEST_KMODULE] = 'G', }; - if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) + if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND) return '!'; - return origin[self->origin]; + return origin[self->symtab_type]; } int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) @@ -1477,8 +1477,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) if (strncmp(self->name, "/tmp/perf-", 10) == 0) { ret = dso__load_perf_map(self, map, filter); - self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : - DSO__ORIG_NOT_FOUND; + self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : + SYMTAB__NOT_FOUND; return ret; } @@ -1486,26 +1486,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) * 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: + for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1; + self->symtab_type != SYMTAB__NOT_FOUND; + self->symtab_type++) { + switch (self->symtab_type) { + case SYMTAB__BUILD_ID_CACHE: /* skip the locally configured cache if a symfs is given */ if (symbol_conf.symfs[0] || (dso__build_id_filename(self, name, size) == NULL)) { continue; } break; - case DSO__ORIG_FEDORA: + case SYMTAB__FEDORA_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s.debug", symbol_conf.symfs, self->long_name); break; - case DSO__ORIG_UBUNTU: + case SYMTAB__UBUNTU_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s", symbol_conf.symfs, self->long_name); break; - case DSO__ORIG_BUILDID: { + case SYMTAB__BUILDID_DEBUGINFO: { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; if (!self->has_build_id) @@ -1519,11 +1519,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) symbol_conf.symfs, build_id_hex, build_id_hex + 2); } break; - case DSO__ORIG_DSO: + case SYMTAB__SYSTEM_PATH_DSO: snprintf(name, size, "%s%s", symbol_conf.symfs, self->long_name); break; - case DSO__ORIG_GUEST_KMODULE: + case SYMTAB__GUEST_KMODULE: if (map->groups && machine) root_dir = machine->root_dir; else @@ -1532,7 +1532,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) root_dir, self->long_name); break; - case DSO__ORIG_KMODULE: + case SYMTAB__SYSTEM_PATH_KMODULE: snprintf(name, size, "%s%s", symbol_conf.symfs, self->long_name); break; @@ -1544,7 +1544,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) */ if (want_symtab) { want_symtab = 0; - self->origin = DSO__ORIG_BUILD_ID_CACHE; + self->symtab_type = SYMTAB__BUILD_ID_CACHE; } else continue; } @@ -1757,9 +1757,9 @@ struct map *machine__new_module(struct machine *self, u64 start, return NULL; if (machine__is_host(self)) - dso->origin = DSO__ORIG_KMODULE; + dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; else - dso->origin = DSO__ORIG_GUEST_KMODULE; + dso->symtab_type = SYMTAB__GUEST_KMODULE; map_groups__insert(&self->kmaps, map); return map; } -- cgit v1.2.2 From 60e4b10c5a27182bc8ce7435050a17cb61c94d00 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 22 Mar 2011 15:42:14 -0300 Subject: perf symbols: Look at .dynsym again if .symtab not found The original intent of the code was to repeat the search with want_symtab = 0. But as the code stands now, we never hit the "default" case of the switch statement. Which means we never repeat the search. Tested-by: Srikar Dronamraju Reported-by: Arun Sharma Reported-by: Srikar Dronamraju Cc: Dave Martin Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 651dbfe7f4f3..17df793c8924 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1486,7 +1486,9 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) * 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->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1; + want_symtab = 1; +restart: + for (self->symtab_type = SYMTAB__BUILD_ID_CACHE; self->symtab_type != SYMTAB__NOT_FOUND; self->symtab_type++) { switch (self->symtab_type) { @@ -1536,17 +1538,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) snprintf(name, size, "%s%s", symbol_conf.symfs, self->long_name); break; - - default: - /* - * 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->symtab_type = SYMTAB__BUILD_ID_CACHE; - } else - continue; + default:; } /* Name is now the name of the next image to try */ @@ -1573,6 +1565,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) } } + /* + * If we wanted a full symtab but no image had one, + * relax our requirements and repeat the search. + */ + if (ret <= 0 && want_symtab) { + want_symtab = 0; + goto restart; + } + free(name); if (ret < 0 && strstr(self->name, " (deleted)") != NULL) return 0; -- cgit v1.2.2 From 6c6804fb2cef2d6aceb38b0eb0803210d77ff390 Mon Sep 17 00:00:00 2001 From: Andrew Lutomirski Date: Thu, 24 Mar 2011 00:36:56 -0400 Subject: perf symbols: Fix vsyscall symbol lookup Perf can't currently trace into the vsyscall page. It looks like it was meant to work. Tested on 2.6.38 and today's -git. The bug is easy to reproduce. Compile this: int main() { int i; struct timespec t; for(i = 0; i < 10000000; i++) clock_gettime(CLOCK_MONOTONIC, &t); return 0; } and run it through perf record; perf report. The top entry shows "[unknown]" and you can't zoom in. It looks like there are two issues. The first is a that a test for user mode executing in kernel space is backwards. (That's the first hunk below). The second (I think) is that something's wrong with the code that generates lots of little struct dso objects for different sections -- when it runs on vmlinux it results in bogus long_name values which cause objdump to fail. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra LPU-Reference: Signed-off-by: Andy Lutomirski Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 17df793c8924..8f73907a959e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1196,6 +1196,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, if (curr_dso == NULL) goto out_elf_end; curr_dso->kernel = self->kernel; + curr_dso->long_name = self->long_name; + curr_dso->long_name_len = self->long_name_len; curr_map = map__new2(start, curr_dso, map->type); if (curr_map == NULL) { @@ -1842,6 +1844,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map, if (fd < 0) return -1; + dso__set_long_name(self, (char *)vmlinux); dso__set_loaded(self, map->type); err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); close(fd); -- cgit v1.2.2 From 4d439517561d009e170e2fe20be1ba25e19abe75 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 29 Mar 2011 14:18:39 -0300 Subject: perf symbols: Properly align symbol_conf.priv_size If symbol_conf.priv_size is not a multiple of "sizeof(u64)" we'll bus error on sparc64 in symbol__new because the "struct symbol *" pointer is computed by adding symbol_conf.priv_size to the memory allocated. We cannot isolate the fix to symbol__new and symbol__delete since the private area is computed by subtracting the priv_size value from a "struct symbol" pointer, so then the private area can still be potentially unaligned. So, simply align the symbol_conf.priv_size value in symbol__init() Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <20110328.175849.112593455.davem@davemloft.net> Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8f73907a959e..f06c10f092ba 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2406,6 +2406,8 @@ int symbol__init(void) if (symbol_conf.initialized) return 0; + symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); + elf_version(EV_CURRENT); if (symbol_conf.sort_by_name) symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - -- cgit v1.2.2 From aeafcbaf4fcfeb74aeed65609ea5ead48dfc09f8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 31 Mar 2011 10:56:28 -0300 Subject: perf symbols: Give more useful names to 'self' parameters One more installment on an area that is mostly dormant. Suggested-by: Thomas Gleixner Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 629 ++++++++++++++++++++++++----------------------- 1 file changed, 320 insertions(+), 309 deletions(-) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f06c10f092ba..516876dfbe52 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -31,13 +31,13 @@ #define NT_GNU_BUILD_ID 3 #endif -static bool dso__build_id_equal(const struct dso *self, u8 *build_id); +static bool dso__build_id_equal(const struct dso *dso, 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, +static int dso__load_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); -static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, +static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); static int vmlinux_path__nr_entries; static char **vmlinux_path; @@ -49,27 +49,27 @@ struct symbol_conf symbol_conf = { .symfs = "", }; -int dso__name_len(const struct dso *self) +int dso__name_len(const struct dso *dso) { if (verbose) - return self->long_name_len; + return dso->long_name_len; - return self->short_name_len; + return dso->short_name_len; } -bool dso__loaded(const struct dso *self, enum map_type type) +bool dso__loaded(const struct dso *dso, enum map_type type) { - return self->loaded & (1 << type); + return dso->loaded & (1 << type); } -bool dso__sorted_by_name(const struct dso *self, enum map_type type) +bool dso__sorted_by_name(const struct dso *dso, enum map_type type) { - return self->sorted_by_name & (1 << type); + return dso->sorted_by_name & (1 << type); } -static void dso__set_sorted_by_name(struct dso *self, enum map_type type) +static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) { - self->sorted_by_name |= (1 << type); + dso->sorted_by_name |= (1 << type); } bool symbol_type__is_a(char symbol_type, enum map_type map_type) @@ -84,9 +84,9 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type) } } -static void symbols__fixup_end(struct rb_root *self) +static void symbols__fixup_end(struct rb_root *symbols) { - struct rb_node *nd, *prevnd = rb_first(self); + struct rb_node *nd, *prevnd = rb_first(symbols); struct symbol *curr, *prev; if (prevnd == NULL) @@ -107,10 +107,10 @@ static void symbols__fixup_end(struct rb_root *self) curr->end = roundup(curr->start, 4096); } -static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) +static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) { struct map *prev, *curr; - struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); + struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); if (prevnd == NULL) return; @@ -130,128 +130,128 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) curr->end = ~0ULL; } -static void map_groups__fixup_end(struct map_groups *self) +static void map_groups__fixup_end(struct map_groups *mg) { int i; for (i = 0; i < MAP__NR_TYPES; ++i) - __map_groups__fixup_end(self, i); + __map_groups__fixup_end(mg, i); } static struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) { size_t namelen = strlen(name) + 1; - struct symbol *self = calloc(1, (symbol_conf.priv_size + - sizeof(*self) + namelen)); - if (self == NULL) + struct symbol *sym = calloc(1, (symbol_conf.priv_size + + sizeof(*sym) + namelen)); + if (sym == NULL) return NULL; if (symbol_conf.priv_size) - self = ((void *)self) + symbol_conf.priv_size; - - self->start = start; - self->end = len ? start + len - 1 : start; - self->binding = binding; - self->namelen = namelen - 1; + sym = ((void *)sym) + symbol_conf.priv_size; - pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end); + sym->start = start; + sym->end = len ? start + len - 1 : start; + sym->binding = binding; + sym->namelen = namelen - 1; - memcpy(self->name, name, namelen); + pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", + __func__, name, start, sym->end); + memcpy(sym->name, name, namelen); - return self; + return sym; } -void symbol__delete(struct symbol *self) +void symbol__delete(struct symbol *sym) { - free(((void *)self) - symbol_conf.priv_size); + free(((void *)sym) - symbol_conf.priv_size); } -static size_t symbol__fprintf(struct symbol *self, FILE *fp) +static size_t symbol__fprintf(struct symbol *sym, FILE *fp) { return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", - self->start, self->end, - self->binding == STB_GLOBAL ? 'g' : - self->binding == STB_LOCAL ? 'l' : 'w', - self->name); + sym->start, sym->end, + sym->binding == STB_GLOBAL ? 'g' : + sym->binding == STB_LOCAL ? 'l' : 'w', + sym->name); } -void dso__set_long_name(struct dso *self, char *name) +void dso__set_long_name(struct dso *dso, char *name) { if (name == NULL) return; - self->long_name = name; - self->long_name_len = strlen(name); + dso->long_name = name; + dso->long_name_len = strlen(name); } -static void dso__set_short_name(struct dso *self, const char *name) +static void dso__set_short_name(struct dso *dso, const char *name) { if (name == NULL) return; - self->short_name = name; - self->short_name_len = strlen(name); + dso->short_name = name; + dso->short_name_len = strlen(name); } -static void dso__set_basename(struct dso *self) +static void dso__set_basename(struct dso *dso) { - dso__set_short_name(self, basename(self->long_name)); + dso__set_short_name(dso, basename(dso->long_name)); } struct dso *dso__new(const char *name) { - struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); + struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); - if (self != NULL) { + if (dso != NULL) { int i; - strcpy(self->name, name); - dso__set_long_name(self, self->name); - dso__set_short_name(self, self->name); + strcpy(dso->name, name); + dso__set_long_name(dso, dso->name); + dso__set_short_name(dso, dso->name); for (i = 0; i < MAP__NR_TYPES; ++i) - self->symbols[i] = self->symbol_names[i] = RB_ROOT; - self->symtab_type = SYMTAB__NOT_FOUND; - self->loaded = 0; - self->sorted_by_name = 0; - self->has_build_id = 0; - self->kernel = DSO_TYPE_USER; - INIT_LIST_HEAD(&self->node); + dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; + dso->symtab_type = SYMTAB__NOT_FOUND; + dso->loaded = 0; + dso->sorted_by_name = 0; + dso->has_build_id = 0; + dso->kernel = DSO_TYPE_USER; + INIT_LIST_HEAD(&dso->node); } - return self; + return dso; } -static void symbols__delete(struct rb_root *self) +static void symbols__delete(struct rb_root *symbols) { struct symbol *pos; - struct rb_node *next = rb_first(self); + struct rb_node *next = rb_first(symbols); while (next) { pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, self); + rb_erase(&pos->rb_node, symbols); symbol__delete(pos); } } -void dso__delete(struct dso *self) +void dso__delete(struct dso *dso) { int i; for (i = 0; i < MAP__NR_TYPES; ++i) - symbols__delete(&self->symbols[i]); - if (self->sname_alloc) - free((char *)self->short_name); - if (self->lname_alloc) - free(self->long_name); - free(self); + symbols__delete(&dso->symbols[i]); + if (dso->sname_alloc) + free((char *)dso->short_name); + if (dso->lname_alloc) + free(dso->long_name); + free(dso); } -void dso__set_build_id(struct dso *self, void *build_id) +void dso__set_build_id(struct dso *dso, void *build_id) { - memcpy(self->build_id, build_id, sizeof(self->build_id)); - self->has_build_id = 1; + memcpy(dso->build_id, build_id, sizeof(dso->build_id)); + dso->has_build_id = 1; } -static void symbols__insert(struct rb_root *self, struct symbol *sym) +static void symbols__insert(struct rb_root *symbols, struct symbol *sym) { - struct rb_node **p = &self->rb_node; + struct rb_node **p = &symbols->rb_node; struct rb_node *parent = NULL; const u64 ip = sym->start; struct symbol *s; @@ -265,17 +265,17 @@ static void symbols__insert(struct rb_root *self, struct symbol *sym) p = &(*p)->rb_right; } rb_link_node(&sym->rb_node, parent, p); - rb_insert_color(&sym->rb_node, self); + rb_insert_color(&sym->rb_node, symbols); } -static struct symbol *symbols__find(struct rb_root *self, u64 ip) +static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) { struct rb_node *n; - if (self == NULL) + if (symbols == NULL) return NULL; - n = self->rb_node; + n = symbols->rb_node; while (n) { struct symbol *s = rb_entry(n, struct symbol, rb_node); @@ -296,9 +296,9 @@ struct symbol_name_rb_node { struct symbol sym; }; -static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) +static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) { - struct rb_node **p = &self->rb_node; + struct rb_node **p = &symbols->rb_node; struct rb_node *parent = NULL; struct symbol_name_rb_node *symn, *s; @@ -313,27 +313,29 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) p = &(*p)->rb_right; } rb_link_node(&symn->rb_node, parent, p); - rb_insert_color(&symn->rb_node, self); + rb_insert_color(&symn->rb_node, symbols); } -static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) +static void symbols__sort_by_name(struct rb_root *symbols, + struct rb_root *source) { struct rb_node *nd; for (nd = rb_first(source); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node); - symbols__insert_by_name(self, pos); + symbols__insert_by_name(symbols, pos); } } -static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) +static struct symbol *symbols__find_by_name(struct rb_root *symbols, + const char *name) { struct rb_node *n; - if (self == NULL) + if (symbols == NULL) return NULL; - n = self->rb_node; + n = symbols->rb_node; while (n) { struct symbol_name_rb_node *s; @@ -353,29 +355,29 @@ static struct symbol *symbols__find_by_name(struct rb_root *self, const char *na return NULL; } -struct symbol *dso__find_symbol(struct dso *self, +struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, u64 addr) { - return symbols__find(&self->symbols[type], addr); + return symbols__find(&dso->symbols[type], addr); } -struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, +struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, const char *name) { - return symbols__find_by_name(&self->symbol_names[type], name); + return symbols__find_by_name(&dso->symbol_names[type], name); } -void dso__sort_by_name(struct dso *self, enum map_type type) +void dso__sort_by_name(struct dso *dso, enum map_type type) { - dso__set_sorted_by_name(self, type); - return symbols__sort_by_name(&self->symbol_names[type], - &self->symbols[type]); + dso__set_sorted_by_name(dso, type); + return symbols__sort_by_name(&dso->symbol_names[type], + &dso->symbols[type]); } -int build_id__sprintf(const u8 *self, int len, char *bf) +int build_id__sprintf(const u8 *build_id, int len, char *bf) { char *bid = bf; - const u8 *raw = self; + const u8 *raw = build_id; int i; for (i = 0; i < len; ++i) { @@ -384,24 +386,25 @@ int build_id__sprintf(const u8 *self, int len, char *bf) bid += 2; } - return raw - self; + return raw - build_id; } -size_t dso__fprintf_buildid(struct dso *self, FILE *fp) +size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) { char sbuild_id[BUILD_ID_SIZE * 2 + 1]; - build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); return fprintf(fp, "%s", sbuild_id); } -size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp) +size_t dso__fprintf_symbols_by_name(struct dso *dso, + enum map_type type, FILE *fp) { size_t ret = 0; struct rb_node *nd; struct symbol_name_rb_node *pos; - for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) { + for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); fprintf(fp, "%s\n", pos->sym.name); } @@ -409,18 +412,18 @@ size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE * return ret; } -size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) +size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) { struct rb_node *nd; - size_t ret = fprintf(fp, "dso: %s (", self->short_name); + size_t ret = fprintf(fp, "dso: %s (", dso->short_name); - if (self->short_name != self->long_name) - ret += fprintf(fp, "%s, ", self->long_name); + if (dso->short_name != dso->long_name) + ret += fprintf(fp, "%s, ", dso->long_name); ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], - self->loaded ? "" : "NOT "); - ret += dso__fprintf_buildid(self, fp); + dso->loaded ? "" : "NOT "); + ret += dso__fprintf_buildid(dso, fp); ret += fprintf(fp, ")\n"); - for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { + for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node); ret += symbol__fprintf(pos, fp); } @@ -543,10 +546,10 @@ static int map__process_kallsym_symbol(void *arg, const char *name, * so that we can in the next step set the symbol ->end address and then * call kernel_maps__split_kallsyms. */ -static int dso__load_all_kallsyms(struct dso *self, const char *filename, +static int dso__load_all_kallsyms(struct dso *dso, const char *filename, struct map *map) { - struct process_kallsyms_args args = { .map = map, .dso = self, }; + struct process_kallsyms_args args = { .map = map, .dso = dso, }; return kallsyms__parse(filename, &args, map__process_kallsym_symbol); } @@ -555,7 +558,7 @@ static int dso__load_all_kallsyms(struct dso *self, const char *filename, * kernel range is broken in several maps, named [kernel].N, as we don't have * the original ELF section names vmlinux have. */ -static int dso__split_kallsyms(struct dso *self, struct map *map, +static int dso__split_kallsyms(struct dso *dso, struct map *map, symbol_filter_t filter) { struct map_groups *kmaps = map__kmap(map)->kmaps; @@ -563,7 +566,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct map *curr_map = map; struct symbol *pos; int count = 0, moved = 0; - struct rb_root *root = &self->symbols[map->type]; + struct rb_root *root = &dso->symbols[map->type]; struct rb_node *next = rb_first(root); int kernel_range = 0; @@ -582,7 +585,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, if (strcmp(curr_map->dso->short_name, module)) { if (curr_map != map && - self->kernel == DSO_TYPE_GUEST_KERNEL && + dso->kernel == DSO_TYPE_GUEST_KERNEL && machine__is_default_guest(machine)) { /* * We assume all symbols of a module are @@ -618,14 +621,14 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, pos->end = curr_map->map_ip(curr_map, pos->end); } else if (curr_map != map) { char dso_name[PATH_MAX]; - struct dso *dso; + struct dso *ndso; if (count == 0) { curr_map = map; goto filter_symbol; } - if (self->kernel == DSO_TYPE_GUEST_KERNEL) + if (dso->kernel == DSO_TYPE_GUEST_KERNEL) snprintf(dso_name, sizeof(dso_name), "[guest.kernel].%d", kernel_range++); @@ -634,15 +637,15 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, "[kernel].%d", kernel_range++); - dso = dso__new(dso_name); - if (dso == NULL) + ndso = dso__new(dso_name); + if (ndso == NULL) return -1; - dso->kernel = self->kernel; + ndso->kernel = dso->kernel; - curr_map = map__new2(pos->start, dso, map->type); + curr_map = map__new2(pos->start, ndso, map->type); if (curr_map == NULL) { - dso__delete(dso); + dso__delete(ndso); return -1; } @@ -665,7 +668,7 @@ discard_symbol: rb_erase(&pos->rb_node, root); } if (curr_map != map && - self->kernel == DSO_TYPE_GUEST_KERNEL && + dso->kernel == DSO_TYPE_GUEST_KERNEL && machine__is_default_guest(kmaps->machine)) { dso__set_loaded(curr_map->dso, curr_map->type); } @@ -673,21 +676,21 @@ discard_symbol: rb_erase(&pos->rb_node, root); return count + moved; } -int dso__load_kallsyms(struct dso *self, const char *filename, +int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, symbol_filter_t filter) { - if (dso__load_all_kallsyms(self, filename, map) < 0) + if (dso__load_all_kallsyms(dso, filename, map) < 0) return -1; - if (self->kernel == DSO_TYPE_GUEST_KERNEL) - self->symtab_type = SYMTAB__GUEST_KALLSYMS; + if (dso->kernel == DSO_TYPE_GUEST_KERNEL) + dso->symtab_type = SYMTAB__GUEST_KALLSYMS; else - self->symtab_type = SYMTAB__KALLSYMS; + dso->symtab_type = SYMTAB__KALLSYMS; - return dso__split_kallsyms(self, map, filter); + return dso__split_kallsyms(dso, map, filter); } -static int dso__load_perf_map(struct dso *self, struct map *map, +static int dso__load_perf_map(struct dso *dso, struct map *map, symbol_filter_t filter) { char *line = NULL; @@ -695,7 +698,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, FILE *file; int nr_syms = 0; - file = fopen(self->long_name, "r"); + file = fopen(dso->long_name, "r"); if (file == NULL) goto out_failure; @@ -733,7 +736,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, if (filter && filter(map, sym)) symbol__delete(sym); else { - symbols__insert(&self->symbols[map->type], sym); + symbols__insert(&dso->symbols[map->type], sym); nr_syms++; } } @@ -752,7 +755,7 @@ out_failure: /** * elf_symtab__for_each_symbol - iterate thru all the symbols * - * @self: struct elf_symtab instance to iterate + * @syms: struct elf_symtab instance to iterate * @idx: uint32_t idx * @sym: GElf_Sym iterator */ @@ -852,7 +855,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, * And always look at the original dso, not at debuginfo packages, that * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). */ -static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, +static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map, symbol_filter_t filter) { uint32_t nr_rel_entries, idx; @@ -871,7 +874,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, char name[PATH_MAX]; snprintf(name, sizeof(name), "%s%s", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); fd = open(name, O_RDONLY); if (fd < 0) goto out; @@ -947,7 +950,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - symbols__insert(&self->symbols[map->type], f); + symbols__insert(&dso->symbols[map->type], f); ++nr; } } @@ -969,7 +972,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - symbols__insert(&self->symbols[map->type], f); + symbols__insert(&dso->symbols[map->type], f); ++nr; } } @@ -985,29 +988,30 @@ out_close: return nr; out: pr_debug("%s: problems reading %s PLT info.\n", - __func__, self->long_name); + __func__, dso->long_name); return 0; } -static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) +static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) { switch (type) { case MAP__FUNCTION: - return elf_sym__is_function(self); + return elf_sym__is_function(sym); case MAP__VARIABLE: - return elf_sym__is_object(self); + return elf_sym__is_object(sym); default: return false; } } -static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) +static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, + enum map_type type) { switch (type) { case MAP__FUNCTION: - return elf_sec__is_text(self, secstrs); + return elf_sec__is_text(shdr, secstrs); case MAP__VARIABLE: - return elf_sec__is_data(self, secstrs); + return elf_sec__is_data(shdr, secstrs); default: return false; } @@ -1032,13 +1036,13 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) return -1; } -static int dso__load_sym(struct dso *self, struct map *map, const char *name, +static int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, symbol_filter_t filter, int kmodule, int want_symtab) { - struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; + struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; struct map *curr_map = map; - struct dso *curr_dso = self; + struct dso *curr_dso = dso; Elf_Data *symstrs, *secstrs; uint32_t nr_syms; int err = -1; @@ -1064,14 +1068,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } /* Always reject images with a mismatched build-id: */ - if (self->has_build_id) { + if (dso->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)) + if (!dso__build_id_equal(dso, build_id)) goto out_elf_end; } @@ -1112,13 +1116,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, nr_syms = shdr.sh_size / shdr.sh_entsize; memset(&sym, 0, sizeof(sym)); - if (self->kernel == DSO_TYPE_USER) { - self->adjust_symbols = (ehdr.e_type == ET_EXEC || + if (dso->kernel == DSO_TYPE_USER) { + dso->adjust_symbols = (ehdr.e_type == ET_EXEC || elf_section_by_name(elf, &ehdr, &shdr, ".gnu.prelink_undo", NULL) != NULL); - } else self->adjust_symbols = 0; - + } else { + dso->adjust_symbols = 0; + } elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { struct symbol *f; const char *elf_name = elf_sym__name(&sym, symstrs); @@ -1168,22 +1173,22 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, (sym.st_value & 1)) --sym.st_value; - if (self->kernel != DSO_TYPE_USER || kmodule) { + if (dso->kernel != DSO_TYPE_USER || kmodule) { char dso_name[PATH_MAX]; if (strcmp(section_name, (curr_dso->short_name + - self->short_name_len)) == 0) + dso->short_name_len)) == 0) goto new_symbol; if (strcmp(section_name, ".text") == 0) { curr_map = map; - curr_dso = self; + curr_dso = dso; goto new_symbol; } snprintf(dso_name, sizeof(dso_name), - "%s%s", self->short_name, section_name); + "%s%s", dso->short_name, section_name); curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); if (curr_map == NULL) { @@ -1195,9 +1200,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, curr_dso = dso__new(dso_name); if (curr_dso == NULL) goto out_elf_end; - curr_dso->kernel = self->kernel; - curr_dso->long_name = self->long_name; - curr_dso->long_name_len = self->long_name_len; + curr_dso->kernel = dso->kernel; + curr_dso->long_name = dso->long_name; + curr_dso->long_name_len = dso->long_name_len; curr_map = map__new2(start, curr_dso, map->type); if (curr_map == NULL) { @@ -1206,9 +1211,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } curr_map->map_ip = identity__map_ip; curr_map->unmap_ip = identity__map_ip; - curr_dso->symtab_type = self->symtab_type; + curr_dso->symtab_type = dso->symtab_type; map_groups__insert(kmap->kmaps, curr_map); - dsos__add(&self->node, curr_dso); + dsos__add(&dso->node, curr_dso); dso__set_loaded(curr_dso, map->type); } else curr_dso = curr_map->dso; @@ -1250,7 +1255,7 @@ new_symbol: * For misannotated, zeroed, ASM function sizes. */ if (nr > 0) { - symbols__fixup_end(&self->symbols[map->type]); + symbols__fixup_end(&dso->symbols[map->type]); if (kmap) { /* * We need to fixup this here too because we create new @@ -1266,9 +1271,9 @@ out_close: return err; } -static bool dso__build_id_equal(const struct dso *self, u8 *build_id) +static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) { - return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; + return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; } bool __dsos__read_build_ids(struct list_head *head, bool with_hits) @@ -1429,7 +1434,7 @@ out: return err; } -char dso__symtab_origin(const struct dso *self) +char dso__symtab_origin(const struct dso *dso) { static const char origin[] = { [SYMTAB__KALLSYMS] = 'k', @@ -1444,12 +1449,12 @@ char dso__symtab_origin(const struct dso *self) [SYMTAB__GUEST_KMODULE] = 'G', }; - if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND) + if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND) return '!'; - return origin[self->symtab_type]; + return origin[dso->symtab_type]; } -int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) +int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) { int size = PATH_MAX; char *name; @@ -1459,12 +1464,12 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) const char *root_dir; int want_symtab; - dso__set_loaded(self, map->type); + dso__set_loaded(dso, map->type); - if (self->kernel == DSO_TYPE_KERNEL) - return dso__load_kernel_sym(self, map, filter); - else if (self->kernel == DSO_TYPE_GUEST_KERNEL) - return dso__load_guest_kernel_sym(self, map, filter); + if (dso->kernel == DSO_TYPE_KERNEL) + return dso__load_kernel_sym(dso, map, filter); + else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) + return dso__load_guest_kernel_sym(dso, map, filter); if (map->groups && map->groups->machine) machine = map->groups->machine; @@ -1475,11 +1480,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) if (!name) return -1; - self->adjust_symbols = 0; + dso->adjust_symbols = 0; - if (strncmp(self->name, "/tmp/perf-", 10) == 0) { - ret = dso__load_perf_map(self, map, filter); - self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : + if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { + ret = dso__load_perf_map(dso, map, filter); + dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : SYMTAB__NOT_FOUND; return ret; } @@ -1490,33 +1495,33 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) */ want_symtab = 1; restart: - for (self->symtab_type = SYMTAB__BUILD_ID_CACHE; - self->symtab_type != SYMTAB__NOT_FOUND; - self->symtab_type++) { - switch (self->symtab_type) { + for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE; + dso->symtab_type != SYMTAB__NOT_FOUND; + dso->symtab_type++) { + switch (dso->symtab_type) { case SYMTAB__BUILD_ID_CACHE: /* skip the locally configured cache if a symfs is given */ if (symbol_conf.symfs[0] || - (dso__build_id_filename(self, name, size) == NULL)) { + (dso__build_id_filename(dso, name, size) == NULL)) { continue; } break; case SYMTAB__FEDORA_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s.debug", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); break; case SYMTAB__UBUNTU_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); break; case SYMTAB__BUILDID_DEBUGINFO: { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; - if (!self->has_build_id) + if (!dso->has_build_id) continue; - build_id__sprintf(self->build_id, - sizeof(self->build_id), + build_id__sprintf(dso->build_id, + sizeof(dso->build_id), build_id_hex); snprintf(name, size, "%s/usr/lib/debug/.build-id/%.2s/%s.debug", @@ -1525,7 +1530,7 @@ restart: break; case SYMTAB__SYSTEM_PATH_DSO: snprintf(name, size, "%s%s", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); break; case SYMTAB__GUEST_KMODULE: if (map->groups && machine) @@ -1533,12 +1538,12 @@ restart: else root_dir = ""; snprintf(name, size, "%s%s%s", symbol_conf.symfs, - root_dir, self->long_name); + root_dir, dso->long_name); break; case SYMTAB__SYSTEM_PATH_KMODULE: snprintf(name, size, "%s%s", symbol_conf.symfs, - self->long_name); + dso->long_name); break; default:; } @@ -1548,7 +1553,7 @@ restart: if (fd < 0) continue; - ret = dso__load_sym(self, map, name, fd, filter, 0, + ret = dso__load_sym(dso, map, name, fd, filter, 0, want_symtab); close(fd); @@ -1560,7 +1565,8 @@ restart: continue; if (ret > 0) { - int nr_plt = dso__synthesize_plt_symbols(self, map, filter); + int nr_plt = dso__synthesize_plt_symbols(dso, map, + filter); if (nr_plt > 0) ret += nr_plt; break; @@ -1577,17 +1583,17 @@ restart: } free(name); - if (ret < 0 && strstr(self->name, " (deleted)") != NULL) + if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) return 0; return ret; } -struct map *map_groups__find_by_name(struct map_groups *self, +struct map *map_groups__find_by_name(struct map_groups *mg, enum map_type type, const char *name) { struct rb_node *nd; - for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { + for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { struct map *map = rb_entry(nd, struct map, rb_node); if (map->dso && strcmp(map->dso->short_name, name) == 0) @@ -1597,28 +1603,28 @@ struct map *map_groups__find_by_name(struct map_groups *self, return NULL; } -static int dso__kernel_module_get_build_id(struct dso *self, - const char *root_dir) +static int dso__kernel_module_get_build_id(struct dso *dso, + const char *root_dir) { char filename[PATH_MAX]; /* * kernel module short names are of the form "[module]" and * we need just "module" here. */ - const char *name = self->short_name + 1; + const char *name = dso->short_name + 1; snprintf(filename, sizeof(filename), "%s/sys/module/%.*s/notes/.note.gnu.build-id", root_dir, (int)strlen(name) - 1, name); - if (sysfs__read_build_id(filename, self->build_id, - sizeof(self->build_id)) == 0) - self->has_build_id = true; + if (sysfs__read_build_id(filename, dso->build_id, + sizeof(dso->build_id)) == 0) + dso->has_build_id = true; return 0; } -static int map_groups__set_modules_path_dir(struct map_groups *self, +static int map_groups__set_modules_path_dir(struct map_groups *mg, const char *dir_name) { struct dirent *dent; @@ -1646,7 +1652,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); - ret = map_groups__set_modules_path_dir(self, path); + ret = map_groups__set_modules_path_dir(mg, path); if (ret < 0) goto out; } else { @@ -1661,7 +1667,8 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, (int)(dot - dent->d_name), dent->d_name); strxfrchar(dso_name, '-', '_'); - map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); + map = map_groups__find_by_name(mg, MAP__FUNCTION, + dso_name); if (map == NULL) continue; @@ -1711,20 +1718,20 @@ static char *get_kernel_version(const char *root_dir) return strdup(name); } -static int machine__set_modules_path(struct machine *self) +static int machine__set_modules_path(struct machine *machine) { char *version; char modules_path[PATH_MAX]; - version = get_kernel_version(self->root_dir); + version = get_kernel_version(machine->root_dir); if (!version) return -1; snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", - self->root_dir, version); + machine->root_dir, version); free(version); - return map_groups__set_modules_path_dir(&self->kmaps, modules_path); + return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); } /* @@ -1734,23 +1741,23 @@ static int machine__set_modules_path(struct machine *self) */ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) { - struct map *self = calloc(1, (sizeof(*self) + - (dso->kernel ? sizeof(struct kmap) : 0))); - if (self != NULL) { + struct map *map = calloc(1, (sizeof(*map) + + (dso->kernel ? sizeof(struct kmap) : 0))); + if (map != NULL) { /* * ->end will be filled after we load all the symbols */ - map__init(self, type, start, 0, 0, dso); + map__init(map, type, start, 0, 0, dso); } - return self; + return map; } -struct map *machine__new_module(struct machine *self, u64 start, +struct map *machine__new_module(struct machine *machine, u64 start, const char *filename) { struct map *map; - struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); + struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); if (dso == NULL) return NULL; @@ -1759,15 +1766,15 @@ struct map *machine__new_module(struct machine *self, u64 start, if (map == NULL) return NULL; - if (machine__is_host(self)) + if (machine__is_host(machine)) dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; else dso->symtab_type = SYMTAB__GUEST_KMODULE; - map_groups__insert(&self->kmaps, map); + map_groups__insert(&machine->kmaps, map); return map; } -static int machine__create_modules(struct machine *self) +static int machine__create_modules(struct machine *machine) { char *line = NULL; size_t n; @@ -1776,10 +1783,10 @@ static int machine__create_modules(struct machine *self) const char *modules; char path[PATH_MAX]; - if (machine__is_default_guest(self)) + if (machine__is_default_guest(machine)) modules = symbol_conf.default_guest_modules; else { - sprintf(path, "%s/proc/modules", self->root_dir); + sprintf(path, "%s/proc/modules", machine->root_dir); modules = path; } @@ -1815,16 +1822,16 @@ static int machine__create_modules(struct machine *self) *sep = '\0'; snprintf(name, sizeof(name), "[%s]", line); - map = machine__new_module(self, start, name); + map = machine__new_module(machine, start, name); if (map == NULL) goto out_delete_line; - dso__kernel_module_get_build_id(map->dso, self->root_dir); + dso__kernel_module_get_build_id(map->dso, machine->root_dir); } free(line); fclose(file); - return machine__set_modules_path(self); + return machine__set_modules_path(machine); out_delete_line: free(line); @@ -1832,7 +1839,7 @@ out_failure: return -1; } -int dso__load_vmlinux(struct dso *self, struct map *map, +int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, symbol_filter_t filter) { int err = -1, fd; @@ -1844,9 +1851,9 @@ int dso__load_vmlinux(struct dso *self, struct map *map, if (fd < 0) return -1; - dso__set_long_name(self, (char *)vmlinux); - dso__set_loaded(self, map->type); - err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); + dso__set_long_name(dso, (char *)vmlinux); + dso__set_loaded(dso, map->type); + err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); close(fd); if (err > 0) @@ -1855,7 +1862,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map, return err; } -int dso__load_vmlinux_path(struct dso *self, struct map *map, +int dso__load_vmlinux_path(struct dso *dso, struct map *map, symbol_filter_t filter) { int i, err = 0; @@ -1864,20 +1871,20 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map, pr_debug("Looking at the vmlinux_path (%d entries long)\n", vmlinux_path__nr_entries + 1); - filename = dso__build_id_filename(self, NULL, 0); + filename = dso__build_id_filename(dso, NULL, 0); if (filename != NULL) { - err = dso__load_vmlinux(self, map, filename, filter); + err = dso__load_vmlinux(dso, map, filename, filter); if (err > 0) { - dso__set_long_name(self, filename); + dso__set_long_name(dso, filename); goto out; } free(filename); } for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); + err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); if (err > 0) { - dso__set_long_name(self, strdup(vmlinux_path[i])); + dso__set_long_name(dso, strdup(vmlinux_path[i])); break; } } @@ -1885,7 +1892,7 @@ out: return err; } -static int dso__load_kernel_sym(struct dso *self, struct map *map, +static int dso__load_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter) { int err; @@ -1912,10 +1919,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } if (symbol_conf.vmlinux_name != NULL) { - err = dso__load_vmlinux(self, map, + err = dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, filter); if (err > 0) { - dso__set_long_name(self, + dso__set_long_name(dso, strdup(symbol_conf.vmlinux_name)); goto out_fixup; } @@ -1923,7 +1930,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } if (vmlinux_path != NULL) { - err = dso__load_vmlinux_path(self, map, filter); + err = dso__load_vmlinux_path(dso, map, filter); if (err > 0) goto out_fixup; } @@ -1937,13 +1944,13 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, * we have a build-id, so check if it is the same as the running kernel, * using it if it is. */ - if (self->has_build_id) { + if (dso->has_build_id) { u8 kallsyms_build_id[BUILD_ID_SIZE]; char sbuild_id[BUILD_ID_SIZE * 2 + 1]; if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, sizeof(kallsyms_build_id)) == 0) { - if (dso__build_id_equal(self, kallsyms_build_id)) { + if (dso__build_id_equal(dso, kallsyms_build_id)) { kallsyms_filename = "/proc/kallsyms"; goto do_kallsyms; } @@ -1952,7 +1959,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, * Now look if we have it on the build-id cache in * $HOME/.debug/[kernel.kallsyms]. */ - build_id__sprintf(self->build_id, sizeof(self->build_id), + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); if (asprintf(&kallsyms_allocated_filename, @@ -1979,7 +1986,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } do_kallsyms: - err = dso__load_kallsyms(self, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); free(kallsyms_allocated_filename); @@ -1987,7 +1994,7 @@ do_kallsyms: if (err > 0) { out_fixup: if (kallsyms_filename != NULL) - dso__set_long_name(self, strdup("[kernel.kallsyms]")); + dso__set_long_name(dso, strdup("[kernel.kallsyms]")); map__fixup_start(map); map__fixup_end(map); } @@ -1995,8 +2002,8 @@ out_fixup: return err; } -static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, - symbol_filter_t filter) +static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, + symbol_filter_t filter) { int err; const char *kallsyms_filename = NULL; @@ -2016,7 +2023,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, * Or use file guest_kallsyms inputted by user on commandline */ if (symbol_conf.default_guest_vmlinux_name != NULL) { - err = dso__load_vmlinux(self, map, + err = dso__load_vmlinux(dso, map, symbol_conf.default_guest_vmlinux_name, filter); goto out_try_fixup; } @@ -2029,7 +2036,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, kallsyms_filename = path; } - err = dso__load_kallsyms(self, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); @@ -2037,7 +2044,7 @@ out_try_fixup: if (err > 0) { if (kallsyms_filename != NULL) { machine__mmap_name(machine, path, sizeof(path)); - dso__set_long_name(self, strdup(path)); + dso__set_long_name(dso, strdup(path)); } map__fixup_start(map); map__fixup_end(map); @@ -2090,12 +2097,12 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp) return ret; } -size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) +size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) { struct rb_node *nd; size_t ret = 0; - for (nd = rb_first(self); nd; nd = rb_next(nd)) { + for (nd = rb_first(machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += __dsos__fprintf(&pos->kernel_dsos, fp); ret += __dsos__fprintf(&pos->user_dsos, fp); @@ -2119,18 +2126,20 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, return ret; } -size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) +size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, + bool with_hits) { - return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + - __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); + return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + + __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); } -size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) +size_t machines__fprintf_dsos_buildid(struct rb_root *machines, + FILE *fp, bool with_hits) { struct rb_node *nd; size_t ret = 0; - for (nd = rb_first(self); nd; nd = rb_next(nd)) { + for (nd = rb_first(machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); } @@ -2139,59 +2148,59 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_ struct dso *dso__new_kernel(const char *name) { - struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); + struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); - if (self != NULL) { - dso__set_short_name(self, "[kernel]"); - self->kernel = DSO_TYPE_KERNEL; + if (dso != NULL) { + dso__set_short_name(dso, "[kernel]"); + dso->kernel = DSO_TYPE_KERNEL; } - return self; + return dso; } static struct dso *dso__new_guest_kernel(struct machine *machine, const char *name) { char bf[PATH_MAX]; - struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); - - if (self != NULL) { - dso__set_short_name(self, "[guest.kernel]"); - self->kernel = DSO_TYPE_GUEST_KERNEL; + struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf, + sizeof(bf))); + if (dso != NULL) { + dso__set_short_name(dso, "[guest.kernel]"); + dso->kernel = DSO_TYPE_GUEST_KERNEL; } - return self; + return dso; } -void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) +void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) { char path[PATH_MAX]; if (machine__is_default_guest(machine)) return; sprintf(path, "%s/sys/kernel/notes", machine->root_dir); - if (sysfs__read_build_id(path, self->build_id, - sizeof(self->build_id)) == 0) - self->has_build_id = true; + if (sysfs__read_build_id(path, dso->build_id, + sizeof(dso->build_id)) == 0) + dso->has_build_id = true; } -static struct dso *machine__create_kernel(struct machine *self) +static struct dso *machine__create_kernel(struct machine *machine) { const char *vmlinux_name = NULL; struct dso *kernel; - if (machine__is_host(self)) { + if (machine__is_host(machine)) { vmlinux_name = symbol_conf.vmlinux_name; kernel = dso__new_kernel(vmlinux_name); } else { - if (machine__is_default_guest(self)) + if (machine__is_default_guest(machine)) vmlinux_name = symbol_conf.default_guest_vmlinux_name; - kernel = dso__new_guest_kernel(self, vmlinux_name); + kernel = dso__new_guest_kernel(machine, vmlinux_name); } if (kernel != NULL) { - dso__read_running_kernel_build_id(kernel, self); - dsos__add(&self->kernel_dsos, kernel); + dso__read_running_kernel_build_id(kernel, machine); + dsos__add(&machine->kernel_dsos, kernel); } return kernel; } @@ -2236,41 +2245,43 @@ static u64 machine__get_kernel_start_addr(struct machine *machine) return args.start; } -int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) +int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) { enum map_type type; - u64 start = machine__get_kernel_start_addr(self); + u64 start = machine__get_kernel_start_addr(machine); for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; - self->vmlinux_maps[type] = map__new2(start, kernel, type); - if (self->vmlinux_maps[type] == NULL) + machine->vmlinux_maps[type] = map__new2(start, kernel, type); + if (machine->vmlinux_maps[type] == NULL) return -1; - self->vmlinux_maps[type]->map_ip = - self->vmlinux_maps[type]->unmap_ip = identity__map_ip; - - kmap = map__kmap(self->vmlinux_maps[type]); - kmap->kmaps = &self->kmaps; - map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); + machine->vmlinux_maps[type]->map_ip = + machine->vmlinux_maps[type]->unmap_ip = + identity__map_ip; + kmap = map__kmap(machine->vmlinux_maps[type]); + kmap->kmaps = &machine->kmaps; + map_groups__insert(&machine->kmaps, + machine->vmlinux_maps[type]); } return 0; } -void machine__destroy_kernel_maps(struct machine *self) +void machine__destroy_kernel_maps(struct machine *machine) { enum map_type type; for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; - if (self->vmlinux_maps[type] == NULL) + if (machine->vmlinux_maps[type] == NULL) continue; - kmap = map__kmap(self->vmlinux_maps[type]); - map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); + kmap = map__kmap(machine->vmlinux_maps[type]); + map_groups__remove(&machine->kmaps, + machine->vmlinux_maps[type]); if (kmap->ref_reloc_sym) { /* * ref_reloc_sym is shared among all maps, so free just @@ -2284,25 +2295,25 @@ void machine__destroy_kernel_maps(struct machine *self) kmap->ref_reloc_sym = NULL; } - map__delete(self->vmlinux_maps[type]); - self->vmlinux_maps[type] = NULL; + map__delete(machine->vmlinux_maps[type]); + machine->vmlinux_maps[type] = NULL; } } -int machine__create_kernel_maps(struct machine *self) +int machine__create_kernel_maps(struct machine *machine) { - struct dso *kernel = machine__create_kernel(self); + struct dso *kernel = machine__create_kernel(machine); if (kernel == NULL || - __machine__create_kernel_maps(self, kernel) < 0) + __machine__create_kernel_maps(machine, kernel) < 0) return -1; - if (symbol_conf.use_modules && machine__create_modules(self) < 0) + if (symbol_conf.use_modules && machine__create_modules(machine) < 0) pr_debug("Problems creating module maps, continuing anyway...\n"); /* * Now that we have all the maps created, just set the ->end of them: */ - map_groups__fixup_end(&self->kmaps); + map_groups__fixup_end(&machine->kmaps); return 0; } @@ -2366,11 +2377,11 @@ out_fail: return -1; } -size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) +size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) { int i; size_t printed = 0; - struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; + struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; if (kdso->has_build_id) { char filename[PATH_MAX]; @@ -2467,9 +2478,9 @@ void symbol__exit(void) symbol_conf.initialized = false; } -int machines__create_kernel_maps(struct rb_root *self, pid_t pid) +int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) { - struct machine *machine = machines__findnew(self, pid); + struct machine *machine = machines__findnew(machines, pid); if (machine == NULL) return -1; @@ -2520,7 +2531,7 @@ char *strxfrchar(char *s, char from, char to) return s; } -int machines__create_guest_kernel_maps(struct rb_root *self) +int machines__create_guest_kernel_maps(struct rb_root *machines) { int ret = 0; struct dirent **namelist = NULL; @@ -2531,7 +2542,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self) if (symbol_conf.default_guest_vmlinux_name || symbol_conf.default_guest_modules || symbol_conf.default_guest_kallsyms) { - machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); + machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); } if (symbol_conf.guestmount) { @@ -2552,7 +2563,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self) pr_debug("Can't access file %s\n", path); goto failure; } - machines__create_kernel_maps(self, pid); + machines__create_kernel_maps(machines, pid); } failure: free(namelist); @@ -2561,23 +2572,23 @@ failure: return ret; } -void machines__destroy_guest_kernel_maps(struct rb_root *self) +void machines__destroy_guest_kernel_maps(struct rb_root *machines) { - struct rb_node *next = rb_first(self); + struct rb_node *next = rb_first(machines); while (next) { struct machine *pos = rb_entry(next, struct machine, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, self); + rb_erase(&pos->rb_node, machines); machine__delete(pos); } } -int machine__load_kallsyms(struct machine *self, const char *filename, +int machine__load_kallsyms(struct machine *machine, const char *filename, enum map_type type, symbol_filter_t filter) { - struct map *map = self->vmlinux_maps[type]; + struct map *map = machine->vmlinux_maps[type]; int ret = dso__load_kallsyms(map->dso, filename, map, filter); if (ret > 0) { @@ -2587,16 +2598,16 @@ int machine__load_kallsyms(struct machine *self, const char *filename, * kernel, with modules between them, fixup the end of all * sections. */ - __map_groups__fixup_end(&self->kmaps, type); + __map_groups__fixup_end(&machine->kmaps, type); } return ret; } -int machine__load_vmlinux_path(struct machine *self, enum map_type type, +int machine__load_vmlinux_path(struct machine *machine, enum map_type type, symbol_filter_t filter) { - struct map *map = self->vmlinux_maps[type]; + struct map *map = machine->vmlinux_maps[type]; int ret = dso__load_vmlinux_path(map->dso, map, filter); if (ret > 0) { -- cgit v1.2.2 From ec80fde746e3ccf93895d25ae1a7071c9af52585 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 26 May 2011 09:53:51 -0300 Subject: perf symbols: Handle /proc/sys/kernel/kptr_restrict Perf uses /proc/modules to figure out where kernel modules are loaded. With the advent of kptr_restrict, non root users get zeroes for all module start addresses. So check if kptr_restrict is non zero and don't generate the syntethic PERF_RECORD_MMAP events for them. Warn the user about it in perf record and in perf report. In perf report the reference relocation symbol being zero means that kptr_restrict was set, thus /proc/kallsyms has only zeroed addresses, so don't use it to fixup symbol addresses when using a valid kallsyms (in the buildid cache) or vmlinux (in the vmlinux path) build-id located automatically or specified by the user. Provide an explanation about it in 'perf report' if kernel samples were taken, checking if a suitable vmlinux or kallsyms was found/specified. Restricted /proc/kallsyms don't go to the buildid cache anymore. Example: [acme@emilia ~]$ perf record -F 100000 sleep 1 WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted, check /proc/sys/kernel/kptr_restrict. Samples in kernel functions may not be resolved if a suitable vmlinux file is not found in the buildid cache or in the vmlinux path. Samples in kernel modules won't be resolved at all. If some relocation was applied (e.g. kexec) symbols may be misresolved even with a suitable vmlinux or kallsyms file. [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.005 MB perf.data (~231 samples) ] [acme@emilia ~]$ [acme@emilia ~]$ perf report --stdio Kernel address maps (/proc/{kallsyms,modules}) were restricted, check /proc/sys/kernel/kptr_restrict before running 'perf record'. If some relocation was applied (e.g. kexec) symbols may be misresolved. Samples in kernel modules can't be resolved as well. # Events: 13 cycles # # Overhead Command Shared Object Symbol # ........ ....... ................. ..................... # 20.24% sleep [kernel.kallsyms] [k] page_fault 20.04% sleep [kernel.kallsyms] [k] filemap_fault 19.78% sleep [kernel.kallsyms] [k] __lru_cache_add 19.69% sleep ld-2.12.so [.] memcpy 14.71% sleep [kernel.kallsyms] [k] dput 4.70% sleep [kernel.kallsyms] [k] flush_signal_handlers 0.73% sleep [kernel.kallsyms] [k] perf_event_comm 0.11% sleep [kernel.kallsyms] [k] native_write_msr_safe # # (For a higher level overview, try: perf report --sort comm,dso) # [acme@emilia ~]$ This is because it found a suitable vmlinux (build-id checked) in /lib/modules/2.6.39-rc7+/build/vmlinux (use -v in perf report to see the long file name). If we remove that file from the vmlinux path: [root@emilia ~]# mv /lib/modules/2.6.39-rc7+/build/vmlinux \ /lib/modules/2.6.39-rc7+/build/vmlinux.OFF [acme@emilia ~]$ perf report --stdio [kernel.kallsyms] with build id 57298cdbe0131f6871667ec0eaab4804dcf6f562 not found, continuing without symbols Kernel address maps (/proc/{kallsyms,modules}) were restricted, check /proc/sys/kernel/kptr_restrict before running 'perf record'. As no suitable kallsyms nor vmlinux was found, kernel samples can't be resolved. Samples in kernel modules can't be resolved as well. # Events: 13 cycles # # Overhead Command Shared Object Symbol # ........ ....... ................. ...... # 80.31% sleep [kernel.kallsyms] [k] 0xffffffff8103425a 19.69% sleep ld-2.12.so [.] memcpy # # (For a higher level overview, try: perf report --sort comm,dso) # [acme@emilia ~]$ Reported-by: Stephane Eranian Suggested-by: David Miller Cc: Dave Jones Cc: David Miller Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Kees Cook Cc: Linus Torvalds Cc: Mike Galbraith Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/n/tip-mt512joaxxbhhp1odop04yit@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'tools/perf/util/symbol.c') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 516876dfbe52..eec196329fd9 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -676,9 +676,30 @@ discard_symbol: rb_erase(&pos->rb_node, root); return count + moved; } +static bool symbol__restricted_filename(const char *filename, + const char *restricted_filename) +{ + bool restricted = false; + + if (symbol_conf.kptr_restrict) { + char *r = realpath(filename, NULL); + + if (r != NULL) { + restricted = strcmp(r, restricted_filename) == 0; + free(r); + return restricted; + } + } + + return restricted; +} + int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, symbol_filter_t filter) { + if (symbol__restricted_filename(filename, "/proc/kallsyms")) + return -1; + if (dso__load_all_kallsyms(dso, filename, map) < 0) return -1; @@ -1790,6 +1811,9 @@ static int machine__create_modules(struct machine *machine) modules = path; } + if (symbol__restricted_filename(path, "/proc/modules")) + return -1; + file = fopen(modules, "r"); if (file == NULL) return -1; @@ -2239,6 +2263,9 @@ static u64 machine__get_kernel_start_addr(struct machine *machine) } } + if (symbol__restricted_filename(filename, "/proc/kallsyms")) + return 0; + if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) return 0; @@ -2410,6 +2437,25 @@ static int setup_list(struct strlist **list, const char *list_str, return 0; } +static bool symbol__read_kptr_restrict(void) +{ + bool value = false; + + if (geteuid() != 0) { + FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); + if (fp != NULL) { + char line[8]; + + if (fgets(line, sizeof(line), fp) != NULL) + value = atoi(line) != 0; + + fclose(fp); + } + } + + return value; +} + int symbol__init(void) { const char *symfs; @@ -2456,6 +2502,8 @@ int symbol__init(void) if (symfs != symbol_conf.symfs) free((void *)symfs); + symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); + symbol_conf.initialized = true; return 0; -- cgit v1.2.2