perf tools: Rewrite and improve support for kernel modules

Representing modules as struct map entries, backed by a DSO, etc,
using /proc/modules to find where the module is loaded.

DSOs now can have a short and long name, so that in verbose mode we
can show exactly which .ko or vmlinux image was used.

As kernel modules now are a DSO separate from the kernel, we can
ask for just the hits for a particular set of kernel modules, just
like we can do with shared libraries:

[root@doppio linux-2.6-tip]# perf report -n --vmlinux
/home/acme/git/build/tip-recvmmsg/vmlinux --modules --dsos \[drm\] | head -15
    84.58%      13266             Xorg  [k] drm_clflush_pages
     4.02%        630             Xorg  [k] trace_kmalloc.clone.0
     3.95%        619             Xorg  [k] drm_ioctl
     2.07%        324             Xorg  [k] drm_addbufs
     1.68%        263             Xorg  [k] drm_gem_close_ioctl
     0.77%        120             Xorg  [k] drm_setmaster_ioctl
     0.70%        110             Xorg  [k] drm_lastclose
     0.68%        106             Xorg  [k] drm_open
     0.54%         85             Xorg  [k] drm_mm_search_free
[root@doppio linux-2.6-tip]#

Specifying --dsos /lib/modules/2.6.31-tip/kernel/drivers/gpu/drm/drm.ko
would have the same effect. Allowing specifying just 'drm.ko' is left
for another patch.

Processing kallsyms so that per kernel module struct map are
instantiated was also left for another patch. That will allow
removing the module name from each of its symbols.

struct symbol was reduced by removing the ->module backpointer and
moving it (well now the map) to struct symbol_entry in perf top,
that is its only user right now.

The total linecount went down by ~500 lines.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Avi Kivity <avi@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 559fb06..e882968 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -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,15 @@
 	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 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 +37,9 @@
 		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 +64,8 @@
 
 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 +74,8 @@
 
 	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 +102,8 @@
 void dso__delete(struct dso *self)
 {
 	dso__delete_symbols(self);
+	if (self->long_name != self->name)
+		free(self->long_name);
 	free(self);
 }
 
@@ -147,7 +151,7 @@
 
 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->long_name);
 
 	struct rb_node *nd;
 	for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
@@ -158,7 +162,8 @@
 	return ret;
 }
 
-static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
+static int dso__load_kallsyms(struct dso *self, struct map *map,
+			      symbol_filter_t filter, int v)
 {
 	struct rb_node *nd, *prevnd;
 	char *line = NULL;
@@ -200,12 +205,12 @@
 		 * 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);
+				  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);
@@ -241,14 +246,15 @@
 	return -1;
 }
 
-static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
+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 +285,12 @@
 			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);
@@ -410,7 +416,7 @@
 	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 +484,7 @@
 				 "%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 +502,7 @@
 				 "%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 +521,13 @@
 		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 +539,7 @@
 	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,8 +596,6 @@
 		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;
 
@@ -607,7 +612,6 @@
 			continue;
 
 		section_name = elf_sec__name(&shdr, secstrs);
