]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - tools/perf/util/symbol.c
Merge branch 'perf/urgent' into perf/core
[karo-tx-linux.git] / tools / perf / util / symbol.c
index fd3d9c8e90fc43b7071583de8aa41af402ec8a3e..582ce72ca4d2df310e9e05658ab910ee1bf5128a 100644 (file)
@@ -2,12 +2,14 @@
 #include "../perf.h"
 #include "string.h"
 #include "symbol.h"
+#include "thread.h"
 
 #include "debug.h"
 
 #include <libelf.h>
 #include <gelf.h>
 #include <elf.h>
+#include <sys/utsname.h>
 
 const char *sym_hist_filter;
 
@@ -18,12 +20,53 @@ enum dso_origin {
        DSO__ORIG_UBUNTU,
        DSO__ORIG_BUILDID,
        DSO__ORIG_DSO,
+       DSO__ORIG_KMODULE,
        DSO__ORIG_NOT_FOUND,
 };
 
-static struct symbol *symbol__new(u64 start, u64 len,
-                                 const char *name, unsigned int priv_size,
-                                 u64 obj_start, int v)
+static void dsos__add(struct dso *dso);
+static struct dso *dsos__find(const char *name);
+
+static struct rb_root kernel_maps;
+
+static void dso__set_symbols_end(struct dso *self)
+{
+       struct rb_node *nd, *prevnd = rb_first(&self->syms);
+
+       if (prevnd == NULL)
+               return;
+
+       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+               struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
+                             *curr = rb_entry(nd, struct symbol, rb_node);
+
+               if (prev->end == prev->start)
+                       prev->end = curr->start - 1;
+               prevnd = nd;
+       }
+}
+
+static void kernel_maps__fixup_sym_end(void)
+{
+       struct map *prev, *curr;
+       struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
+
+       if (prevnd == NULL)
+               return;
+
+       curr = rb_entry(prevnd, struct map, rb_node);
+       dso__set_symbols_end(curr->dso);
+
+       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+               prev = curr;
+               curr = rb_entry(nd, struct map, rb_node);
+               prev->end = curr->start - 1;
+               dso__set_symbols_end(curr->dso);
+       }
+}
+
+static struct symbol *symbol__new(u64 start, u64 len, const char *name,
+                                 unsigned int priv_size, int v)
 {
        size_t namelen = strlen(name) + 1;
        struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -32,10 +75,9 @@ static struct symbol *symbol__new(u64 start, u64 len,
                return NULL;
 
        if (v >= 2)
-               printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
-                       (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
+               printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n",
+                       start, (unsigned long)len, name, self->hist);
 
-       self->obj_start= obj_start;
        self->hist = NULL;
        self->hist_sum = 0;
 
@@ -60,12 +102,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
 
 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
 {
-       if (!self->module)
-               return fprintf(fp, " %llx-%llx %s\n",
+       return fprintf(fp, " %llx-%llx %s\n",
                       self->start, self->end, self->name);
-       else
-               return fprintf(fp, " %llx-%llx %s \t[%s]\n",
-                      self->start, self->end, self->name, self->module->name);
 }
 
 struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -74,6 +112,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
 
        if (self != NULL) {
                strcpy(self->name, name);
+               self->long_name = self->name;
+               self->short_name = self->name;
                self->syms = RB_ROOT;
                self->sym_priv_size = sym_priv_size;
                self->find_symbol = dso__find_symbol;
@@ -100,6 +140,8 @@ static void dso__delete_symbols(struct dso *self)
 void dso__delete(struct dso *self)
 {
        dso__delete_symbols(self);
+       if (self->long_name != self->name)
+               free(self->long_name);
        free(self);
 }
 
@@ -147,7 +189,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
 
 size_t dso__fprintf(struct dso *self, FILE *fp)
 {
-       size_t ret = fprintf(fp, "dso: %s\n", self->name);
+       size_t ret = fprintf(fp, "dso: %s\n", self->short_name);
 
        struct rb_node *nd;
        for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
@@ -158,9 +200,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
        return ret;
 }
 
-static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
+static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v)
 {
-       struct rb_node *nd, *prevnd;
+       struct map *map = kernel_map;
        char *line = NULL;
        size_t n;
        FILE *file = fopen("/proc/kallsyms", "r");
@@ -174,6 +216,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
                struct symbol *sym;
                int line_len, len;
                char symbol_type;
+               char *module, *symbol_name;
 
                line_len = getline(&line, &n, file);
                if (line_len < 0)
@@ -196,40 +239,50 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
                 */
                if (symbol_type != 'T' && symbol_type != 'W')
                        continue;
+
+               symbol_name = line + len + 2;
+               module = strchr(symbol_name, '\t');
+               if (module) {
+                       char *module_name_end;
+
+                       if (!use_modules)
+                               continue;
+                       *module = '\0';
+                       module = strchr(module + 1, '[');
+                       if (!module)
+                               continue;
+                       module_name_end = strchr(module + 1, ']');
+                       if (!module_name_end)
+                               continue;
+                       *(module_name_end + 1) = '\0';
+                       if (strcmp(map->dso->name, module)) {
+                               map = kernel_maps__find_by_dso_name(module);
+                               if (!map) {
+                                       fputs("/proc/{kallsyms,modules} "
+                                             "inconsistency!\n", stderr);
+                                       return -1;
+                               }
+                       }
+                       start = map->map_ip(map, start);
+               } else
+                       map = kernel_map;
                /*
                 * Well fix up the end later, when we have all sorted.
                 */
-               sym = symbol__new(start, 0xdead, line + len + 2,
-                                 self->sym_priv_size, 0, v);
+               sym = symbol__new(start, 0, symbol_name,
+                                 map->dso->sym_priv_size, v);
 
                if (sym == NULL)
                        goto out_delete_line;
 
-               if (filter && filter(self, sym))
-                       symbol__delete(sym, self->sym_priv_size);
+               if (filter && filter(map, sym))
+                       symbol__delete(sym, map->dso->sym_priv_size);
                else {
-                       dso__insert_symbol(self, sym);
+                       dso__insert_symbol(map->dso, sym);
                        count++;
                }
        }
 
-       /*
-        * Now that we have all sorted out, just set the ->end of all
-        * symbols
-        */
-       prevnd = rb_first(&self->syms);
-
-       if (prevnd == NULL)
-               goto out_delete_line;
-
-       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
-               struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
-                             *curr = rb_entry(nd, struct symbol, rb_node);
-
-               prev->end = curr->start - 1;
-               prevnd = nd;
-       }
-
        free(line);
        fclose(file);
 
@@ -241,14 +294,33 @@ out_failure:
        return -1;
 }
 
-static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
+static size_t kernel_maps__fprintf(FILE *fp)
+{
+       size_t printed = fprintf(stderr, "Kernel maps:\n");
+       struct rb_node *nd;
+
+       printed += map__fprintf(kernel_map, fp);
+       printed += dso__fprintf(kernel_map->dso, fp);
+
+       for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+               struct map *pos = rb_entry(nd, struct map, rb_node);
+
+               printed += map__fprintf(pos, fp);
+               printed += dso__fprintf(pos->dso, fp);
+       }
+
+       return printed + fprintf(stderr, "END kernel maps\n");
+}
+
+static int dso__load_perf_map(struct dso *self, struct map *map,
+                             symbol_filter_t filter, int v)
 {
        char *line = NULL;
        size_t n;
        FILE *file;
        int nr_syms = 0;
 
-       file = fopen(self->name, "r");
+       file = fopen(self->long_name, "r");
        if (file == NULL)
                goto out_failure;
 
@@ -279,12 +351,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
                        continue;
 
                sym = symbol__new(start, size, line + len,
-                                 self->sym_priv_size, start, v);
+                                 self->sym_priv_size, v);
 
                if (sym == NULL)
                        goto out_delete_line;
 
