summaryrefslogtreecommitdiff
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c449
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);