-		obj_start = sym.st_value;
 
 		if (self->adjust_symbols) {
 			if (v >= 2)
@@ -615,18 +619,8 @@
 					(u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
 
 			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;
-			}
-		}
+		} else if (kmodule)
+			sym.st_value += shdr.sh_offset;
 		/*
 		 * 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
@@ -638,15 +632,14 @@
 			elf_name = demangled;
 
 		f = symbol__new(sym.st_value, sym.st_size, elf_name,
-				self->sym_priv_size, obj_start, v);
+				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 +664,7 @@
 	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 +673,7 @@
 	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 +702,7 @@
 		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 +720,7 @@
 		[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 +728,7 @@
 	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 +741,7 @@
 	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 +754,12 @@
 		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 +773,7 @@
 			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 +783,7 @@
 		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,89 +804,247 @@
 	return ret;
 }
 
-static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
-			     symbol_filter_t filter, int v)
+static struct rb_root kernel_maps;
+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)
+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);
+	}
+
+	if (mapp)
+		*mapp = map;
+
+	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;
+	}
 
-	fd = open(mod->path, O_RDONLY);
-
-	if (fd < 0)
-		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, count = 0;
+	struct dirent *dent;
+	int nr_symbols = 0, err;
+	DIR *dir = opendir(dirname);
 
-	err = mod_dso__load_modules(mods);
-
-	if (err <= 0)
-		return 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);
-
-		if (err < 0)
-			break;
-
-		next = rb_next(&pos->rb_node);
-		count += err;
+	if (!dir) {
+		if (v)
+			fprintf(stderr, "%s: cannot open %s dir\n", __func__,
+				dirname);
+		return -1;
 	}
 
-	if (err < 0) {
-		mod_dso__delete_modules(mods);
-		mod_dso__delete_self(mods);
-		return err;
-	}
+	while ((dent = readdir(dir)) != NULL) {
+		char path[PATH_MAX];
 
-	return count;
-}
+		if (dent->d_type == DT_DIR) {
+			if (!strcmp(dent->d_name, ".") ||
+			    !strcmp(dent->d_name, ".."))
+				continue;
 
-static inline void dso__fill_symbol_holes(struct dso *self)
-{
-	struct symbol *prev = NULL;
-	struct rb_node *nd;
+			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;
 
-	for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
-		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+			if (dot == NULL || strcmp(dot, ".ko"))
+				continue;
+			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
+				 (int)(dot - dent->d_name), dent->d_name);
 
-		if (prev) {
-			u64 hole = 0;
-			int alias = pos->start == prev->start;
+			map = kernel_maps__find_by_dso_name(dso_name);
+			if (map == NULL)
+				continue;
 
-			if (!alias)
-				hole = prev->start - pos->end - 1;
+			snprintf(path, sizeof(path), "%s/%s",
+				 dirname, dent->d_name);
 
-			if (hole || alias) {
-				if (alias)
-					pos->end = prev->end;
-				else if (hole)
-					pos->end = prev->start - 1;
+			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;
 			}
 		}
-		prev = pos;
+		nr_symbols += err;
 	}
+
+	return nr_symbols;
+failure:
+	closedir(dir);
+	return -1;
 }
 
-static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
+static int dsos__load_modules_sym(symbol_filter_t filter, int v)
+{
+	struct utsname uts;
+	char modules_path[PATH_MAX];
+
+	if (uname(&uts) < 0)
+		return -1;
+
+	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
+		 uts.release);
+
+	return dsos__load_modules_sym_dir(modules_path, filter, v);
+}
+
+/*
+ * 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 map *self = malloc(sizeof(*self));
+
+	if (self != NULL) {
+		self->start = start;
+		/*
+		 * Will be filled after we load all the symbols
+		 */
+		self->end = 0;
+
+		self->pgoff = 0;
+		self->dso = dso;
+		self->map_ip = map__map_ip;
+		RB_CLEAR_NODE(&self->rb_node);
+	}
+	return self;
+}
+
+int dsos__load_modules(unsigned int sym_priv_size,
+		       symbol_filter_t filter, int v)
+{
+	char *line = NULL;
+	size_t n;
+	FILE *file = fopen("/proc/modules", "r");
+	struct map *map;
+
+	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;
+		}
+
+		dso->origin = DSO__ORIG_KMODULE;
+		kernel_maps__insert(map);
+		dsos__add(dso);
+	}
+
+	free(line);
+	fclose(file);
+
+	v = 1;
+	return dsos__load_modules_sym(filter, v);
+
+out_delete_line:
+	free(line);
+out_failure:
+	return -1;
+}
+
+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);
@@ -898,28 +1052,36 @@
 	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 (vmlinux) {
-		err = dso__load_vmlinux(self, vmlinux, filter, v);
+		err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
 		if (err > 0 && use_modules) {
-			int syms = dso__load_modules(self, filter, v);
+			int syms = dsos__load_modules(sym_priv_size, filter, v);
 
 			if (syms < 0) {
-				fprintf(stderr, "dso__load_modules failed!\n");
+				fprintf(stderr, "dsos__load_modules failed!\n");
 				return syms;
 			}
 			err += syms;
@@ -927,18 +1089,34 @@
 	}
 
 	if (err <= 0)
-		err = dso__load_kallsyms(self, filter, v);
+		err = dso__load_kallsyms(dso, kernel_map, filter, 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);
+
+		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);
+	}
 
 	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;
@@ -970,7 +1148,7 @@
 	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;
@@ -995,43 +1173,20 @@
 		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);