-               if (filter && filter(self, sym))
+               if (filter && filter(map, sym))
                        symbol__delete(sym, self->sym_priv_size);
                else {
                        dso__insert_symbol(self, sym);
@@ -324,8 +396,7 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
 {
        return elf_sym__type(sym) == STT_FUNC &&
               sym->st_name != 0 &&
-              sym->st_shndx != SHN_UNDEF &&
-              sym->st_size != 0;
+              sym->st_shndx != SHN_UNDEF;
 }
 
 static inline int elf_sym__is_label(const GElf_Sym *sym)
@@ -410,7 +481,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
        Elf *elf;
        int nr = 0, symidx, fd, err = 0;
 
-       fd = open(self->name, O_RDONLY);
+       fd = open(self->long_name, O_RDONLY);
        if (fd < 0)
                goto out;
 
@@ -478,7 +549,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
                                 "%s@plt", elf_sym__name(&sym, symstrs));
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-                                       sympltname, self->sym_priv_size, 0, v);
+                                       sympltname, self->sym_priv_size, v);
                        if (!f)
                                goto out_elf_end;
 
@@ -496,7 +567,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
                                 "%s@plt", elf_sym__name(&sym, symstrs));
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-                                       sympltname, self->sym_priv_size, 0, v);
+                                       sympltname, self->sym_priv_size, v);
                        if (!f)
                                goto out_elf_end;
 
