xref: /linux/tools/perf/util/symbol.c (revision 1eee78aea9252fabcd333805d5d9fa42a1bf9427)
15aab621bSArnaldo Carvalho de Melo #include <dirent.h>
25aab621bSArnaldo Carvalho de Melo #include <errno.h>
35aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
45aab621bSArnaldo Carvalho de Melo #include <stdio.h>
55aab621bSArnaldo Carvalho de Melo #include <string.h>
65aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
85aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
95aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
105aab621bSArnaldo Carvalho de Melo #include <unistd.h>
119486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
12b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
13e334c726SNamhyung Kim #include "util.h"
148a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1569d2591aSArnaldo Carvalho de Melo #include "machine.h"
1686470930SIngo Molnar #include "symbol.h"
175aab621bSArnaldo Carvalho de Melo #include "strlist.h"
18e03eaa40SDavid Ahern #include "intlist.h"
190a7e6d1bSNamhyung Kim #include "header.h"
2086470930SIngo Molnar 
2186470930SIngo Molnar #include <elf.h>
22f1617b40SArnaldo Carvalho de Melo #include <limits.h>
23c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h>
24439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
252cdbc46dSPeter Zijlstra 
26aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
279de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
28aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
29a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
303f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries;
313f067dcaSArnaldo Carvalho de Melo char **vmlinux_path;
32439d473bSArnaldo Carvalho de Melo 
3375be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
34b32d133aSArnaldo Carvalho de Melo 	.use_modules		= true,
35b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path	= true,
363e6a2a7fSStephane Eranian 	.annotate_src		= true,
37328ccdacSNamhyung Kim 	.demangle		= true,
38763122adSAvi Kivity 	.demangle_kernel	= false,
39e511db5eSNamhyung Kim 	.cumulate_callchain	= true,
40c8302367SJiri Olsa 	.show_hist_headers	= true,
41ec5761eaSDavid Ahern 	.symfs			= "",
42b32d133aSArnaldo Carvalho de Melo };
43b32d133aSArnaldo Carvalho de Melo 
4444f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = {
4544f24cb3SJiri Olsa 	DSO_BINARY_TYPE__KALLSYMS,
4644f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KALLSYMS,
4744f24cb3SJiri Olsa 	DSO_BINARY_TYPE__JAVA_JIT,
4844f24cb3SJiri Olsa 	DSO_BINARY_TYPE__DEBUGLINK,
4944f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
5044f24cb3SJiri Olsa 	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
5144f24cb3SJiri Olsa 	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
5244f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
5344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
5444f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KMODULE,
55c00c48fcSNamhyung Kim 	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
5644f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
57c00c48fcSNamhyung Kim 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
589cd00941SRicardo Ribalda Delgado 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
5944f24cb3SJiri Olsa 	DSO_BINARY_TYPE__NOT_FOUND,
6044f24cb3SJiri Olsa };
6144f24cb3SJiri Olsa 
62028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
6344f24cb3SJiri Olsa 
6436a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
656893d4eeSArnaldo Carvalho de Melo {
6631877908SAnton Blanchard 	symbol_type = toupper(symbol_type);
6731877908SAnton Blanchard 
686893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
696893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
706893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
71f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
7231877908SAnton Blanchard 		return symbol_type == 'D';
736893d4eeSArnaldo Carvalho de Melo 	default:
746893d4eeSArnaldo Carvalho de Melo 		return false;
756893d4eeSArnaldo Carvalho de Melo 	}
766893d4eeSArnaldo Carvalho de Melo }
776893d4eeSArnaldo Carvalho de Melo 
78694bf407SAnton Blanchard static int prefix_underscores_count(const char *str)
79694bf407SAnton Blanchard {
80694bf407SAnton Blanchard 	const char *tail = str;
81694bf407SAnton Blanchard 
82694bf407SAnton Blanchard 	while (*tail == '_')
83694bf407SAnton Blanchard 		tail++;
84694bf407SAnton Blanchard 
85694bf407SAnton Blanchard 	return tail - str;
86694bf407SAnton Blanchard }
87694bf407SAnton Blanchard 
88fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma,
89fb6d5942SNaveen N. Rao 				    struct symbol *symb __maybe_unused)
90fb6d5942SNaveen N. Rao {
91fb6d5942SNaveen N. Rao 	/* Avoid "SyS" kernel syscall aliases */
92fb6d5942SNaveen N. Rao 	if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
93fb6d5942SNaveen N. Rao 		return SYMBOL_B;
94fb6d5942SNaveen N. Rao 	if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
95fb6d5942SNaveen N. Rao 		return SYMBOL_B;
96fb6d5942SNaveen N. Rao 
97fb6d5942SNaveen N. Rao 	return SYMBOL_A;
98fb6d5942SNaveen N. Rao }
99694bf407SAnton Blanchard 
100694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
101694bf407SAnton Blanchard {
102694bf407SAnton Blanchard 	s64 a;
103694bf407SAnton Blanchard 	s64 b;
1043445432bSAdrian Hunter 	size_t na, nb;
105694bf407SAnton Blanchard 
106694bf407SAnton Blanchard 	/* Prefer a symbol with non zero length */
107694bf407SAnton Blanchard 	a = syma->end - syma->start;
108694bf407SAnton Blanchard 	b = symb->end - symb->start;
109694bf407SAnton Blanchard 	if ((b == 0) && (a > 0))
110694bf407SAnton Blanchard 		return SYMBOL_A;
111694bf407SAnton Blanchard 	else if ((a == 0) && (b > 0))
112694bf407SAnton Blanchard 		return SYMBOL_B;
113694bf407SAnton Blanchard 
114694bf407SAnton Blanchard 	/* Prefer a non weak symbol over a weak one */
115694bf407SAnton Blanchard 	a = syma->binding == STB_WEAK;
116694bf407SAnton Blanchard 	b = symb->binding == STB_WEAK;
117694bf407SAnton Blanchard 	if (b && !a)
118694bf407SAnton Blanchard 		return SYMBOL_A;
119694bf407SAnton Blanchard 	if (a && !b)
120694bf407SAnton Blanchard 		return SYMBOL_B;
121694bf407SAnton Blanchard 
122694bf407SAnton Blanchard 	/* Prefer a global symbol over a non global one */
123694bf407SAnton Blanchard 	a = syma->binding == STB_GLOBAL;
124694bf407SAnton Blanchard 	b = symb->binding == STB_GLOBAL;
125694bf407SAnton Blanchard 	if (a && !b)
126694bf407SAnton Blanchard 		return SYMBOL_A;
127694bf407SAnton Blanchard 	if (b && !a)
128694bf407SAnton Blanchard 		return SYMBOL_B;
129694bf407SAnton Blanchard 
130694bf407SAnton Blanchard 	/* Prefer a symbol with less underscores */
131694bf407SAnton Blanchard 	a = prefix_underscores_count(syma->name);
132694bf407SAnton Blanchard 	b = prefix_underscores_count(symb->name);
133694bf407SAnton Blanchard 	if (b > a)
134694bf407SAnton Blanchard 		return SYMBOL_A;
135694bf407SAnton Blanchard 	else if (a > b)
136694bf407SAnton Blanchard 		return SYMBOL_B;
137694bf407SAnton Blanchard 
1383445432bSAdrian Hunter 	/* Choose the symbol with the longest name */
1393445432bSAdrian Hunter 	na = strlen(syma->name);
1403445432bSAdrian Hunter 	nb = strlen(symb->name);
1413445432bSAdrian Hunter 	if (na > nb)
142694bf407SAnton Blanchard 		return SYMBOL_A;
1433445432bSAdrian Hunter 	else if (na < nb)
144694bf407SAnton Blanchard 		return SYMBOL_B;
1453445432bSAdrian Hunter 
146fb6d5942SNaveen N. Rao 	return arch__choose_best_symbol(syma, symb);
147694bf407SAnton Blanchard }
148694bf407SAnton Blanchard 
149e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols)
150694bf407SAnton Blanchard {
151694bf407SAnton Blanchard 	struct rb_node *nd;
152694bf407SAnton Blanchard 	struct symbol *curr, *next;
153694bf407SAnton Blanchard 
154694bf407SAnton Blanchard 	nd = rb_first(symbols);
155694bf407SAnton Blanchard 
156694bf407SAnton Blanchard 	while (nd) {
157694bf407SAnton Blanchard 		curr = rb_entry(nd, struct symbol, rb_node);
158694bf407SAnton Blanchard again:
159694bf407SAnton Blanchard 		nd = rb_next(&curr->rb_node);
160694bf407SAnton Blanchard 		next = rb_entry(nd, struct symbol, rb_node);
161694bf407SAnton Blanchard 
162694bf407SAnton Blanchard 		if (!nd)
163694bf407SAnton Blanchard 			break;
164694bf407SAnton Blanchard 
165694bf407SAnton Blanchard 		if (curr->start != next->start)
166694bf407SAnton Blanchard 			continue;
167694bf407SAnton Blanchard 
168694bf407SAnton Blanchard 		if (choose_best_symbol(curr, next) == SYMBOL_A) {
169694bf407SAnton Blanchard 			rb_erase(&next->rb_node, symbols);
170d4f74eb8SChenggang Qin 			symbol__delete(next);
171694bf407SAnton Blanchard 			goto again;
172694bf407SAnton Blanchard 		} else {
173694bf407SAnton Blanchard 			nd = rb_next(&curr->rb_node);
174694bf407SAnton Blanchard 			rb_erase(&curr->rb_node, symbols);
175d4f74eb8SChenggang Qin 			symbol__delete(curr);
176694bf407SAnton Blanchard 		}
177694bf407SAnton Blanchard 	}
178694bf407SAnton Blanchard }
179694bf407SAnton Blanchard 
180e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols)
181af427bf5SArnaldo Carvalho de Melo {
182aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(symbols);
1832e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
184af427bf5SArnaldo Carvalho de Melo 
185af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
186af427bf5SArnaldo Carvalho de Melo 		return;
187af427bf5SArnaldo Carvalho de Melo 
1882e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
1892e538c4aSArnaldo Carvalho de Melo 
190af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
1912e538c4aSArnaldo Carvalho de Melo 		prev = curr;
1922e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
193af427bf5SArnaldo Carvalho de Melo 
1943b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
1952c241bd3SArnaldo Carvalho de Melo 			prev->end = curr->start;
196af427bf5SArnaldo Carvalho de Melo 	}
197af427bf5SArnaldo Carvalho de Melo 
1982e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
1992e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
2002e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
2012e538c4aSArnaldo Carvalho de Melo }
2022e538c4aSArnaldo Carvalho de Melo 
203e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
204af427bf5SArnaldo Carvalho de Melo {
205*1eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
2064bb7123dSArnaldo Carvalho de Melo 	struct map *next, *curr;
207af427bf5SArnaldo Carvalho de Melo 
2084bb7123dSArnaldo Carvalho de Melo 	curr = maps__first(maps);
2094bb7123dSArnaldo Carvalho de Melo 	if (curr == NULL)
210af427bf5SArnaldo Carvalho de Melo 		return;
211af427bf5SArnaldo Carvalho de Melo 
2124bb7123dSArnaldo Carvalho de Melo 	for (next = map__next(curr); next; next = map__next(curr)) {
2134bb7123dSArnaldo Carvalho de Melo 		curr->end = next->start;
2144bb7123dSArnaldo Carvalho de Melo 		curr = next;
2152e538c4aSArnaldo Carvalho de Melo 	}
21690c83218SArnaldo Carvalho de Melo 
21790c83218SArnaldo Carvalho de Melo 	/*
21890c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
21990c83218SArnaldo Carvalho de Melo 	 * last map final address.
22090c83218SArnaldo Carvalho de Melo 	 */
2219d1faba5SIan Munsie 	curr->end = ~0ULL;
222af427bf5SArnaldo Carvalho de Melo }
223af427bf5SArnaldo Carvalho de Melo 
224e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
22586470930SIngo Molnar {
22686470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
227aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
228aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
229aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
23086470930SIngo Molnar 		return NULL;
23186470930SIngo Molnar 
23275be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
233aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
23436479484SArnaldo Carvalho de Melo 
235aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
2362c241bd3SArnaldo Carvalho de Melo 	sym->end     = len ? start + len : start;
237aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
238aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
239e4204992SArnaldo Carvalho de Melo 
240aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
241aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
242aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
243e4204992SArnaldo Carvalho de Melo 
244aeafcbafSArnaldo Carvalho de Melo 	return sym;
24586470930SIngo Molnar }
24686470930SIngo Molnar 
247aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
24886470930SIngo Molnar {
249aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
25086470930SIngo Molnar }
25186470930SIngo Molnar 
252cdd059d7SJiri Olsa size_t symbol__fprintf(struct symbol *sym, FILE *fp)
25386470930SIngo Molnar {
2549486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
255aeafcbafSArnaldo Carvalho de Melo 		       sym->start, sym->end,
256aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_GLOBAL ? 'g' :
257aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_LOCAL  ? 'l' : 'w',
258aeafcbafSArnaldo Carvalho de Melo 		       sym->name);
25986470930SIngo Molnar }
26086470930SIngo Molnar 
261a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym,
262a978f2abSAkihiro Nagai 				    const struct addr_location *al, FILE *fp)
263a978f2abSAkihiro Nagai {
264a978f2abSAkihiro Nagai 	unsigned long offset;
265a978f2abSAkihiro Nagai 	size_t length;
266a978f2abSAkihiro Nagai 
267a978f2abSAkihiro Nagai 	if (sym && sym->name) {
268a978f2abSAkihiro Nagai 		length = fprintf(fp, "%s", sym->name);
269a978f2abSAkihiro Nagai 		if (al) {
2700b8c25d9SDavid Ahern 			if (al->addr < sym->end)
271a978f2abSAkihiro Nagai 				offset = al->addr - sym->start;
2720b8c25d9SDavid Ahern 			else
2730b8c25d9SDavid Ahern 				offset = al->addr - al->map->start - sym->start;
274a978f2abSAkihiro Nagai 			length += fprintf(fp, "+0x%lx", offset);
275a978f2abSAkihiro Nagai 		}
276a978f2abSAkihiro Nagai 		return length;
277a978f2abSAkihiro Nagai 	} else
278a978f2abSAkihiro Nagai 		return fprintf(fp, "[unknown]");
279a978f2abSAkihiro Nagai }
280a978f2abSAkihiro Nagai 
281547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
282547a92e0SAkihiro Nagai {
283a978f2abSAkihiro Nagai 	return symbol__fprintf_symname_offs(sym, NULL, fp);
284547a92e0SAkihiro Nagai }
285547a92e0SAkihiro Nagai 
286cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols)
28786470930SIngo Molnar {
28886470930SIngo Molnar 	struct symbol *pos;
289aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
29086470930SIngo Molnar 
29186470930SIngo Molnar 	while (next) {
29286470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
29386470930SIngo Molnar 		next = rb_next(&pos->rb_node);
294aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
29500a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
29686470930SIngo Molnar 	}
29786470930SIngo Molnar }
29886470930SIngo Molnar 
299e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym)
30086470930SIngo Molnar {
301aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
30286470930SIngo Molnar 	struct rb_node *parent = NULL;
3039cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
30486470930SIngo Molnar 	struct symbol *s;
30586470930SIngo Molnar 
30686470930SIngo Molnar 	while (*p != NULL) {
30786470930SIngo Molnar 		parent = *p;
30886470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
30986470930SIngo Molnar 		if (ip < s->start)
31086470930SIngo Molnar 			p = &(*p)->rb_left;
31186470930SIngo Molnar 		else
31286470930SIngo Molnar 			p = &(*p)->rb_right;
31386470930SIngo Molnar 	}
31486470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
315aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
31686470930SIngo Molnar }
31786470930SIngo Molnar 
318aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
31986470930SIngo Molnar {
32086470930SIngo Molnar 	struct rb_node *n;
32186470930SIngo Molnar 
322aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
32386470930SIngo Molnar 		return NULL;
32486470930SIngo Molnar 
325aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
32686470930SIngo Molnar 
32786470930SIngo Molnar 	while (n) {
32886470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
32986470930SIngo Molnar 
33086470930SIngo Molnar 		if (ip < s->start)
33186470930SIngo Molnar 			n = n->rb_left;
3322c241bd3SArnaldo Carvalho de Melo 		else if (ip >= s->end)
33386470930SIngo Molnar 			n = n->rb_right;
33486470930SIngo Molnar 		else
33586470930SIngo Molnar 			return s;
33686470930SIngo Molnar 	}
33786470930SIngo Molnar 
33886470930SIngo Molnar 	return NULL;
33986470930SIngo Molnar }
34086470930SIngo Molnar 
3418e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols)
3428e0cf965SAdrian Hunter {
3438e0cf965SAdrian Hunter 	struct rb_node *n = rb_first(symbols);
3448e0cf965SAdrian Hunter 
3458e0cf965SAdrian Hunter 	if (n)
3468e0cf965SAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3478e0cf965SAdrian Hunter 
3488e0cf965SAdrian Hunter 	return NULL;
3498e0cf965SAdrian Hunter }
3508e0cf965SAdrian Hunter 
3519c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym)
3529c00a81bSAdrian Hunter {
3539c00a81bSAdrian Hunter 	struct rb_node *n = rb_next(&sym->rb_node);
3549c00a81bSAdrian Hunter 
3559c00a81bSAdrian Hunter 	if (n)
3569c00a81bSAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3579c00a81bSAdrian Hunter 
3589c00a81bSAdrian Hunter 	return NULL;
3599c00a81bSAdrian Hunter }
3609c00a81bSAdrian Hunter 
36179406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
36279406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
36379406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
36479406cd7SArnaldo Carvalho de Melo };
36579406cd7SArnaldo Carvalho de Melo 
366aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
36779406cd7SArnaldo Carvalho de Melo {
368aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
36979406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
37002a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
37102a9d037SRabin Vincent 
37202a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
37379406cd7SArnaldo Carvalho de Melo 
37479406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
37579406cd7SArnaldo Carvalho de Melo 		parent = *p;
37679406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
37779406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
37879406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
37979406cd7SArnaldo Carvalho de Melo 		else
38079406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
38179406cd7SArnaldo Carvalho de Melo 	}
38279406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
383aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
38479406cd7SArnaldo Carvalho de Melo }
38579406cd7SArnaldo Carvalho de Melo 
386aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
387aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
38879406cd7SArnaldo Carvalho de Melo {
38979406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
39079406cd7SArnaldo Carvalho de Melo 
39179406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
39279406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
393aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
39479406cd7SArnaldo Carvalho de Melo 	}
39579406cd7SArnaldo Carvalho de Melo }
39679406cd7SArnaldo Carvalho de Melo 
397aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
398aeafcbafSArnaldo Carvalho de Melo 					    const char *name)
39979406cd7SArnaldo Carvalho de Melo {
40079406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
4015bcaaca3SMartin Liška 	struct symbol_name_rb_node *s = NULL;
40279406cd7SArnaldo Carvalho de Melo 
403aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
40479406cd7SArnaldo Carvalho de Melo 		return NULL;
40579406cd7SArnaldo Carvalho de Melo 
406aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
40779406cd7SArnaldo Carvalho de Melo 
40879406cd7SArnaldo Carvalho de Melo 	while (n) {
40979406cd7SArnaldo Carvalho de Melo 		int cmp;
41079406cd7SArnaldo Carvalho de Melo 
41179406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
412031b84c4SNaveen N. Rao 		cmp = arch__compare_symbol_names(name, s->sym.name);
41379406cd7SArnaldo Carvalho de Melo 
41479406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
41579406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
41679406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
41779406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
41879406cd7SArnaldo Carvalho de Melo 		else
419de480999SNamhyung Kim 			break;
42079406cd7SArnaldo Carvalho de Melo 	}
42179406cd7SArnaldo Carvalho de Melo 
422de480999SNamhyung Kim 	if (n == NULL)
42379406cd7SArnaldo Carvalho de Melo 		return NULL;
424de480999SNamhyung Kim 
425de480999SNamhyung Kim 	/* return first symbol that has same name (if any) */
426de480999SNamhyung Kim 	for (n = rb_prev(n); n; n = rb_prev(n)) {
427de480999SNamhyung Kim 		struct symbol_name_rb_node *tmp;
428de480999SNamhyung Kim 
429de480999SNamhyung Kim 		tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
430031b84c4SNaveen N. Rao 		if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
431de480999SNamhyung Kim 			break;
432de480999SNamhyung Kim 
433de480999SNamhyung Kim 		s = tmp;
434de480999SNamhyung Kim 	}
435de480999SNamhyung Kim 
436de480999SNamhyung Kim 	return &s->sym;
43779406cd7SArnaldo Carvalho de Melo }
43879406cd7SArnaldo Carvalho de Melo 
439aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
44079406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
441fcf1203aSArnaldo Carvalho de Melo {
442aeafcbafSArnaldo Carvalho de Melo 	return symbols__find(&dso->symbols[type], addr);
443fcf1203aSArnaldo Carvalho de Melo }
444fcf1203aSArnaldo Carvalho de Melo 
4459c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
4468e0cf965SAdrian Hunter {
4478e0cf965SAdrian Hunter 	return symbols__first(&dso->symbols[type]);
4488e0cf965SAdrian Hunter }
4498e0cf965SAdrian Hunter 
4509c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym)
4519c00a81bSAdrian Hunter {
4529c00a81bSAdrian Hunter 	return symbols__next(sym);
4539c00a81bSAdrian Hunter }
4549c00a81bSAdrian Hunter 
45518bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym)
45618bd7264SArnaldo Carvalho de Melo {
45718bd7264SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
45818bd7264SArnaldo Carvalho de Melo 	struct rb_node *n = rb_next(&s->rb_node);
45918bd7264SArnaldo Carvalho de Melo 
46018bd7264SArnaldo Carvalho de Melo 	return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
46118bd7264SArnaldo Carvalho de Melo }
46218bd7264SArnaldo Carvalho de Melo 
46318bd7264SArnaldo Carvalho de Melo  /*
46418bd7264SArnaldo Carvalho de Melo   * Teturns first symbol that matched with @name.
46518bd7264SArnaldo Carvalho de Melo   */
466aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
46779406cd7SArnaldo Carvalho de Melo 					const char *name)
46879406cd7SArnaldo Carvalho de Melo {
469aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
47079406cd7SArnaldo Carvalho de Melo }
47179406cd7SArnaldo Carvalho de Melo 
472aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
47379406cd7SArnaldo Carvalho de Melo {
474aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
475aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
476aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
47779406cd7SArnaldo Carvalho de Melo }
47879406cd7SArnaldo Carvalho de Melo 
479aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso,
480aeafcbafSArnaldo Carvalho de Melo 				    enum map_type type, FILE *fp)
48190f18e63SSrikar Dronamraju {
48290f18e63SSrikar Dronamraju 	size_t ret = 0;
48390f18e63SSrikar Dronamraju 	struct rb_node *nd;
48490f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
48590f18e63SSrikar Dronamraju 
486aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
48790f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
48890f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
48990f18e63SSrikar Dronamraju 	}
49090f18e63SSrikar Dronamraju 
49190f18e63SSrikar Dronamraju 	return ret;
49290f18e63SSrikar Dronamraju }
49390f18e63SSrikar Dronamraju 
494316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg,
495316d70d6SAdrian Hunter 		   int (*process_module)(void *arg, const char *name,
496316d70d6SAdrian Hunter 					 u64 start))
497316d70d6SAdrian Hunter {
498316d70d6SAdrian Hunter 	char *line = NULL;
499316d70d6SAdrian Hunter 	size_t n;
500316d70d6SAdrian Hunter 	FILE *file;
501316d70d6SAdrian Hunter 	int err = 0;
502316d70d6SAdrian Hunter 
503316d70d6SAdrian Hunter 	file = fopen(filename, "r");
504316d70d6SAdrian Hunter 	if (file == NULL)
505316d70d6SAdrian Hunter 		return -1;
506316d70d6SAdrian Hunter 
507316d70d6SAdrian Hunter 	while (1) {
508316d70d6SAdrian Hunter 		char name[PATH_MAX];
509316d70d6SAdrian Hunter 		u64 start;
510316d70d6SAdrian Hunter 		char *sep;
511316d70d6SAdrian Hunter 		ssize_t line_len;
512316d70d6SAdrian Hunter 
513316d70d6SAdrian Hunter 		line_len = getline(&line, &n, file);
514316d70d6SAdrian Hunter 		if (line_len < 0) {
515316d70d6SAdrian Hunter 			if (feof(file))
516316d70d6SAdrian Hunter 				break;
517316d70d6SAdrian Hunter 			err = -1;
518316d70d6SAdrian Hunter 			goto out;
519316d70d6SAdrian Hunter 		}
520316d70d6SAdrian Hunter 
521316d70d6SAdrian Hunter 		if (!line) {
522316d70d6SAdrian Hunter 			err = -1;
523316d70d6SAdrian Hunter 			goto out;
524316d70d6SAdrian Hunter 		}
525316d70d6SAdrian Hunter 
526316d70d6SAdrian Hunter 		line[--line_len] = '\0'; /* \n */
527316d70d6SAdrian Hunter 
528316d70d6SAdrian Hunter 		sep = strrchr(line, 'x');
529316d70d6SAdrian Hunter 		if (sep == NULL)
530316d70d6SAdrian Hunter 			continue;
531316d70d6SAdrian Hunter 
532316d70d6SAdrian Hunter 		hex2u64(sep + 1, &start);
533316d70d6SAdrian Hunter 
534316d70d6SAdrian Hunter 		sep = strchr(line, ' ');
535316d70d6SAdrian Hunter 		if (sep == NULL)
536316d70d6SAdrian Hunter 			continue;
537316d70d6SAdrian Hunter 
538316d70d6SAdrian Hunter 		*sep = '\0';
539316d70d6SAdrian Hunter 
540316d70d6SAdrian Hunter 		scnprintf(name, sizeof(name), "[%s]", line);
541316d70d6SAdrian Hunter 
542316d70d6SAdrian Hunter 		err = process_module(arg, name, start);
543316d70d6SAdrian Hunter 		if (err)
544316d70d6SAdrian Hunter 			break;
545316d70d6SAdrian Hunter 	}
546316d70d6SAdrian Hunter out:
547316d70d6SAdrian Hunter 	free(line);
548316d70d6SAdrian Hunter 	fclose(file);
549316d70d6SAdrian Hunter 	return err;
550316d70d6SAdrian Hunter }
551316d70d6SAdrian Hunter 
552682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
553682b335aSArnaldo Carvalho de Melo 	struct map *map;
554682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
555682b335aSArnaldo Carvalho de Melo };
556682b335aSArnaldo Carvalho de Melo 
557e7110b9fSArnaldo Carvalho de Melo /*
558e7110b9fSArnaldo Carvalho de Melo  * These are symbols in the kernel image, so make sure that
559e7110b9fSArnaldo Carvalho de Melo  * sym is from a kernel DSO.
560e7110b9fSArnaldo Carvalho de Melo  */
56182d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym)
56282d1deb0SDavid Ahern {
56382d1deb0SDavid Ahern 	const char * const idle_symbols[] = {
56482d1deb0SDavid Ahern 		"cpu_idle",
565e0336ed6SArnaldo Carvalho de Melo 		"cpu_startup_entry",
56682d1deb0SDavid Ahern 		"intel_idle",
56782d1deb0SDavid Ahern 		"default_idle",
56882d1deb0SDavid Ahern 		"native_safe_halt",
56982d1deb0SDavid Ahern 		"enter_idle",
57082d1deb0SDavid Ahern 		"exit_idle",
57182d1deb0SDavid Ahern 		"mwait_idle",
57282d1deb0SDavid Ahern 		"mwait_idle_with_hints",
57382d1deb0SDavid Ahern 		"poll_idle",
57482d1deb0SDavid Ahern 		"ppc64_runlatch_off",
57582d1deb0SDavid Ahern 		"pseries_dedicated_idle_sleep",
57682d1deb0SDavid Ahern 		NULL
57782d1deb0SDavid Ahern 	};
57882d1deb0SDavid Ahern 
57982d1deb0SDavid Ahern 	int i;
58082d1deb0SDavid Ahern 
58182d1deb0SDavid Ahern 	if (!sym)
58282d1deb0SDavid Ahern 		return false;
58382d1deb0SDavid Ahern 
58482d1deb0SDavid Ahern 	for (i = 0; idle_symbols[i]; i++) {
58582d1deb0SDavid Ahern 		if (!strcmp(idle_symbols[i], sym->name))
58682d1deb0SDavid Ahern 			return true;
58782d1deb0SDavid Ahern 	}
58882d1deb0SDavid Ahern 
58982d1deb0SDavid Ahern 	return false;
59082d1deb0SDavid Ahern }
59182d1deb0SDavid Ahern 
592682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
59382151520SCody P Schafer 				       char type, u64 start)
594682b335aSArnaldo Carvalho de Melo {
595682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
596682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
597682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
598682b335aSArnaldo Carvalho de Melo 
599682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
600682b335aSArnaldo Carvalho de Melo 		return 0;
601682b335aSArnaldo Carvalho de Melo 
60282151520SCody P Schafer 	/*
60382151520SCody P Schafer 	 * module symbols are not sorted so we add all
60482151520SCody P Schafer 	 * symbols, setting length to 0, and rely on
60582151520SCody P Schafer 	 * symbols__fixup_end() to fix it up.
60682151520SCody P Schafer 	 */
60782151520SCody P Schafer 	sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
6082e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
609682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
61082164161SArnaldo Carvalho de Melo 	/*
61182164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6124e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
61382164161SArnaldo Carvalho de Melo 	 */
6144e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
615a1645ce1SZhang, Yanmin 
616682b335aSArnaldo Carvalho de Melo 	return 0;
6172e538c4aSArnaldo Carvalho de Melo }
6182e538c4aSArnaldo Carvalho de Melo 
619682b335aSArnaldo Carvalho de Melo /*
620682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
621682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
622682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
623682b335aSArnaldo Carvalho de Melo  */
624aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6259e201442SArnaldo Carvalho de Melo 				  struct map *map)
626682b335aSArnaldo Carvalho de Melo {
627aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6289e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6292e538c4aSArnaldo Carvalho de Melo }
6302e538c4aSArnaldo Carvalho de Melo 
6318e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
6328e0cf965SAdrian Hunter 					 symbol_filter_t filter)
6338e0cf965SAdrian Hunter {
634ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
6358e0cf965SAdrian Hunter 	struct map *curr_map;
6368e0cf965SAdrian Hunter 	struct symbol *pos;
6378e0cf965SAdrian Hunter 	int count = 0, moved = 0;
6388e0cf965SAdrian Hunter 	struct rb_root *root = &dso->symbols[map->type];
6398e0cf965SAdrian Hunter 	struct rb_node *next = rb_first(root);
6408e0cf965SAdrian Hunter 
641ba92732eSWang Nan 	if (!kmaps)
642ba92732eSWang Nan 		return -1;
643ba92732eSWang Nan 
6448e0cf965SAdrian Hunter 	while (next) {
6458e0cf965SAdrian Hunter 		char *module;
6468e0cf965SAdrian Hunter 
6478e0cf965SAdrian Hunter 		pos = rb_entry(next, struct symbol, rb_node);
6488e0cf965SAdrian Hunter 		next = rb_next(&pos->rb_node);
6498e0cf965SAdrian Hunter 
6508e0cf965SAdrian Hunter 		module = strchr(pos->name, '\t');
6518e0cf965SAdrian Hunter 		if (module)
6528e0cf965SAdrian Hunter 			*module = '\0';
6538e0cf965SAdrian Hunter 
6548e0cf965SAdrian Hunter 		curr_map = map_groups__find(kmaps, map->type, pos->start);
6558e0cf965SAdrian Hunter 
6568e0cf965SAdrian Hunter 		if (!curr_map || (filter && filter(curr_map, pos))) {
6578e0cf965SAdrian Hunter 			rb_erase(&pos->rb_node, root);
6588e0cf965SAdrian Hunter 			symbol__delete(pos);
6598e0cf965SAdrian Hunter 		} else {
6608e0cf965SAdrian Hunter 			pos->start -= curr_map->start - curr_map->pgoff;
6618e0cf965SAdrian Hunter 			if (pos->end)
6628e0cf965SAdrian Hunter 				pos->end -= curr_map->start - curr_map->pgoff;
6638e0cf965SAdrian Hunter 			if (curr_map != map) {
6648e0cf965SAdrian Hunter 				rb_erase(&pos->rb_node, root);
6658e0cf965SAdrian Hunter 				symbols__insert(
6668e0cf965SAdrian Hunter 					&curr_map->dso->symbols[curr_map->type],
6678e0cf965SAdrian Hunter 					pos);
6688e0cf965SAdrian Hunter 				++moved;
6698e0cf965SAdrian Hunter 			} else {
6708e0cf965SAdrian Hunter 				++count;
6718e0cf965SAdrian Hunter 			}
6728e0cf965SAdrian Hunter 		}
6738e0cf965SAdrian Hunter 	}
6748e0cf965SAdrian Hunter 
6758e0cf965SAdrian Hunter 	/* Symbols have been adjusted */
6768e0cf965SAdrian Hunter 	dso->adjust_symbols = 1;
6778e0cf965SAdrian Hunter 
6788e0cf965SAdrian Hunter 	return count + moved;
6798e0cf965SAdrian Hunter }
6808e0cf965SAdrian Hunter 
6812e538c4aSArnaldo Carvalho de Melo /*
6822e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
6832e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
6842e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
6852e538c4aSArnaldo Carvalho de Melo  */
686d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
6879de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
6882e538c4aSArnaldo Carvalho de Melo {
689ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
690ba92732eSWang Nan 	struct machine *machine;
6914e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
6922e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
6938a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
694aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
6954e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
6962e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
6972e538c4aSArnaldo Carvalho de Melo 
698ba92732eSWang Nan 	if (!kmaps)
699ba92732eSWang Nan 		return -1;
700ba92732eSWang Nan 
701ba92732eSWang Nan 	machine = kmaps->machine;
702ba92732eSWang Nan 
7032e538c4aSArnaldo Carvalho de Melo 	while (next) {
7042e538c4aSArnaldo Carvalho de Melo 		char *module;
7052e538c4aSArnaldo Carvalho de Melo 
7062e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
7072e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
7082e538c4aSArnaldo Carvalho de Melo 
7092e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
7102e538c4aSArnaldo Carvalho de Melo 		if (module) {
71175be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
7121de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
7131de8e245SArnaldo Carvalho de Melo 
7142e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
7152e538c4aSArnaldo Carvalho de Melo 
716b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
717a1645ce1SZhang, Yanmin 				if (curr_map != map &&
718aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
71923346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
720a1645ce1SZhang, Yanmin 					/*
721a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
722a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
723a1645ce1SZhang, Yanmin 					 * points to a module and all its
724a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
725a1645ce1SZhang, Yanmin 					 * loaded.
726a1645ce1SZhang, Yanmin 					 */
727a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
728a1645ce1SZhang, Yanmin 							curr_map->type);
729af427bf5SArnaldo Carvalho de Melo 				}
730b7cece76SArnaldo Carvalho de Melo 
731a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
732a1645ce1SZhang, Yanmin 							map->type, module);
733a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7342f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
735a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
736a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
73723346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
738a1645ce1SZhang, Yanmin 					curr_map = map;
739a1645ce1SZhang, Yanmin 					goto discard_symbol;
740a1645ce1SZhang, Yanmin 				}
741a1645ce1SZhang, Yanmin 
742a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
74323346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
744b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
745af427bf5SArnaldo Carvalho de Melo 			}
74686470930SIngo Molnar 			/*
7472e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
7482e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
74986470930SIngo Molnar 			 */
7504e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
7514e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
7524e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
7532e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
754aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
75586470930SIngo Molnar 
756d9b62abaSAdrian Hunter 			if (delta) {
757d9b62abaSAdrian Hunter 				/* Kernel was relocated at boot time */
758d9b62abaSAdrian Hunter 				pos->start -= delta;
759d9b62abaSAdrian Hunter 				pos->end -= delta;
760d9b62abaSAdrian Hunter 			}
761d9b62abaSAdrian Hunter 
7628a953312SArnaldo Carvalho de Melo 			if (count == 0) {
7638a953312SArnaldo Carvalho de Melo 				curr_map = map;
7648a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
7658a953312SArnaldo Carvalho de Melo 			}
7668a953312SArnaldo Carvalho de Melo 
767aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
768a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
769a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
770a1645ce1SZhang, Yanmin 					kernel_range++);
771a1645ce1SZhang, Yanmin 			else
772a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
773a1645ce1SZhang, Yanmin 					"[kernel].%d",
7742e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
77586470930SIngo Molnar 
776aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
777aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
7782e538c4aSArnaldo Carvalho de Melo 				return -1;
7792e538c4aSArnaldo Carvalho de Melo 
780aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
781a1645ce1SZhang, Yanmin 
782aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
78337fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
784aeafcbafSArnaldo Carvalho de Melo 				dso__delete(ndso);
7852e538c4aSArnaldo Carvalho de Melo 				return -1;
7862e538c4aSArnaldo Carvalho de Melo 			}
7872e538c4aSArnaldo Carvalho de Melo 
7884e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
7899de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
7902e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
791d9b62abaSAdrian Hunter 		} else if (delta) {
792d9b62abaSAdrian Hunter 			/* Kernel was relocated at boot time */
793d9b62abaSAdrian Hunter 			pos->start -= delta;
794d9b62abaSAdrian Hunter 			pos->end -= delta;
7952e538c4aSArnaldo Carvalho de Melo 		}
7968a953312SArnaldo Carvalho de Melo filter_symbol:
7974e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
7981de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
79900a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
8002e538c4aSArnaldo Carvalho de Melo 		} else {
8014e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
8024e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
8034e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
8048a953312SArnaldo Carvalho de Melo 				++moved;
8058a953312SArnaldo Carvalho de Melo 			} else
8068a953312SArnaldo Carvalho de Melo 				++count;
8079974f496SMike Galbraith 		}
80886470930SIngo Molnar 	}
80986470930SIngo Molnar 
810a1645ce1SZhang, Yanmin 	if (curr_map != map &&
811aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
81223346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
813a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
814a1645ce1SZhang, Yanmin 	}
815a1645ce1SZhang, Yanmin 
8168a953312SArnaldo Carvalho de Melo 	return count + moved;
81786470930SIngo Molnar }
81886470930SIngo Molnar 
8193f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename,
820ec80fde7SArnaldo Carvalho de Melo 				 const char *restricted_filename)
821ec80fde7SArnaldo Carvalho de Melo {
822ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
823ec80fde7SArnaldo Carvalho de Melo 
824ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
825ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
826ec80fde7SArnaldo Carvalho de Melo 
827ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
828ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
829ec80fde7SArnaldo Carvalho de Melo 			free(r);
830ec80fde7SArnaldo Carvalho de Melo 			return restricted;
831ec80fde7SArnaldo Carvalho de Melo 		}
832ec80fde7SArnaldo Carvalho de Melo 	}
833ec80fde7SArnaldo Carvalho de Melo 
834ec80fde7SArnaldo Carvalho de Melo 	return restricted;
835ec80fde7SArnaldo Carvalho de Melo }
836ec80fde7SArnaldo Carvalho de Melo 
83752afdaf9SAdrian Hunter struct module_info {
83852afdaf9SAdrian Hunter 	struct rb_node rb_node;
83952afdaf9SAdrian Hunter 	char *name;
84052afdaf9SAdrian Hunter 	u64 start;
84152afdaf9SAdrian Hunter };
84252afdaf9SAdrian Hunter 
84352afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules)
84452afdaf9SAdrian Hunter {
84552afdaf9SAdrian Hunter 	struct rb_node **p = &modules->rb_node;
84652afdaf9SAdrian Hunter 	struct rb_node *parent = NULL;
84752afdaf9SAdrian Hunter 	struct module_info *m;
84852afdaf9SAdrian Hunter 
84952afdaf9SAdrian Hunter 	while (*p != NULL) {
85052afdaf9SAdrian Hunter 		parent = *p;
85152afdaf9SAdrian Hunter 		m = rb_entry(parent, struct module_info, rb_node);
85252afdaf9SAdrian Hunter 		if (strcmp(mi->name, m->name) < 0)
85352afdaf9SAdrian Hunter 			p = &(*p)->rb_left;
85452afdaf9SAdrian Hunter 		else
85552afdaf9SAdrian Hunter 			p = &(*p)->rb_right;
85652afdaf9SAdrian Hunter 	}
85752afdaf9SAdrian Hunter 	rb_link_node(&mi->rb_node, parent, p);
85852afdaf9SAdrian Hunter 	rb_insert_color(&mi->rb_node, modules);
85952afdaf9SAdrian Hunter }
86052afdaf9SAdrian Hunter 
86152afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules)
86252afdaf9SAdrian Hunter {
86352afdaf9SAdrian Hunter 	struct module_info *mi;
86452afdaf9SAdrian Hunter 	struct rb_node *next = rb_first(modules);
86552afdaf9SAdrian Hunter 
86652afdaf9SAdrian Hunter 	while (next) {
86752afdaf9SAdrian Hunter 		mi = rb_entry(next, struct module_info, rb_node);
86852afdaf9SAdrian Hunter 		next = rb_next(&mi->rb_node);
86952afdaf9SAdrian Hunter 		rb_erase(&mi->rb_node, modules);
87074cf249dSArnaldo Carvalho de Melo 		zfree(&mi->name);
87152afdaf9SAdrian Hunter 		free(mi);
87252afdaf9SAdrian Hunter 	}
87352afdaf9SAdrian Hunter }
87452afdaf9SAdrian Hunter 
87552afdaf9SAdrian Hunter static struct module_info *find_module(const char *name,
87652afdaf9SAdrian Hunter 				       struct rb_root *modules)
87752afdaf9SAdrian Hunter {
87852afdaf9SAdrian Hunter 	struct rb_node *n = modules->rb_node;
87952afdaf9SAdrian Hunter 
88052afdaf9SAdrian Hunter 	while (n) {
88152afdaf9SAdrian Hunter 		struct module_info *m;
88252afdaf9SAdrian Hunter 		int cmp;
88352afdaf9SAdrian Hunter 
88452afdaf9SAdrian Hunter 		m = rb_entry(n, struct module_info, rb_node);
88552afdaf9SAdrian Hunter 		cmp = strcmp(name, m->name);
88652afdaf9SAdrian Hunter 		if (cmp < 0)
88752afdaf9SAdrian Hunter 			n = n->rb_left;
88852afdaf9SAdrian Hunter 		else if (cmp > 0)
88952afdaf9SAdrian Hunter 			n = n->rb_right;
89052afdaf9SAdrian Hunter 		else
89152afdaf9SAdrian Hunter 			return m;
89252afdaf9SAdrian Hunter 	}
89352afdaf9SAdrian Hunter 
89452afdaf9SAdrian Hunter 	return NULL;
89552afdaf9SAdrian Hunter }
89652afdaf9SAdrian Hunter 
89752afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start)
89852afdaf9SAdrian Hunter {
89952afdaf9SAdrian Hunter 	struct rb_root *modules = arg;
90052afdaf9SAdrian Hunter 	struct module_info *mi;
90152afdaf9SAdrian Hunter 
90252afdaf9SAdrian Hunter 	mi = zalloc(sizeof(struct module_info));
90352afdaf9SAdrian Hunter 	if (!mi)
90452afdaf9SAdrian Hunter 		return -ENOMEM;
90552afdaf9SAdrian Hunter 
90652afdaf9SAdrian Hunter 	mi->name = strdup(name);
90752afdaf9SAdrian Hunter 	mi->start = start;
90852afdaf9SAdrian Hunter 
90952afdaf9SAdrian Hunter 	if (!mi->name) {
91052afdaf9SAdrian Hunter 		free(mi);
91152afdaf9SAdrian Hunter 		return -ENOMEM;
91252afdaf9SAdrian Hunter 	}
91352afdaf9SAdrian Hunter 
91452afdaf9SAdrian Hunter 	add_module(mi, modules);
91552afdaf9SAdrian Hunter 
91652afdaf9SAdrian Hunter 	return 0;
91752afdaf9SAdrian Hunter }
91852afdaf9SAdrian Hunter 
91952afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules)
92052afdaf9SAdrian Hunter {
92152afdaf9SAdrian Hunter 	if (symbol__restricted_filename(filename, "/proc/modules"))
92252afdaf9SAdrian Hunter 		return -1;
92352afdaf9SAdrian Hunter 
92452afdaf9SAdrian Hunter 	if (modules__parse(filename, modules, __read_proc_modules)) {
92552afdaf9SAdrian Hunter 		delete_modules(modules);
92652afdaf9SAdrian Hunter 		return -1;
92752afdaf9SAdrian Hunter 	}
92852afdaf9SAdrian Hunter 
92952afdaf9SAdrian Hunter 	return 0;
93052afdaf9SAdrian Hunter }
93152afdaf9SAdrian Hunter 
932fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to)
933fc1b691dSAdrian Hunter {
934fc1b691dSAdrian Hunter 	struct rb_root from_modules = RB_ROOT;
935fc1b691dSAdrian Hunter 	struct rb_root to_modules = RB_ROOT;
936fc1b691dSAdrian Hunter 	struct rb_node *from_node, *to_node;
937fc1b691dSAdrian Hunter 	struct module_info *from_m, *to_m;
938fc1b691dSAdrian Hunter 	int ret = -1;
939fc1b691dSAdrian Hunter 
940fc1b691dSAdrian Hunter 	if (read_proc_modules(from, &from_modules))
941fc1b691dSAdrian Hunter 		return -1;
942fc1b691dSAdrian Hunter 
943fc1b691dSAdrian Hunter 	if (read_proc_modules(to, &to_modules))
944fc1b691dSAdrian Hunter 		goto out_delete_from;
945fc1b691dSAdrian Hunter 
946fc1b691dSAdrian Hunter 	from_node = rb_first(&from_modules);
947fc1b691dSAdrian Hunter 	to_node = rb_first(&to_modules);
948fc1b691dSAdrian Hunter 	while (from_node) {
949fc1b691dSAdrian Hunter 		if (!to_node)
950fc1b691dSAdrian Hunter 			break;
951fc1b691dSAdrian Hunter 
952fc1b691dSAdrian Hunter 		from_m = rb_entry(from_node, struct module_info, rb_node);
953fc1b691dSAdrian Hunter 		to_m = rb_entry(to_node, struct module_info, rb_node);
954fc1b691dSAdrian Hunter 
955fc1b691dSAdrian Hunter 		if (from_m->start != to_m->start ||
956fc1b691dSAdrian Hunter 		    strcmp(from_m->name, to_m->name))
957fc1b691dSAdrian Hunter 			break;
958fc1b691dSAdrian Hunter 
959fc1b691dSAdrian Hunter 		from_node = rb_next(from_node);
960fc1b691dSAdrian Hunter 		to_node = rb_next(to_node);
961fc1b691dSAdrian Hunter 	}
962fc1b691dSAdrian Hunter 
963fc1b691dSAdrian Hunter 	if (!from_node && !to_node)
964fc1b691dSAdrian Hunter 		ret = 0;
965fc1b691dSAdrian Hunter 
966fc1b691dSAdrian Hunter 	delete_modules(&to_modules);
967fc1b691dSAdrian Hunter out_delete_from:
968fc1b691dSAdrian Hunter 	delete_modules(&from_modules);
969fc1b691dSAdrian Hunter 
970fc1b691dSAdrian Hunter 	return ret;
971fc1b691dSAdrian Hunter }
972fc1b691dSAdrian Hunter 
97352afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map,
97452afdaf9SAdrian Hunter 				  struct map_groups *kmaps)
97552afdaf9SAdrian Hunter {
97652afdaf9SAdrian Hunter 	struct rb_root modules = RB_ROOT;
97752afdaf9SAdrian Hunter 	struct map *old_map;
97852afdaf9SAdrian Hunter 	int err;
97952afdaf9SAdrian Hunter 
98052afdaf9SAdrian Hunter 	err = read_proc_modules(filename, &modules);
98152afdaf9SAdrian Hunter 	if (err)
98252afdaf9SAdrian Hunter 		return err;
98352afdaf9SAdrian Hunter 
98452afdaf9SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
98552afdaf9SAdrian Hunter 	while (old_map) {
98652afdaf9SAdrian Hunter 		struct map *next = map_groups__next(old_map);
98752afdaf9SAdrian Hunter 		struct module_info *mi;
98852afdaf9SAdrian Hunter 
98952afdaf9SAdrian Hunter 		if (old_map == map || old_map->start == map->start) {
99052afdaf9SAdrian Hunter 			/* The kernel map */
99152afdaf9SAdrian Hunter 			old_map = next;
99252afdaf9SAdrian Hunter 			continue;
99352afdaf9SAdrian Hunter 		}
99452afdaf9SAdrian Hunter 
99552afdaf9SAdrian Hunter 		/* Module must be in memory at the same address */
99652afdaf9SAdrian Hunter 		mi = find_module(old_map->dso->short_name, &modules);
99752afdaf9SAdrian Hunter 		if (!mi || mi->start != old_map->start) {
99852afdaf9SAdrian Hunter 			err = -EINVAL;
99952afdaf9SAdrian Hunter 			goto out;
100052afdaf9SAdrian Hunter 		}
100152afdaf9SAdrian Hunter 
100252afdaf9SAdrian Hunter 		old_map = next;
100352afdaf9SAdrian Hunter 	}
100452afdaf9SAdrian Hunter out:
100552afdaf9SAdrian Hunter 	delete_modules(&modules);
100652afdaf9SAdrian Hunter 	return err;
100752afdaf9SAdrian Hunter }
100852afdaf9SAdrian Hunter 
100952afdaf9SAdrian Hunter /*
101052afdaf9SAdrian Hunter  * If kallsyms is referenced by name then we look for filename in the same
101152afdaf9SAdrian Hunter  * directory.
101252afdaf9SAdrian Hunter  */
101352afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename,
101452afdaf9SAdrian Hunter 					    const char *base_name,
101552afdaf9SAdrian Hunter 					    const char *kallsyms_filename)
101652afdaf9SAdrian Hunter {
101752afdaf9SAdrian Hunter 	char *name;
101852afdaf9SAdrian Hunter 
101952afdaf9SAdrian Hunter 	strcpy(filename, kallsyms_filename);
102052afdaf9SAdrian Hunter 	name = strrchr(filename, '/');
102152afdaf9SAdrian Hunter 	if (!name)
102252afdaf9SAdrian Hunter 		return false;
102352afdaf9SAdrian Hunter 
102452afdaf9SAdrian Hunter 	name += 1;
102552afdaf9SAdrian Hunter 
102652afdaf9SAdrian Hunter 	if (!strcmp(name, "kallsyms")) {
102752afdaf9SAdrian Hunter 		strcpy(name, base_name);
102852afdaf9SAdrian Hunter 		return true;
102952afdaf9SAdrian Hunter 	}
103052afdaf9SAdrian Hunter 
103152afdaf9SAdrian Hunter 	return false;
103252afdaf9SAdrian Hunter }
103352afdaf9SAdrian Hunter 
103452afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename,
103552afdaf9SAdrian Hunter 				  struct map *map)
103652afdaf9SAdrian Hunter {
1037ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
103852afdaf9SAdrian Hunter 	char modules_filename[PATH_MAX];
103952afdaf9SAdrian Hunter 
1040ba92732eSWang Nan 	if (!kmaps)
1041ba92732eSWang Nan 		return -EINVAL;
1042ba92732eSWang Nan 
104352afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(modules_filename, "modules",
104452afdaf9SAdrian Hunter 					     kallsyms_filename))
104552afdaf9SAdrian Hunter 		return -EINVAL;
104652afdaf9SAdrian Hunter 
104752afdaf9SAdrian Hunter 	if (do_validate_kcore_modules(modules_filename, map, kmaps))
104852afdaf9SAdrian Hunter 		return -EINVAL;
104952afdaf9SAdrian Hunter 
105052afdaf9SAdrian Hunter 	return 0;
105152afdaf9SAdrian Hunter }
105252afdaf9SAdrian Hunter 
1053a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename,
1054a00d28cbSAdrian Hunter 				    struct map *map)
1055a00d28cbSAdrian Hunter {
1056a00d28cbSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1057a00d28cbSAdrian Hunter 
1058ba92732eSWang Nan 	if (!kmap)
1059ba92732eSWang Nan 		return -EINVAL;
1060ba92732eSWang Nan 
1061a00d28cbSAdrian Hunter 	if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1062a00d28cbSAdrian Hunter 		u64 start;
1063a00d28cbSAdrian Hunter 
1064a00d28cbSAdrian Hunter 		start = kallsyms__get_function_start(kallsyms_filename,
1065a00d28cbSAdrian Hunter 						     kmap->ref_reloc_sym->name);
1066a00d28cbSAdrian Hunter 		if (start != kmap->ref_reloc_sym->addr)
1067a00d28cbSAdrian Hunter 			return -EINVAL;
1068a00d28cbSAdrian Hunter 	}
1069a00d28cbSAdrian Hunter 
1070a00d28cbSAdrian Hunter 	return validate_kcore_modules(kallsyms_filename, map);
1071a00d28cbSAdrian Hunter }
1072a00d28cbSAdrian Hunter 
10738e0cf965SAdrian Hunter struct kcore_mapfn_data {
10748e0cf965SAdrian Hunter 	struct dso *dso;
10758e0cf965SAdrian Hunter 	enum map_type type;
10768e0cf965SAdrian Hunter 	struct list_head maps;
10778e0cf965SAdrian Hunter };
10788e0cf965SAdrian Hunter 
10798e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
10808e0cf965SAdrian Hunter {
10818e0cf965SAdrian Hunter 	struct kcore_mapfn_data *md = data;
10828e0cf965SAdrian Hunter 	struct map *map;
10838e0cf965SAdrian Hunter 
10848e0cf965SAdrian Hunter 	map = map__new2(start, md->dso, md->type);
10858e0cf965SAdrian Hunter 	if (map == NULL)
10868e0cf965SAdrian Hunter 		return -ENOMEM;
10878e0cf965SAdrian Hunter 
10888e0cf965SAdrian Hunter 	map->end = map->start + len;
10898e0cf965SAdrian Hunter 	map->pgoff = pgoff;
10908e0cf965SAdrian Hunter 
10918e0cf965SAdrian Hunter 	list_add(&map->node, &md->maps);
10928e0cf965SAdrian Hunter 
10938e0cf965SAdrian Hunter 	return 0;
10948e0cf965SAdrian Hunter }
10958e0cf965SAdrian Hunter 
10968e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map,
10978e0cf965SAdrian Hunter 			   const char *kallsyms_filename)
10988e0cf965SAdrian Hunter {
1099ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
1100ba92732eSWang Nan 	struct machine *machine;
11018e0cf965SAdrian Hunter 	struct kcore_mapfn_data md;
11028e0cf965SAdrian Hunter 	struct map *old_map, *new_map, *replacement_map = NULL;
11038e0cf965SAdrian Hunter 	bool is_64_bit;
11048e0cf965SAdrian Hunter 	int err, fd;
11058e0cf965SAdrian Hunter 	char kcore_filename[PATH_MAX];
11068e0cf965SAdrian Hunter 	struct symbol *sym;
11078e0cf965SAdrian Hunter 
1108ba92732eSWang Nan 	if (!kmaps)
1109ba92732eSWang Nan 		return -EINVAL;
1110ba92732eSWang Nan 
1111ba92732eSWang Nan 	machine = kmaps->machine;
1112ba92732eSWang Nan 
11138e0cf965SAdrian Hunter 	/* This function requires that the map is the kernel map */
11148e0cf965SAdrian Hunter 	if (map != machine->vmlinux_maps[map->type])
11158e0cf965SAdrian Hunter 		return -EINVAL;
11168e0cf965SAdrian Hunter 
111752afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
11188e0cf965SAdrian Hunter 					     kallsyms_filename))
11198e0cf965SAdrian Hunter 		return -EINVAL;
11208e0cf965SAdrian Hunter 
1121a00d28cbSAdrian Hunter 	/* Modules and kernel must be present at their original addresses */
1122a00d28cbSAdrian Hunter 	if (validate_kcore_addresses(kallsyms_filename, map))
112352afdaf9SAdrian Hunter 		return -EINVAL;
112452afdaf9SAdrian Hunter 
11258e0cf965SAdrian Hunter 	md.dso = dso;
11268e0cf965SAdrian Hunter 	md.type = map->type;
11278e0cf965SAdrian Hunter 	INIT_LIST_HEAD(&md.maps);
11288e0cf965SAdrian Hunter 
11298e0cf965SAdrian Hunter 	fd = open(kcore_filename, O_RDONLY);
11308e0cf965SAdrian Hunter 	if (fd < 0)
11318e0cf965SAdrian Hunter 		return -EINVAL;
11328e0cf965SAdrian Hunter 
11338e0cf965SAdrian Hunter 	/* Read new maps into temporary lists */
11348e0cf965SAdrian Hunter 	err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
11358e0cf965SAdrian Hunter 			      &is_64_bit);
11368e0cf965SAdrian Hunter 	if (err)
11378e0cf965SAdrian Hunter 		goto out_err;
1138c6d8f2a4SAdrian Hunter 	dso->is_64_bit = is_64_bit;
11398e0cf965SAdrian Hunter 
11408e0cf965SAdrian Hunter 	if (list_empty(&md.maps)) {
11418e0cf965SAdrian Hunter 		err = -EINVAL;
11428e0cf965SAdrian Hunter 		goto out_err;
11438e0cf965SAdrian Hunter 	}
11448e0cf965SAdrian Hunter 
11458e0cf965SAdrian Hunter 	/* Remove old maps */
11468e0cf965SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
11478e0cf965SAdrian Hunter 	while (old_map) {
11488e0cf965SAdrian Hunter 		struct map *next = map_groups__next(old_map);
11498e0cf965SAdrian Hunter 
11508e0cf965SAdrian Hunter 		if (old_map != map)
11518e0cf965SAdrian Hunter 			map_groups__remove(kmaps, old_map);
11528e0cf965SAdrian Hunter 		old_map = next;
11538e0cf965SAdrian Hunter 	}
11548e0cf965SAdrian Hunter 
11558e0cf965SAdrian Hunter 	/* Find the kernel map using the first symbol */
11568e0cf965SAdrian Hunter 	sym = dso__first_symbol(dso, map->type);
11578e0cf965SAdrian Hunter 	list_for_each_entry(new_map, &md.maps, node) {
11588e0cf965SAdrian Hunter 		if (sym && sym->start >= new_map->start &&
11598e0cf965SAdrian Hunter 		    sym->start < new_map->end) {
11608e0cf965SAdrian Hunter 			replacement_map = new_map;
11618e0cf965SAdrian Hunter 			break;
11628e0cf965SAdrian Hunter 		}
11638e0cf965SAdrian Hunter 	}
11648e0cf965SAdrian Hunter 
11658e0cf965SAdrian Hunter 	if (!replacement_map)
11668e0cf965SAdrian Hunter 		replacement_map = list_entry(md.maps.next, struct map, node);
11678e0cf965SAdrian Hunter 
11688e0cf965SAdrian Hunter 	/* Add new maps */
11698e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
11708e0cf965SAdrian Hunter 		new_map = list_entry(md.maps.next, struct map, node);
11718e0cf965SAdrian Hunter 		list_del(&new_map->node);
11728e0cf965SAdrian Hunter 		if (new_map == replacement_map) {
11738e0cf965SAdrian Hunter 			map->start	= new_map->start;
11748e0cf965SAdrian Hunter 			map->end	= new_map->end;
11758e0cf965SAdrian Hunter 			map->pgoff	= new_map->pgoff;
11768e0cf965SAdrian Hunter 			map->map_ip	= new_map->map_ip;
11778e0cf965SAdrian Hunter 			map->unmap_ip	= new_map->unmap_ip;
11788e0cf965SAdrian Hunter 			map__delete(new_map);
11798e0cf965SAdrian Hunter 			/* Ensure maps are correctly ordered */
11808e0cf965SAdrian Hunter 			map_groups__remove(kmaps, map);
11818e0cf965SAdrian Hunter 			map_groups__insert(kmaps, map);
11828e0cf965SAdrian Hunter 		} else {
11838e0cf965SAdrian Hunter 			map_groups__insert(kmaps, new_map);
11848e0cf965SAdrian Hunter 		}
11858e0cf965SAdrian Hunter 	}
11868e0cf965SAdrian Hunter 
11878e0cf965SAdrian Hunter 	/*
11888e0cf965SAdrian Hunter 	 * Set the data type and long name so that kcore can be read via
11898e0cf965SAdrian Hunter 	 * dso__data_read_addr().
11908e0cf965SAdrian Hunter 	 */
11918e0cf965SAdrian Hunter 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
11925f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
11938e0cf965SAdrian Hunter 	else
11945f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__KCORE;
11957e155d4dSArnaldo Carvalho de Melo 	dso__set_long_name(dso, strdup(kcore_filename), true);
11968e0cf965SAdrian Hunter 
11978e0cf965SAdrian Hunter 	close(fd);
11988e0cf965SAdrian Hunter 
11998e0cf965SAdrian Hunter 	if (map->type == MAP__FUNCTION)
12008e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel object code\n", kcore_filename);
12018e0cf965SAdrian Hunter 	else
12028e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel data\n", kcore_filename);
12038e0cf965SAdrian Hunter 
12048e0cf965SAdrian Hunter 	return 0;
12058e0cf965SAdrian Hunter 
12068e0cf965SAdrian Hunter out_err:
12078e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
12088e0cf965SAdrian Hunter 		map = list_entry(md.maps.next, struct map, node);
12098e0cf965SAdrian Hunter 		list_del(&map->node);
12108e0cf965SAdrian Hunter 		map__delete(map);
12118e0cf965SAdrian Hunter 	}
12128e0cf965SAdrian Hunter 	close(fd);
12138e0cf965SAdrian Hunter 	return -EINVAL;
12148e0cf965SAdrian Hunter }
12158e0cf965SAdrian Hunter 
1216d9b62abaSAdrian Hunter /*
1217d9b62abaSAdrian Hunter  * If the kernel is relocated at boot time, kallsyms won't match.  Compute the
1218d9b62abaSAdrian Hunter  * delta based on the relocation reference symbol.
1219d9b62abaSAdrian Hunter  */
1220d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1221d9b62abaSAdrian Hunter {
1222d9b62abaSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1223d9b62abaSAdrian Hunter 	u64 addr;
1224d9b62abaSAdrian Hunter 
1225ba92732eSWang Nan 	if (!kmap)
1226ba92732eSWang Nan 		return -1;
1227ba92732eSWang Nan 
1228d9b62abaSAdrian Hunter 	if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1229d9b62abaSAdrian Hunter 		return 0;
1230d9b62abaSAdrian Hunter 
1231d9b62abaSAdrian Hunter 	addr = kallsyms__get_function_start(filename,
1232d9b62abaSAdrian Hunter 					    kmap->ref_reloc_sym->name);
1233d9b62abaSAdrian Hunter 	if (!addr)
1234d9b62abaSAdrian Hunter 		return -1;
1235d9b62abaSAdrian Hunter 
1236d9b62abaSAdrian Hunter 	*delta = addr - kmap->ref_reloc_sym->addr;
1237d9b62abaSAdrian Hunter 	return 0;
1238d9b62abaSAdrian Hunter }
1239d9b62abaSAdrian Hunter 
1240aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
12419de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
12422e538c4aSArnaldo Carvalho de Melo {
1243d9b62abaSAdrian Hunter 	u64 delta = 0;
1244d9b62abaSAdrian Hunter 
1245ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1246ec80fde7SArnaldo Carvalho de Melo 		return -1;
1247ec80fde7SArnaldo Carvalho de Melo 
1248aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
12492e538c4aSArnaldo Carvalho de Melo 		return -1;
12502e538c4aSArnaldo Carvalho de Melo 
1251d9b62abaSAdrian Hunter 	if (kallsyms__delta(map, filename, &delta))
1252d9b62abaSAdrian Hunter 		return -1;
1253d9b62abaSAdrian Hunter 
1254694bf407SAnton Blanchard 	symbols__fixup_duplicate(&dso->symbols[map->type]);
12553f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
12563f5a4272SAnton Blanchard 
1257aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
125844f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1259a1645ce1SZhang, Yanmin 	else
126044f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
12612e538c4aSArnaldo Carvalho de Melo 
12628e0cf965SAdrian Hunter 	if (!dso__load_kcore(dso, map, filename))
12638e0cf965SAdrian Hunter 		return dso__split_kallsyms_for_kcore(dso, map, filter);
12648e0cf965SAdrian Hunter 	else
1265d9b62abaSAdrian Hunter 		return dso__split_kallsyms(dso, map, delta, filter);
1266af427bf5SArnaldo Carvalho de Melo }
1267af427bf5SArnaldo Carvalho de Melo 
1268aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
12696beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
127080d496beSPekka Enberg {
127180d496beSPekka Enberg 	char *line = NULL;
127280d496beSPekka Enberg 	size_t n;
127380d496beSPekka Enberg 	FILE *file;
127480d496beSPekka Enberg 	int nr_syms = 0;
127580d496beSPekka Enberg 
1276aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
127780d496beSPekka Enberg 	if (file == NULL)
127880d496beSPekka Enberg 		goto out_failure;
127980d496beSPekka Enberg 
128080d496beSPekka Enberg 	while (!feof(file)) {
12819cffa8d5SPaul Mackerras 		u64 start, size;
128280d496beSPekka Enberg 		struct symbol *sym;
128380d496beSPekka Enberg 		int line_len, len;
128480d496beSPekka Enberg 
128580d496beSPekka Enberg 		line_len = getline(&line, &n, file);
128680d496beSPekka Enberg 		if (line_len < 0)
128780d496beSPekka Enberg 			break;
128880d496beSPekka Enberg 
128980d496beSPekka Enberg 		if (!line)
129080d496beSPekka Enberg 			goto out_failure;
129180d496beSPekka Enberg 
129280d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
129380d496beSPekka Enberg 
129480d496beSPekka Enberg 		len = hex2u64(line, &start);
129580d496beSPekka Enberg 
129680d496beSPekka Enberg 		len++;
129780d496beSPekka Enberg 		if (len + 2 >= line_len)
129880d496beSPekka Enberg 			continue;
129980d496beSPekka Enberg 
130080d496beSPekka Enberg 		len += hex2u64(line + len, &size);
130180d496beSPekka Enberg 
130280d496beSPekka Enberg 		len++;
130380d496beSPekka Enberg 		if (len + 2 >= line_len)
130480d496beSPekka Enberg 			continue;
130580d496beSPekka Enberg 
1306c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
130780d496beSPekka Enberg 
130880d496beSPekka Enberg 		if (sym == NULL)
130980d496beSPekka Enberg 			goto out_delete_line;
131080d496beSPekka Enberg 
1311439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
131200a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
131380d496beSPekka Enberg 		else {
1314aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
131580d496beSPekka Enberg 			nr_syms++;
131680d496beSPekka Enberg 		}
131780d496beSPekka Enberg 	}
131880d496beSPekka Enberg 
131980d496beSPekka Enberg 	free(line);
132080d496beSPekka Enberg 	fclose(file);
132180d496beSPekka Enberg 
132280d496beSPekka Enberg 	return nr_syms;
132380d496beSPekka Enberg 
132480d496beSPekka Enberg out_delete_line:
132580d496beSPekka Enberg 	free(line);
132680d496beSPekka Enberg out_failure:
132780d496beSPekka Enberg 	return -1;
132880d496beSPekka Enberg }
132980d496beSPekka Enberg 
13301029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
13311029f9feSNamhyung Kim 					   enum dso_binary_type type)
13321029f9feSNamhyung Kim {
13331029f9feSNamhyung Kim 	switch (type) {
13341029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__JAVA_JIT:
13351029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__DEBUGLINK:
13361029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
13371029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
13381029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
13391029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
13401029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
13411029f9feSNamhyung Kim 		return !kmod && dso->kernel == DSO_TYPE_USER;
13421029f9feSNamhyung Kim 
13431029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KALLSYMS:
13441029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__VMLINUX:
13451029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KCORE:
13461029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_KERNEL;
13471029f9feSNamhyung Kim 
13481029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
13491029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
13501029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KCORE:
13511029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
13521029f9feSNamhyung Kim 
13531029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE:
1354c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
13551029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1356c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
13571029f9feSNamhyung Kim 		/*
13581029f9feSNamhyung Kim 		 * kernel modules know their symtab type - it's set when
13591029f9feSNamhyung Kim 		 * creating a module dso in machine__new_module().
13601029f9feSNamhyung Kim 		 */
13611029f9feSNamhyung Kim 		return kmod && dso->symtab_type == type;
13621029f9feSNamhyung Kim 
13631029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
13641029f9feSNamhyung Kim 		return true;
13651029f9feSNamhyung Kim 
13661029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__NOT_FOUND:
13671029f9feSNamhyung Kim 	default:
13681029f9feSNamhyung Kim 		return false;
13691029f9feSNamhyung Kim 	}
13701029f9feSNamhyung Kim }
13711029f9feSNamhyung Kim 
1372aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
137386470930SIngo Molnar {
1374c338aee8SArnaldo Carvalho de Melo 	char *name;
137586470930SIngo Molnar 	int ret = -1;
137644f24cb3SJiri Olsa 	u_int i;
137723346f21SArnaldo Carvalho de Melo 	struct machine *machine;
137844f24cb3SJiri Olsa 	char *root_dir = (char *) "";
13793aafe5aeSCody P Schafer 	int ss_pos = 0;
13803aafe5aeSCody P Schafer 	struct symsrc ss_[2];
13813aafe5aeSCody P Schafer 	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
13821029f9feSNamhyung Kim 	bool kmod;
138386470930SIngo Molnar 
13844a936edcSNamhyung Kim 	pthread_mutex_lock(&dso->lock);
138566bd8424SArnaldo Carvalho de Melo 
13864a936edcSNamhyung Kim 	/* check again under the dso->lock */
13874a936edcSNamhyung Kim 	if (dso__loaded(dso, map->type)) {
13884a936edcSNamhyung Kim 		ret = 1;
13894a936edcSNamhyung Kim 		goto out;
13904a936edcSNamhyung Kim 	}
13914a936edcSNamhyung Kim 
13924a936edcSNamhyung Kim 	if (dso->kernel) {
1393aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel == DSO_TYPE_KERNEL)
13944a936edcSNamhyung Kim 			ret = dso__load_kernel_sym(dso, map, filter);
1395aeafcbafSArnaldo Carvalho de Melo 		else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
13964a936edcSNamhyung Kim 			ret = dso__load_guest_kernel_sym(dso, map, filter);
13974a936edcSNamhyung Kim 
13984a936edcSNamhyung Kim 		goto out;
13994a936edcSNamhyung Kim 	}
1400a1645ce1SZhang, Yanmin 
140123346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
140223346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1403a1645ce1SZhang, Yanmin 	else
140423346f21SArnaldo Carvalho de Melo 		machine = NULL;
1405c338aee8SArnaldo Carvalho de Melo 
1406aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1407f5812a7aSArnaldo Carvalho de Melo 
1408aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1409981c1252SPekka Enberg 		struct stat st;
1410981c1252SPekka Enberg 
1411e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
14124a936edcSNamhyung Kim 			goto out;
1413981c1252SPekka Enberg 
1414981c1252SPekka Enberg 		if (st.st_uid && (st.st_uid != geteuid())) {
1415981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1416981c1252SPekka Enberg 				"ignoring it.\n", dso->name);
14174a936edcSNamhyung Kim 			goto out;
1418981c1252SPekka Enberg 		}
1419981c1252SPekka Enberg 
1420aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
142144f24cb3SJiri Olsa 		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
142244f24cb3SJiri Olsa 					     DSO_BINARY_TYPE__NOT_FOUND;
14234a936edcSNamhyung Kim 		goto out;
142494cb9e38SArnaldo Carvalho de Melo 	}
142594cb9e38SArnaldo Carvalho de Melo 
142644f24cb3SJiri Olsa 	if (machine)
142744f24cb3SJiri Olsa 		root_dir = machine->root_dir;
142844f24cb3SJiri Olsa 
1429164c800eSDavid Ahern 	name = malloc(PATH_MAX);
1430164c800eSDavid Ahern 	if (!name)
14314a936edcSNamhyung Kim 		goto out;
1432164c800eSDavid Ahern 
14331029f9feSNamhyung Kim 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1434c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
1435c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
1436c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
14371029f9feSNamhyung Kim 
14381029f9feSNamhyung Kim 	/*
14391029f9feSNamhyung Kim 	 * Iterate over candidate debug images.
14403aafe5aeSCody P Schafer 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
14413aafe5aeSCody P Schafer 	 * and/or opd section) for processing.
14426da80ce8SDave Martin 	 */
144344f24cb3SJiri Olsa 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
14443aafe5aeSCody P Schafer 		struct symsrc *ss = &ss_[ss_pos];
14453aafe5aeSCody P Schafer 		bool next_slot = false;
144644f24cb3SJiri Olsa 
1447005f9294SCody P Schafer 		enum dso_binary_type symtab_type = binary_type_symtab[i];
144844f24cb3SJiri Olsa 
14491029f9feSNamhyung Kim 		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
14501029f9feSNamhyung Kim 			continue;
14511029f9feSNamhyung Kim 
1452ee4e9625SArnaldo Carvalho de Melo 		if (dso__read_binary_type_filename(dso, symtab_type,
145344f24cb3SJiri Olsa 						   root_dir, name, PATH_MAX))
14546da80ce8SDave Martin 			continue;
145586470930SIngo Molnar 
14566da80ce8SDave Martin 		/* Name is now the name of the next image to try */
14573aafe5aeSCody P Schafer 		if (symsrc__init(ss, dso, name, symtab_type) < 0)
14586da80ce8SDave Martin 			continue;
14596da80ce8SDave Martin 
14603aafe5aeSCody P Schafer 		if (!syms_ss && symsrc__has_symtab(ss)) {
14613aafe5aeSCody P Schafer 			syms_ss = ss;
14623aafe5aeSCody P Schafer 			next_slot = true;
14630058aef6SAdrian Hunter 			if (!dso->symsrc_filename)
14640058aef6SAdrian Hunter 				dso->symsrc_filename = strdup(name);
1465d26cd12bSCody P Schafer 		}
1466d26cd12bSCody P Schafer 
14673aafe5aeSCody P Schafer 		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
14683aafe5aeSCody P Schafer 			runtime_ss = ss;
14693aafe5aeSCody P Schafer 			next_slot = true;
1470a44f605bSCody P Schafer 		}
147186470930SIngo Molnar 
14723aafe5aeSCody P Schafer 		if (next_slot) {
14733aafe5aeSCody P Schafer 			ss_pos++;
147433ff581eSJiri Olsa 
14753aafe5aeSCody P Schafer 			if (syms_ss && runtime_ss)
14766da80ce8SDave Martin 				break;
147798e9f03bSNamhyung Kim 		} else {
147898e9f03bSNamhyung Kim 			symsrc__destroy(ss);
1479a25e46c4SArnaldo Carvalho de Melo 		}
14803aafe5aeSCody P Schafer 
14816da80ce8SDave Martin 	}
14826da80ce8SDave Martin 
14833aafe5aeSCody P Schafer 	if (!runtime_ss && !syms_ss)
14843aafe5aeSCody P Schafer 		goto out_free;
14853aafe5aeSCody P Schafer 
14863aafe5aeSCody P Schafer 	if (runtime_ss && !syms_ss) {
14873aafe5aeSCody P Schafer 		syms_ss = runtime_ss;
148860e4b10cSArnaldo Carvalho de Melo 	}
148960e4b10cSArnaldo Carvalho de Melo 
14903aafe5aeSCody P Schafer 	/* We'll have to hope for the best */
14913aafe5aeSCody P Schafer 	if (!runtime_ss && syms_ss)
14923aafe5aeSCody P Schafer 		runtime_ss = syms_ss;
14933aafe5aeSCody P Schafer 
14941029f9feSNamhyung Kim 	if (syms_ss)
14951029f9feSNamhyung Kim 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
14961029f9feSNamhyung Kim 	else
14973aafe5aeSCody P Schafer 		ret = -1;
14983aafe5aeSCody P Schafer 
1499f47b58b7SDavid Ahern 	if (ret > 0) {
15003aafe5aeSCody P Schafer 		int nr_plt;
15013aafe5aeSCody P Schafer 
15023aafe5aeSCody P Schafer 		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
15033aafe5aeSCody P Schafer 		if (nr_plt > 0)
15043aafe5aeSCody P Schafer 			ret += nr_plt;
15053aafe5aeSCody P Schafer 	}
15063aafe5aeSCody P Schafer 
15073aafe5aeSCody P Schafer 	for (; ss_pos > 0; ss_pos--)
15083aafe5aeSCody P Schafer 		symsrc__destroy(&ss_[ss_pos - 1]);
15093aafe5aeSCody P Schafer out_free:
151086470930SIngo Molnar 	free(name);
1511aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
15124a936edcSNamhyung Kim 		ret = 0;
15134a936edcSNamhyung Kim out:
15144a936edcSNamhyung Kim 	dso__set_loaded(dso, map->type);
15154a936edcSNamhyung Kim 	pthread_mutex_unlock(&dso->lock);
15164a936edcSNamhyung Kim 
151786470930SIngo Molnar 	return ret;
151886470930SIngo Molnar }
151986470930SIngo Molnar 
1520aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
152179406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1522439d473bSArnaldo Carvalho de Melo {
1523*1eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
15244bb7123dSArnaldo Carvalho de Melo 	struct map *map;
1525439d473bSArnaldo Carvalho de Melo 
15264bb7123dSArnaldo Carvalho de Melo 	for (map = maps__first(maps); map; map = map__next(map)) {
1527b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1528439d473bSArnaldo Carvalho de Melo 			return map;
1529439d473bSArnaldo Carvalho de Melo 	}
1530439d473bSArnaldo Carvalho de Melo 
1531439d473bSArnaldo Carvalho de Melo 	return NULL;
1532439d473bSArnaldo Carvalho de Melo }
1533439d473bSArnaldo Carvalho de Melo 
1534aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
15355230fb7dSArnaldo Carvalho de Melo 		      const char *vmlinux, bool vmlinux_allocated,
15365230fb7dSArnaldo Carvalho de Melo 		      symbol_filter_t filter)
153786470930SIngo Molnar {
1538b68e2f91SCody P Schafer 	int err = -1;
1539b68e2f91SCody P Schafer 	struct symsrc ss;
1540ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
1541005f9294SCody P Schafer 	enum dso_binary_type symtab_type;
154286470930SIngo Molnar 
15435698d2c9SNamhyung Kim 	if (vmlinux[0] == '/')
15445698d2c9SNamhyung Kim 		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
15455698d2c9SNamhyung Kim 	else
1546972f393bSArnaldo Carvalho de Melo 		symbol__join_symfs(symfs_vmlinux, vmlinux);
154786470930SIngo Molnar 
154821ea4539SCody P Schafer 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1549005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
155021ea4539SCody P Schafer 	else
1551005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__VMLINUX;
155221ea4539SCody P Schafer 
1553005f9294SCody P Schafer 	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1554b68e2f91SCody P Schafer 		return -1;
1555b68e2f91SCody P Schafer 
1556261360b6SCody P Schafer 	err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
1557b68e2f91SCody P Schafer 	symsrc__destroy(&ss);
155886470930SIngo Molnar 
1559515850e4SCody P Schafer 	if (err > 0) {
156039b12f78SAdrian Hunter 		if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
15615f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
156239b12f78SAdrian Hunter 		else
15635f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
1564bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, vmlinux, vmlinux_allocated);
1565515850e4SCody P Schafer 		dso__set_loaded(dso, map->type);
1566ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
1567515850e4SCody P Schafer 	}
15683846df2eSArnaldo Carvalho de Melo 
156986470930SIngo Molnar 	return err;
157086470930SIngo Molnar }
157186470930SIngo Molnar 
1572aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
15739de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1574a19afe46SArnaldo Carvalho de Melo {
1575a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
157600dc8657SNamhyung Kim 	char *filename = NULL;
1577a19afe46SArnaldo Carvalho de Melo 
157800dc8657SNamhyung Kim 	if (!symbol_conf.ignore_vmlinux_buildid)
1579aeafcbafSArnaldo Carvalho de Melo 		filename = dso__build_id_filename(dso, NULL, 0);
15805ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
15815230fb7dSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, true, filter);
15825230fb7dSArnaldo Carvalho de Melo 		if (err > 0)
15835ad90e4eSArnaldo Carvalho de Melo 			goto out;
15845ad90e4eSArnaldo Carvalho de Melo 		free(filename);
15855ad90e4eSArnaldo Carvalho de Melo 	}
1586a19afe46SArnaldo Carvalho de Melo 
158700dc8657SNamhyung Kim 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
158800dc8657SNamhyung Kim 		 vmlinux_path__nr_entries + 1);
158900dc8657SNamhyung Kim 
1590a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
15915230fb7dSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
15925230fb7dSArnaldo Carvalho de Melo 		if (err > 0)
1593a19afe46SArnaldo Carvalho de Melo 			break;
1594a19afe46SArnaldo Carvalho de Melo 	}
15955ad90e4eSArnaldo Carvalho de Melo out:
1596a19afe46SArnaldo Carvalho de Melo 	return err;
1597a19afe46SArnaldo Carvalho de Melo }
1598a19afe46SArnaldo Carvalho de Melo 
15990544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
16000544d422SAdrian Hunter {
16010544d422SAdrian Hunter 	char kallsyms_filename[PATH_MAX];
16020544d422SAdrian Hunter 	struct dirent *dent;
16030544d422SAdrian Hunter 	int ret = -1;
16040544d422SAdrian Hunter 	DIR *d;
16050544d422SAdrian Hunter 
16060544d422SAdrian Hunter 	d = opendir(dir);
16070544d422SAdrian Hunter 	if (!d)
16080544d422SAdrian Hunter 		return -1;
16090544d422SAdrian Hunter 
16100544d422SAdrian Hunter 	while (1) {
16110544d422SAdrian Hunter 		dent = readdir(d);
16120544d422SAdrian Hunter 		if (!dent)
16130544d422SAdrian Hunter 			break;
16140544d422SAdrian Hunter 		if (dent->d_type != DT_DIR)
16150544d422SAdrian Hunter 			continue;
16160544d422SAdrian Hunter 		scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
16170544d422SAdrian Hunter 			  "%s/%s/kallsyms", dir, dent->d_name);
1618a00d28cbSAdrian Hunter 		if (!validate_kcore_addresses(kallsyms_filename, map)) {
16190544d422SAdrian Hunter 			strlcpy(dir, kallsyms_filename, dir_sz);
16200544d422SAdrian Hunter 			ret = 0;
16210544d422SAdrian Hunter 			break;
16220544d422SAdrian Hunter 		}
16230544d422SAdrian Hunter 	}
16240544d422SAdrian Hunter 
16250544d422SAdrian Hunter 	closedir(d);
16260544d422SAdrian Hunter 
16270544d422SAdrian Hunter 	return ret;
16280544d422SAdrian Hunter }
16290544d422SAdrian Hunter 
16300544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map)
16310544d422SAdrian Hunter {
16320544d422SAdrian Hunter 	u8 host_build_id[BUILD_ID_SIZE];
16330544d422SAdrian Hunter 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
16340544d422SAdrian Hunter 	bool is_host = false;
16350544d422SAdrian Hunter 	char path[PATH_MAX];
16360544d422SAdrian Hunter 
16370544d422SAdrian Hunter 	if (!dso->has_build_id) {
16380544d422SAdrian Hunter 		/*
16390544d422SAdrian Hunter 		 * Last resort, if we don't have a build-id and couldn't find
16400544d422SAdrian Hunter 		 * any vmlinux file, try the running kernel kallsyms table.
16410544d422SAdrian Hunter 		 */
16420544d422SAdrian Hunter 		goto proc_kallsyms;
16430544d422SAdrian Hunter 	}
16440544d422SAdrian Hunter 
16450544d422SAdrian Hunter 	if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
16460544d422SAdrian Hunter 				 sizeof(host_build_id)) == 0)
16470544d422SAdrian Hunter 		is_host = dso__build_id_equal(dso, host_build_id);
16480544d422SAdrian Hunter 
16490544d422SAdrian Hunter 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
16500544d422SAdrian Hunter 
1651449867e3SAdrian Hunter 	scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
1652449867e3SAdrian Hunter 		  sbuild_id);
1653449867e3SAdrian Hunter 
16540544d422SAdrian Hunter 	/* Use /proc/kallsyms if possible */
16550544d422SAdrian Hunter 	if (is_host) {
16560544d422SAdrian Hunter 		DIR *d;
16570544d422SAdrian Hunter 		int fd;
16580544d422SAdrian Hunter 
16590544d422SAdrian Hunter 		/* If no cached kcore go with /proc/kallsyms */
16600544d422SAdrian Hunter 		d = opendir(path);
16610544d422SAdrian Hunter 		if (!d)
16620544d422SAdrian Hunter 			goto proc_kallsyms;
16630544d422SAdrian Hunter 		closedir(d);
16640544d422SAdrian Hunter 
16650544d422SAdrian Hunter 		/*
16660544d422SAdrian Hunter 		 * Do not check the build-id cache, until we know we cannot use
16670544d422SAdrian Hunter 		 * /proc/kcore.
16680544d422SAdrian Hunter 		 */
16690544d422SAdrian Hunter 		fd = open("/proc/kcore", O_RDONLY);
16700544d422SAdrian Hunter 		if (fd != -1) {
16710544d422SAdrian Hunter 			close(fd);
16720544d422SAdrian Hunter 			/* If module maps match go with /proc/kallsyms */
1673a00d28cbSAdrian Hunter 			if (!validate_kcore_addresses("/proc/kallsyms", map))
16740544d422SAdrian Hunter 				goto proc_kallsyms;
16750544d422SAdrian Hunter 		}
16760544d422SAdrian Hunter 
16770544d422SAdrian Hunter 		/* Find kallsyms in build-id cache with kcore */
16780544d422SAdrian Hunter 		if (!find_matching_kcore(map, path, sizeof(path)))
16790544d422SAdrian Hunter 			return strdup(path);
16800544d422SAdrian Hunter 
16810544d422SAdrian Hunter 		goto proc_kallsyms;
16820544d422SAdrian Hunter 	}
16830544d422SAdrian Hunter 
1684449867e3SAdrian Hunter 	/* Find kallsyms in build-id cache with kcore */
1685449867e3SAdrian Hunter 	if (!find_matching_kcore(map, path, sizeof(path)))
1686449867e3SAdrian Hunter 		return strdup(path);
1687449867e3SAdrian Hunter 
16880544d422SAdrian Hunter 	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
16890544d422SAdrian Hunter 		  buildid_dir, sbuild_id);
16900544d422SAdrian Hunter 
16910544d422SAdrian Hunter 	if (access(path, F_OK)) {
16920544d422SAdrian Hunter 		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
16930544d422SAdrian Hunter 		       sbuild_id);
16940544d422SAdrian Hunter 		return NULL;
16950544d422SAdrian Hunter 	}
16960544d422SAdrian Hunter 
16970544d422SAdrian Hunter 	return strdup(path);
16980544d422SAdrian Hunter 
16990544d422SAdrian Hunter proc_kallsyms:
17000544d422SAdrian Hunter 	return strdup("/proc/kallsyms");
17010544d422SAdrian Hunter }
17020544d422SAdrian Hunter 
1703aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
17049de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
170586470930SIngo Molnar {
1706cc612d81SArnaldo Carvalho de Melo 	int err;
17079e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
17089e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1709dc8d6ab2SArnaldo Carvalho de Melo 	/*
1710b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1711b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1712dc8d6ab2SArnaldo Carvalho de Melo 	 *
1713dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1714dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1715dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1716dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1717dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1718dc8d6ab2SArnaldo Carvalho de Melo 	 *
1719dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1720dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1721dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1722dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1723dc8d6ab2SArnaldo Carvalho de Melo 	 */
1724b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1725b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1726b226a5a7SDavid Ahern 		goto do_kallsyms;
1727b226a5a7SDavid Ahern 	}
1728b226a5a7SDavid Ahern 
1729fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
17305230fb7dSArnaldo Carvalho de Melo 		return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
17315230fb7dSArnaldo Carvalho de Melo 					 false, filter);
1732dc8d6ab2SArnaldo Carvalho de Melo 	}
1733439d473bSArnaldo Carvalho de Melo 
1734fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
1735aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
1736a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
173739b12f78SAdrian Hunter 			return err;
1738cc612d81SArnaldo Carvalho de Melo 	}
1739cc612d81SArnaldo Carvalho de Melo 
1740ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1741ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1742ec5761eaSDavid Ahern 		return -1;
1743ec5761eaSDavid Ahern 
17440544d422SAdrian Hunter 	kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
17450544d422SAdrian Hunter 	if (!kallsyms_allocated_filename)
17468d0591f6SArnaldo Carvalho de Melo 		return -1;
17478d0591f6SArnaldo Carvalho de Melo 
174819fc2dedSArnaldo Carvalho de Melo 	kallsyms_filename = kallsyms_allocated_filename;
174919fc2dedSArnaldo Carvalho de Melo 
1750dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
1751aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
17523846df2eSArnaldo Carvalho de Melo 	if (err > 0)
17533846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1754dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1755dc8d6ab2SArnaldo Carvalho de Melo 
17568e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1757bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
1758bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, "[kernel.kallsyms]", false);
17596a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
17606a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1761439d473bSArnaldo Carvalho de Melo 	}
176294cb9e38SArnaldo Carvalho de Melo 
176386470930SIngo Molnar 	return err;
176486470930SIngo Molnar }
176586470930SIngo Molnar 
1766aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1767a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
1768a1645ce1SZhang, Yanmin {
1769a1645ce1SZhang, Yanmin 	int err;
1770a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
177123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1772a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1773a1645ce1SZhang, Yanmin 
1774a1645ce1SZhang, Yanmin 	if (!map->groups) {
1775a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1776a1645ce1SZhang, Yanmin 		return -1;
1777a1645ce1SZhang, Yanmin 	}
177823346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1779a1645ce1SZhang, Yanmin 
178023346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1781a1645ce1SZhang, Yanmin 		/*
1782a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1783a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1784a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1785a1645ce1SZhang, Yanmin 		 */
1786a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1787aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
17885230fb7dSArnaldo Carvalho de Melo 						symbol_conf.default_guest_vmlinux_name,
17895230fb7dSArnaldo Carvalho de Melo 						false, filter);
179039b12f78SAdrian Hunter 			return err;
1791a1645ce1SZhang, Yanmin 		}
1792a1645ce1SZhang, Yanmin 
1793a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1794a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1795a1645ce1SZhang, Yanmin 			return -1;
1796a1645ce1SZhang, Yanmin 	} else {
179723346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1798a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1799a1645ce1SZhang, Yanmin 	}
1800a1645ce1SZhang, Yanmin 
1801aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
18028e0cf965SAdrian Hunter 	if (err > 0)
180339b12f78SAdrian Hunter 		pr_debug("Using %s for symbols\n", kallsyms_filename);
18048e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1805bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
180648ea8f54SArnaldo Carvalho de Melo 		machine__mmap_name(machine, path, sizeof(path));
18077e155d4dSArnaldo Carvalho de Melo 		dso__set_long_name(dso, strdup(path), true);
1808a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1809a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1810a1645ce1SZhang, Yanmin 	}
1811a1645ce1SZhang, Yanmin 
1812a1645ce1SZhang, Yanmin 	return err;
1813a1645ce1SZhang, Yanmin }
1814cd84c2acSFrederic Weisbecker 
1815cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
18162446042cSArnaldo Carvalho de Melo {
181704662523SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0)
181804662523SArnaldo Carvalho de Melo 		zfree(&vmlinux_path[vmlinux_path__nr_entries]);
1819c4f03547SWang Nan 	vmlinux_path__nr_entries = 0;
1820cc612d81SArnaldo Carvalho de Melo 
182104662523SArnaldo Carvalho de Melo 	zfree(&vmlinux_path);
1822cc612d81SArnaldo Carvalho de Melo }
1823cc612d81SArnaldo Carvalho de Melo 
18240a7e6d1bSNamhyung Kim static int vmlinux_path__init(struct perf_session_env *env)
1825cc612d81SArnaldo Carvalho de Melo {
1826cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1827cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
18280a7e6d1bSNamhyung Kim 	char *kernel_version;
1829cc612d81SArnaldo Carvalho de Melo 
1830c657f423SAnton Blanchard 	vmlinux_path = malloc(sizeof(char *) * 6);
1831cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1832cc612d81SArnaldo Carvalho de Melo 		return -1;
1833cc612d81SArnaldo Carvalho de Melo 
1834cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1835cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1836cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1837cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1838cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1839cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1840cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1841cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1842ec5761eaSDavid Ahern 
18430a7e6d1bSNamhyung Kim 	/* only try kernel version if no symfs was given */
1844ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1845ec5761eaSDavid Ahern 		return 0;
1846ec5761eaSDavid Ahern 
18470a7e6d1bSNamhyung Kim 	if (env) {
18480a7e6d1bSNamhyung Kim 		kernel_version = env->os_release;
18490a7e6d1bSNamhyung Kim 	} else {
1850ec5761eaSDavid Ahern 		if (uname(&uts) < 0)
1851e96c674fSNamhyung Kim 			goto out_fail;
1852ec5761eaSDavid Ahern 
18530a7e6d1bSNamhyung Kim 		kernel_version = uts.release;
18540a7e6d1bSNamhyung Kim 	}
18550a7e6d1bSNamhyung Kim 
18560a7e6d1bSNamhyung Kim 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
1857cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1858cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1859cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1860cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1861c657f423SAnton Blanchard 	snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
1862c657f423SAnton Blanchard 		 kernel_version);
1863c657f423SAnton Blanchard 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1864c657f423SAnton Blanchard 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1865c657f423SAnton Blanchard 		goto out_fail;
1866c657f423SAnton Blanchard         ++vmlinux_path__nr_entries;
18670a7e6d1bSNamhyung Kim 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
1868cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1869cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1870cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1871cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1872cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
18730a7e6d1bSNamhyung Kim 		 kernel_version);
1874cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1875cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1876cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1877cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1878cc612d81SArnaldo Carvalho de Melo 
1879cc612d81SArnaldo Carvalho de Melo 	return 0;
1880cc612d81SArnaldo Carvalho de Melo 
1881cc612d81SArnaldo Carvalho de Melo out_fail:
1882cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1883cc612d81SArnaldo Carvalho de Melo 	return -1;
1884cc612d81SArnaldo Carvalho de Melo }
1885cc612d81SArnaldo Carvalho de Melo 
18863bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str,
1887655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
1888655000e7SArnaldo Carvalho de Melo {
1889655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
1890655000e7SArnaldo Carvalho de Melo 		return 0;
1891655000e7SArnaldo Carvalho de Melo 
1892655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
1893655000e7SArnaldo Carvalho de Melo 	if (!*list) {
1894655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
1895655000e7SArnaldo Carvalho de Melo 		return -1;
1896655000e7SArnaldo Carvalho de Melo 	}
1897655000e7SArnaldo Carvalho de Melo 	return 0;
1898655000e7SArnaldo Carvalho de Melo }
1899655000e7SArnaldo Carvalho de Melo 
1900e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str,
1901e03eaa40SDavid Ahern 		  const char *list_name)
1902e03eaa40SDavid Ahern {
1903e03eaa40SDavid Ahern 	if (list_str == NULL)
1904e03eaa40SDavid Ahern 		return 0;
1905e03eaa40SDavid Ahern 
1906e03eaa40SDavid Ahern 	*list = intlist__new(list_str);
1907e03eaa40SDavid Ahern 	if (!*list) {
1908e03eaa40SDavid Ahern 		pr_err("problems parsing %s list\n", list_name);
1909e03eaa40SDavid Ahern 		return -1;
1910e03eaa40SDavid Ahern 	}
1911e03eaa40SDavid Ahern 	return 0;
1912e03eaa40SDavid Ahern }
1913e03eaa40SDavid Ahern 
1914ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
1915ec80fde7SArnaldo Carvalho de Melo {
1916ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
1917ec80fde7SArnaldo Carvalho de Melo 
1918ec80fde7SArnaldo Carvalho de Melo 	if (geteuid() != 0) {
1919ec80fde7SArnaldo Carvalho de Melo 		FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
1920ec80fde7SArnaldo Carvalho de Melo 		if (fp != NULL) {
1921ec80fde7SArnaldo Carvalho de Melo 			char line[8];
1922ec80fde7SArnaldo Carvalho de Melo 
1923ec80fde7SArnaldo Carvalho de Melo 			if (fgets(line, sizeof(line), fp) != NULL)
1924ec80fde7SArnaldo Carvalho de Melo 				value = atoi(line) != 0;
1925ec80fde7SArnaldo Carvalho de Melo 
1926ec80fde7SArnaldo Carvalho de Melo 			fclose(fp);
1927ec80fde7SArnaldo Carvalho de Melo 		}
1928ec80fde7SArnaldo Carvalho de Melo 	}
1929ec80fde7SArnaldo Carvalho de Melo 
1930ec80fde7SArnaldo Carvalho de Melo 	return value;
1931ec80fde7SArnaldo Carvalho de Melo }
1932ec80fde7SArnaldo Carvalho de Melo 
19330a7e6d1bSNamhyung Kim int symbol__init(struct perf_session_env *env)
1934cc612d81SArnaldo Carvalho de Melo {
1935ec5761eaSDavid Ahern 	const char *symfs;
1936ec5761eaSDavid Ahern 
193785e00b55SJovi Zhang 	if (symbol_conf.initialized)
193885e00b55SJovi Zhang 		return 0;
193985e00b55SJovi Zhang 
19409ac3e487SIrina Tirdea 	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
19414d439517SDavid S. Miller 
1942166ccc9cSNamhyung Kim 	symbol__elf_init();
1943166ccc9cSNamhyung Kim 
194475be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
194575be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
194679406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
1947b32d133aSArnaldo Carvalho de Melo 
19480a7e6d1bSNamhyung Kim 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
1949cc612d81SArnaldo Carvalho de Melo 		return -1;
1950cc612d81SArnaldo Carvalho de Melo 
1951c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1952c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
1953c410a338SArnaldo Carvalho de Melo 		return -1;
1954c410a338SArnaldo Carvalho de Melo 	}
1955c410a338SArnaldo Carvalho de Melo 
1956655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
1957655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
1958655000e7SArnaldo Carvalho de Melo 		return -1;
1959655000e7SArnaldo Carvalho de Melo 
1960655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
1961655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
1962655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
1963655000e7SArnaldo Carvalho de Melo 
1964e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.pid_list,
1965e03eaa40SDavid Ahern 		       symbol_conf.pid_list_str, "pid") < 0)
1966e03eaa40SDavid Ahern 		goto out_free_comm_list;
1967e03eaa40SDavid Ahern 
1968e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.tid_list,
1969e03eaa40SDavid Ahern 		       symbol_conf.tid_list_str, "tid") < 0)
1970e03eaa40SDavid Ahern 		goto out_free_pid_list;
1971e03eaa40SDavid Ahern 
1972655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
1973655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
1974e03eaa40SDavid Ahern 		goto out_free_tid_list;
1975655000e7SArnaldo Carvalho de Melo 
1976ec5761eaSDavid Ahern 	/*
1977ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
1978ec5761eaSDavid Ahern 	 * reset here for simplicity.
1979ec5761eaSDavid Ahern 	 */
1980ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
1981ec5761eaSDavid Ahern 	if (symfs == NULL)
1982ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
1983ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
1984ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
1985ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
1986ec5761eaSDavid Ahern 		free((void *)symfs);
1987ec5761eaSDavid Ahern 
1988ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
1989ec80fde7SArnaldo Carvalho de Melo 
199085e00b55SJovi Zhang 	symbol_conf.initialized = true;
19914aa65636SArnaldo Carvalho de Melo 	return 0;
1992655000e7SArnaldo Carvalho de Melo 
1993e03eaa40SDavid Ahern out_free_tid_list:
1994e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
1995e03eaa40SDavid Ahern out_free_pid_list:
1996e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
1997655000e7SArnaldo Carvalho de Melo out_free_comm_list:
1998655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
1999d74c896bSNamhyung Kim out_free_dso_list:
2000d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2001655000e7SArnaldo Carvalho de Melo 	return -1;
2002cc612d81SArnaldo Carvalho de Melo }
2003cc612d81SArnaldo Carvalho de Melo 
2004d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2005d65a458bSArnaldo Carvalho de Melo {
200685e00b55SJovi Zhang 	if (!symbol_conf.initialized)
200785e00b55SJovi Zhang 		return;
2008d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2009d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2010d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2011e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2012e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2013d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2014d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
201585e00b55SJovi Zhang 	symbol_conf.initialized = false;
2016d65a458bSArnaldo Carvalho de Melo }
2017