perf annotate: Defer allocating sym_priv->hist array
[pandora-kernel.git] / tools / perf / util / symbol.c
index f1f609d..323c0ae 100644 (file)
@@ -1,6 +1,5 @@
 #include "util.h"
 #include "../perf.h"
-#include "session.h"
 #include "sort.h"
 #include "string.h"
 #include "symbol.h"
@@ -34,7 +33,7 @@ enum dso_origin {
 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,
-                               struct perf_session *session, symbol_filter_t filter);
+                               symbol_filter_t filter);
 static int vmlinux_path__nr_entries;
 static char **vmlinux_path;
 
@@ -54,11 +53,6 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type)
        return self->sorted_by_name & (1 << type);
 }
 
-static void dso__set_loaded(struct dso *self, enum map_type type)
-{
-       self->loaded |= (1 << type);
-}
-
 static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
 {
        self->sorted_by_name |= (1 << type);
@@ -143,14 +137,14 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
        self->start = start;
        self->end   = len ? start + len - 1 : start;
 
-       pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
+       pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
 
        memcpy(self->name, name, namelen);
 
        return self;
 }
 
-static void symbol__delete(struct symbol *self)
+void symbol__delete(struct symbol *self)
 {
        free(((void *)self) - symbol_conf.priv_size);
 }
@@ -373,6 +367,10 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
        struct rb_node *nd;
        size_t ret = fprintf(fp, "dso: %s (", self->short_name);
 
+       if (self->short_name != self->long_name)
+               ret += fprintf(fp, "%s, ", self->long_name);
+       ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
+                      self->loaded ? "" : "NOT ");
        ret += dso__fprintf_buildid(self, fp);
        ret += fprintf(fp, ")\n");
        for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