@@ -515,12 +586,13 @@ out_close:
                return nr;
 out:
        fprintf(stderr, "%s: problems reading %s PLT info.\n",
-               __func__, self->name);
+               __func__, self->long_name);
        return 0;
 }
 
-static int dso__load_sym(struct dso *self, int fd, const char *name,
-                        symbol_filter_t filter, int v, struct module *mod)
+static int dso__load_sym(struct dso *self, struct map *map, const char *name,
+                        int fd, symbol_filter_t filter, int kernel,
+                        int kmodule, int v)
 {
        Elf_Data *symstrs, *secstrs;
        uint32_t nr_syms;
@@ -532,7 +604,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        GElf_Sym sym;
        Elf_Scn *sec, *sec_strndx;
        Elf *elf;
-       int nr = 0, kernel = !strcmp("[kernel]", self->name);
+       int nr = 0;
 
        elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
        if (elf == NULL) {
@@ -589,10 +661,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                struct symbol *f;
                const char *elf_name;
                char *demangled;
-               u64 obj_start;
-               struct section *section = NULL;
                int is_label = elf_sym__is_label(&sym);
                const char *section_name;
+               u64 sh_offset = 0;
 
                if (!is_label && !elf_sym__is_function(&sym))
                        continue;
@@ -607,7 +678,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                        continue;
 
                section_name = elf_sec__name(&shdr, secstrs);
-               obj_start = sym.st_value;
+
+               if ((kernel || kmodule)) {
+                       if (strstr(section_name, ".init"))
+                               sh_offset = shdr.sh_offset;
+               }
 
                if (self->adjust_symbols) {
                        if (v >= 2)
@@ -616,17 +691,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
 
                        sym.st_value -= shdr.sh_addr - shdr.sh_offset;
                }
-
-               if (mod) {
-                       section = mod->sections->find_section(mod->sections, section_name);
-                       if (section)
-                               sym.st_value += section->vma;
-                       else {
-                               fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
-                                       mod->name, section_name);
-                               goto out_elf_end;
-                       }
-               }
                /*
                 * We need to figure out if the object was created from C++ sources
                 * DWARF DW_compile_unit has this, but we don't always have access
@@ -637,16 +701,15 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                if (demangled != NULL)
                        elf_name = demangled;
 
-               f = symbol__new(sym.st_value, sym.st_size, elf_name,
-                               self->sym_priv_size, obj_start, v);
+               f = symbol__new(sym.st_value + sh_offset, sym.st_size, elf_name,
+                               self->sym_priv_size, v);
                free(demangled);
                if (!f)
                        goto out_elf_end;
 
-               if (filter && filter(self, f))
+               if (filter && filter(map, f))
                        symbol__delete(f, self->sym_priv_size);
                else {
-                       f->module = mod;
                        dso__insert_symbol(self, f);
                        nr++;
                }
@@ -671,7 +734,7 @@ static char *dso__read_build_id(struct dso *self, int v)
        char *build_id = NULL, *bid;
        unsigned char *raw;
        Elf *elf;
-       int fd = open(self->name, O_RDONLY);
+       int fd = open(self->long_name, O_RDONLY);
 
        if (fd < 0)
                goto out;
@@ -680,7 +743,7 @@ static char *dso__read_build_id(struct dso *self, int v)
        if (elf == NULL) {
                if (v)
                        fprintf(stderr, "%s: cannot read %s ELF file.\n",
-                               __func__, self->name);
+                               __func__, self->long_name);
                goto out_close;
        }
 
@@ -709,7 +772,7 @@ static char *dso__read_build_id(struct dso *self, int v)
                bid += 2;
        }
        if (v >= 2)
-               printf("%s(%s): %s\n", __func__, self->name, build_id);
+               printf("%s(%s): %s\n", __func__, self->long_name, build_id);
 out_elf_end:
        elf_end(elf);
 out_close:
@@ -727,6 +790,7 @@ char dso__symtab_origin(const struct dso *self)
                [DSO__ORIG_UBUNTU] =   'u',
                [DSO__ORIG_BUILDID] =  'b',
                [DSO__ORIG_DSO] =      'd',
+               [DSO__ORIG_KMODULE] =  'K',
        };
 
        if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -734,7 +798,7 @@ char dso__symtab_origin(const struct dso *self)
        return origin[self->origin];
 }
 
-int dso__load(struct dso *self, symbol_filter_t filter, int v)
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v)
 {
        int size = PATH_MAX;
        char *name = malloc(size), *build_id = NULL;
@@ -747,7 +811,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v)
        self->adjust_symbols = 0;
 
        if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
-               ret = dso__load_perf_map(self, filter, v);
+               ret = dso__load_perf_map(self, map, filter, v);
                self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
                                         DSO__ORIG_NOT_FOUND;
                return ret;
@@ -760,10 +824,12 @@ more:
                self->origin++;
                switch (self->origin) {
                case DSO__ORIG_FEDORA:
-                       snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
+                       snprintf(name, size, "/usr/lib/debug%s.debug",
+                                self->long_name);
                        break;
                case DSO__ORIG_UBUNTU:
-                       snprintf(name, size, "/usr/lib/debug%s", self->name);
+                       snprintf(name, size, "/usr/lib/debug%s",
+                                self->long_name);
                        break;
                case DSO__ORIG_BUILDID:
                        build_id = dso__read_build_id(self, v);
@@ -777,7 +843,7 @@ more:
                        self->origin++;
                        /* Fall thru */
                case DSO__ORIG_DSO:
-                       snprintf(name, size, "%s", self->name);
+                       snprintf(name, size, "%s", self->long_name);
                        break;
 
                default:
@@ -787,7 +853,7 @@ more:
                fd = open(name, O_RDONLY);
        } while (fd < 0);
 
