diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 449 |
1 files changed, 67 insertions, 382 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c0c3696..7eb0362 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -51,7 +51,6 @@ static enum dso_binary_type binary_type_symtab[] = { DSO_BINARY_TYPE__SYSTEM_PATH_DSO, DSO_BINARY_TYPE__GUEST_KMODULE, DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, - DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, DSO_BINARY_TYPE__NOT_FOUND, }; @@ -160,12 +159,10 @@ again: if (choose_best_symbol(curr, next) == SYMBOL_A) { rb_erase(&next->rb_node, symbols); - symbol__delete(next); goto again; } else { nd = rb_next(&curr->rb_node); rb_erase(&curr->rb_node, symbols); - symbol__delete(curr); } } } @@ -502,64 +499,6 @@ out_failure: return -1; } -int modules__parse(const char *filename, void *arg, - int (*process_module)(void *arg, const char *name, - u64 start)) -{ - char *line = NULL; - size_t n; - FILE *file; - int err = 0; - - file = fopen(filename, "r"); - if (file == NULL) - return -1; - - while (1) { - char name[PATH_MAX]; - u64 start; - char *sep; - ssize_t line_len; - - line_len = getline(&line, &n, file); - if (line_len < 0) { - if (feof(file)) - break; - err = -1; - goto out; - } - - if (!line) { - err = -1; - goto out; - } - - line[--line_len] = '\0'; /* \n */ - - sep = strrchr(line, 'x'); - if (sep == NULL) - continue; - - hex2u64(sep + 1, &start); - - sep = strchr(line, ' '); - if (sep == NULL) - continue; - - *sep = '\0'; - - scnprintf(name, sizeof(name), "[%s]", line); - - err = process_module(arg, name, start); - if (err) - break; - } -out: - free(line); - fclose(file); - return err; -} - struct process_kallsyms_args { struct map *map; struct dso *dso; @@ -800,242 +739,51 @@ bool symbol__restricted_filename(const char *filename, return restricted; } -struct module_info { - struct rb_node rb_node; - char *name; - u64 start; +struct kcore_mapfn_data { + struct dso *dso; + enum map_type type; + struct list_head maps; }; -static void add_module(struct module_info *mi, struct rb_root *modules) -{ - struct rb_node **p = &modules->rb_node; - struct rb_node *parent = NULL; - struct module_info *m; - - while (*p != NULL) { - parent = *p; - m = rb_entry(parent, struct module_info, rb_node); - if (strcmp(mi->name, m->name) < 0) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - rb_link_node(&mi->rb_node, parent, p); - rb_insert_color(&mi->rb_node, modules); -} - -static void delete_modules(struct rb_root *modules) -{ - struct module_info *mi; - struct rb_node *next = rb_first(modules); - - while (next) { - mi = rb_entry(next, struct module_info, rb_node); - next = rb_next(&mi->rb_node); - rb_erase(&mi->rb_node, modules); - free(mi->name); - free(mi); - } -} - -static struct module_info *find_module(const char *name, - struct rb_root *modules) -{ - struct rb_node *n = modules->rb_node; - - while (n) { - struct module_info *m; - int cmp; - - m = rb_entry(n, struct module_info, rb_node); - cmp = strcmp(name, m->name); - if (cmp < 0) - n = n->rb_left; - else if (cmp > 0) - n = n->rb_right; - else - return m; - } - - return NULL; -} - -static int __read_proc_modules(void *arg, const char *name, u64 start) +static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) { - struct rb_root *modules = arg; - struct module_info *mi; - - mi = zalloc(sizeof(struct module_info)); - if (!mi) - return -ENOMEM; - - mi->name = strdup(name); - mi->start = start; + struct kcore_mapfn_data *md = data; + struct map *map; - if (!mi->name) { - free(mi); + map = map__new2(start, md->dso, md->type); + if (map == NULL) return -ENOMEM; - } - - add_module(mi, modules); - - return 0; -} -static int read_proc_modules(const char *filename, struct rb_root *modules) -{ - if (symbol__restricted_filename(filename, "/proc/modules")) - return -1; + map->end = map->start + len; + map->pgoff = pgoff; - if (modules__parse(filename, modules, __read_proc_modules)) { - delete_modules(modules); - return -1; - } + list_add(&map->node, &md->maps); return 0; } -int compare_proc_modules(const char *from, const char *to) -{ - struct rb_root from_modules = RB_ROOT; - struct rb_root to_modules = RB_ROOT; - struct rb_node *from_node, *to_node; - struct module_info *from_m, *to_m; - int ret = -1; - - if (read_proc_modules(from, &from_modules)) - return -1; - - if (read_proc_modules(to, &to_modules)) - goto out_delete_from; - - from_node = rb_first(&from_modules); - to_node = rb_first(&to_modules); - while (from_node) { - if (!to_node) - break; - - from_m = rb_entry(from_node, struct module_info, rb_node); - to_m = rb_entry(to_node, struct module_info, rb_node); - - if (from_m->start != to_m->start || - strcmp(from_m->name, to_m->name)) - break; - - from_node = rb_next(from_node); - to_node = rb_next(to_node); - } - - if (!from_node && !to_node) - ret = 0; - - delete_modules(&to_modules); -out_delete_from: - delete_modules(&from_modules); - - return ret; -} - -static int do_validate_kcore_modules(const char *filename, struct map *map, - struct map_groups *kmaps) -{ - struct rb_root modules = RB_ROOT; - struct map *old_map; - int err; - - err = read_proc_modules(filename, &modules); - if (err) - return err; - - old_map = map_groups__first(kmaps, map->type); - while (old_map) { - struct map *next = map_groups__next(old_map); - struct module_info *mi; - - if (old_map == map || old_map->start == map->start) { - /* The kernel map */ - old_map = next; - continue; - } - - /* Module must be in memory at the same address */ - mi = find_module(old_map->dso->short_name, &modules); - if (!mi || mi->start != old_map->start) { - err = -EINVAL; - goto out; - } - - old_map = next; - } -out: - delete_modules(&modules); - return err; -} - /* - * If kallsyms is referenced by name then we look for filename in the same + * If kallsyms is referenced by name then we look for kcore in the same * directory. */ -static bool filename_from_kallsyms_filename(char *filename, - const char *base_name, - const char *kallsyms_filename) +static bool kcore_filename_from_kallsyms_filename(char *kcore_filename, + const char *kallsyms_filename) { char *name; - strcpy(filename, kallsyms_filename); - name = strrchr(filename, '/'); + strcpy(kcore_filename, kallsyms_filename); + name = strrchr(kcore_filename, '/'); if (!name) return false; - name += 1; - - if (!strcmp(name, "kallsyms")) { - strcpy(name, base_name); + if (!strcmp(name, "/kallsyms")) { + strcpy(name, "/kcore"); return true; } return false; } -static int validate_kcore_modules(const char *kallsyms_filename, - struct map *map) -{ - struct map_groups *kmaps = map__kmap(map)->kmaps; - char modules_filename[PATH_MAX]; - - if (!filename_from_kallsyms_filename(modules_filename, "modules", - kallsyms_filename)) - return -EINVAL; - - if (do_validate_kcore_modules(modules_filename, map, kmaps)) - return -EINVAL; - - return 0; -} - -struct kcore_mapfn_data { - struct dso *dso; - enum map_type type; - struct list_head maps; -}; - -static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) -{ - struct kcore_mapfn_data *md = data; - struct map *map; - - map = map__new2(start, md->dso, md->type); - if (map == NULL) - return -ENOMEM; - - map->end = map->start + len; - map->pgoff = pgoff; - - list_add(&map->node, &md->maps); - - return 0; -} - static int dso__load_kcore(struct dso *dso, struct map *map, const char *kallsyms_filename) { @@ -1052,12 +800,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map, if (map != machine->vmlinux_maps[map->type]) return -EINVAL; - if (!filename_from_kallsyms_filename(kcore_filename, "kcore", - kallsyms_filename)) - return -EINVAL; - - /* All modules must be present at their original addresses */ - if (validate_kcore_modules(kallsyms_filename, map)) + if (!kcore_filename_from_kallsyms_filename(kcore_filename, + kallsyms_filename)) return -EINVAL; md.dso = dso; @@ -1444,105 +1188,6 @@ out: return err; } -static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) -{ - char kallsyms_filename[PATH_MAX]; - struct dirent *dent; - int ret = -1; - DIR *d; - - d = opendir(dir); - if (!d) - return -1; - - while (1) { - dent = readdir(d); - if (!dent) - break; - if (dent->d_type != DT_DIR) - continue; - scnprintf(kallsyms_filename, sizeof(kallsyms_filename), - "%s/%s/kallsyms", dir, dent->d_name); - if (!validate_kcore_modules(kallsyms_filename, map)) { - strlcpy(dir, kallsyms_filename, dir_sz); - ret = 0; - break; - } - } - - closedir(d); - - return ret; -} - -static char *dso__find_kallsyms(struct dso *dso, struct map *map) -{ - u8 host_build_id[BUILD_ID_SIZE]; - char sbuild_id[BUILD_ID_SIZE * 2 + 1]; - bool is_host = false; - char path[PATH_MAX]; - - if (!dso->has_build_id) { - /* - * Last resort, if we don't have a build-id and couldn't find - * any vmlinux file, try the running kernel kallsyms table. - */ - goto proc_kallsyms; - } - - if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, - sizeof(host_build_id)) == 0) - is_host = dso__build_id_equal(dso, host_build_id); - - build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); - - /* Use /proc/kallsyms if possible */ - if (is_host) { - DIR *d; - int fd; - - /* If no cached kcore go with /proc/kallsyms */ - scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", - buildid_dir, sbuild_id); - d = opendir(path); - if (!d) - goto proc_kallsyms; - closedir(d); - - /* - * Do not check the build-id cache, until we know we cannot use - * /proc/kcore. - */ - fd = open("/proc/kcore", O_RDONLY); - if (fd != -1) { - close(fd); - /* If module maps match go with /proc/kallsyms */ - if (!validate_kcore_modules("/proc/kallsyms", map)) - goto proc_kallsyms; - } - - /* Find kallsyms in build-id cache with kcore */ - if (!find_matching_kcore(map, path, sizeof(path))) - return strdup(path); - - goto proc_kallsyms; - } - - scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", - buildid_dir, sbuild_id); - - if (access(path, F_OK)) { - pr_err("No kallsyms or vmlinux with build-id %s was found\n", - sbuild_id); - return NULL; - } - - return strdup(path); - -proc_kallsyms: - return strdup("/proc/kallsyms"); -} - static int dso__load_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter) { @@ -1569,7 +1214,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, goto do_kallsyms; } - if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { + if (symbol_conf.vmlinux_name != NULL) { err = dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, filter); if (err > 0) { @@ -1581,7 +1226,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, return err; } - if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { + if (vmlinux_path != NULL) { err = dso__load_vmlinux_path(dso, map, filter); if (err > 0) return err; @@ -1591,11 +1236,51 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, if (symbol_conf.symfs[0] != 0) return -1; - kallsyms_allocated_filename = dso__find_kallsyms(dso, map); - if (!kallsyms_allocated_filename) - 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, + * using it if it is. + */ + 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(dso, kallsyms_build_id)) { + kallsyms_filename = "/proc/kallsyms"; + goto do_kallsyms; + } + } + /* + * Now look if we have it on the build-id cache in + * $HOME/.debug/[kernel.kallsyms]. + */ + build_id__sprintf(dso->build_id, sizeof(dso->build_id), + sbuild_id); - kallsyms_filename = kallsyms_allocated_filename; + if (asprintf(&kallsyms_allocated_filename, + "%s/.debug/[kernel.kallsyms]/%s", + getenv("HOME"), sbuild_id) == -1) { + pr_err("Not enough memory for kallsyms file lookup\n"); + return -1; + } + + kallsyms_filename = kallsyms_allocated_filename; + + if (access(kallsyms_filename, F_OK)) { + pr_err("No kallsyms or vmlinux with build-id %s " + "was found\n", sbuild_id); + free(kallsyms_allocated_filename); + return -1; + } + } else { + /* + * Last resort, if we don't have a build-id and couldn't find + * any vmlinux file, try the running kernel kallsyms table. + */ + kallsyms_filename = "/proc/kallsyms"; + } do_kallsyms: err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); |