xref: /linux/tools/perf/util/symbol.c (revision b2f8fb237e9cc407a02aca401369c15babae35dd)
15aab621bSArnaldo Carvalho de Melo #define _GNU_SOURCE
25aab621bSArnaldo Carvalho de Melo #include <ctype.h>
35aab621bSArnaldo Carvalho de Melo #include <dirent.h>
45aab621bSArnaldo Carvalho de Melo #include <errno.h>
55aab621bSArnaldo Carvalho de Melo #include <libgen.h>
65aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
75aab621bSArnaldo Carvalho de Melo #include <stdio.h>
85aab621bSArnaldo Carvalho de Melo #include <string.h>
95aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
105aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
115aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
125aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
135aab621bSArnaldo Carvalho de Melo #include <unistd.h>
14b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
158a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1686470930SIngo Molnar #include "symbol.h"
175aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1886470930SIngo Molnar 
1986470930SIngo Molnar #include <libelf.h>
2086470930SIngo Molnar #include <gelf.h>
2186470930SIngo Molnar #include <elf.h>
22f1617b40SArnaldo Carvalho de Melo #include <limits.h>
23439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
242cdbc46dSPeter Zijlstra 
253b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN
263b01a413SArnaldo Carvalho de Melo #define KSYM_NAME_LEN 128
273b01a413SArnaldo Carvalho de Melo #endif
283b01a413SArnaldo Carvalho de Melo 
29c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
30c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
31c12e15e7SArnaldo Carvalho de Melo #endif
32c12e15e7SArnaldo Carvalho de Melo 
3321916c38SDave Martin static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
3421916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size);
35b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
363610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
37c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
389de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
39a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
40a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
41cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
42cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
43439d473bSArnaldo Carvalho de Melo 
4475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
45d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
46b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
47b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
48ec5761eaSDavid Ahern 	.symfs            = "",
49b32d133aSArnaldo Carvalho de Melo };
50b32d133aSArnaldo Carvalho de Melo 
518a6c5b26SArnaldo Carvalho de Melo int dso__name_len(const struct dso *self)
528a6c5b26SArnaldo Carvalho de Melo {
538a6c5b26SArnaldo Carvalho de Melo 	if (verbose)
548a6c5b26SArnaldo Carvalho de Melo 		return self->long_name_len;
558a6c5b26SArnaldo Carvalho de Melo 
568a6c5b26SArnaldo Carvalho de Melo 	return self->short_name_len;
578a6c5b26SArnaldo Carvalho de Melo }
588a6c5b26SArnaldo Carvalho de Melo 
593610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
603610583cSArnaldo Carvalho de Melo {
613610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
623610583cSArnaldo Carvalho de Melo }
633610583cSArnaldo Carvalho de Melo 
6479406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type)
6579406cd7SArnaldo Carvalho de Melo {
6679406cd7SArnaldo Carvalho de Melo 	return self->sorted_by_name & (1 << type);
6779406cd7SArnaldo Carvalho de Melo }
6879406cd7SArnaldo Carvalho de Melo 
6979406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
7079406cd7SArnaldo Carvalho de Melo {
7179406cd7SArnaldo Carvalho de Melo 	self->sorted_by_name |= (1 << type);
7279406cd7SArnaldo Carvalho de Melo }
7379406cd7SArnaldo Carvalho de Melo 
7436a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
756893d4eeSArnaldo Carvalho de Melo {
766893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
776893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
786893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
79f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
80f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
816893d4eeSArnaldo Carvalho de Melo 	default:
826893d4eeSArnaldo Carvalho de Melo 		return false;
836893d4eeSArnaldo Carvalho de Melo 	}
846893d4eeSArnaldo Carvalho de Melo }
856893d4eeSArnaldo Carvalho de Melo 
86fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
87af427bf5SArnaldo Carvalho de Melo {
88fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
892e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
90af427bf5SArnaldo Carvalho de Melo 
91af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
92af427bf5SArnaldo Carvalho de Melo 		return;
93af427bf5SArnaldo Carvalho de Melo 
942e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
952e538c4aSArnaldo Carvalho de Melo 
96af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
972e538c4aSArnaldo Carvalho de Melo 		prev = curr;
982e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
99af427bf5SArnaldo Carvalho de Melo 
1003b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
101af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
102af427bf5SArnaldo Carvalho de Melo 	}
103af427bf5SArnaldo Carvalho de Melo 
1042e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
1052e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
1062e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
1072e538c4aSArnaldo Carvalho de Melo }
1082e538c4aSArnaldo Carvalho de Melo 
1099958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
110af427bf5SArnaldo Carvalho de Melo {
111af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
11295011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
113af427bf5SArnaldo Carvalho de Melo 
114af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
115af427bf5SArnaldo Carvalho de Melo 		return;
116af427bf5SArnaldo Carvalho de Melo 
117af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
118af427bf5SArnaldo Carvalho de Melo 
119af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
120af427bf5SArnaldo Carvalho de Melo 		prev = curr;
121af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
122af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1232e538c4aSArnaldo Carvalho de Melo 	}
12490c83218SArnaldo Carvalho de Melo 
12590c83218SArnaldo Carvalho de Melo 	/*
12690c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
12790c83218SArnaldo Carvalho de Melo 	 * last map final address.
12890c83218SArnaldo Carvalho de Melo 	 */
1299d1faba5SIan Munsie 	curr->end = ~0ULL;
130af427bf5SArnaldo Carvalho de Melo }
131af427bf5SArnaldo Carvalho de Melo 
1329958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
13323ea4a3fSArnaldo Carvalho de Melo {
13423ea4a3fSArnaldo Carvalho de Melo 	int i;
13523ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1369958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
13723ea4a3fSArnaldo Carvalho de Melo }
13823ea4a3fSArnaldo Carvalho de Melo 
139c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
140c408fedfSArnaldo Carvalho de Melo 				  const char *name)
14186470930SIngo Molnar {
14286470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
1435aab621bSArnaldo Carvalho de Melo 	struct symbol *self = calloc(1, (symbol_conf.priv_size +
1445aab621bSArnaldo Carvalho de Melo 					 sizeof(*self) + namelen));
14536479484SArnaldo Carvalho de Melo 	if (self == NULL)
14686470930SIngo Molnar 		return NULL;
14786470930SIngo Molnar 
14875be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
14975be6cf4SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol_conf.priv_size;
15036479484SArnaldo Carvalho de Melo 
15186470930SIngo Molnar 	self->start   = start;
1526cfcc53eSMike Galbraith 	self->end     = len ? start + len - 1 : start;
153c408fedfSArnaldo Carvalho de Melo 	self->binding = binding;
154fefb0b94SArnaldo Carvalho de Melo 	self->namelen = namelen - 1;
155e4204992SArnaldo Carvalho de Melo 
15629a9f66dSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
157e4204992SArnaldo Carvalho de Melo 
15886470930SIngo Molnar 	memcpy(self->name, name, namelen);
15986470930SIngo Molnar 
16086470930SIngo Molnar 	return self;
16186470930SIngo Molnar }
16286470930SIngo Molnar 
163628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self)
16486470930SIngo Molnar {
16575be6cf4SArnaldo Carvalho de Melo 	free(((void *)self) - symbol_conf.priv_size);
16686470930SIngo Molnar }
16786470930SIngo Molnar 
16886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
16986470930SIngo Molnar {
170c408fedfSArnaldo Carvalho de Melo 	return fprintf(fp, " %llx-%llx %c %s\n",
171c408fedfSArnaldo Carvalho de Melo 		       self->start, self->end,
172c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_GLOBAL ? 'g' :
173c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_LOCAL  ? 'l' : 'w',
174c408fedfSArnaldo Carvalho de Melo 		       self->name);
17586470930SIngo Molnar }
17686470930SIngo Molnar 
177b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name)
178cfc10d3bSArnaldo Carvalho de Melo {
179ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
180ef6ae724SArnaldo Carvalho de Melo 		return;
181cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
182cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
183cfc10d3bSArnaldo Carvalho de Melo }
184cfc10d3bSArnaldo Carvalho de Melo 
185b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name)
186b63be8d7SArnaldo Carvalho de Melo {
187b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
188b63be8d7SArnaldo Carvalho de Melo 		return;
189b63be8d7SArnaldo Carvalho de Melo 	self->short_name = name;
190b63be8d7SArnaldo Carvalho de Melo 	self->short_name_len = strlen(name);
191b63be8d7SArnaldo Carvalho de Melo }
192b63be8d7SArnaldo Carvalho de Melo 
193cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
194cfc10d3bSArnaldo Carvalho de Melo {
195b63be8d7SArnaldo Carvalho de Melo 	dso__set_short_name(self, basename(self->long_name));
196cfc10d3bSArnaldo Carvalho de Melo }
197cfc10d3bSArnaldo Carvalho de Melo 
19800a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
19986470930SIngo Molnar {
2005aab621bSArnaldo Carvalho de Melo 	struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
20186470930SIngo Molnar 
20286470930SIngo Molnar 	if (self != NULL) {
2036a4694a4SArnaldo Carvalho de Melo 		int i;
20486470930SIngo Molnar 		strcpy(self->name, name);
205cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
206b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, self->name);
2076a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
20879406cd7SArnaldo Carvalho de Melo 			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
20952d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
21094cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
2118d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
21279406cd7SArnaldo Carvalho de Melo 		self->sorted_by_name = 0;
2138d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
214a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_USER;
2150ab061cdSMasami Hiramatsu 		INIT_LIST_HEAD(&self->node);
21686470930SIngo Molnar 	}
21786470930SIngo Molnar 
21886470930SIngo Molnar 	return self;
21986470930SIngo Molnar }
22086470930SIngo Molnar 
221fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
22286470930SIngo Molnar {
22386470930SIngo Molnar 	struct symbol *pos;
224fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
22586470930SIngo Molnar 
22686470930SIngo Molnar 	while (next) {
22786470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
22886470930SIngo Molnar 		next = rb_next(&pos->rb_node);
229fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
23000a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
23186470930SIngo Molnar 	}
23286470930SIngo Molnar }
23386470930SIngo Molnar 
23486470930SIngo Molnar void dso__delete(struct dso *self)
23586470930SIngo Molnar {
2366a4694a4SArnaldo Carvalho de Melo 	int i;
2376a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2386a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
2396e406257SArnaldo Carvalho de Melo 	if (self->sname_alloc)
2406e406257SArnaldo Carvalho de Melo 		free((char *)self->short_name);
2416e406257SArnaldo Carvalho de Melo 	if (self->lname_alloc)
242439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
24386470930SIngo Molnar 	free(self);
24486470930SIngo Molnar }
24586470930SIngo Molnar 
2468d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2478d06367fSArnaldo Carvalho de Melo {
2488d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2498d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2508d06367fSArnaldo Carvalho de Melo }
2518d06367fSArnaldo Carvalho de Melo 
252fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
25386470930SIngo Molnar {
254fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
25586470930SIngo Molnar 	struct rb_node *parent = NULL;
2569cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
25786470930SIngo Molnar 	struct symbol *s;
25886470930SIngo Molnar 
25986470930SIngo Molnar 	while (*p != NULL) {
26086470930SIngo Molnar 		parent = *p;
26186470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
26286470930SIngo Molnar 		if (ip < s->start)
26386470930SIngo Molnar 			p = &(*p)->rb_left;
26486470930SIngo Molnar 		else
26586470930SIngo Molnar 			p = &(*p)->rb_right;
26686470930SIngo Molnar 	}
26786470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
268fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
26986470930SIngo Molnar }
27086470930SIngo Molnar 
271fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
27286470930SIngo Molnar {
27386470930SIngo Molnar 	struct rb_node *n;
27486470930SIngo Molnar 
27586470930SIngo Molnar 	if (self == NULL)
27686470930SIngo Molnar 		return NULL;
27786470930SIngo Molnar 
278fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
27986470930SIngo Molnar 
28086470930SIngo Molnar 	while (n) {
28186470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
28286470930SIngo Molnar 
28386470930SIngo Molnar 		if (ip < s->start)
28486470930SIngo Molnar 			n = n->rb_left;
28586470930SIngo Molnar 		else if (ip > s->end)
28686470930SIngo Molnar 			n = n->rb_right;
28786470930SIngo Molnar 		else
28886470930SIngo Molnar 			return s;
28986470930SIngo Molnar 	}
29086470930SIngo Molnar 
29186470930SIngo Molnar 	return NULL;
29286470930SIngo Molnar }
29386470930SIngo Molnar 
29479406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
29579406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
29679406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
29779406cd7SArnaldo Carvalho de Melo };
29879406cd7SArnaldo Carvalho de Melo 
29979406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
30079406cd7SArnaldo Carvalho de Melo {
30179406cd7SArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
30279406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
30302a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
30402a9d037SRabin Vincent 
30502a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
30679406cd7SArnaldo Carvalho de Melo 
30779406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
30879406cd7SArnaldo Carvalho de Melo 		parent = *p;
30979406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
31079406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
31179406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
31279406cd7SArnaldo Carvalho de Melo 		else
31379406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
31479406cd7SArnaldo Carvalho de Melo 	}
31579406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
31679406cd7SArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, self);
31779406cd7SArnaldo Carvalho de Melo }
31879406cd7SArnaldo Carvalho de Melo 
31979406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
32079406cd7SArnaldo Carvalho de Melo {
32179406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
32279406cd7SArnaldo Carvalho de Melo 
32379406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
32479406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
32579406cd7SArnaldo Carvalho de Melo 		symbols__insert_by_name(self, pos);
32679406cd7SArnaldo Carvalho de Melo 	}
32779406cd7SArnaldo Carvalho de Melo }
32879406cd7SArnaldo Carvalho de Melo 
32979406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
33079406cd7SArnaldo Carvalho de Melo {
33179406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
33279406cd7SArnaldo Carvalho de Melo 
33379406cd7SArnaldo Carvalho de Melo 	if (self == NULL)
33479406cd7SArnaldo Carvalho de Melo 		return NULL;
33579406cd7SArnaldo Carvalho de Melo 
33679406cd7SArnaldo Carvalho de Melo 	n = self->rb_node;
33779406cd7SArnaldo Carvalho de Melo 
33879406cd7SArnaldo Carvalho de Melo 	while (n) {
33979406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
34079406cd7SArnaldo Carvalho de Melo 		int cmp;
34179406cd7SArnaldo Carvalho de Melo 
34279406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
34379406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
34479406cd7SArnaldo Carvalho de Melo 
34579406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
34679406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
34779406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
34879406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
34979406cd7SArnaldo Carvalho de Melo 		else
35079406cd7SArnaldo Carvalho de Melo 			return &s->sym;
35179406cd7SArnaldo Carvalho de Melo 	}
35279406cd7SArnaldo Carvalho de Melo 
35379406cd7SArnaldo Carvalho de Melo 	return NULL;
35479406cd7SArnaldo Carvalho de Melo }
35579406cd7SArnaldo Carvalho de Melo 
35679406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self,
35779406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
358fcf1203aSArnaldo Carvalho de Melo {
3596a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
360fcf1203aSArnaldo Carvalho de Melo }
361fcf1203aSArnaldo Carvalho de Melo 
36279406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
36379406cd7SArnaldo Carvalho de Melo 					const char *name)
36479406cd7SArnaldo Carvalho de Melo {
36579406cd7SArnaldo Carvalho de Melo 	return symbols__find_by_name(&self->symbol_names[type], name);
36679406cd7SArnaldo Carvalho de Melo }
36779406cd7SArnaldo Carvalho de Melo 
36879406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type)
36979406cd7SArnaldo Carvalho de Melo {
37079406cd7SArnaldo Carvalho de Melo 	dso__set_sorted_by_name(self, type);
37179406cd7SArnaldo Carvalho de Melo 	return symbols__sort_by_name(&self->symbol_names[type],
37279406cd7SArnaldo Carvalho de Melo 				     &self->symbols[type]);
37379406cd7SArnaldo Carvalho de Melo }
37479406cd7SArnaldo Carvalho de Melo 
375ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf)
3768d06367fSArnaldo Carvalho de Melo {
3778d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
378ef12a141SArnaldo Carvalho de Melo 	const u8 *raw = self;
3798d06367fSArnaldo Carvalho de Melo 	int i;
3808d06367fSArnaldo Carvalho de Melo 
3818d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
3828d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
3838d06367fSArnaldo Carvalho de Melo 		++raw;
3848d06367fSArnaldo Carvalho de Melo 		bid += 2;
3858d06367fSArnaldo Carvalho de Melo 	}
3868d06367fSArnaldo Carvalho de Melo 
3878d06367fSArnaldo Carvalho de Melo 	return raw - self;
3888d06367fSArnaldo Carvalho de Melo }
3898d06367fSArnaldo Carvalho de Melo 
3909e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
39186470930SIngo Molnar {
3928d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
3938d06367fSArnaldo Carvalho de Melo 
3948d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
3959e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
3969e03eb2dSArnaldo Carvalho de Melo }
3979e03eb2dSArnaldo Carvalho de Melo 
39890f18e63SSrikar Dronamraju size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp)
39990f18e63SSrikar Dronamraju {
40090f18e63SSrikar Dronamraju 	size_t ret = 0;
40190f18e63SSrikar Dronamraju 	struct rb_node *nd;
40290f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
40390f18e63SSrikar Dronamraju 
40490f18e63SSrikar Dronamraju 	for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) {
40590f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
40690f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
40790f18e63SSrikar Dronamraju 	}
40890f18e63SSrikar Dronamraju 
40990f18e63SSrikar Dronamraju 	return ret;
41090f18e63SSrikar Dronamraju }
41190f18e63SSrikar Dronamraju 
41295011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
4139e03eb2dSArnaldo Carvalho de Melo {
4149e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
4159e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
4169e03eb2dSArnaldo Carvalho de Melo 
4173846df2eSArnaldo Carvalho de Melo 	if (self->short_name != self->long_name)
4183846df2eSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", self->long_name);
4193846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
4203846df2eSArnaldo Carvalho de Melo 		       self->loaded ? "" : "NOT ");
4219e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
4226a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
42395011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
42486470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
42586470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
42686470930SIngo Molnar 	}
42786470930SIngo Molnar 
42886470930SIngo Molnar 	return ret;
42986470930SIngo Molnar }
43086470930SIngo Molnar 
4319e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
4329e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
4333b01a413SArnaldo Carvalho de Melo 					  char type, u64 start, u64 end))
43486470930SIngo Molnar {
43586470930SIngo Molnar 	char *line = NULL;
43686470930SIngo Molnar 	size_t n;
4373b01a413SArnaldo Carvalho de Melo 	int err = -1;
4383b01a413SArnaldo Carvalho de Melo 	u64 prev_start = 0;
4393b01a413SArnaldo Carvalho de Melo 	char prev_symbol_type = 0;
4403b01a413SArnaldo Carvalho de Melo 	char *prev_symbol_name;
4419e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
44286470930SIngo Molnar 
44386470930SIngo Molnar 	if (file == NULL)
44486470930SIngo Molnar 		goto out_failure;
44586470930SIngo Molnar 
4463b01a413SArnaldo Carvalho de Melo 	prev_symbol_name = malloc(KSYM_NAME_LEN);
4473b01a413SArnaldo Carvalho de Melo 	if (prev_symbol_name == NULL)
4483b01a413SArnaldo Carvalho de Melo 		goto out_close;
4493b01a413SArnaldo Carvalho de Melo 
4503b01a413SArnaldo Carvalho de Melo 	err = 0;
4513b01a413SArnaldo Carvalho de Melo 
45286470930SIngo Molnar 	while (!feof(file)) {
4539cffa8d5SPaul Mackerras 		u64 start;
45486470930SIngo Molnar 		int line_len, len;
45586470930SIngo Molnar 		char symbol_type;
4562e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
45786470930SIngo Molnar 
45886470930SIngo Molnar 		line_len = getline(&line, &n, file);
459a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
46086470930SIngo Molnar 			break;
46186470930SIngo Molnar 
46286470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
46386470930SIngo Molnar 
46486470930SIngo Molnar 		len = hex2u64(line, &start);
46586470930SIngo Molnar 
46686470930SIngo Molnar 		len++;
46786470930SIngo Molnar 		if (len + 2 >= line_len)
46886470930SIngo Molnar 			continue;
46986470930SIngo Molnar 
47086470930SIngo Molnar 		symbol_type = toupper(line[len]);
4713b01a413SArnaldo Carvalho de Melo 		len += 2;
4723b01a413SArnaldo Carvalho de Melo 		symbol_name = line + len;
4733b01a413SArnaldo Carvalho de Melo 		len = line_len - len;
474682b335aSArnaldo Carvalho de Melo 
4753b01a413SArnaldo Carvalho de Melo 		if (len >= KSYM_NAME_LEN) {
4763b01a413SArnaldo Carvalho de Melo 			err = -1;
4773b01a413SArnaldo Carvalho de Melo 			break;
4783b01a413SArnaldo Carvalho de Melo 		}
4793b01a413SArnaldo Carvalho de Melo 
4803b01a413SArnaldo Carvalho de Melo 		if (prev_symbol_type) {
4813b01a413SArnaldo Carvalho de Melo 			u64 end = start;
4823b01a413SArnaldo Carvalho de Melo 			if (end != prev_start)
4833b01a413SArnaldo Carvalho de Melo 				--end;
4843b01a413SArnaldo Carvalho de Melo 			err = process_symbol(arg, prev_symbol_name,
4853b01a413SArnaldo Carvalho de Melo 					     prev_symbol_type, prev_start, end);
486682b335aSArnaldo Carvalho de Melo 			if (err)
487682b335aSArnaldo Carvalho de Melo 				break;
488682b335aSArnaldo Carvalho de Melo 		}
489682b335aSArnaldo Carvalho de Melo 
4903b01a413SArnaldo Carvalho de Melo 		memcpy(prev_symbol_name, symbol_name, len + 1);
4913b01a413SArnaldo Carvalho de Melo 		prev_symbol_type = symbol_type;
4923b01a413SArnaldo Carvalho de Melo 		prev_start = start;
4933b01a413SArnaldo Carvalho de Melo 	}
4943b01a413SArnaldo Carvalho de Melo 
4953b01a413SArnaldo Carvalho de Melo 	free(prev_symbol_name);
496682b335aSArnaldo Carvalho de Melo 	free(line);
4973b01a413SArnaldo Carvalho de Melo out_close:
498682b335aSArnaldo Carvalho de Melo 	fclose(file);
499682b335aSArnaldo Carvalho de Melo 	return err;
500682b335aSArnaldo Carvalho de Melo 
501682b335aSArnaldo Carvalho de Melo out_failure:
502682b335aSArnaldo Carvalho de Melo 	return -1;
503682b335aSArnaldo Carvalho de Melo }
504682b335aSArnaldo Carvalho de Melo 
505682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
506682b335aSArnaldo Carvalho de Melo 	struct map *map;
507682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
508682b335aSArnaldo Carvalho de Melo };
509682b335aSArnaldo Carvalho de Melo 
510c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
511c408fedfSArnaldo Carvalho de Melo {
512c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
513c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
514c408fedfSArnaldo Carvalho de Melo 
515c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
516c408fedfSArnaldo Carvalho de Melo }
517c408fedfSArnaldo Carvalho de Melo 
518682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
5193b01a413SArnaldo Carvalho de Melo 				       char type, u64 start, u64 end)
520682b335aSArnaldo Carvalho de Melo {
521682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
522682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
523682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
524682b335aSArnaldo Carvalho de Melo 
525682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
526682b335aSArnaldo Carvalho de Melo 		return 0;
527682b335aSArnaldo Carvalho de Melo 
5283b01a413SArnaldo Carvalho de Melo 	sym = symbol__new(start, end - start + 1,
5293b01a413SArnaldo Carvalho de Melo 			  kallsyms2elf_type(type), name);
5302e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
531682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
53282164161SArnaldo Carvalho de Melo 	/*
53382164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
5344e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
53582164161SArnaldo Carvalho de Melo 	 */
5364e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
537a1645ce1SZhang, Yanmin 
538682b335aSArnaldo Carvalho de Melo 	return 0;
5392e538c4aSArnaldo Carvalho de Melo }
5402e538c4aSArnaldo Carvalho de Melo 
541682b335aSArnaldo Carvalho de Melo /*
542682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
543682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
544682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
545682b335aSArnaldo Carvalho de Melo  */
5469e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename,
5479e201442SArnaldo Carvalho de Melo 				  struct map *map)
548682b335aSArnaldo Carvalho de Melo {
549682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = self, };
5509e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
5512e538c4aSArnaldo Carvalho de Melo }
5522e538c4aSArnaldo Carvalho de Melo 
5532e538c4aSArnaldo Carvalho de Melo /*
5542e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
5552e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
5562e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
5572e538c4aSArnaldo Carvalho de Melo  */
5589958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
5599de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
5602e538c4aSArnaldo Carvalho de Melo {
5619de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
56223346f21SArnaldo Carvalho de Melo 	struct machine *machine = kmaps->machine;
5634e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
5642e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
5658a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
5664e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
5674e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
5682e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
5692e538c4aSArnaldo Carvalho de Melo 
5702e538c4aSArnaldo Carvalho de Melo 	while (next) {
5712e538c4aSArnaldo Carvalho de Melo 		char *module;
5722e538c4aSArnaldo Carvalho de Melo 
5732e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
5742e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
5752e538c4aSArnaldo Carvalho de Melo 
5762e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
5772e538c4aSArnaldo Carvalho de Melo 		if (module) {
57875be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
5791de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
5801de8e245SArnaldo Carvalho de Melo 
5812e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
5822e538c4aSArnaldo Carvalho de Melo 
583b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
584a1645ce1SZhang, Yanmin 				if (curr_map != map &&
585a1645ce1SZhang, Yanmin 				    self->kernel == DSO_TYPE_GUEST_KERNEL &&
58623346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
587a1645ce1SZhang, Yanmin 					/*
588a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
589a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
590a1645ce1SZhang, Yanmin 					 * points to a module and all its
591a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
592a1645ce1SZhang, Yanmin 					 * loaded.
593a1645ce1SZhang, Yanmin 					 */
594a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
595a1645ce1SZhang, Yanmin 							curr_map->type);
596af427bf5SArnaldo Carvalho de Melo 				}
597b7cece76SArnaldo Carvalho de Melo 
598a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
599a1645ce1SZhang, Yanmin 							map->type, module);
600a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
6012f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
602a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
603a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
60423346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
605a1645ce1SZhang, Yanmin 					curr_map = map;
606a1645ce1SZhang, Yanmin 					goto discard_symbol;
607a1645ce1SZhang, Yanmin 				}
608a1645ce1SZhang, Yanmin 
609a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
61023346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
611b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
612af427bf5SArnaldo Carvalho de Melo 			}
61386470930SIngo Molnar 			/*
6142e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
6152e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
61686470930SIngo Molnar 			 */
6174e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
6184e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
6194e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
6202e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
6212e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
62286470930SIngo Molnar 
6238a953312SArnaldo Carvalho de Melo 			if (count == 0) {
6248a953312SArnaldo Carvalho de Melo 				curr_map = map;
6258a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
6268a953312SArnaldo Carvalho de Melo 			}
6278a953312SArnaldo Carvalho de Melo 
628a1645ce1SZhang, Yanmin 			if (self->kernel == DSO_TYPE_GUEST_KERNEL)
629a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
630a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
631a1645ce1SZhang, Yanmin 					kernel_range++);
632a1645ce1SZhang, Yanmin 			else
633a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
634a1645ce1SZhang, Yanmin 					"[kernel].%d",
6352e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
63686470930SIngo Molnar 
63700a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
6382e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
6392e538c4aSArnaldo Carvalho de Melo 				return -1;
6402e538c4aSArnaldo Carvalho de Melo 
641a1645ce1SZhang, Yanmin 			dso->kernel = self->kernel;
642a1645ce1SZhang, Yanmin 
6434e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
64437fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
6452e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
6462e538c4aSArnaldo Carvalho de Melo 				return -1;
6472e538c4aSArnaldo Carvalho de Melo 			}
6482e538c4aSArnaldo Carvalho de Melo 
6494e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
6509de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
6512e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
6522e538c4aSArnaldo Carvalho de Melo 		}
6538a953312SArnaldo Carvalho de Melo filter_symbol:
6544e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
6551de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
65600a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
6572e538c4aSArnaldo Carvalho de Melo 		} else {
6584e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
6594e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
6604e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
6618a953312SArnaldo Carvalho de Melo 				++moved;
6628a953312SArnaldo Carvalho de Melo 			} else
6638a953312SArnaldo Carvalho de Melo 				++count;
6649974f496SMike Galbraith 		}
66586470930SIngo Molnar 	}
66686470930SIngo Molnar 
667a1645ce1SZhang, Yanmin 	if (curr_map != map &&
668a1645ce1SZhang, Yanmin 	    self->kernel == DSO_TYPE_GUEST_KERNEL &&
66923346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
670a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
671a1645ce1SZhang, Yanmin 	}
672a1645ce1SZhang, Yanmin 
6738a953312SArnaldo Carvalho de Melo 	return count + moved;
67486470930SIngo Molnar }
67586470930SIngo Molnar 
6769de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename,
6779de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
6782e538c4aSArnaldo Carvalho de Melo {
6799e201442SArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, filename, map) < 0)
6802e538c4aSArnaldo Carvalho de Melo 		return -1;
6812e538c4aSArnaldo Carvalho de Melo 
682a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_GUEST_KERNEL)
683a1645ce1SZhang, Yanmin 		self->origin = DSO__ORIG_GUEST_KERNEL;
684a1645ce1SZhang, Yanmin 	else
6854e06255fSArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_KERNEL;
6862e538c4aSArnaldo Carvalho de Melo 
6879de89fe7SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, filter);
688af427bf5SArnaldo Carvalho de Melo }
689af427bf5SArnaldo Carvalho de Melo 
690439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
6916beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
69280d496beSPekka Enberg {
69380d496beSPekka Enberg 	char *line = NULL;
69480d496beSPekka Enberg 	size_t n;
69580d496beSPekka Enberg 	FILE *file;
69680d496beSPekka Enberg 	int nr_syms = 0;
69780d496beSPekka Enberg 
698439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
69980d496beSPekka Enberg 	if (file == NULL)
70080d496beSPekka Enberg 		goto out_failure;
70180d496beSPekka Enberg 
70280d496beSPekka Enberg 	while (!feof(file)) {
7039cffa8d5SPaul Mackerras 		u64 start, size;
70480d496beSPekka Enberg 		struct symbol *sym;
70580d496beSPekka Enberg 		int line_len, len;
70680d496beSPekka Enberg 
70780d496beSPekka Enberg 		line_len = getline(&line, &n, file);
70880d496beSPekka Enberg 		if (line_len < 0)
70980d496beSPekka Enberg 			break;
71080d496beSPekka Enberg 
71180d496beSPekka Enberg 		if (!line)
71280d496beSPekka Enberg 			goto out_failure;
71380d496beSPekka Enberg 
71480d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
71580d496beSPekka Enberg 
71680d496beSPekka Enberg 		len = hex2u64(line, &start);
71780d496beSPekka Enberg 
71880d496beSPekka Enberg 		len++;
71980d496beSPekka Enberg 		if (len + 2 >= line_len)
72080d496beSPekka Enberg 			continue;
72180d496beSPekka Enberg 
72280d496beSPekka Enberg 		len += hex2u64(line + len, &size);
72380d496beSPekka Enberg 
72480d496beSPekka Enberg 		len++;
72580d496beSPekka Enberg 		if (len + 2 >= line_len)
72680d496beSPekka Enberg 			continue;
72780d496beSPekka Enberg 
728c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
72980d496beSPekka Enberg 
73080d496beSPekka Enberg 		if (sym == NULL)
73180d496beSPekka Enberg 			goto out_delete_line;
73280d496beSPekka Enberg 
733439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
73400a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
73580d496beSPekka Enberg 		else {
7366a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
73780d496beSPekka Enberg 			nr_syms++;
73880d496beSPekka Enberg 		}
73980d496beSPekka Enberg 	}
74080d496beSPekka Enberg 
74180d496beSPekka Enberg 	free(line);
74280d496beSPekka Enberg 	fclose(file);
74380d496beSPekka Enberg 
74480d496beSPekka Enberg 	return nr_syms;
74580d496beSPekka Enberg 
74680d496beSPekka Enberg out_delete_line:
74780d496beSPekka Enberg 	free(line);
74880d496beSPekka Enberg out_failure:
74980d496beSPekka Enberg 	return -1;
75080d496beSPekka Enberg }
75180d496beSPekka Enberg 
75286470930SIngo Molnar /**
75386470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
75486470930SIngo Molnar  *
75586470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
75683a0944fSIngo Molnar  * @idx: uint32_t idx
75786470930SIngo Molnar  * @sym: GElf_Sym iterator
75886470930SIngo Molnar  */
75983a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
76083a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
76183a0944fSIngo Molnar 	     idx < nr_syms; \
76283a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
76386470930SIngo Molnar 
76486470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
76586470930SIngo Molnar {
76686470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
76786470930SIngo Molnar }
76886470930SIngo Molnar 
76986470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
77086470930SIngo Molnar {
77186470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
77286470930SIngo Molnar 	       sym->st_name != 0 &&
77381833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
77486470930SIngo Molnar }
77586470930SIngo Molnar 
776f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
777f1dfa0b1SArnaldo Carvalho de Melo {
778f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
779f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
780f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
781f1dfa0b1SArnaldo Carvalho de Melo }
782f1dfa0b1SArnaldo Carvalho de Melo 
7836cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
7846cfcc53eSMike Galbraith {
7856cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
7866cfcc53eSMike Galbraith 		sym->st_name != 0 &&
7876cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
7886cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
7896cfcc53eSMike Galbraith }
7906cfcc53eSMike Galbraith 
7916cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
7926cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7936cfcc53eSMike Galbraith {
7946cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
7956cfcc53eSMike Galbraith }
7966cfcc53eSMike Galbraith 
7976cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
7986cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7996cfcc53eSMike Galbraith {
8006cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
8016cfcc53eSMike Galbraith }
8026cfcc53eSMike Galbraith 
803f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
804f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
805f1dfa0b1SArnaldo Carvalho de Melo {
806f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
807f1dfa0b1SArnaldo Carvalho de Melo }
808f1dfa0b1SArnaldo Carvalho de Melo 
80986470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
81086470930SIngo Molnar 					const Elf_Data *symstrs)
81186470930SIngo Molnar {
81286470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
81386470930SIngo Molnar }
81486470930SIngo Molnar 
81586470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
81686470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
81783a0944fSIngo Molnar 				    size_t *idx)
81886470930SIngo Molnar {
81986470930SIngo Molnar 	Elf_Scn *sec = NULL;
82086470930SIngo Molnar 	size_t cnt = 1;
82186470930SIngo Molnar 
82286470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
82386470930SIngo Molnar 		char *str;
82486470930SIngo Molnar 
82586470930SIngo Molnar 		gelf_getshdr(sec, shp);
82686470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
82786470930SIngo Molnar 		if (!strcmp(name, str)) {
82883a0944fSIngo Molnar 			if (idx)
82983a0944fSIngo Molnar 				*idx = cnt;
83086470930SIngo Molnar 			break;
83186470930SIngo Molnar 		}
83286470930SIngo Molnar 		++cnt;
83386470930SIngo Molnar 	}
83486470930SIngo Molnar 
83586470930SIngo Molnar 	return sec;
83686470930SIngo Molnar }
83786470930SIngo Molnar 
83886470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
83986470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
84086470930SIngo Molnar 	     idx < nr_entries; \
84186470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
84286470930SIngo Molnar 
84386470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
84486470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
84586470930SIngo Molnar 	     idx < nr_entries; \
84686470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
84786470930SIngo Molnar 
848a25e46c4SArnaldo Carvalho de Melo /*
849a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
850a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
851a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
852a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
853a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
854a25e46c4SArnaldo Carvalho de Melo  */
85582164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
85682164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
85786470930SIngo Molnar {
85886470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
85986470930SIngo Molnar 	GElf_Sym sym;
8609cffa8d5SPaul Mackerras 	u64 plt_offset;
86186470930SIngo Molnar 	GElf_Shdr shdr_plt;
86286470930SIngo Molnar 	struct symbol *f;
863a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
86486470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
865a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
866a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
867a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
86886470930SIngo Molnar 	char sympltname[1024];
869a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
870a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
871ec5761eaSDavid Ahern 	char name[PATH_MAX];
87286470930SIngo Molnar 
873ec5761eaSDavid Ahern 	snprintf(name, sizeof(name), "%s%s",
874ec5761eaSDavid Ahern 		 symbol_conf.symfs, self->long_name);
875ec5761eaSDavid Ahern 	fd = open(name, O_RDONLY);
876a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
877a25e46c4SArnaldo Carvalho de Melo 		goto out;
878a25e46c4SArnaldo Carvalho de Melo 
87984087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
880a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
881a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
882a25e46c4SArnaldo Carvalho de Melo 
883a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
884a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
885a25e46c4SArnaldo Carvalho de Melo 
886a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
887a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
888a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
889a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
890a25e46c4SArnaldo Carvalho de Melo 
891a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
89286470930SIngo Molnar 					  ".rela.plt", NULL);
89386470930SIngo Molnar 	if (scn_plt_rel == NULL) {
894a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
89586470930SIngo Molnar 						  ".rel.plt", NULL);
89686470930SIngo Molnar 		if (scn_plt_rel == NULL)
897a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
89886470930SIngo Molnar 	}
89986470930SIngo Molnar 
900a25e46c4SArnaldo Carvalho de Melo 	err = -1;
90186470930SIngo Molnar 
902a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
903a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
904a25e46c4SArnaldo Carvalho de Melo 
905a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
906a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
90786470930SIngo Molnar 
90886470930SIngo Molnar 	/*
90983a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
91086470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
91186470930SIngo Molnar 	 */
91286470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
91386470930SIngo Molnar 	if (reldata == NULL)
914a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
91586470930SIngo Molnar 
91686470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
91786470930SIngo Molnar 	if (syms == NULL)
918a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
91986470930SIngo Molnar 
920a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
92186470930SIngo Molnar 	if (scn_symstrs == NULL)
922a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
92386470930SIngo Molnar 
92486470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
92586470930SIngo Molnar 	if (symstrs == NULL)
926a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
92786470930SIngo Molnar 
92886470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
92986470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
93086470930SIngo Molnar 
93186470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
93286470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
93386470930SIngo Molnar 
93486470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
93586470930SIngo Molnar 					   nr_rel_entries) {
93686470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
93786470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
93886470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
93986470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
94086470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
94186470930SIngo Molnar 
94286470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
943c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
94486470930SIngo Molnar 			if (!f)
945a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
94686470930SIngo Molnar 
94782164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
94882164161SArnaldo Carvalho de Melo 				symbol__delete(f);
94982164161SArnaldo Carvalho de Melo 			else {
9506a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
95186470930SIngo Molnar 				++nr;
95286470930SIngo Molnar 			}
95382164161SArnaldo Carvalho de Melo 		}
95486470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
95586470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
95686470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
95786470930SIngo Molnar 					  nr_rel_entries) {
95886470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
95986470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
96086470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
96186470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
96286470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
96386470930SIngo Molnar 
96486470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
965c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
96686470930SIngo Molnar 			if (!f)
967a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
96886470930SIngo Molnar 
96982164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
97082164161SArnaldo Carvalho de Melo 				symbol__delete(f);
97182164161SArnaldo Carvalho de Melo 			else {
9726a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
97386470930SIngo Molnar 				++nr;
97486470930SIngo Molnar 			}
97586470930SIngo Molnar 		}
97682164161SArnaldo Carvalho de Melo 	}
97786470930SIngo Molnar 
978a25e46c4SArnaldo Carvalho de Melo 	err = 0;
979a25e46c4SArnaldo Carvalho de Melo out_elf_end:
980a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
981a25e46c4SArnaldo Carvalho de Melo out_close:
982a25e46c4SArnaldo Carvalho de Melo 	close(fd);
983a25e46c4SArnaldo Carvalho de Melo 
984a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
98586470930SIngo Molnar 		return nr;
986a25e46c4SArnaldo Carvalho de Melo out:
987fe2197b8SArnaldo Carvalho de Melo 	pr_debug("%s: problems reading %s PLT info.\n",
988439d473bSArnaldo Carvalho de Melo 		 __func__, self->long_name);
989a25e46c4SArnaldo Carvalho de Melo 	return 0;
99086470930SIngo Molnar }
99186470930SIngo Molnar 
992d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
993d45868d3SArnaldo Carvalho de Melo {
994d45868d3SArnaldo Carvalho de Melo 	switch (type) {
995d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
996d45868d3SArnaldo Carvalho de Melo 		return elf_sym__is_function(self);
997f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
998f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sym__is_object(self);
999d45868d3SArnaldo Carvalho de Melo 	default:
1000d45868d3SArnaldo Carvalho de Melo 		return false;
1001d45868d3SArnaldo Carvalho de Melo 	}
1002d45868d3SArnaldo Carvalho de Melo }
1003d45868d3SArnaldo Carvalho de Melo 
1004d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
1005d45868d3SArnaldo Carvalho de Melo {
1006d45868d3SArnaldo Carvalho de Melo 	switch (type) {
1007d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1008d45868d3SArnaldo Carvalho de Melo 		return elf_sec__is_text(self, secstrs);
1009f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
1010f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sec__is_data(self, secstrs);
1011d45868d3SArnaldo Carvalho de Melo 	default:
1012d45868d3SArnaldo Carvalho de Melo 		return false;
1013d45868d3SArnaldo Carvalho de Melo 	}
1014d45868d3SArnaldo Carvalho de Melo }
1015d45868d3SArnaldo Carvalho de Melo 
101670c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
101770c3856bSEric B Munson {
101870c3856bSEric B Munson 	Elf_Scn *sec = NULL;
101970c3856bSEric B Munson 	GElf_Shdr shdr;
102070c3856bSEric B Munson 	size_t cnt = 1;
102170c3856bSEric B Munson 
102270c3856bSEric B Munson 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
102370c3856bSEric B Munson 		gelf_getshdr(sec, &shdr);
102470c3856bSEric B Munson 
102570c3856bSEric B Munson 		if ((addr >= shdr.sh_addr) &&
102670c3856bSEric B Munson 		    (addr < (shdr.sh_addr + shdr.sh_size)))
102770c3856bSEric B Munson 			return cnt;
102870c3856bSEric B Munson 
102970c3856bSEric B Munson 		++cnt;
103070c3856bSEric B Munson 	}
103170c3856bSEric B Munson 
103270c3856bSEric B Munson 	return -1;
103370c3856bSEric B Munson }
103470c3856bSEric B Munson 
10359de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name,
10366da80ce8SDave Martin 			 int fd, symbol_filter_t filter, int kmodule,
10376da80ce8SDave Martin 			 int want_symtab)
103886470930SIngo Molnar {
10399de89fe7SArnaldo Carvalho de Melo 	struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
10402e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
10412e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
10426cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
104386470930SIngo Molnar 	uint32_t nr_syms;
104486470930SIngo Molnar 	int err = -1;
104583a0944fSIngo Molnar 	uint32_t idx;
104686470930SIngo Molnar 	GElf_Ehdr ehdr;
104770c3856bSEric B Munson 	GElf_Shdr shdr, opdshdr;
104870c3856bSEric B Munson 	Elf_Data *syms, *opddata = NULL;
104986470930SIngo Molnar 	GElf_Sym sym;
105070c3856bSEric B Munson 	Elf_Scn *sec, *sec_strndx, *opdsec;
105186470930SIngo Molnar 	Elf *elf;
1052439d473bSArnaldo Carvalho de Melo 	int nr = 0;
105370c3856bSEric B Munson 	size_t opdidx = 0;
105486470930SIngo Molnar 
105584087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
105686470930SIngo Molnar 	if (elf == NULL) {
10578b1389efSDave Martin 		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
105886470930SIngo Molnar 		goto out_close;
105986470930SIngo Molnar 	}
106086470930SIngo Molnar 
106186470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
10628b1389efSDave Martin 		pr_debug("%s: cannot get elf header.\n", __func__);
106386470930SIngo Molnar 		goto out_elf_end;
106486470930SIngo Molnar 	}
106586470930SIngo Molnar 
10666da80ce8SDave Martin 	/* Always reject images with a mismatched build-id: */
106721916c38SDave Martin 	if (self->has_build_id) {
106821916c38SDave Martin 		u8 build_id[BUILD_ID_SIZE];
106921916c38SDave Martin 
107021916c38SDave Martin 		if (elf_read_build_id(elf, build_id,
107121916c38SDave Martin 				      BUILD_ID_SIZE) != BUILD_ID_SIZE)
107221916c38SDave Martin 			goto out_elf_end;
107321916c38SDave Martin 
107421916c38SDave Martin 		if (!dso__build_id_equal(self, build_id))
107521916c38SDave Martin 			goto out_elf_end;
107621916c38SDave Martin 	}
107721916c38SDave Martin 
107886470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
107986470930SIngo Molnar 	if (sec == NULL) {
10806da80ce8SDave Martin 		if (want_symtab)
10816da80ce8SDave Martin 			goto out_elf_end;
10826da80ce8SDave Martin 
1083a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1084a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
108586470930SIngo Molnar 			goto out_elf_end;
108686470930SIngo Molnar 	}
108786470930SIngo Molnar 
108870c3856bSEric B Munson 	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
108970c3856bSEric B Munson 	if (opdsec)
109070c3856bSEric B Munson 		opddata = elf_rawdata(opdsec, NULL);
109170c3856bSEric B Munson 
109286470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
109386470930SIngo Molnar 	if (syms == NULL)
109486470930SIngo Molnar 		goto out_elf_end;
109586470930SIngo Molnar 
109686470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
109786470930SIngo Molnar 	if (sec == NULL)
109886470930SIngo Molnar 		goto out_elf_end;
109986470930SIngo Molnar 
110086470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
110186470930SIngo Molnar 	if (symstrs == NULL)
110286470930SIngo Molnar 		goto out_elf_end;
110386470930SIngo Molnar 
11046cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
11056cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
11066cfcc53eSMike Galbraith 		goto out_elf_end;
11076cfcc53eSMike Galbraith 
11086cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
11099b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
11106cfcc53eSMike Galbraith 		goto out_elf_end;
11116cfcc53eSMike Galbraith 
111286470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
111386470930SIngo Molnar 
1114e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
1115a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_USER) {
111630d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
111730d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
1118f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
111930d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
1120d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
1121d20ff6bdSMike Galbraith 
112283a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
112386470930SIngo Molnar 		struct symbol *f;
112456b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
11252e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
11266cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
11276cfcc53eSMike Galbraith 		const char *section_name;
112886470930SIngo Molnar 
11299de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
11309de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
11319de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
113256b03f3cSArnaldo Carvalho de Melo 
1133d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
113486470930SIngo Molnar 			continue;
113586470930SIngo Molnar 
1136696b97a5SDave Martin 		/* Reject ARM ELF "mapping symbols": these aren't unique and
1137696b97a5SDave Martin 		 * don't identify functions, so will confuse the profile
1138696b97a5SDave Martin 		 * output: */
1139696b97a5SDave Martin 		if (ehdr.e_machine == EM_ARM) {
1140696b97a5SDave Martin 			if (!strcmp(elf_name, "$a") ||
1141696b97a5SDave Martin 			    !strcmp(elf_name, "$d") ||
1142696b97a5SDave Martin 			    !strcmp(elf_name, "$t"))
1143696b97a5SDave Martin 				continue;
1144696b97a5SDave Martin 		}
1145696b97a5SDave Martin 
114670c3856bSEric B Munson 		if (opdsec && sym.st_shndx == opdidx) {
114770c3856bSEric B Munson 			u32 offset = sym.st_value - opdshdr.sh_addr;
114870c3856bSEric B Munson 			u64 *opd = opddata->d_buf + offset;
114970c3856bSEric B Munson 			sym.st_value = *opd;
115070c3856bSEric B Munson 			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
115170c3856bSEric B Munson 		}
115270c3856bSEric B Munson 
115386470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
115486470930SIngo Molnar 		if (!sec)
115586470930SIngo Molnar 			goto out_elf_end;
115686470930SIngo Molnar 
115786470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
11586cfcc53eSMike Galbraith 
1159d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
11606cfcc53eSMike Galbraith 			continue;
11616cfcc53eSMike Galbraith 
11626cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
116386470930SIngo Molnar 
1164*b2f8fb23SDr. David Alan Gilbert 		/* On ARM, symbols for thumb functions have 1 added to
1165*b2f8fb23SDr. David Alan Gilbert 		 * the symbol address as a flag - remove it */
1166*b2f8fb23SDr. David Alan Gilbert 		if ((ehdr.e_machine == EM_ARM) &&
1167*b2f8fb23SDr. David Alan Gilbert 		    (map->type == MAP__FUNCTION) &&
1168*b2f8fb23SDr. David Alan Gilbert 		    (sym.st_value & 1))
1169*b2f8fb23SDr. David Alan Gilbert 			--sym.st_value;
1170*b2f8fb23SDr. David Alan Gilbert 
1171a1645ce1SZhang, Yanmin 		if (self->kernel != DSO_TYPE_USER || kmodule) {
11722e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
11732e538c4aSArnaldo Carvalho de Melo 
11742e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1175b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1176b63be8d7SArnaldo Carvalho de Melo 				    self->short_name_len)) == 0)
11772e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
11782e538c4aSArnaldo Carvalho de Melo 
11792e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
11802e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
11812e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
11822e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1183af427bf5SArnaldo Carvalho de Melo 			}
1184af427bf5SArnaldo Carvalho de Melo 
11852e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
11862e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
11872e538c4aSArnaldo Carvalho de Melo 
11889de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
11892e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
11902e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
11912e538c4aSArnaldo Carvalho de Melo 
11922e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
11932e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
11942e538c4aSArnaldo Carvalho de Melo 
119500a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
11962e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
11972e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1198a1645ce1SZhang, Yanmin 				curr_dso->kernel = self->kernel;
11993610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
12006275ce2dSArnaldo Carvalho de Melo 						     map->type);
12012e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
12022e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
12032e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
12042e538c4aSArnaldo Carvalho de Melo 				}
1205ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1206ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1207b0a9ab62SArnaldo Carvalho de Melo 				curr_dso->origin = self->origin;
12089de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1209a1645ce1SZhang, Yanmin 				dsos__add(&self->node, curr_dso);
12106275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
12112e538c4aSArnaldo Carvalho de Melo 			} else
12122e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
12132e538c4aSArnaldo Carvalho de Melo 
12142e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
12152e538c4aSArnaldo Carvalho de Melo 		}
12162e538c4aSArnaldo Carvalho de Melo 
12172e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
121829a9f66dSArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#Lx "
121929a9f66dSArnaldo Carvalho de Melo 				  "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
122029a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
122129a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
122286470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1223af427bf5SArnaldo Carvalho de Melo 		}
122428ac909bSArnaldo Carvalho de Melo 		/*
122528ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
122628ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
122728ac909bSArnaldo Carvalho de Melo 		 * to it...
122828ac909bSArnaldo Carvalho de Melo 		 */
122983a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
123028ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
123183a0944fSIngo Molnar 			elf_name = demangled;
12322e538c4aSArnaldo Carvalho de Melo new_symbol:
1233c408fedfSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size,
1234c408fedfSArnaldo Carvalho de Melo 				GELF_ST_BIND(sym.st_info), elf_name);
123528ac909bSArnaldo Carvalho de Melo 		free(demangled);
123686470930SIngo Molnar 		if (!f)
123786470930SIngo Molnar 			goto out_elf_end;
123886470930SIngo Molnar 
12392e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
124000a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
124186470930SIngo Molnar 		else {
12426a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
124386470930SIngo Molnar 			nr++;
124486470930SIngo Molnar 		}
124586470930SIngo Molnar 	}
124686470930SIngo Molnar 
12472e538c4aSArnaldo Carvalho de Melo 	/*
12482e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
12492e538c4aSArnaldo Carvalho de Melo 	 */
12506275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
12516a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
12526275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
12536275ce2dSArnaldo Carvalho de Melo 			/*
12546275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
12556275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
12566275ce2dSArnaldo Carvalho de Melo 			 */
12576275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
12586275ce2dSArnaldo Carvalho de Melo 		}
12596275ce2dSArnaldo Carvalho de Melo 	}
126086470930SIngo Molnar 	err = nr;
126186470930SIngo Molnar out_elf_end:
126286470930SIngo Molnar 	elf_end(elf);
126386470930SIngo Molnar out_close:
126486470930SIngo Molnar 	return err;
126586470930SIngo Molnar }
126686470930SIngo Molnar 
126778075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
126878075caaSArnaldo Carvalho de Melo {
126978075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
127078075caaSArnaldo Carvalho de Melo }
127178075caaSArnaldo Carvalho de Melo 
1272a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
127357f395a7SFrederic Weisbecker {
1274e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
127557f395a7SFrederic Weisbecker 	struct dso *pos;
127657f395a7SFrederic Weisbecker 
12776122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
12786122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
12796122e4e4SArnaldo Carvalho de Melo 			continue;
1280f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
1281f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
1282f6e1467dSArnaldo Carvalho de Melo 			continue;
1283f6e1467dSArnaldo Carvalho de Melo 		}
1284e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1285e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1286e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1287e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
128857f395a7SFrederic Weisbecker 		}
12896122e4e4SArnaldo Carvalho de Melo 	}
129057f395a7SFrederic Weisbecker 
1291e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
129257f395a7SFrederic Weisbecker }
129357f395a7SFrederic Weisbecker 
1294fd7a346eSArnaldo Carvalho de Melo /*
1295fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1296fd7a346eSArnaldo Carvalho de Melo  */
1297fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1298fd7a346eSArnaldo Carvalho de Melo 
129921916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size)
13004d1e00a8SArnaldo Carvalho de Melo {
130121916c38SDave Martin 	int err = -1;
13024d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
13034d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1304fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
13054d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1306e57cfcdaSPekka Enberg 	Elf_Kind ek;
1307fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
13084d1e00a8SArnaldo Carvalho de Melo 
13092643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
13102643ce11SArnaldo Carvalho de Melo 		goto out;
13112643ce11SArnaldo Carvalho de Melo 
1312e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1313e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
131421916c38SDave Martin 		goto out;
1315e57cfcdaSPekka Enberg 
13164d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
13176beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
131821916c38SDave Martin 		goto out;
13194d1e00a8SArnaldo Carvalho de Melo 	}
13204d1e00a8SArnaldo Carvalho de Melo 
13212643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
13222643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1323fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1324fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1325fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
13264d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
132721916c38SDave Martin 			goto out;
1328fd7a346eSArnaldo Carvalho de Melo 	}
13294d1e00a8SArnaldo Carvalho de Melo 
1330fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1331fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
133221916c38SDave Martin 		goto out;
1333fd7a346eSArnaldo Carvalho de Melo 
1334fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1335fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1336fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1337fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1338fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1339fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1340fd7a346eSArnaldo Carvalho de Melo 
1341fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1342fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1343fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1344fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1345fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1346fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1347fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
13482643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1349fd7a346eSArnaldo Carvalho de Melo 				break;
1350fd7a346eSArnaldo Carvalho de Melo 			}
1351fd7a346eSArnaldo Carvalho de Melo 		}
1352fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1353fd7a346eSArnaldo Carvalho de Melo 	}
135421916c38SDave Martin 
135521916c38SDave Martin out:
135621916c38SDave Martin 	return err;
135721916c38SDave Martin }
135821916c38SDave Martin 
135921916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size)
136021916c38SDave Martin {
136121916c38SDave Martin 	int fd, err = -1;
136221916c38SDave Martin 	Elf *elf;
136321916c38SDave Martin 
136421916c38SDave Martin 	if (size < BUILD_ID_SIZE)
136521916c38SDave Martin 		goto out;
136621916c38SDave Martin 
136721916c38SDave Martin 	fd = open(filename, O_RDONLY);
136821916c38SDave Martin 	if (fd < 0)
136921916c38SDave Martin 		goto out;
137021916c38SDave Martin 
137121916c38SDave Martin 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
137221916c38SDave Martin 	if (elf == NULL) {
137321916c38SDave Martin 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
137421916c38SDave Martin 		goto out_close;
137521916c38SDave Martin 	}
137621916c38SDave Martin 
137721916c38SDave Martin 	err = elf_read_build_id(elf, bf, size);
137821916c38SDave Martin 
13792643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
13802643ce11SArnaldo Carvalho de Melo out_close:
13812643ce11SArnaldo Carvalho de Melo 	close(fd);
13822643ce11SArnaldo Carvalho de Melo out:
13832643ce11SArnaldo Carvalho de Melo 	return err;
13842643ce11SArnaldo Carvalho de Melo }
13852643ce11SArnaldo Carvalho de Melo 
1386f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1387f1617b40SArnaldo Carvalho de Melo {
1388f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1389f1617b40SArnaldo Carvalho de Melo 
1390f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1391f1617b40SArnaldo Carvalho de Melo 		goto out;
1392f1617b40SArnaldo Carvalho de Melo 
1393f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1394f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1395f1617b40SArnaldo Carvalho de Melo 		goto out;
1396f1617b40SArnaldo Carvalho de Melo 
1397f1617b40SArnaldo Carvalho de Melo 	while (1) {
1398f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1399f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1400f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1401f1617b40SArnaldo Carvalho de Melo 
1402f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1403f1617b40SArnaldo Carvalho de Melo 			break;
1404f1617b40SArnaldo Carvalho de Melo 
1405fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1406fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1407f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1408f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1409f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1410f1617b40SArnaldo Carvalho de Melo 				break;
1411f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1412f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1413f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1414f1617b40SArnaldo Carvalho de Melo 					err = 0;
1415f1617b40SArnaldo Carvalho de Melo 					break;
1416f1617b40SArnaldo Carvalho de Melo 				}
1417f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1418f1617b40SArnaldo Carvalho de Melo 				break;
1419f1617b40SArnaldo Carvalho de Melo 		} else {
1420f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1421f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1422f1617b40SArnaldo Carvalho de Melo 				break;
1423f1617b40SArnaldo Carvalho de Melo 		}
1424f1617b40SArnaldo Carvalho de Melo 	}
1425f1617b40SArnaldo Carvalho de Melo 	close(fd);
1426f1617b40SArnaldo Carvalho de Melo out:
1427f1617b40SArnaldo Carvalho de Melo 	return err;
1428f1617b40SArnaldo Carvalho de Melo }
1429f1617b40SArnaldo Carvalho de Melo 
143094cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
143194cb9e38SArnaldo Carvalho de Melo {
143294cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
143394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
143494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
14354cf40131SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILD_ID_CACHE] = 'B',
143694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
143794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
143894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
143994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1440439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
1441a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KERNEL] =  'g',
1442a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KMODULE] =  'G',
144394cb9e38SArnaldo Carvalho de Melo 	};
144494cb9e38SArnaldo Carvalho de Melo 
144594cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
144694cb9e38SArnaldo Carvalho de Melo 		return '!';
144794cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
144894cb9e38SArnaldo Carvalho de Melo }
144994cb9e38SArnaldo Carvalho de Melo 
14509de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
145186470930SIngo Molnar {
14524d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1453c338aee8SArnaldo Carvalho de Melo 	char *name;
145486470930SIngo Molnar 	int ret = -1;
145586470930SIngo Molnar 	int fd;
145623346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1457a1645ce1SZhang, Yanmin 	const char *root_dir;
14586da80ce8SDave Martin 	int want_symtab;
145986470930SIngo Molnar 
14603610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
146166bd8424SArnaldo Carvalho de Melo 
1462a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_KERNEL)
14639de89fe7SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, filter);
1464a1645ce1SZhang, Yanmin 	else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1465a1645ce1SZhang, Yanmin 		return dso__load_guest_kernel_sym(self, map, filter);
1466a1645ce1SZhang, Yanmin 
146723346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
146823346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1469a1645ce1SZhang, Yanmin 	else
147023346f21SArnaldo Carvalho de Melo 		machine = NULL;
1471c338aee8SArnaldo Carvalho de Melo 
1472c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
147386470930SIngo Molnar 	if (!name)
147486470930SIngo Molnar 		return -1;
147586470930SIngo Molnar 
147630d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1477f5812a7aSArnaldo Carvalho de Melo 
147894cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
14796beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
148094cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
148194cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
148294cb9e38SArnaldo Carvalho de Melo 		return ret;
148394cb9e38SArnaldo Carvalho de Melo 	}
148494cb9e38SArnaldo Carvalho de Melo 
14856da80ce8SDave Martin 	/* Iterate over candidate debug images.
14866da80ce8SDave Martin 	 * On the first pass, only load images if they have a full symtab.
14876da80ce8SDave Martin 	 * Failing that, do a second pass where we accept .dynsym also
14886da80ce8SDave Martin 	 */
14896da80ce8SDave Martin 	for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
14906da80ce8SDave Martin 	     self->origin != DSO__ORIG_NOT_FOUND;
14916da80ce8SDave Martin 	     self->origin++) {
149294cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
14936da80ce8SDave Martin 		case DSO__ORIG_BUILD_ID_CACHE:
1494ec5761eaSDavid Ahern 			/* skip the locally configured cache if a symfs is given */
1495ec5761eaSDavid Ahern 			if (symbol_conf.symfs[0] ||
1496ec5761eaSDavid Ahern 			    (dso__build_id_filename(self, name, size) == NULL)) {
14976da80ce8SDave Martin 				continue;
1498ec5761eaSDavid Ahern 			}
14996da80ce8SDave Martin 			break;
150094cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1501ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s.debug",
1502ec5761eaSDavid Ahern 				 symbol_conf.symfs, self->long_name);
150386470930SIngo Molnar 			break;
150494cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1505ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s",
1506ec5761eaSDavid Ahern 				 symbol_conf.symfs, self->long_name);
150786470930SIngo Molnar 			break;
15086da80ce8SDave Martin 		case DSO__ORIG_BUILDID: {
1509b36f19d5SArnaldo Carvalho de Melo 			char build_id_hex[BUILD_ID_SIZE * 2 + 1];
15106da80ce8SDave Martin 
15116da80ce8SDave Martin 			if (!self->has_build_id)
15126da80ce8SDave Martin 				continue;
15136da80ce8SDave Martin 
151421916c38SDave Martin 			build_id__sprintf(self->build_id,
151521916c38SDave Martin 					  sizeof(self->build_id),
1516d3379ab9SArnaldo Carvalho de Melo 					  build_id_hex);
15174d1e00a8SArnaldo Carvalho de Melo 			snprintf(name, size,
1518ec5761eaSDavid Ahern 				 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1519ec5761eaSDavid Ahern 				 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
15204d1e00a8SArnaldo Carvalho de Melo 			}
15216da80ce8SDave Martin 			break;
152294cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1523ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s",
1524ec5761eaSDavid Ahern 			     symbol_conf.symfs, self->long_name);
152586470930SIngo Molnar 			break;
1526a1645ce1SZhang, Yanmin 		case DSO__ORIG_GUEST_KMODULE:
152723346f21SArnaldo Carvalho de Melo 			if (map->groups && map->groups->machine)
152823346f21SArnaldo Carvalho de Melo 				root_dir = map->groups->machine->root_dir;
1529a1645ce1SZhang, Yanmin 			else
1530a1645ce1SZhang, Yanmin 				root_dir = "";
1531ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1532ec5761eaSDavid Ahern 				 root_dir, self->long_name);
1533ec5761eaSDavid Ahern 			break;
1534ec5761eaSDavid Ahern 
1535ec5761eaSDavid Ahern 		case DSO__ORIG_KMODULE:
1536ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s", symbol_conf.symfs,
1537ec5761eaSDavid Ahern 				 self->long_name);
1538a1645ce1SZhang, Yanmin 			break;
153986470930SIngo Molnar 
154086470930SIngo Molnar 		default:
15416da80ce8SDave Martin 			/*
15426da80ce8SDave Martin 			 * If we wanted a full symtab but no image had one,
15436da80ce8SDave Martin 			 * relax our requirements and repeat the search.
15446da80ce8SDave Martin 			 */
15456da80ce8SDave Martin 			if (want_symtab) {
15466da80ce8SDave Martin 				want_symtab = 0;
15476da80ce8SDave Martin 				self->origin = DSO__ORIG_BUILD_ID_CACHE;
15486da80ce8SDave Martin 			} else
15496da80ce8SDave Martin 				continue;
155086470930SIngo Molnar 		}
155186470930SIngo Molnar 
15526da80ce8SDave Martin 		/* Name is now the name of the next image to try */
15536da80ce8SDave Martin 		fd = open(name, O_RDONLY);
15546da80ce8SDave Martin 		if (fd < 0)
15556da80ce8SDave Martin 			continue;
15566da80ce8SDave Martin 
15576da80ce8SDave Martin 		ret = dso__load_sym(self, map, name, fd, filter, 0,
15586da80ce8SDave Martin 				    want_symtab);
155986470930SIngo Molnar 		close(fd);
156086470930SIngo Molnar 
156186470930SIngo Molnar 		/*
15626da80ce8SDave Martin 		 * Some people seem to have debuginfo files _WITHOUT_ debug
15636da80ce8SDave Martin 		 * info!?!?
156486470930SIngo Molnar 		 */
156586470930SIngo Molnar 		if (!ret)
15666da80ce8SDave Martin 			continue;
156786470930SIngo Molnar 
1568a25e46c4SArnaldo Carvalho de Melo 		if (ret > 0) {
156982164161SArnaldo Carvalho de Melo 			int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1570a25e46c4SArnaldo Carvalho de Melo 			if (nr_plt > 0)
1571a25e46c4SArnaldo Carvalho de Melo 				ret += nr_plt;
15726da80ce8SDave Martin 			break;
1573a25e46c4SArnaldo Carvalho de Melo 		}
15746da80ce8SDave Martin 	}
15756da80ce8SDave Martin 
157686470930SIngo Molnar 	free(name);
15771340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
15781340e6bbSArnaldo Carvalho de Melo 		return 0;
157986470930SIngo Molnar 	return ret;
158086470930SIngo Molnar }
158186470930SIngo Molnar 
158279406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self,
158379406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1584439d473bSArnaldo Carvalho de Melo {
1585439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1586439d473bSArnaldo Carvalho de Melo 
158779406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1588439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1589439d473bSArnaldo Carvalho de Melo 
1590b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1591439d473bSArnaldo Carvalho de Melo 			return map;
1592439d473bSArnaldo Carvalho de Melo 	}
1593439d473bSArnaldo Carvalho de Melo 
1594439d473bSArnaldo Carvalho de Melo 	return NULL;
1595439d473bSArnaldo Carvalho de Melo }
1596439d473bSArnaldo Carvalho de Melo 
1597a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self,
1598a1645ce1SZhang, Yanmin 				const char *root_dir)
1599b7cece76SArnaldo Carvalho de Melo {
1600b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1601b7cece76SArnaldo Carvalho de Melo 	/*
1602b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1603b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1604b7cece76SArnaldo Carvalho de Melo 	 */
1605b7cece76SArnaldo Carvalho de Melo 	const char *name = self->short_name + 1;
1606b7cece76SArnaldo Carvalho de Melo 
1607b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1608a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1609a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1610b7cece76SArnaldo Carvalho de Melo 
1611b7cece76SArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, self->build_id,
1612b7cece76SArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1613b7cece76SArnaldo Carvalho de Melo 		self->has_build_id = true;
1614b7cece76SArnaldo Carvalho de Melo 
1615b7cece76SArnaldo Carvalho de Melo 	return 0;
1616b7cece76SArnaldo Carvalho de Melo }
1617b7cece76SArnaldo Carvalho de Melo 
1618a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self,
1619a1645ce1SZhang, Yanmin 				const char *dir_name)
16206cfcc53eSMike Galbraith {
1621439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
16225aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
162374534341SGui Jianfeng 	int ret = 0;
16246cfcc53eSMike Galbraith 
1625439d473bSArnaldo Carvalho de Melo 	if (!dir) {
16265aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1627439d473bSArnaldo Carvalho de Melo 		return -1;
1628439d473bSArnaldo Carvalho de Melo 	}
16296cfcc53eSMike Galbraith 
1630439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1631439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1632a1645ce1SZhang, Yanmin 		struct stat st;
1633439d473bSArnaldo Carvalho de Melo 
1634a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
1635a1645ce1SZhang, Yanmin 		sprintf(path, "%s/%s", dir_name, dent->d_name);
1636a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1637a1645ce1SZhang, Yanmin 			continue;
1638a1645ce1SZhang, Yanmin 
1639a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1640439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1641439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1642439d473bSArnaldo Carvalho de Melo 				continue;
1643439d473bSArnaldo Carvalho de Melo 
1644439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
16455aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
164674534341SGui Jianfeng 			ret = map_groups__set_modules_path_dir(self, path);
164774534341SGui Jianfeng 			if (ret < 0)
164874534341SGui Jianfeng 				goto out;
1649439d473bSArnaldo Carvalho de Melo 		} else {
1650439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1651439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1652439d473bSArnaldo Carvalho de Melo 			struct map *map;
1653cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1654439d473bSArnaldo Carvalho de Melo 
1655439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1656439d473bSArnaldo Carvalho de Melo 				continue;
1657439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1658439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1659439d473bSArnaldo Carvalho de Melo 
1660a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
16619de89fe7SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1662439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1663439d473bSArnaldo Carvalho de Melo 				continue;
1664439d473bSArnaldo Carvalho de Melo 
1665439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
16665aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
1667439d473bSArnaldo Carvalho de Melo 
1668cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
166974534341SGui Jianfeng 			if (long_name == NULL) {
167074534341SGui Jianfeng 				ret = -1;
167174534341SGui Jianfeng 				goto out;
167274534341SGui Jianfeng 			}
1673cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
16746e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1675a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1676439d473bSArnaldo Carvalho de Melo 		}
1677439d473bSArnaldo Carvalho de Melo 	}
1678439d473bSArnaldo Carvalho de Melo 
167974534341SGui Jianfeng out:
1680439d473bSArnaldo Carvalho de Melo 	closedir(dir);
168174534341SGui Jianfeng 	return ret;
1682439d473bSArnaldo Carvalho de Melo }
1683439d473bSArnaldo Carvalho de Melo 
1684a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1685439d473bSArnaldo Carvalho de Melo {
1686a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1687a1645ce1SZhang, Yanmin 	FILE *file;
1688a1645ce1SZhang, Yanmin 	char *name, *tmp;
1689a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1690a1645ce1SZhang, Yanmin 
1691a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1692a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1693a1645ce1SZhang, Yanmin 	if (!file)
1694a1645ce1SZhang, Yanmin 		return NULL;
1695a1645ce1SZhang, Yanmin 
1696a1645ce1SZhang, Yanmin 	version[0] = '\0';
1697a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1698a1645ce1SZhang, Yanmin 	fclose(file);
1699a1645ce1SZhang, Yanmin 
1700a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1701a1645ce1SZhang, Yanmin 	if (!name)
1702a1645ce1SZhang, Yanmin 		return NULL;
1703a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1704a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1705a1645ce1SZhang, Yanmin 	if (tmp)
1706a1645ce1SZhang, Yanmin 		*tmp = '\0';
1707a1645ce1SZhang, Yanmin 
1708a1645ce1SZhang, Yanmin 	return strdup(name);
1709a1645ce1SZhang, Yanmin }
1710a1645ce1SZhang, Yanmin 
1711d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self)
1712a1645ce1SZhang, Yanmin {
1713a1645ce1SZhang, Yanmin 	char *version;
1714439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1715439d473bSArnaldo Carvalho de Melo 
1716d28c6223SArnaldo Carvalho de Melo 	version = get_kernel_version(self->root_dir);
1717a1645ce1SZhang, Yanmin 	if (!version)
1718439d473bSArnaldo Carvalho de Melo 		return -1;
1719439d473bSArnaldo Carvalho de Melo 
1720a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1721d28c6223SArnaldo Carvalho de Melo 		 self->root_dir, version);
1722a1645ce1SZhang, Yanmin 	free(version);
1723439d473bSArnaldo Carvalho de Melo 
1724d28c6223SArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
1725439d473bSArnaldo Carvalho de Melo }
17266cfcc53eSMike Galbraith 
17276cfcc53eSMike Galbraith /*
1728439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1729439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1730439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
17316cfcc53eSMike Galbraith  */
17323610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1733439d473bSArnaldo Carvalho de Melo {
17345aab621bSArnaldo Carvalho de Melo 	struct map *self = calloc(1, (sizeof(*self) +
17355aab621bSArnaldo Carvalho de Melo 				      (dso->kernel ? sizeof(struct kmap) : 0)));
1736439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1737439d473bSArnaldo Carvalho de Melo 		/*
1738afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1739439d473bSArnaldo Carvalho de Melo 		 */
17403610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1741439d473bSArnaldo Carvalho de Melo 	}
1742afb7b4f0SArnaldo Carvalho de Melo 
1743439d473bSArnaldo Carvalho de Melo 	return self;
1744439d473bSArnaldo Carvalho de Melo }
1745439d473bSArnaldo Carvalho de Melo 
1746d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start,
1747d28c6223SArnaldo Carvalho de Melo 				const char *filename)
1748b7cece76SArnaldo Carvalho de Melo {
1749b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1750d28c6223SArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
1751b7cece76SArnaldo Carvalho de Melo 
1752b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1753b7cece76SArnaldo Carvalho de Melo 		return NULL;
1754b7cece76SArnaldo Carvalho de Melo 
1755b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1756b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1757b7cece76SArnaldo Carvalho de Melo 		return NULL;
1758b7cece76SArnaldo Carvalho de Melo 
1759d28c6223SArnaldo Carvalho de Melo 	if (machine__is_host(self))
1760b7cece76SArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1761a1645ce1SZhang, Yanmin 	else
1762a1645ce1SZhang, Yanmin 		dso->origin = DSO__ORIG_GUEST_KMODULE;
1763d28c6223SArnaldo Carvalho de Melo 	map_groups__insert(&self->kmaps, map);
1764b7cece76SArnaldo Carvalho de Melo 	return map;
1765b7cece76SArnaldo Carvalho de Melo }
1766b7cece76SArnaldo Carvalho de Melo 
1767d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self)
1768439d473bSArnaldo Carvalho de Melo {
1769439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1770439d473bSArnaldo Carvalho de Melo 	size_t n;
1771a1645ce1SZhang, Yanmin 	FILE *file;
1772439d473bSArnaldo Carvalho de Melo 	struct map *map;
1773a1645ce1SZhang, Yanmin 	const char *modules;
1774a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1775439d473bSArnaldo Carvalho de Melo 
1776d28c6223SArnaldo Carvalho de Melo 	if (machine__is_default_guest(self))
1777a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
1778a1645ce1SZhang, Yanmin 	else {
1779d28c6223SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", self->root_dir);
1780a1645ce1SZhang, Yanmin 		modules = path;
1781a1645ce1SZhang, Yanmin 	}
1782a1645ce1SZhang, Yanmin 
1783a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
1784439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1785439d473bSArnaldo Carvalho de Melo 		return -1;
1786439d473bSArnaldo Carvalho de Melo 
1787439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1788439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1789439d473bSArnaldo Carvalho de Melo 		u64 start;
1790439d473bSArnaldo Carvalho de Melo 		char *sep;
1791439d473bSArnaldo Carvalho de Melo 		int line_len;
1792439d473bSArnaldo Carvalho de Melo 
1793439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1794439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
17956cfcc53eSMike Galbraith 			break;
17966cfcc53eSMike Galbraith 
1797439d473bSArnaldo Carvalho de Melo 		if (!line)
1798439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1799439d473bSArnaldo Carvalho de Melo 
1800439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1801439d473bSArnaldo Carvalho de Melo 
1802439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1803439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1804439d473bSArnaldo Carvalho de Melo 			continue;
1805439d473bSArnaldo Carvalho de Melo 
1806439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1807439d473bSArnaldo Carvalho de Melo 
1808439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1809439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1810439d473bSArnaldo Carvalho de Melo 			continue;
1811439d473bSArnaldo Carvalho de Melo 
1812439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1813439d473bSArnaldo Carvalho de Melo 
1814439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
1815d28c6223SArnaldo Carvalho de Melo 		map = machine__new_module(self, start, name);
1816b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1817439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1818d28c6223SArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, self->root_dir);
18196cfcc53eSMike Galbraith 	}
18206cfcc53eSMike Galbraith 
1821439d473bSArnaldo Carvalho de Melo 	free(line);
1822439d473bSArnaldo Carvalho de Melo 	fclose(file);
1823439d473bSArnaldo Carvalho de Melo 
1824d28c6223SArnaldo Carvalho de Melo 	return machine__set_modules_path(self);
1825439d473bSArnaldo Carvalho de Melo 
1826439d473bSArnaldo Carvalho de Melo out_delete_line:
1827439d473bSArnaldo Carvalho de Melo 	free(line);
1828439d473bSArnaldo Carvalho de Melo out_failure:
1829439d473bSArnaldo Carvalho de Melo 	return -1;
18306cfcc53eSMike Galbraith }
18316cfcc53eSMike Galbraith 
1832fd930ff9SFranck Bui-Huu int dso__load_vmlinux(struct dso *self, struct map *map,
18336beba7adSArnaldo Carvalho de Melo 		      const char *vmlinux, symbol_filter_t filter)
183486470930SIngo Molnar {
1835fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
1836ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
183786470930SIngo Molnar 
1838ec5761eaSDavid Ahern 	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
1839ec5761eaSDavid Ahern 		 symbol_conf.symfs, vmlinux);
1840ec5761eaSDavid Ahern 	fd = open(symfs_vmlinux, O_RDONLY);
184186470930SIngo Molnar 	if (fd < 0)
184286470930SIngo Molnar 		return -1;
184386470930SIngo Molnar 
18443610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
1845ec5761eaSDavid Ahern 	err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
184686470930SIngo Molnar 	close(fd);
184786470930SIngo Molnar 
18483846df2eSArnaldo Carvalho de Melo 	if (err > 0)
1849ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
18503846df2eSArnaldo Carvalho de Melo 
185186470930SIngo Molnar 	return err;
185286470930SIngo Molnar }
185386470930SIngo Molnar 
1854a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map,
18559de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1856a19afe46SArnaldo Carvalho de Melo {
1857a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
18585ad90e4eSArnaldo Carvalho de Melo 	char *filename;
1859a19afe46SArnaldo Carvalho de Melo 
1860a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
18615ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
18625ad90e4eSArnaldo Carvalho de Melo 
18635ad90e4eSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(self, NULL, 0);
18645ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
18655ad90e4eSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, filename, filter);
18665ad90e4eSArnaldo Carvalho de Melo 		if (err > 0) {
18675ad90e4eSArnaldo Carvalho de Melo 			dso__set_long_name(self, filename);
18685ad90e4eSArnaldo Carvalho de Melo 			goto out;
18695ad90e4eSArnaldo Carvalho de Melo 		}
18705ad90e4eSArnaldo Carvalho de Melo 		free(filename);
18715ad90e4eSArnaldo Carvalho de Melo 	}
1872a19afe46SArnaldo Carvalho de Melo 
1873a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
18749de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1875a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1876a19afe46SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(vmlinux_path[i]));
1877a19afe46SArnaldo Carvalho de Melo 			break;
1878a19afe46SArnaldo Carvalho de Melo 		}
1879a19afe46SArnaldo Carvalho de Melo 	}
18805ad90e4eSArnaldo Carvalho de Melo out:
1881a19afe46SArnaldo Carvalho de Melo 	return err;
1882a19afe46SArnaldo Carvalho de Melo }
1883a19afe46SArnaldo Carvalho de Melo 
1884c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
18859de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
188686470930SIngo Molnar {
1887cc612d81SArnaldo Carvalho de Melo 	int err;
18889e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
18899e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1890dc8d6ab2SArnaldo Carvalho de Melo 	/*
1891b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1892b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1893dc8d6ab2SArnaldo Carvalho de Melo 	 *
1894dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1895dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1896dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1897dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1898dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1899dc8d6ab2SArnaldo Carvalho de Melo 	 *
1900dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1901dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1902dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1903dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1904dc8d6ab2SArnaldo Carvalho de Melo 	 */
1905b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1906b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1907b226a5a7SDavid Ahern 		goto do_kallsyms;
1908b226a5a7SDavid Ahern 	}
1909b226a5a7SDavid Ahern 
1910dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
19119de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map,
1912dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1913e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
1914e7dadc00SArnaldo Carvalho de Melo 			dso__set_long_name(self,
1915e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
1916e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
1917e7dadc00SArnaldo Carvalho de Melo 		}
1918e7dadc00SArnaldo Carvalho de Melo 		return err;
1919dc8d6ab2SArnaldo Carvalho de Melo 	}
1920439d473bSArnaldo Carvalho de Melo 
1921cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
19229de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(self, map, filter);
1923a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1924cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1925cc612d81SArnaldo Carvalho de Melo 	}
1926cc612d81SArnaldo Carvalho de Melo 
1927ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1928ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1929ec5761eaSDavid Ahern 		return -1;
1930ec5761eaSDavid Ahern 
1931b7cece76SArnaldo Carvalho de Melo 	/*
1932b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1933b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1934b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1935b7cece76SArnaldo Carvalho de Melo 	 */
1936b7cece76SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1937b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
19389e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1939b7cece76SArnaldo Carvalho de Melo 
1940b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
19418d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
19429e201442SArnaldo Carvalho de Melo 			if (dso__build_id_equal(self, kallsyms_build_id)) {
19439e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1944b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
19458d0591f6SArnaldo Carvalho de Melo 			}
19469e201442SArnaldo Carvalho de Melo 		}
1947dc8d6ab2SArnaldo Carvalho de Melo 		/*
1948dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1949dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1950dc8d6ab2SArnaldo Carvalho de Melo 		 */
19519e201442SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
19529e201442SArnaldo Carvalho de Melo 				  sbuild_id);
19539e201442SArnaldo Carvalho de Melo 
19549e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
19559e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
19563846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
19573846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
19588d0591f6SArnaldo Carvalho de Melo 			return -1;
19593846df2eSArnaldo Carvalho de Melo 		}
19608d0591f6SArnaldo Carvalho de Melo 
196119fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
196219fc2dedSArnaldo Carvalho de Melo 
1963dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
19643846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
19653846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
19669e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
1967dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
1968ef6ae724SArnaldo Carvalho de Melo 		}
1969dc8d6ab2SArnaldo Carvalho de Melo 	} else {
1970dc8d6ab2SArnaldo Carvalho de Melo 		/*
1971dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
1972dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
1973dc8d6ab2SArnaldo Carvalho de Melo 		 */
1974dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
1975dc8d6ab2SArnaldo Carvalho de Melo 	}
1976dc8d6ab2SArnaldo Carvalho de Melo 
1977dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
19789de89fe7SArnaldo Carvalho de Melo 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
19793846df2eSArnaldo Carvalho de Melo 	if (err > 0)
19803846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1981dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1982dc8d6ab2SArnaldo Carvalho de Melo 
1983439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1984cc612d81SArnaldo Carvalho de Melo out_fixup:
1985e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
1986dc8d6ab2SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup("[kernel.kallsyms]"));
19876a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
19886a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1989439d473bSArnaldo Carvalho de Melo 	}
199094cb9e38SArnaldo Carvalho de Melo 
199186470930SIngo Molnar 	return err;
199286470930SIngo Molnar }
199386470930SIngo Molnar 
1994a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1995a1645ce1SZhang, Yanmin 				symbol_filter_t filter)
1996a1645ce1SZhang, Yanmin {
1997a1645ce1SZhang, Yanmin 	int err;
1998a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
199923346f21SArnaldo Carvalho de Melo 	struct machine *machine;
2000a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2001a1645ce1SZhang, Yanmin 
2002a1645ce1SZhang, Yanmin 	if (!map->groups) {
2003a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
2004a1645ce1SZhang, Yanmin 		return -1;
2005a1645ce1SZhang, Yanmin 	}
200623346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
2007a1645ce1SZhang, Yanmin 
200823346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
2009a1645ce1SZhang, Yanmin 		/*
2010a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
2011a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
2012a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
2013a1645ce1SZhang, Yanmin 		 */
2014a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
2015a1645ce1SZhang, Yanmin 			err = dso__load_vmlinux(self, map,
2016a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
2017a1645ce1SZhang, Yanmin 			goto out_try_fixup;
2018a1645ce1SZhang, Yanmin 		}
2019a1645ce1SZhang, Yanmin 
2020a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
2021a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
2022a1645ce1SZhang, Yanmin 			return -1;
2023a1645ce1SZhang, Yanmin 	} else {
202423346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2025a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
2026a1645ce1SZhang, Yanmin 	}
2027a1645ce1SZhang, Yanmin 
2028a1645ce1SZhang, Yanmin 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
2029a1645ce1SZhang, Yanmin 	if (err > 0)
2030a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
2031a1645ce1SZhang, Yanmin 
2032a1645ce1SZhang, Yanmin out_try_fixup:
2033a1645ce1SZhang, Yanmin 	if (err > 0) {
2034a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
203548ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
203623346f21SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(path));
2037a1645ce1SZhang, Yanmin 		}
2038a1645ce1SZhang, Yanmin 		map__fixup_start(map);
2039a1645ce1SZhang, Yanmin 		map__fixup_end(map);
2040a1645ce1SZhang, Yanmin 	}
2041a1645ce1SZhang, Yanmin 
2042a1645ce1SZhang, Yanmin 	return err;
2043a1645ce1SZhang, Yanmin }
2044cd84c2acSFrederic Weisbecker 
2045b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
2046cd84c2acSFrederic Weisbecker {
2047b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
2048cd84c2acSFrederic Weisbecker }
2049cd84c2acSFrederic Weisbecker 
2050b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
2051cd84c2acSFrederic Weisbecker {
2052cd84c2acSFrederic Weisbecker 	struct dso *pos;
2053cd84c2acSFrederic Weisbecker 
2054b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
2055cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
2056cd84c2acSFrederic Weisbecker 			return pos;
2057cd84c2acSFrederic Weisbecker 	return NULL;
2058cd84c2acSFrederic Weisbecker }
2059cd84c2acSFrederic Weisbecker 
2060a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
2061cd84c2acSFrederic Weisbecker {
2062a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
2063cd84c2acSFrederic Weisbecker 
2064e4204992SArnaldo Carvalho de Melo 	if (!dso) {
206500a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
2066cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
2067a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
2068cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
2069cfc10d3bSArnaldo Carvalho de Melo 		}
2070e4204992SArnaldo Carvalho de Melo 	}
2071cd84c2acSFrederic Weisbecker 
2072cd84c2acSFrederic Weisbecker 	return dso;
2073cd84c2acSFrederic Weisbecker }
2074cd84c2acSFrederic Weisbecker 
20751f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2076cd84c2acSFrederic Weisbecker {
2077cd84c2acSFrederic Weisbecker 	struct dso *pos;
2078cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2079cd84c2acSFrederic Weisbecker 
208095011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
208195011c60SArnaldo Carvalho de Melo 		int i;
208295011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
2083cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
2084cd84c2acSFrederic Weisbecker 	}
2085cd84c2acSFrederic Weisbecker 
2086cbf69680SArnaldo Carvalho de Melo 	return ret;
2087cbf69680SArnaldo Carvalho de Melo }
2088cbf69680SArnaldo Carvalho de Melo 
2089cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
2090b0da954aSArnaldo Carvalho de Melo {
2091a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2092cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2093a1645ce1SZhang, Yanmin 
2094cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
209523346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2096cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2097cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
2098a1645ce1SZhang, Yanmin 	}
2099cbf69680SArnaldo Carvalho de Melo 
2100cbf69680SArnaldo Carvalho de Melo 	return ret;
2101b0da954aSArnaldo Carvalho de Melo }
2102b0da954aSArnaldo Carvalho de Melo 
210388d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
210488d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
21059e03eb2dSArnaldo Carvalho de Melo {
21069e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
21079e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
21089e03eb2dSArnaldo Carvalho de Melo 
2109b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
211088d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
211188d3d9b7SArnaldo Carvalho de Melo 			continue;
21129e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
21139e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
21149e03eb2dSArnaldo Carvalho de Melo 	}
21159e03eb2dSArnaldo Carvalho de Melo 	return ret;
21169e03eb2dSArnaldo Carvalho de Melo }
21179e03eb2dSArnaldo Carvalho de Melo 
2118f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
2119f869097eSArnaldo Carvalho de Melo {
2120f869097eSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
2121f869097eSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
2122f869097eSArnaldo Carvalho de Melo }
2123f869097eSArnaldo Carvalho de Melo 
2124cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
2125b0da954aSArnaldo Carvalho de Melo {
2126a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2127a1645ce1SZhang, Yanmin 	size_t ret = 0;
2128a1645ce1SZhang, Yanmin 
2129cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
213023346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2131f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2132a1645ce1SZhang, Yanmin 	}
2133a1645ce1SZhang, Yanmin 	return ret;
2134b0da954aSArnaldo Carvalho de Melo }
2135b0da954aSArnaldo Carvalho de Melo 
2136fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name)
2137fd1d908cSArnaldo Carvalho de Melo {
2138fd1d908cSArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
2139fd1d908cSArnaldo Carvalho de Melo 
2140fd1d908cSArnaldo Carvalho de Melo 	if (self != NULL) {
2141b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, "[kernel]");
2142a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_KERNEL;
2143fd1d908cSArnaldo Carvalho de Melo 	}
2144fd1d908cSArnaldo Carvalho de Melo 
2145fd1d908cSArnaldo Carvalho de Melo 	return self;
2146fd1d908cSArnaldo Carvalho de Melo }
2147fd1d908cSArnaldo Carvalho de Melo 
214823346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine,
2149a1645ce1SZhang, Yanmin 					const char *name)
2150fd1d908cSArnaldo Carvalho de Melo {
215148ea8f54SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
215248ea8f54SArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
2153a1645ce1SZhang, Yanmin 
2154a1645ce1SZhang, Yanmin 	if (self != NULL) {
2155a1645ce1SZhang, Yanmin 		dso__set_short_name(self, "[guest.kernel]");
2156a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_GUEST_KERNEL;
2157a1645ce1SZhang, Yanmin 	}
2158a1645ce1SZhang, Yanmin 
2159a1645ce1SZhang, Yanmin 	return self;
2160a1645ce1SZhang, Yanmin }
2161a1645ce1SZhang, Yanmin 
216223346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
2163a1645ce1SZhang, Yanmin {
2164a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2165a1645ce1SZhang, Yanmin 
216623346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2167a1645ce1SZhang, Yanmin 		return;
216823346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2169a1645ce1SZhang, Yanmin 	if (sysfs__read_build_id(path, self->build_id,
2170fd1d908cSArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
2171fd1d908cSArnaldo Carvalho de Melo 		self->has_build_id = true;
2172fd1d908cSArnaldo Carvalho de Melo }
2173fd1d908cSArnaldo Carvalho de Melo 
21745c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self)
2175cd84c2acSFrederic Weisbecker {
2176a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
2177a1645ce1SZhang, Yanmin 	struct dso *kernel;
2178cd84c2acSFrederic Weisbecker 
21795c0541d5SArnaldo Carvalho de Melo 	if (machine__is_host(self)) {
2180a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2181a1645ce1SZhang, Yanmin 		kernel = dso__new_kernel(vmlinux_name);
2182a1645ce1SZhang, Yanmin 	} else {
21835c0541d5SArnaldo Carvalho de Melo 		if (machine__is_default_guest(self))
2184a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
21855c0541d5SArnaldo Carvalho de Melo 		kernel = dso__new_guest_kernel(self, vmlinux_name);
21868d92c02aSArnaldo Carvalho de Melo 	}
2187cd84c2acSFrederic Weisbecker 
2188a1645ce1SZhang, Yanmin 	if (kernel != NULL) {
21895c0541d5SArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, self);
21905c0541d5SArnaldo Carvalho de Melo 		dsos__add(&self->kernel_dsos, kernel);
2191a1645ce1SZhang, Yanmin 	}
2192f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2193f1dfa0b1SArnaldo Carvalho de Melo }
2194f1dfa0b1SArnaldo Carvalho de Melo 
2195d214afbdSMing Lei struct process_args {
2196d214afbdSMing Lei 	u64 start;
2197d214afbdSMing Lei };
2198d214afbdSMing Lei 
2199d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name,
22003b01a413SArnaldo Carvalho de Melo 			     char type __used, u64 start, u64 end __used)
2201d214afbdSMing Lei {
2202d214afbdSMing Lei 	struct process_args *args = arg;
2203d214afbdSMing Lei 
2204d214afbdSMing Lei 	if (strchr(name, '['))
2205d214afbdSMing Lei 		return 0;
2206d214afbdSMing Lei 
2207d214afbdSMing Lei 	args->start = start;
2208d214afbdSMing Lei 	return 1;
2209d214afbdSMing Lei }
2210d214afbdSMing Lei 
2211d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */
2212d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine)
2213d214afbdSMing Lei {
2214d214afbdSMing Lei 	const char *filename;
2215d214afbdSMing Lei 	char path[PATH_MAX];
2216d214afbdSMing Lei 	struct process_args args;
2217d214afbdSMing Lei 
2218d214afbdSMing Lei 	if (machine__is_host(machine)) {
2219d214afbdSMing Lei 		filename = "/proc/kallsyms";
2220d214afbdSMing Lei 	} else {
2221d214afbdSMing Lei 		if (machine__is_default_guest(machine))
2222d214afbdSMing Lei 			filename = (char *)symbol_conf.default_guest_kallsyms;
2223d214afbdSMing Lei 		else {
2224d214afbdSMing Lei 			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2225d214afbdSMing Lei 			filename = path;
2226d214afbdSMing Lei 		}
2227d214afbdSMing Lei 	}
2228d214afbdSMing Lei 
2229d214afbdSMing Lei 	if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2230d214afbdSMing Lei 		return 0;
2231d214afbdSMing Lei 
2232d214afbdSMing Lei 	return args.start;
2233d214afbdSMing Lei }
2234d214afbdSMing Lei 
2235d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2236f1dfa0b1SArnaldo Carvalho de Melo {
2237de176489SArnaldo Carvalho de Melo 	enum map_type type;
2238d214afbdSMing Lei 	u64 start = machine__get_kernel_start_addr(self);
2239f1dfa0b1SArnaldo Carvalho de Melo 
2240de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
22419de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
22429de89fe7SArnaldo Carvalho de Melo 
2243d214afbdSMing Lei 		self->vmlinux_maps[type] = map__new2(start, kernel, type);
2244d28c6223SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2245f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2246f1dfa0b1SArnaldo Carvalho de Melo 
2247d28c6223SArnaldo Carvalho de Melo 		self->vmlinux_maps[type]->map_ip =
2248d28c6223SArnaldo Carvalho de Melo 			self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
22499de89fe7SArnaldo Carvalho de Melo 
2250d28c6223SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2251d28c6223SArnaldo Carvalho de Melo 		kmap->kmaps = &self->kmaps;
2252d28c6223SArnaldo Carvalho de Melo 		map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
2253f1dfa0b1SArnaldo Carvalho de Melo 	}
2254f1dfa0b1SArnaldo Carvalho de Melo 
2255f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
22562446042cSArnaldo Carvalho de Melo }
22572446042cSArnaldo Carvalho de Melo 
2258076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self)
2259076c6e45SArnaldo Carvalho de Melo {
2260076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
2261076c6e45SArnaldo Carvalho de Melo 
2262076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
2263076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
2264076c6e45SArnaldo Carvalho de Melo 
2265076c6e45SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2266076c6e45SArnaldo Carvalho de Melo 			continue;
2267076c6e45SArnaldo Carvalho de Melo 
2268076c6e45SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2269076c6e45SArnaldo Carvalho de Melo 		map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
2270076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
2271076c6e45SArnaldo Carvalho de Melo 			/*
2272076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
2273076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
2274076c6e45SArnaldo Carvalho de Melo 			 */
2275076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
2276076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
2277076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
2278076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
2279076c6e45SArnaldo Carvalho de Melo 			}
2280076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
2281076c6e45SArnaldo Carvalho de Melo 		}
2282076c6e45SArnaldo Carvalho de Melo 
2283076c6e45SArnaldo Carvalho de Melo 		map__delete(self->vmlinux_maps[type]);
2284076c6e45SArnaldo Carvalho de Melo 		self->vmlinux_maps[type] = NULL;
2285076c6e45SArnaldo Carvalho de Melo 	}
2286076c6e45SArnaldo Carvalho de Melo }
2287076c6e45SArnaldo Carvalho de Melo 
22885c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self)
22895c0541d5SArnaldo Carvalho de Melo {
22905c0541d5SArnaldo Carvalho de Melo 	struct dso *kernel = machine__create_kernel(self);
22915c0541d5SArnaldo Carvalho de Melo 
22925c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
22935c0541d5SArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(self, kernel) < 0)
22945c0541d5SArnaldo Carvalho de Melo 		return -1;
22955c0541d5SArnaldo Carvalho de Melo 
22965c0541d5SArnaldo Carvalho de Melo 	if (symbol_conf.use_modules && machine__create_modules(self) < 0)
22975c0541d5SArnaldo Carvalho de Melo 		pr_debug("Problems creating module maps, continuing anyway...\n");
22985c0541d5SArnaldo Carvalho de Melo 	/*
22995c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
23005c0541d5SArnaldo Carvalho de Melo 	 */
23015c0541d5SArnaldo Carvalho de Melo 	map_groups__fixup_end(&self->kmaps);
23025c0541d5SArnaldo Carvalho de Melo 	return 0;
23035c0541d5SArnaldo Carvalho de Melo }
23045c0541d5SArnaldo Carvalho de Melo 
2305cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
23062446042cSArnaldo Carvalho de Melo {
2307cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2308cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2309cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2310cc612d81SArnaldo Carvalho de Melo 	}
2311cc612d81SArnaldo Carvalho de Melo 
2312cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2313cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2314cc612d81SArnaldo Carvalho de Melo }
2315cc612d81SArnaldo Carvalho de Melo 
2316cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2317cc612d81SArnaldo Carvalho de Melo {
2318cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2319cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2320cc612d81SArnaldo Carvalho de Melo 
2321cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2322cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2323cc612d81SArnaldo Carvalho de Melo 		return -1;
2324cc612d81SArnaldo Carvalho de Melo 
2325cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2326cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2327cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2328cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2329cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2330cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2331cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2332cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2333ec5761eaSDavid Ahern 
2334ec5761eaSDavid Ahern 	/* only try running kernel version if no symfs was given */
2335ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2336ec5761eaSDavid Ahern 		return 0;
2337ec5761eaSDavid Ahern 
2338ec5761eaSDavid Ahern 	if (uname(&uts) < 0)
2339ec5761eaSDavid Ahern 		return -1;
2340ec5761eaSDavid Ahern 
2341cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2342cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2343cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2344cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2345cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2346cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2347cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2348cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2349cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2350cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2351cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2352cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2353cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2354cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2355cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2356cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2357cc612d81SArnaldo Carvalho de Melo 
2358cc612d81SArnaldo Carvalho de Melo 	return 0;
2359cc612d81SArnaldo Carvalho de Melo 
2360cc612d81SArnaldo Carvalho de Melo out_fail:
2361cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2362cc612d81SArnaldo Carvalho de Melo 	return -1;
2363cc612d81SArnaldo Carvalho de Melo }
2364cc612d81SArnaldo Carvalho de Melo 
23655ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp)
2366b0a9ab62SArnaldo Carvalho de Melo {
2367b0a9ab62SArnaldo Carvalho de Melo 	int i;
2368b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
23695ad90e4eSArnaldo Carvalho de Melo 	struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso;
23705ad90e4eSArnaldo Carvalho de Melo 
23715ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
23725ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
23735ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
23745ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
23755ad90e4eSArnaldo Carvalho de Melo 	}
2376b0a9ab62SArnaldo Carvalho de Melo 
2377b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
23785ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
23795ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
2380b0a9ab62SArnaldo Carvalho de Melo 
2381b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2382b0a9ab62SArnaldo Carvalho de Melo }
2383b0a9ab62SArnaldo Carvalho de Melo 
2384655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2385655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2386655000e7SArnaldo Carvalho de Melo {
2387655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2388655000e7SArnaldo Carvalho de Melo 		return 0;
2389655000e7SArnaldo Carvalho de Melo 
2390655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2391655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2392655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2393655000e7SArnaldo Carvalho de Melo 		return -1;
2394655000e7SArnaldo Carvalho de Melo 	}
2395655000e7SArnaldo Carvalho de Melo 	return 0;
2396655000e7SArnaldo Carvalho de Melo }
2397655000e7SArnaldo Carvalho de Melo 
239875be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2399cc612d81SArnaldo Carvalho de Melo {
2400ec5761eaSDavid Ahern 	const char *symfs;
2401ec5761eaSDavid Ahern 
240285e00b55SJovi Zhang 	if (symbol_conf.initialized)
240385e00b55SJovi Zhang 		return 0;
240485e00b55SJovi Zhang 
240595011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
240675be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
240775be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
240879406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2409b32d133aSArnaldo Carvalho de Melo 
241075be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2411cc612d81SArnaldo Carvalho de Melo 		return -1;
2412cc612d81SArnaldo Carvalho de Melo 
2413c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2414c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2415c410a338SArnaldo Carvalho de Melo 		return -1;
2416c410a338SArnaldo Carvalho de Melo 	}
2417c410a338SArnaldo Carvalho de Melo 
2418655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2419655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2420655000e7SArnaldo Carvalho de Melo 		return -1;
2421655000e7SArnaldo Carvalho de Melo 
2422655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2423655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2424655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2425655000e7SArnaldo Carvalho de Melo 
2426655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2427655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2428655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2429655000e7SArnaldo Carvalho de Melo 
2430ec5761eaSDavid Ahern 	/*
2431ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2432ec5761eaSDavid Ahern 	 * reset here for simplicity.
2433ec5761eaSDavid Ahern 	 */
2434ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2435ec5761eaSDavid Ahern 	if (symfs == NULL)
2436ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2437ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2438ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2439ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2440ec5761eaSDavid Ahern 		free((void *)symfs);
2441ec5761eaSDavid Ahern 
244285e00b55SJovi Zhang 	symbol_conf.initialized = true;
24434aa65636SArnaldo Carvalho de Melo 	return 0;
2444655000e7SArnaldo Carvalho de Melo 
2445655000e7SArnaldo Carvalho de Melo out_free_dso_list:
2446655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2447655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2448655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2449655000e7SArnaldo Carvalho de Melo 	return -1;
2450cc612d81SArnaldo Carvalho de Melo }
2451cc612d81SArnaldo Carvalho de Melo 
2452d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2453d65a458bSArnaldo Carvalho de Melo {
245485e00b55SJovi Zhang 	if (!symbol_conf.initialized)
245585e00b55SJovi Zhang 		return;
2456d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2457d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2458d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2459d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2460d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
246185e00b55SJovi Zhang 	symbol_conf.initialized = false;
2462d65a458bSArnaldo Carvalho de Melo }
2463d65a458bSArnaldo Carvalho de Melo 
2464d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
24654aa65636SArnaldo Carvalho de Melo {
2466d28c6223SArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(self, pid);
24679de89fe7SArnaldo Carvalho de Melo 
246823346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2469a1645ce1SZhang, Yanmin 		return -1;
24704aa65636SArnaldo Carvalho de Melo 
24715c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2472cd84c2acSFrederic Weisbecker }
24735aab621bSArnaldo Carvalho de Melo 
24745aab621bSArnaldo Carvalho de Melo static int hex(char ch)
24755aab621bSArnaldo Carvalho de Melo {
24765aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
24775aab621bSArnaldo Carvalho de Melo 		return ch - '0';
24785aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
24795aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
24805aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
24815aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
24825aab621bSArnaldo Carvalho de Melo 	return -1;
24835aab621bSArnaldo Carvalho de Melo }
24845aab621bSArnaldo Carvalho de Melo 
24855aab621bSArnaldo Carvalho de Melo /*
24865aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
24875aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
24885aab621bSArnaldo Carvalho de Melo  */
24895aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
24905aab621bSArnaldo Carvalho de Melo {
24915aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
24925aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
24935aab621bSArnaldo Carvalho de Melo 
24945aab621bSArnaldo Carvalho de Melo 	while (*p) {
24955aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
24965aab621bSArnaldo Carvalho de Melo 
24975aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
24985aab621bSArnaldo Carvalho de Melo 			break;
24995aab621bSArnaldo Carvalho de Melo 
25005aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
25015aab621bSArnaldo Carvalho de Melo 		p++;
25025aab621bSArnaldo Carvalho de Melo 	}
25035aab621bSArnaldo Carvalho de Melo 
25045aab621bSArnaldo Carvalho de Melo 	return p - ptr;
25055aab621bSArnaldo Carvalho de Melo }
25065aab621bSArnaldo Carvalho de Melo 
25075aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
25085aab621bSArnaldo Carvalho de Melo {
25095aab621bSArnaldo Carvalho de Melo 	char *p = s;
25105aab621bSArnaldo Carvalho de Melo 
25115aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
25125aab621bSArnaldo Carvalho de Melo 		*p++ = to;
25135aab621bSArnaldo Carvalho de Melo 
25145aab621bSArnaldo Carvalho de Melo 	return s;
25155aab621bSArnaldo Carvalho de Melo }
2516a1645ce1SZhang, Yanmin 
2517d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self)
2518a1645ce1SZhang, Yanmin {
2519a1645ce1SZhang, Yanmin 	int ret = 0;
2520a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2521a1645ce1SZhang, Yanmin 	int i, items = 0;
2522a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2523a1645ce1SZhang, Yanmin 	pid_t pid;
2524a1645ce1SZhang, Yanmin 
2525a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2526a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2527a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2528d28c6223SArnaldo Carvalho de Melo 		machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
2529a1645ce1SZhang, Yanmin 	}
2530a1645ce1SZhang, Yanmin 
2531a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2532a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2533a1645ce1SZhang, Yanmin 		if (items <= 0)
2534a1645ce1SZhang, Yanmin 			return -ENOENT;
2535a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2536a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2537a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2538a1645ce1SZhang, Yanmin 				continue;
2539a1645ce1SZhang, Yanmin 			}
2540a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2541a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2542a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2543a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2544a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2545a1645ce1SZhang, Yanmin 			if (ret) {
2546a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2547a1645ce1SZhang, Yanmin 				goto failure;
2548a1645ce1SZhang, Yanmin 			}
2549d28c6223SArnaldo Carvalho de Melo 			machines__create_kernel_maps(self, pid);
2550a1645ce1SZhang, Yanmin 		}
2551a1645ce1SZhang, Yanmin failure:
2552a1645ce1SZhang, Yanmin 		free(namelist);
2553a1645ce1SZhang, Yanmin 	}
2554a1645ce1SZhang, Yanmin 
2555a1645ce1SZhang, Yanmin 	return ret;
2556a1645ce1SZhang, Yanmin }
25575c0541d5SArnaldo Carvalho de Melo 
2558076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self)
2559076c6e45SArnaldo Carvalho de Melo {
2560076c6e45SArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
2561076c6e45SArnaldo Carvalho de Melo 
2562076c6e45SArnaldo Carvalho de Melo 	while (next) {
2563076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2564076c6e45SArnaldo Carvalho de Melo 
2565076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2566076c6e45SArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
2567076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2568076c6e45SArnaldo Carvalho de Melo 	}
2569076c6e45SArnaldo Carvalho de Melo }
2570076c6e45SArnaldo Carvalho de Melo 
25715c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename,
25725c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
25735c0541d5SArnaldo Carvalho de Melo {
25745c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
25755c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
25765c0541d5SArnaldo Carvalho de Melo 
25775c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
25785c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
25795c0541d5SArnaldo Carvalho de Melo 		/*
25805c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
25815c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
25825c0541d5SArnaldo Carvalho de Melo 		 * sections.
25835c0541d5SArnaldo Carvalho de Melo 		 */
25845c0541d5SArnaldo Carvalho de Melo 		__map_groups__fixup_end(&self->kmaps, type);
25855c0541d5SArnaldo Carvalho de Melo 	}
25865c0541d5SArnaldo Carvalho de Melo 
25875c0541d5SArnaldo Carvalho de Melo 	return ret;
25885c0541d5SArnaldo Carvalho de Melo }
25895c0541d5SArnaldo Carvalho de Melo 
25905c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type,
25915c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
25925c0541d5SArnaldo Carvalho de Melo {
25935c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
25945c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
25955c0541d5SArnaldo Carvalho de Melo 
25965c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
25975c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
25985c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
25995c0541d5SArnaldo Carvalho de Melo 	}
26005c0541d5SArnaldo Carvalho de Melo 
26015c0541d5SArnaldo Carvalho de Melo 	return ret;
26025c0541d5SArnaldo Carvalho de Melo }
2603