-       ret = dso__load_sym(self, fd, name, filter, v, NULL);
+       ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v);
        close(fd);
 
        /*
@@ -808,87 +874,245 @@ out:
        return ret;
 }
 
-static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
-                            symbol_filter_t filter, int v)
+struct map *kernel_map;
+
+static void kernel_maps__insert(struct map *map)
 {
-       struct module *mod = mod_dso__find_module(mods, name);
-       int err = 0, fd;
+       maps__insert(&kernel_maps, map);
+}
 
-       if (mod == NULL || !mod->active)
-               return err;
+struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
+{
+       /*
+        * We can't have kernel_map in kernel_maps because it spans an address
+        * space that includes the modules. The right way to fix this is to
+        * create several maps, so that we don't have overlapping ranges with
+        * modules. For now lets look first on the kernel dso.
+        */
+       struct map *map = maps__find(&kernel_maps, ip);
+       struct symbol *sym;
+
+       if (map) {
+               ip = map->map_ip(map, ip);
+               sym = map->dso->find_symbol(map->dso, ip);
+       } else {
+               map = kernel_map;
+               sym = map->dso->find_symbol(map->dso, ip);
+       }
 
-       fd = open(mod->path, O_RDONLY);
+       if (mapp)
+               *mapp = map;
 
-       if (fd < 0)
+       return sym;
+}
+
+struct map *kernel_maps__find_by_dso_name(const char *name)
+{
+       struct rb_node *nd;
+
+       for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+               struct map *map = rb_entry(nd, struct map, rb_node);
+
+               if (map->dso && strcmp(map->dso->name, name) == 0)
+                       return map;
+       }
+
+       return NULL;
+}
+
+static int dso__load_module_sym(struct dso *self, struct map *map,
+                               symbol_filter_t filter, int v)
+{
+       int err = 0, fd = open(self->long_name, O_RDONLY);
+
+       if (fd < 0) {
+               if (v)
+                       fprintf(stderr, "%s: cannot open %s\n",
+                               __func__, self->long_name);
                return err;
+       }
 
-       err = dso__load_sym(self, fd, name, filter, v, mod);
+       err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v);
        close(fd);
 
        return err;
 }
 
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
+static int dsos__load_modules_sym_dir(char *dirname,
+                                     symbol_filter_t filter, int v)
 {
-       struct mod_dso *mods = mod_dso__new_dso("modules");
-       struct module *pos;
-       struct rb_node *next;
-       int err;
+       struct dirent *dent;
+       int nr_symbols = 0, err;
+       DIR *dir = opendir(dirname);
 
-       err = mod_dso__load_modules(mods);
+       if (!dir) {
+               if (v)
+                       fprintf(stderr, "%s: cannot open %s dir\n", __func__,
+                               dirname);
+               return -1;
+       }
 
-       if (err <= 0)
-               return err;
+       while ((dent = readdir(dir)) != NULL) {
+               char path[PATH_MAX];
+
+               if (dent->d_type == DT_DIR) {
+                       if (!strcmp(dent->d_name, ".") ||
+                           !strcmp(dent->d_name, ".."))
+                               continue;
+
+                       snprintf(path, sizeof(path), "%s/%s",
+                                dirname, dent->d_name);
+                       err = dsos__load_modules_sym_dir(path, filter, v);
+                       if (err < 0)
+                               goto failure;
+               } else {
+                       char *dot = strrchr(dent->d_name, '.'),
+                            dso_name[PATH_MAX];
+                       struct map *map;
+                       struct rb_node *last;
+
+                       if (dot == NULL || strcmp(dot, ".ko"))
+                               continue;
+                       snprintf(dso_name, sizeof(dso_name), "[%.*s]",
+                                (int)(dot - dent->d_name), dent->d_name);
+
+                       strxfrchar(dso_name, '-', '_');
+                       map = kernel_maps__find_by_dso_name(dso_name);
+                       if (map == NULL)
+                               continue;
+
+                       snprintf(path, sizeof(path), "%s/%s",
+                                dirname, dent->d_name);
+
+                       map->dso->long_name = strdup(path);
+                       if (map->dso->long_name == NULL)
+                               goto failure;
+
+                       err = dso__load_module_sym(map->dso, map, filter, v);
+                       if (err < 0)
+                               goto failure;
+                       last = rb_last(&map->dso->syms);
+                       if (last) {
+                               struct symbol *sym;
+                               sym = rb_entry(last, struct symbol, rb_node);
+                               map->end = map->start + sym->end;
+                       }
+               }
+               nr_symbols += err;
+       }
 
-       /*
-        * Iterate over modules, and load active symbols.
-        */
-       next = rb_first(&mods->mods);
-       while (next) {
-               pos = rb_entry(next, struct module, rb_node);
-               err = dso__load_module(self, mods, pos->name, filter, v);
+       return nr_symbols;
+failure:
+       closedir(dir);
+       return -1;
+}
 
-               if (err < 0)
-                       break;
+static int dsos__load_modules_sym(symbol_filter_t filter, int v)
+{
+       struct utsname uts;
+       char modules_path[PATH_MAX];
 
-               next = rb_next(&pos->rb_node);
-       }
+       if (uname(&uts) < 0)
+               return -1;
 
-       if (err < 0) {
-               mod_dso__delete_modules(mods);
-               mod_dso__delete_self(mods);
-       }
+       snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
+                uts.release);
 