@@ -480,8 +478,9 @@ static int dso__load_all_kallsyms(struct dso *self, const char *filename,
  * the original ELF section names vmlinux have.
  */
 static int dso__split_kallsyms(struct dso *self, struct map *map,
-                              struct perf_session *session, symbol_filter_t filter)
+                              symbol_filter_t filter)
 {
+       struct map_groups *kmaps = map__kmap(map)->kmaps;
        struct map *curr_map = map;
        struct symbol *pos;
        int count = 0;
@@ -503,7 +502,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
                        *module++ = '\0';
 
                        if (strcmp(curr_map->dso->short_name, module)) {
-                               curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
+                               curr_map = map_groups__find_by_name(kmaps, map->type, module);
                                if (curr_map == NULL) {
                                        pr_debug("/proc/{kallsyms,modules} "
                                                 "inconsistency while looking "
@@ -532,13 +531,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
                                return -1;
 
                        curr_map = map__new2(pos->start, dso, map->type);
-                       if (map == NULL) {
+                       if (curr_map == NULL) {
                                dso__delete(dso);
                                return -1;
                        }
 
                        curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
-                       map_groups__insert(&session->kmaps, curr_map);
+                       map_groups__insert(kmaps, curr_map);
                        ++kernel_range;
                }
 
@@ -557,9 +556,8 @@ discard_symbol:             rb_erase(&pos->rb_node, root);
        return count;
 }
 
-
-static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
-                             struct perf_session *session, symbol_filter_t filter)
+int dso__load_kallsyms(struct dso *self, const char *filename,
+                      struct map *map, symbol_filter_t filter)
 {
        if (dso__load_all_kallsyms(self, filename, map) < 0)
                return -1;
@@ -567,7 +565,7 @@ static int dso__load_kallsyms(struct dso *self, const char *filename, struct map
        symbols__fixup_end(&self->symbols[map->type]);
        self->origin = DSO__ORIG_KERNEL;
 
-       return dso__split_kallsyms(self, map, session, filter);
+       return dso__split_kallsyms(self, map, filter);
 }
 
 static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -893,10 +891,10 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
        }
 }
 
-static int dso__load_sym(struct dso *self, struct map *map,
-                        struct perf_session *session, const char *name, int fd,
-                        symbol_filter_t filter, int kernel, int kmodule)
+static int dso__load_sym(struct dso *self, struct map *map, const char *name,
+                        int fd, symbol_filter_t filter, int kmodule)
 {
+       struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
        struct map *curr_map = map;
        struct dso *curr_dso = self;
        size_t dso_name_len = strlen(self->short_name);
@@ -953,7 +951,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
        nr_syms = shdr.sh_size / shdr.sh_entsize;
 
        memset(&sym, 0, sizeof(sym));
-       if (!kernel) {
+       if (!self->kernel) {
                self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
                                elf_section_by_name(elf, &ehdr, &shdr,
                                                     ".gnu.prelink_undo",
@@ -967,9 +965,9 @@ static int dso__load_sym(struct dso *self, struct map *map,
                int is_label = elf_sym__is_label(&sym);
                const char *section_name;
 
-               if (kernel && session->ref_reloc_sym.name != NULL &&
-                   strcmp(elf_name, session->ref_reloc_sym.name) == 0)
-                       perf_session__reloc_vmlinux_maps(session, sym.st_value);
+               if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
+                   strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
+                       kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
 
                if (!is_label && !elf_sym__is_a(&sym, map->type))
                        continue;
@@ -985,7 +983,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
 
                section_name = elf_sec__name(&shdr, secstrs);
 
-               if (kernel || kmodule) {
+               if (self->kernel || kmodule) {
                        char dso_name[PATH_MAX];
 
                        if (strcmp(section_name,
@@ -1001,7 +999,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
                        snprintf(dso_name, sizeof(dso_name),
                                 "%s%s", self->short_name, section_name);
 
-                       curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
+                       curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
                        if (curr_map == NULL) {
                                u64 start = sym.st_value;
 
@@ -1012,7 +1010,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
                                if (curr_dso == NULL)
                                        goto out_elf_end;
                                curr_map = map__new2(start, curr_dso,
-                                                    MAP__FUNCTION);
+                                                    map->type);
                                if (curr_map == NULL) {
                                        dso__delete(curr_dso);
                                        goto out_elf_end;
@@ -1020,8 +1018,9 @@ static int dso__load_sym(struct dso *self, struct map *map,
                                curr_map->map_ip = identity__map_ip;
                                curr_map->unmap_ip = identity__map_ip;
                                curr_dso->origin = DSO__ORIG_KERNEL;
-                               map_groups__insert(&session->kmaps, curr_map);
+                               map_groups__insert(kmap->kmaps, curr_map);
                                dsos__add(&dsos__kernel, curr_dso);
+                               dso__set_loaded(curr_dso, map->type);
                        } else
                                curr_dso = curr_map->dso;
 
@@ -1029,9 +1028,10 @@ static int dso__load_sym(struct dso *self, struct map *map,
                }
 
                if (curr_dso->adjust_symbols) {
-                       pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
-                                 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
-                                 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
+                       pr_debug4("%s: adjusting symbol: st_value: %#Lx "
+                                 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
+                                 (u64)sym.st_value, (u64)shdr.sh_addr,
+                                 (u64)shdr.sh_offset);
                        sym.st_value -= shdr.sh_addr - shdr.sh_offset;
                }
                /*
@@ -1059,8 +1059,16 @@ new_symbol:
        /*
         * For misannotated, zeroed, ASM function sizes.
         */
-       if (nr > 0)
+       if (nr > 0) {
                symbols__fixup_end(&self->symbols[map->type]);
+               if (kmap) {
+                       /*
+                        * We need to fixup this here too because we create new
+                        * maps here, for things like vsyscall sections.
+                        */
+                       __map_groups__fixup_end(kmap->kmaps, map->type);
+               }
+       }
        err = nr;
 out_elf_end:
        elf_end(elf);
@@ -1073,25 +1081,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
        return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
 }
 
-static bool __dsos__read_build_ids(struct list_head *head)
+static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
 {
        bool have_build_id = false;
        struct dso *pos;
 
-       list_for_each_entry(pos, head, node)
+       list_for_each_entry(pos, head, node) {
+               if (with_hits && !pos->hit)
+                       continue;
                if (filename__read_build_id(pos->long_name, pos->build_id,
                                            sizeof(pos->build_id)) > 0) {
                        have_build_id     = true;
                        pos->has_build_id = true;
                }
+       }
 
        return have_build_id;
 }
 
-bool dsos__read_build_ids(void)
+bool dsos__read_build_ids(bool with_hits)
 {
-       bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
-            ubuildids = __dsos__read_build_ids(&dsos__user);
+       bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
+            ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
        return kbuildids || ubuildids;
 }
 
@@ -1236,8 +1247,7 @@ char dso__symtab_origin(const struct dso *self)
        return origin[self->origin];
 }
 
-int dso__load(struct dso *self, struct map *map, struct perf_session *session,
-             symbol_filter_t filter)
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
 {
        int size = PATH_MAX;
        char *name;
@@ -1249,7 +1259,7 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
        dso__set_loaded(self, map->type);
 
        if (self->kernel)
-               return dso__load_kernel_sym(self, map, session, filter);
+               return dso__load_kernel_sym(self, map, filter);
 
        name = malloc(size);
        if (!name)
@@ -1320,7 +1330,7 @@ open_file:
                fd = open(name, O_RDONLY);
        } while (fd < 0);
 
-       ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
+       ret = dso__load_sym(self, map, name, fd, filter, 0);
        close(fd);
 
        /*
@@ -1376,7 +1386,7 @@ static int dso__kernel_module_get_build_id(struct dso *self)
        return 0;
 }
 
-static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
+static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
 {
        struct dirent *dent;
        DIR *dir = opendir(dirname);
@@ -1396,7 +1406,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
 
                        snprintf(path, sizeof(path), "%s/%s",
                                 dirname, dent->d_name);
-                       if (perf_session__set_modules_path_dir(self, path) < 0)
+                       if (map_groups__set_modules_path_dir(self, path) < 0)
                                goto failure;
                } else {
                        char *dot = strrchr(dent->d_name, '.'),
@@ -1410,7 +1420,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
                                 (int)(dot - dent->d_name), dent->d_name);
 
                        strxfrchar(dso_name, '-', '_');
-                       map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
+                       map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
                        if (map == NULL)
                                continue;
 
@@ -1431,7 +1441,7 @@ failure:
        return -1;
 }
 
-static int perf_session__set_modules_path(struct perf_session *self)
+static int map_groups__set_modules_path(struct map_groups *self)
 {
        struct utsname uts;
        char modules_path[PATH_MAX];
@@ -1442,7 +1452,7 @@ static int perf_session__set_modules_path(struct perf_session *self)
        snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
                 uts.release);
 
-       return perf_session__set_modules_path_dir(self, modules_path);
+       return map_groups__set_modules_path_dir(self, modules_path);
 }
 
 /*
@@ -1452,8 +1462,8 @@ static int perf_session__set_modules_path(struct perf_session *self)
  */
 static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
 {
-       struct map *self = malloc(sizeof(*self));
-
+       struct map *self = zalloc(sizeof(*self) +
+                                 (dso->kernel ? sizeof(struct kmap) : 0));
        if (self != NULL) {
                /*
                 * ->end will be filled after we load all the symbols
@@ -1464,8 +1474,8 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
        return self;
 }
 
-struct map *perf_session__new_module_map(struct perf_session *self, u64 start,
-                                        const char *filename)
+struct map *map_groups__new_module(struct map_groups *self, u64 start,
+                                  const char *filename)
 {
        struct map *map;
        struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
@@ -1478,11 +1488,11 @@ struct map *perf_session__new_module_map(struct perf_session *self, u64 start,
                return NULL;
 
        dso->origin = DSO__ORIG_KMODULE;
-       map_groups__insert(&self->kmaps, map);
+       map_groups__insert(self, map);
        return map;
 }
 
-static int perf_session__create_module_maps(struct perf_session *self)
+static int map_groups__create_modules(struct map_groups *self)
 {
        char *line = NULL;
        size_t n;
@@ -1520,7 +1530,7 @@ static int perf_session__create_module_maps(struct perf_session *self)
                *sep = '\0';
 
                snprintf(name, sizeof(name), "[%s]", line);
-               map = perf_session__new_module_map(self, start, name);
+               map = map_groups__new_module(self, start, name);
                if (map == NULL)
                        goto out_delete_line;
                dso__kernel_module_get_build_id(map->dso);
@@ -1529,7 +1539,7 @@ static int perf_session__create_module_maps(struct perf_session *self)
        free(line);
        fclose(file);
 
-       return perf_session__set_modules_path(self);
+       return map_groups__set_modules_path(self);
 
 out_delete_line:
        free(line);
@@ -1538,7 +1548,6 @@ out_failure:
 }
 
 static int dso__load_vmlinux(struct dso *self, struct map *map,
-                            struct perf_session *session,
                             const char *vmlinux, symbol_filter_t filter)
 {
        int err = -1, fd;
@@ -1572,14 +1581,36 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
                return -1;
 
        dso__set_loaded(self, map->type);
-       err = dso__load_sym(self, map, session, vmlinux, fd, filter, 1, 0);
+       err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
        close(fd);
 
+       if (err > 0)
+               pr_debug("Using %s for symbols\n", vmlinux);
+
+       return err;
+}
+
+int dso__load_vmlinux_path(struct dso *self, struct map *map,
+                          symbol_filter_t filter)
+{
+       int i, err = 0;
+
+       pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+                vmlinux_path__nr_entries);
+
+       for (i = 0; i < vmlinux_path__nr_entries; ++i) {
+               err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
+               if (err > 0) {
+                       dso__set_long_name(self, strdup(vmlinux_path[i]));
+                       break;
+               }
+       }
+
        return err;
 }
 
 static int dso__load_kernel_sym(struct dso *self, struct map *map,
-                               struct perf_session *session, symbol_filter_t filter)
+                               symbol_filter_t filter)
 {
        int err;
        const char *kallsyms_filename = NULL;
@@ -1600,26 +1631,15 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
         * match.
         */
        if (symbol_conf.vmlinux_name != NULL) {
-               err = dso__load_vmlinux(self, map, session,
+               err = dso__load_vmlinux(self, map,
                                        symbol_conf.vmlinux_name, filter);
                goto out_try_fixup;
        }
 
        if (vmlinux_path != NULL) {
-               int i;
-               pr_debug("Looking at the vmlinux_path (%d entries long)\n",
-                        vmlinux_path__nr_entries);
-               for (i = 0; i < vmlinux_path__nr_entries; ++i) {
-                       err = dso__load_vmlinux(self, map, session,
-                                               vmlinux_path[i], filter);
-                       if (err > 0) {
-                               pr_debug("Using %s for symbols\n",
-                                        vmlinux_path[i]);
-                               dso__set_long_name(self,
-                                                  strdup(vmlinux_path[i]));
-                               goto out_fixup;
-                       }
-               }
+               err = dso__load_vmlinux_path(self, map, filter);
+               if (err > 0)
+                       goto out_fixup;
        }
 
        /*
@@ -1647,12 +1667,16 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
 
                if (asprintf(&kallsyms_allocated_filename,
                             "%s/.debug/[kernel.kallsyms]/%s",
-                            getenv("HOME"), sbuild_id) == -1)
+                            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;
                }
@@ -1665,7 +1689,9 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
        }
 
 do_kallsyms:
-       err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter);
+       err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
+       if (err > 0)
+               pr_debug("Using %s for symbols\n", kallsyms_filename);
        free(kallsyms_allocated_filename);
 
 out_try_fixup:
@@ -1682,7 +1708,6 @@ out_fixup:
 
 LIST_HEAD(dsos__user);
 LIST_HEAD(dsos__kernel);
-struct dso *vdso;
 
 static void dsos__add(struct list_head *head, struct dso *dso)
 {
@@ -1752,33 +1777,35 @@ size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
                __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
 }
 
-static struct dso *dsos__create_kernel(const char *vmlinux)
+struct dso *dso__new_kernel(const char *name)
 {
-       struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
+       struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
 
-       if (kernel == NULL)
-               return NULL;
+       if (self != NULL) {
+               self->short_name = "[kernel]";
+               self->kernel     = 1;
+       }
 
-       kernel->short_name = "[kernel]";
-       kernel->kernel     = 1;
+       return self;
+}
 
-       vdso = dso__new("[vdso]");
-       if (vdso == NULL)
-               goto out_delete_kernel_dso;
-       dso__set_loaded(vdso, MAP__FUNCTION);
+void dso__read_running_kernel_build_id(struct dso *self)
+{
+       if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
+                                sizeof(self->build_id)) == 0)
+               self->has_build_id = true;
+}
 
-       if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
-                                sizeof(kernel->build_id)) == 0)
-               kernel->has_build_id = true;
+static struct dso *dsos__create_kernel(const char *vmlinux)
+{
+       struct dso *kernel = dso__new_kernel(vmlinux);
 
-       dsos__add(&dsos__kernel, kernel);
-       dsos__add(&dsos__user, vdso);
+       if (kernel != NULL) {
+               dso__read_running_kernel_build_id(kernel);
+               dsos__add(&dsos__kernel, kernel);
+       }
 
        return kernel;
-
-out_delete_kernel_dso:
-       dso__delete(kernel);
-       return NULL;
 }
 
 int __map_groups__create_kernel_maps(struct map_groups *self,
@@ -1788,30 +1815,23 @@ int __map_groups__create_kernel_maps(struct map_groups *self,
        enum map_type type;
 
        for (type = 0; type < MAP__NR_TYPES; ++type) {
+               struct kmap *kmap;
+
                vmlinux_maps[type] = map__new2(0, kernel, type);
                if (vmlinux_maps[type] == NULL)
                        return -1;
 
                vmlinux_maps[type]->map_ip =
                        vmlinux_maps[type]->unmap_ip = identity__map_ip;
+
+               kmap = map__kmap(vmlinux_maps[type]);
+               kmap->kmaps = self;
                map_groups__insert(self, vmlinux_maps[type]);
        }
 
        return 0;
 }
 
-static int map_groups__create_kernel_maps(struct map_groups *self,
-                                         struct map *vmlinux_maps[MAP__NR_TYPES],
-                                         const char *vmlinux)
-{
-       struct dso *kernel = dsos__create_kernel(vmlinux);
-
-       if (kernel == NULL)
-               return -1;
-
-       return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel);
-}
-
 static void vmlinux_path__exit(void)
 {
        while (--vmlinux_path__nr_entries >= 0) {
@@ -1917,19 +1937,22 @@ out_free_comm_list:
        return -1;
 }
 
-int perf_session__create_kernel_maps(struct perf_session *self)
+int map_groups__create_kernel_maps(struct map_groups *self,
+                                  struct map *vmlinux_maps[MAP__NR_TYPES])
 {
-       if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps,
-                                          symbol_conf.vmlinux_name) < 0)
+       struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
+
+       if (kernel == NULL)
+               return -1;
+
+       if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
                return -1;
 
-       if (symbol_conf.use_modules &&
-           perf_session__create_module_maps(self) < 0)
-               pr_debug("Failed to load list of modules for session %s, "
-                        "continuing...\n", self->filename);
+       if (symbol_conf.use_modules && map_groups__create_modules(self) < 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(self);
        return 0;
 }