]> Pileus Git - ~andy/linux/blobdiff - tools/perf/util/symbol.c
perf symbols: Destroy unused symsrcs
[~andy/linux] / tools / perf / util / symbol.c
index e377c2e96191493688075f7a559c6c1886b62b77..e89afc097d8ad2d4b818f07e02321084110e6ddc 100644 (file)
 
 #include <elf.h>
 #include <limits.h>
+#include <symbol/kallsyms.h>
 #include <sys/utsname.h>
 
-#ifndef KSYM_NAME_LEN
-#define KSYM_NAME_LEN 256
-#endif
-
 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 *dso, struct map *map,
@@ -446,62 +443,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
        return ret;
 }
 
-int kallsyms__parse(const char *filename, void *arg,
-                   int (*process_symbol)(void *arg, const char *name,
-                                         char type, u64 start))
-{
-       char *line = NULL;
-       size_t n;
-       int err = -1;
-       FILE *file = fopen(filename, "r");
-
-       if (file == NULL)
-               goto out_failure;
-
-       err = 0;
-
-       while (!feof(file)) {
-               u64 start;
-               int line_len, len;
-               char symbol_type;
-               char *symbol_name;
-
-               line_len = getline(&line, &n, file);
-               if (line_len < 0 || !line)
-                       break;
-
-               line[--line_len] = '\0'; /* \n */
-
-               len = hex2u64(line, &start);
-
-               len++;
-               if (len + 2 >= line_len)
-                       continue;
-
-               symbol_type = line[len];
-               len += 2;
-               symbol_name = line + len;
-               len = line_len - len;
-
-               if (len >= KSYM_NAME_LEN) {
-                       err = -1;
-                       break;
-               }
-
-               err = process_symbol(arg, symbol_name,
-                                    symbol_type, start);
-               if (err)
-                       break;
-       }
-
-       free(line);
-       fclose(file);
-       return err;
-
-out_failure:
-       return -1;
-}
-
 int modules__parse(const char *filename, void *arg,
                   int (*process_module)(void *arg, const char *name,
                                         u64 start))
@@ -565,14 +506,6 @@ struct process_kallsyms_args {
        struct dso *dso;
 };
 
-static u8 kallsyms2elf_type(char type)
-{
-       if (type == 'W')
-               return STB_WEAK;
-
-       return isupper(type) ? STB_GLOBAL : STB_LOCAL;
-}
-
 bool symbol__is_idle(struct symbol *sym)
 {
        const char * const idle_symbols[] = {
@@ -694,7 +627,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
  * 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 *dso, struct map *map,
+static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
                               symbol_filter_t filter)
 {
        struct map_groups *kmaps = map__kmap(map)->kmaps;
@@ -759,6 +692,12 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map,
                        char dso_name[PATH_MAX];
                        struct dso *ndso;
 
+                       if (delta) {
+                               /* Kernel was relocated at boot time */
+                               pos->start -= delta;
+                               pos->end -= delta;
+                       }
+
                        if (count == 0) {
                                curr_map = map;
                                goto filter_symbol;
@@ -788,6 +727,10 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map,
                        curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
                        map_groups__insert(kmaps, curr_map);
                        ++kernel_range;
+               } else if (delta) {
+                       /* Kernel was relocated at boot time */
+                       pos->start -= delta;
+                       pos->end -= delta;
                }
 filter_symbol:
                if (filter && filter(curr_map, pos)) {
@@ -863,7 +806,7 @@ static void delete_modules(struct rb_root *modules)
                mi = rb_entry(next, struct module_info, rb_node);
                next = rb_next(&mi->rb_node);
                rb_erase(&mi->rb_node, modules);
-               free(mi->name);
+               zfree(&mi->name);
                free(mi);
        }
 }
@@ -1043,6 +986,23 @@ static int validate_kcore_modules(const char *kallsyms_filename,
        return 0;
 }
 
+static int validate_kcore_addresses(const char *kallsyms_filename,
+                                   struct map *map)
+{
+       struct kmap *kmap = map__kmap(map);
+
+       if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
+               u64 start;
+
+               start = kallsyms__get_function_start(kallsyms_filename,
+                                                    kmap->ref_reloc_sym->name);
+               if (start != kmap->ref_reloc_sym->addr)
+                       return -EINVAL;
+       }
+
+       return validate_kcore_modules(kallsyms_filename, map);
+}
+
 struct kcore_mapfn_data {
        struct dso *dso;
        enum map_type type;
@@ -1086,8 +1046,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
                                             kallsyms_filename))
                return -EINVAL;
 