-       return err;
+       return dsos__load_modules_sym_dir(modules_path, filter, v);
 }
 
-static inline void dso__fill_symbol_holes(struct dso *self)
+/*
+ * Constructor variant for modules (where we know from /proc/modules where
+ * they are loaded) and for vmlinux, where only after we load all the
+ * symbols we'll know where it starts and ends.
+ */
+static struct map *map__new2(u64 start, struct dso *dso)
 {
-       struct symbol *prev = NULL;
-       struct rb_node *nd;
+       struct map *self = malloc(sizeof(*self));
 
-       for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
-               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+       if (self != NULL) {
+               self->start = start;
+               /*
+                * Will be filled after we load all the symbols
+                */
+               self->end = 0;
 
-               if (prev) {
-                       u64 hole = 0;
-                       int alias = pos->start == prev->start;
+               self->pgoff = 0;
+               self->dso = dso;
+               self->map_ip = map__map_ip;
+               RB_CLEAR_NODE(&self->rb_node);
+       }
+       return self;
+}
 
-                       if (!alias)
-                               hole = prev->start - pos->end - 1;
+static int dsos__load_modules(unsigned int sym_priv_size)
+{
+       char *line = NULL;
+       size_t n;
+       FILE *file = fopen("/proc/modules", "r");
+       struct map *map;
 
-                       if (hole || alias) {
-                               if (alias)
-                                       pos->end = prev->end;
-                               else if (hole)
-                                       pos->end = prev->start - 1;
-                       }
+       if (file == NULL)
+               return -1;
+
+       while (!feof(file)) {
+               char name[PATH_MAX];
+               u64 start;
+               struct dso *dso;
+               char *sep;
+               int line_len;
+
+               line_len = getline(&line, &n, file);
+               if (line_len < 0)
+                       break;
+
+               if (!line)
+                       goto out_failure;
+
+               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';
+
+               snprintf(name, sizeof(name), "[%s]", line);
+               dso = dso__new(name, sym_priv_size);
+
+               if (dso == NULL)
+                       goto out_delete_line;
+
+               map = map__new2(start, dso);
+               if (map == NULL) {
+                       dso__delete(dso);
+                       goto out_delete_line;
                }
-               prev = pos;
+
+               dso->origin = DSO__ORIG_KMODULE;
+               kernel_maps__insert(map);
+               dsos__add(dso);
        }
+
+       free(line);
+       fclose(file);
+
+       return 0;
+
+out_delete_line:
+       free(line);
+out_failure:
+       return -1;
 }
 
-static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
+static int dso__load_vmlinux(struct dso *self, struct map *map,
+                            const char *vmlinux,
                             symbol_filter_t filter, int v)
 {
        int err, fd = open(vmlinux, O_RDONLY);
@@ -896,40 +1120,86 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
        if (fd < 0)
                return -1;
 
-       err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
-
-       if (err > 0)
-               dso__fill_symbol_holes(self);
+       err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v);
 
        close(fd);
 
        return err;
 }
 
-int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int v, int use_modules)
+int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
+                     symbol_filter_t filter, int v, int use_modules)
 {
        int err = -1;
+       struct dso *dso = dso__new(vmlinux, sym_priv_size);
+
+       if (dso == NULL)
+               return -1;
+
+       dso->short_name = "[kernel]";
+       kernel_map = map__new2(0, dso);
+       if (kernel_map == NULL)
+               goto out_delete_dso;
+
+       kernel_map->map_ip = vdso__map_ip;
+
+       if (use_modules && dsos__load_modules(sym_priv_size) < 0) {
+               fprintf(stderr, "Failed to load list of modules in use! "
+                               "Continuing...\n");
+               use_modules = 0;
+       }
 
        if (vmlinux) {
-               err = dso__load_vmlinux(self, vmlinux, filter, v);
-               if (err > 0 && use_modules)
-                       err = dso__load_modules(self, filter, v);
+               err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
+               if (err > 0 && use_modules) {
+                       int syms = dsos__load_modules_sym(filter, v);
+
+                       if (syms < 0)
+                               fprintf(stderr, "Failed to read module symbols!"
+                                       " Continuing...\n");
+                       else
+                               err += syms;
+               }
        }
 
        if (err <= 0)
-               err = dso__load_kallsyms(self, filter, v);
+               err = maps__load_kallsyms(filter, use_modules, v);
 
-       if (err > 0)
-               self->origin = DSO__ORIG_KERNEL;
+       if (err > 0) {
+               struct rb_node *node = rb_first(&dso->syms);
+               struct symbol *sym = rb_entry(node, struct symbol, rb_node);
+               /*
+                * Now that we have all sorted out, just set the ->end of all
+                * symbols that still don't have it.
+                */
+               dso__set_symbols_end(dso);
+               kernel_maps__fixup_sym_end();
+
+               kernel_map->start = sym->start;
+               node = rb_last(&dso->syms);
+               sym = rb_entry(node, struct symbol, rb_node);
+               kernel_map->end = sym->end;
+
+               dso->origin = DSO__ORIG_KERNEL;
+               /*
+                * XXX See kernel_maps__find_symbol comment
+                * kernel_maps__insert(kernel_map)
+                */
+               dsos__add(dso);
+
+               if (v > 0)
+                       kernel_maps__fprintf(stderr);
+       }
 
        return err;
+
+out_delete_dso:
+       dso__delete(dso);
+       return -1;
 }
 
 LIST_HEAD(dsos);