-       /* All modules must be present at their original addresses */
-       if (validate_kcore_modules(kallsyms_filename, map))
+       /* Modules and kernel must be present at their original addresses */
+       if (validate_kcore_addresses(kallsyms_filename, map))
                return -EINVAL;
 
        md.dso = dso;
@@ -1156,9 +1116,9 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
         * dso__data_read_addr().
         */
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
-               dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE;
+               dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
        else
-               dso->data_type = DSO_BINARY_TYPE__KCORE;
+               dso->binary_type = DSO_BINARY_TYPE__KCORE;
        dso__set_long_name(dso, strdup(kcore_filename), true);
 
        close(fd);
@@ -1180,15 +1140,41 @@ out_err:
        return -EINVAL;
 }
 
+/*
+ * If the kernel is relocated at boot time, kallsyms won't match.  Compute the
+ * delta based on the relocation reference symbol.
+ */
+static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
+{
+       struct kmap *kmap = map__kmap(map);
+       u64 addr;
+
+       if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
+               return 0;
+
+       addr = kallsyms__get_function_start(filename,
+                                           kmap->ref_reloc_sym->name);
+       if (!addr)
+               return -1;
+
+       *delta = addr - kmap->ref_reloc_sym->addr;
+       return 0;
+}
+
 int dso__load_kallsyms(struct dso *dso, const char *filename,
                       struct map *map, symbol_filter_t filter)
 {
+       u64 delta = 0;
+
        if (symbol__restricted_filename(filename, "/proc/kallsyms"))
                return -1;
 
        if (dso__load_all_kallsyms(dso, filename, map) < 0)
                return -1;
 
+       if (kallsyms__delta(map, filename, &delta))
+               return -1;
+
        symbols__fixup_duplicate(&dso->symbols[map->type]);
        symbols__fixup_end(&dso->symbols[map->type]);
 
@@ -1200,7 +1186,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
        if (!dso__load_kcore(dso, map, filename))
                return dso__split_kallsyms_for_kcore(dso, map, filter);
        else
-               return dso__split_kallsyms(dso, map, filter);
+               return dso__split_kallsyms(dso, map, delta, filter);
 }
 
 static int dso__load_perf_map(struct dso *dso, struct map *map,
@@ -1325,8 +1311,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 
                enum dso_binary_type symtab_type = binary_type_symtab[i];
 
-               if (dso__binary_type_file(dso, symtab_type,
-                                         root_dir, name, PATH_MAX))
+               if (dso__read_binary_type_filename(dso, symtab_type,
+                                                  root_dir, name, PATH_MAX))
                        continue;
 
                /* Name is now the name of the next image to try */
@@ -1350,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 
                        if (syms_ss && runtime_ss)
                                break;
+               } else {
+                       symsrc__destroy(ss);
                }
 
        }
@@ -1435,9 +1423,9 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
 
        if (err > 0) {
                if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
-                       dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
+                       dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
                else
-                       dso->data_type = DSO_BINARY_TYPE__VMLINUX;
+                       dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
                dso__set_long_name(dso, vmlinux, vmlinux_allocated);
                dso__set_loaded(dso, map->type);
                pr_debug("Using %s for symbols\n", symfs_vmlinux);
@@ -1491,7 +1479,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
                        continue;
                scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
                          "%s/%s/kallsyms", dir, dent->d_name);
-               if (!validate_kcore_modules(kallsyms_filename, map)) {
+               if (!validate_kcore_addresses(kallsyms_filename, map)) {
                        strlcpy(dir, kallsyms_filename, dir_sz);
                        ret = 0;
                        break;
@@ -1546,7 +1534,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
                if (fd != -1) {
                        close(fd);
                        /* If module maps match go with /proc/kallsyms */
-                       if (!validate_kcore_modules("/proc/kallsyms", map))
+                       if (!validate_kcore_addresses("/proc/kallsyms", map))
                                goto proc_kallsyms;
                }
 
@@ -1688,13 +1676,10 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
 
 static void vmlinux_path__exit(void)
 {
-       while (--vmlinux_path__nr_entries >= 0) {
-               free(vmlinux_path[vmlinux_path__nr_entries]);
-               vmlinux_path[vmlinux_path__nr_entries] = NULL;
-       }
+       while (--vmlinux_path__nr_entries >= 0)
+               zfree(&vmlinux_path[vmlinux_path__nr_entries]);
 
-       free(vmlinux_path);
-       vmlinux_path = NULL;
+       zfree(&vmlinux_path);
 }
 
 static int vmlinux_path__init(void)