-struct dso     *kernel_dso;
 struct dso     *vdso;
-struct dso     *hypervisor_dso;
 
 const char     *vmlinux_name = "vmlinux";
 int            modules;
@@ -961,7 +1231,7 @@ struct dso *dsos__findnew(const char *name)
        if (!dso)
                goto out_delete_dso;
 
-       nr = dso__load(dso, NULL, verbose);
+       nr = dso__load(dso, NULL, NULL, verbose);
        if (nr < 0) {
                eprintf("Failed to open: %s\n", name);
                goto out_delete_dso;
@@ -986,43 +1256,20 @@ void dsos__fprintf(FILE *fp)
                dso__fprintf(pos, fp);
 }
 
-static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
-{
-       return dso__find_symbol(dso, ip);
-}
-
 int load_kernel(void)
 {
-       int err;
-
-       kernel_dso = dso__new("[kernel]", 0);
-       if (!kernel_dso)
+       if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
-       if (err <= 0) {
-               dso__delete(kernel_dso);
-               kernel_dso = NULL;
-       } else
-               dsos__add(kernel_dso);
-
        vdso = dso__new("[vdso]", 0);
        if (!vdso)
                return -1;
 
-       vdso->find_symbol = vdso__find_symbol;
-
        dsos__add(vdso);
 
-       hypervisor_dso = dso__new("[hypervisor]", 0);
-       if (!hypervisor_dso)
-               return -1;
-       dsos__add(hypervisor_dso);
-
-       return err;
+       return 0;
 }
 
-
 void symbol__init(void)
 {
        elf_version(EV_CURRENT);