xref: /linux/tools/perf/util/symbol.c (revision 2059fc7a5a9e667797b8ec503bfb4685afee48d8)
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 {
2051eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
2064bb7123dSArnaldo Carvalho de Melo 	struct map *next, *curr;
207af427bf5SArnaldo Carvalho de Melo 
2086a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_wrlock(&maps->lock);
2096a2ffcddSArnaldo Carvalho de Melo 
2104bb7123dSArnaldo Carvalho de Melo 	curr = maps__first(maps);
2114bb7123dSArnaldo Carvalho de Melo 	if (curr == NULL)
2126a2ffcddSArnaldo Carvalho de Melo 		goto out_unlock;
213af427bf5SArnaldo Carvalho de Melo 
2144bb7123dSArnaldo Carvalho de Melo 	for (next = map__next(curr); next; next = map__next(curr)) {
2154bb7123dSArnaldo Carvalho de Melo 		curr->end = next->start;
2164bb7123dSArnaldo Carvalho de Melo 		curr = next;
2172e538c4aSArnaldo Carvalho de Melo 	}
21890c83218SArnaldo Carvalho de Melo 
21990c83218SArnaldo Carvalho de Melo 	/*
22090c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
22190c83218SArnaldo Carvalho de Melo 	 * last map final address.
22290c83218SArnaldo Carvalho de Melo 	 */
2239d1faba5SIan Munsie 	curr->end = ~0ULL;
2246a2ffcddSArnaldo Carvalho de Melo 
2256a2ffcddSArnaldo Carvalho de Melo out_unlock:
2266a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_unlock(&maps->lock);
227af427bf5SArnaldo Carvalho de Melo }
228af427bf5SArnaldo Carvalho de Melo 
229e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
23086470930SIngo Molnar {
23186470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
232aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
233aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
234aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
23586470930SIngo Molnar 		return NULL;
23686470930SIngo Molnar 
23775be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
238aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
23936479484SArnaldo Carvalho de Melo 
240aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
2412c241bd3SArnaldo Carvalho de Melo 	sym->end     = len ? start + len : start;
242aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
243aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
244e4204992SArnaldo Carvalho de Melo 
245aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
246aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
247aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
248e4204992SArnaldo Carvalho de Melo 
249aeafcbafSArnaldo Carvalho de Melo 	return sym;
25086470930SIngo Molnar }
25186470930SIngo Molnar 
252aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
25386470930SIngo Molnar {
254aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
25586470930SIngo Molnar }
25686470930SIngo Molnar 
257cdd059d7SJiri Olsa size_t symbol__fprintf(struct symbol *sym, FILE *fp)
25886470930SIngo Molnar {
2599486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
260aeafcbafSArnaldo Carvalho de Melo 		       sym->start, sym->end,
261aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_GLOBAL ? 'g' :
262aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_LOCAL  ? 'l' : 'w',
263aeafcbafSArnaldo Carvalho de Melo 		       sym->name);
26486470930SIngo Molnar }
26586470930SIngo Molnar 
266a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym,
267a978f2abSAkihiro Nagai 				    const struct addr_location *al, FILE *fp)
268a978f2abSAkihiro Nagai {
269a978f2abSAkihiro Nagai 	unsigned long offset;
270a978f2abSAkihiro Nagai 	size_t length;
271a978f2abSAkihiro Nagai 
272a978f2abSAkihiro Nagai 	if (sym && sym->name) {
273a978f2abSAkihiro Nagai 		length = fprintf(fp, "%s", sym->name);
274a978f2abSAkihiro Nagai 		if (al) {
2750b8c25d9SDavid Ahern 			if (al->addr < sym->end)
276a978f2abSAkihiro Nagai 				offset = al->addr - sym->start;
2770b8c25d9SDavid Ahern 			else
2780b8c25d9SDavid Ahern 				offset = al->addr - al->map->start - sym->start;
279a978f2abSAkihiro Nagai 			length += fprintf(fp, "+0x%lx", offset);
280a978f2abSAkihiro Nagai 		}
281a978f2abSAkihiro Nagai 		return length;
282a978f2abSAkihiro Nagai 	} else
283a978f2abSAkihiro Nagai 		return fprintf(fp, "[unknown]");
284a978f2abSAkihiro Nagai }
285a978f2abSAkihiro Nagai 
286547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
287547a92e0SAkihiro Nagai {
288a978f2abSAkihiro Nagai 	return symbol__fprintf_symname_offs(sym, NULL, fp);
289547a92e0SAkihiro Nagai }
290547a92e0SAkihiro Nagai 
291cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols)
29286470930SIngo Molnar {
29386470930SIngo Molnar 	struct symbol *pos;
294aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
29586470930SIngo Molnar 
29686470930SIngo Molnar 	while (next) {
29786470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
29886470930SIngo Molnar 		next = rb_next(&pos->rb_node);
299aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
30000a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
30186470930SIngo Molnar 	}
30286470930SIngo Molnar }
30386470930SIngo Molnar 
304e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym)
30586470930SIngo Molnar {
306aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
30786470930SIngo Molnar 	struct rb_node *parent = NULL;
3089cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
30986470930SIngo Molnar 	struct symbol *s;
31086470930SIngo Molnar 
31186470930SIngo Molnar 	while (*p != NULL) {
31286470930SIngo Molnar 		parent = *p;
31386470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
31486470930SIngo Molnar 		if (ip < s->start)
31586470930SIngo Molnar 			p = &(*p)->rb_left;
31686470930SIngo Molnar 		else
31786470930SIngo Molnar 			p = &(*p)->rb_right;
31886470930SIngo Molnar 	}
31986470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
320aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
32186470930SIngo Molnar }
32286470930SIngo Molnar 
323aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
32486470930SIngo Molnar {
32586470930SIngo Molnar 	struct rb_node *n;
32686470930SIngo Molnar 
327aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
32886470930SIngo Molnar 		return NULL;
32986470930SIngo Molnar 
330aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
33186470930SIngo Molnar 
33286470930SIngo Molnar 	while (n) {
33386470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
33486470930SIngo Molnar 
33586470930SIngo Molnar 		if (ip < s->start)
33686470930SIngo Molnar 			n = n->rb_left;
3372c241bd3SArnaldo Carvalho de Melo 		else if (ip >= s->end)
33886470930SIngo Molnar 			n = n->rb_right;
33986470930SIngo Molnar 		else
34086470930SIngo Molnar 			return s;
34186470930SIngo Molnar 	}
34286470930SIngo Molnar 
34386470930SIngo Molnar 	return NULL;
34486470930SIngo Molnar }
34586470930SIngo Molnar 
3468e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols)
3478e0cf965SAdrian Hunter {
3488e0cf965SAdrian Hunter 	struct rb_node *n = rb_first(symbols);
3498e0cf965SAdrian Hunter 
3508e0cf965SAdrian Hunter 	if (n)
3518e0cf965SAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3528e0cf965SAdrian Hunter 
3538e0cf965SAdrian Hunter 	return NULL;
3548e0cf965SAdrian Hunter }
3558e0cf965SAdrian Hunter 
3569c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym)
3579c00a81bSAdrian Hunter {
3589c00a81bSAdrian Hunter 	struct rb_node *n = rb_next(&sym->rb_node);
3599c00a81bSAdrian Hunter 
3609c00a81bSAdrian Hunter 	if (n)
3619c00a81bSAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3629c00a81bSAdrian Hunter 
3639c00a81bSAdrian Hunter 	return NULL;
3649c00a81bSAdrian Hunter }
3659c00a81bSAdrian Hunter 
36679406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
36779406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
36879406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
36979406cd7SArnaldo Carvalho de Melo };
37079406cd7SArnaldo Carvalho de Melo 
371aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
37279406cd7SArnaldo Carvalho de Melo {
373aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
37479406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
37502a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
37602a9d037SRabin Vincent 
37702a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
37879406cd7SArnaldo Carvalho de Melo 
37979406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
38079406cd7SArnaldo Carvalho de Melo 		parent = *p;
38179406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
38279406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
38379406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
38479406cd7SArnaldo Carvalho de Melo 		else
38579406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
38679406cd7SArnaldo Carvalho de Melo 	}
38779406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
388aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
38979406cd7SArnaldo Carvalho de Melo }
39079406cd7SArnaldo Carvalho de Melo 
391aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
392aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
39379406cd7SArnaldo Carvalho de Melo {
39479406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
39579406cd7SArnaldo Carvalho de Melo 
39679406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
39779406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
398aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
39979406cd7SArnaldo Carvalho de Melo 	}
40079406cd7SArnaldo Carvalho de Melo }
40179406cd7SArnaldo Carvalho de Melo 
402aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
403aeafcbafSArnaldo Carvalho de Melo 					    const char *name)
40479406cd7SArnaldo Carvalho de Melo {
40579406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
4065bcaaca3SMartin Liška 	struct symbol_name_rb_node *s = NULL;
40779406cd7SArnaldo Carvalho de Melo 
408aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
40979406cd7SArnaldo Carvalho de Melo 		return NULL;
41079406cd7SArnaldo Carvalho de Melo 
411aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
41279406cd7SArnaldo Carvalho de Melo 
41379406cd7SArnaldo Carvalho de Melo 	while (n) {
41479406cd7SArnaldo Carvalho de Melo 		int cmp;
41579406cd7SArnaldo Carvalho de Melo 
41679406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
417031b84c4SNaveen N. Rao 		cmp = arch__compare_symbol_names(name, s->sym.name);
41879406cd7SArnaldo Carvalho de Melo 
41979406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
42079406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
42179406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
42279406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
42379406cd7SArnaldo Carvalho de Melo 		else
424de480999SNamhyung Kim 			break;
42579406cd7SArnaldo Carvalho de Melo 	}
42679406cd7SArnaldo Carvalho de Melo 
427de480999SNamhyung Kim 	if (n == NULL)
42879406cd7SArnaldo Carvalho de Melo 		return NULL;
429de480999SNamhyung Kim 
430de480999SNamhyung Kim 	/* return first symbol that has same name (if any) */
431de480999SNamhyung Kim 	for (n = rb_prev(n); n; n = rb_prev(n)) {
432de480999SNamhyung Kim 		struct symbol_name_rb_node *tmp;
433de480999SNamhyung Kim 
434de480999SNamhyung Kim 		tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
435031b84c4SNaveen N. Rao 		if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
436de480999SNamhyung Kim 			break;
437de480999SNamhyung Kim 
438de480999SNamhyung Kim 		s = tmp;
439de480999SNamhyung Kim 	}
440de480999SNamhyung Kim 
441de480999SNamhyung Kim 	return &s->sym;
44279406cd7SArnaldo Carvalho de Melo }
44379406cd7SArnaldo Carvalho de Melo 
444c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso)
445c0b4dffbSArnaldo Carvalho de Melo {
446c0b4dffbSArnaldo Carvalho de Melo 	enum map_type type;
447c0b4dffbSArnaldo Carvalho de Melo 
448c0b4dffbSArnaldo Carvalho de Melo 	for (type = MAP__FUNCTION; type <= MAP__VARIABLE; ++type) {
449c0b4dffbSArnaldo Carvalho de Melo 		dso->last_find_result[type].addr   = 0;
450c0b4dffbSArnaldo Carvalho de Melo 		dso->last_find_result[type].symbol = NULL;
451c0b4dffbSArnaldo Carvalho de Melo 	}
452c0b4dffbSArnaldo Carvalho de Melo }
453c0b4dffbSArnaldo Carvalho de Melo 
454aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
45579406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
456fcf1203aSArnaldo Carvalho de Melo {
457b685ac22SArnaldo Carvalho de Melo 	if (dso->last_find_result[type].addr != addr) {
458b685ac22SArnaldo Carvalho de Melo 		dso->last_find_result[type].addr   = addr;
459b685ac22SArnaldo Carvalho de Melo 		dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr);
460b685ac22SArnaldo Carvalho de Melo 	}
461b685ac22SArnaldo Carvalho de Melo 
462b685ac22SArnaldo Carvalho de Melo 	return dso->last_find_result[type].symbol;
463fcf1203aSArnaldo Carvalho de Melo }
464fcf1203aSArnaldo Carvalho de Melo 
4659c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
4668e0cf965SAdrian Hunter {
4678e0cf965SAdrian Hunter 	return symbols__first(&dso->symbols[type]);
4688e0cf965SAdrian Hunter }
4698e0cf965SAdrian Hunter 
4709c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym)
4719c00a81bSAdrian Hunter {
4729c00a81bSAdrian Hunter 	return symbols__next(sym);
4739c00a81bSAdrian Hunter }
4749c00a81bSAdrian Hunter 
47518bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym)
47618bd7264SArnaldo Carvalho de Melo {
47718bd7264SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
47818bd7264SArnaldo Carvalho de Melo 	struct rb_node *n = rb_next(&s->rb_node);
47918bd7264SArnaldo Carvalho de Melo 
48018bd7264SArnaldo Carvalho de Melo 	return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
48118bd7264SArnaldo Carvalho de Melo }
48218bd7264SArnaldo Carvalho de Melo 
48318bd7264SArnaldo Carvalho de Melo  /*
48418bd7264SArnaldo Carvalho de Melo   * Teturns first symbol that matched with @name.
48518bd7264SArnaldo Carvalho de Melo   */
486aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
48779406cd7SArnaldo Carvalho de Melo 					const char *name)
48879406cd7SArnaldo Carvalho de Melo {
489aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
49079406cd7SArnaldo Carvalho de Melo }
49179406cd7SArnaldo Carvalho de Melo 
492aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
49379406cd7SArnaldo Carvalho de Melo {
494aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
495aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
496aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
49779406cd7SArnaldo Carvalho de Melo }
49879406cd7SArnaldo Carvalho de Melo 
499aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso,
500aeafcbafSArnaldo Carvalho de Melo 				    enum map_type type, FILE *fp)
50190f18e63SSrikar Dronamraju {
50290f18e63SSrikar Dronamraju 	size_t ret = 0;
50390f18e63SSrikar Dronamraju 	struct rb_node *nd;
50490f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
50590f18e63SSrikar Dronamraju 
506aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
50790f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
50890f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
50990f18e63SSrikar Dronamraju 	}
51090f18e63SSrikar Dronamraju 
51190f18e63SSrikar Dronamraju 	return ret;
51290f18e63SSrikar Dronamraju }
51390f18e63SSrikar Dronamraju 
514316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg,
515316d70d6SAdrian Hunter 		   int (*process_module)(void *arg, const char *name,
516316d70d6SAdrian Hunter 					 u64 start))
517316d70d6SAdrian Hunter {
518316d70d6SAdrian Hunter 	char *line = NULL;
519316d70d6SAdrian Hunter 	size_t n;
520316d70d6SAdrian Hunter 	FILE *file;
521316d70d6SAdrian Hunter 	int err = 0;
522316d70d6SAdrian Hunter 
523316d70d6SAdrian Hunter 	file = fopen(filename, "r");
524316d70d6SAdrian Hunter 	if (file == NULL)
525316d70d6SAdrian Hunter 		return -1;
526316d70d6SAdrian Hunter 
527316d70d6SAdrian Hunter 	while (1) {
528316d70d6SAdrian Hunter 		char name[PATH_MAX];
529316d70d6SAdrian Hunter 		u64 start;
530316d70d6SAdrian Hunter 		char *sep;
531316d70d6SAdrian Hunter 		ssize_t line_len;
532316d70d6SAdrian Hunter 
533316d70d6SAdrian Hunter 		line_len = getline(&line, &n, file);
534316d70d6SAdrian Hunter 		if (line_len < 0) {
535316d70d6SAdrian Hunter 			if (feof(file))
536316d70d6SAdrian Hunter 				break;
537316d70d6SAdrian Hunter 			err = -1;
538316d70d6SAdrian Hunter 			goto out;
539316d70d6SAdrian Hunter 		}
540316d70d6SAdrian Hunter 
541316d70d6SAdrian Hunter 		if (!line) {
542316d70d6SAdrian Hunter 			err = -1;
543316d70d6SAdrian Hunter 			goto out;
544316d70d6SAdrian Hunter 		}
545316d70d6SAdrian Hunter 
546316d70d6SAdrian Hunter 		line[--line_len] = '\0'; /* \n */
547316d70d6SAdrian Hunter 
548316d70d6SAdrian Hunter 		sep = strrchr(line, 'x');
549316d70d6SAdrian Hunter 		if (sep == NULL)
550316d70d6SAdrian Hunter 			continue;
551316d70d6SAdrian Hunter 
552316d70d6SAdrian Hunter 		hex2u64(sep + 1, &start);
553316d70d6SAdrian Hunter 
554316d70d6SAdrian Hunter 		sep = strchr(line, ' ');
555316d70d6SAdrian Hunter 		if (sep == NULL)
556316d70d6SAdrian Hunter 			continue;
557316d70d6SAdrian Hunter 
558316d70d6SAdrian Hunter 		*sep = '\0';
559316d70d6SAdrian Hunter 
560316d70d6SAdrian Hunter 		scnprintf(name, sizeof(name), "[%s]", line);
561316d70d6SAdrian Hunter 
562316d70d6SAdrian Hunter 		err = process_module(arg, name, start);
563316d70d6SAdrian Hunter 		if (err)
564316d70d6SAdrian Hunter 			break;
565316d70d6SAdrian Hunter 	}
566316d70d6SAdrian Hunter out:
567316d70d6SAdrian Hunter 	free(line);
568316d70d6SAdrian Hunter 	fclose(file);
569316d70d6SAdrian Hunter 	return err;
570316d70d6SAdrian Hunter }
571316d70d6SAdrian Hunter 
572682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
573682b335aSArnaldo Carvalho de Melo 	struct map *map;
574682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
575682b335aSArnaldo Carvalho de Melo };
576682b335aSArnaldo Carvalho de Melo 
577e7110b9fSArnaldo Carvalho de Melo /*
578e7110b9fSArnaldo Carvalho de Melo  * These are symbols in the kernel image, so make sure that
579e7110b9fSArnaldo Carvalho de Melo  * sym is from a kernel DSO.
580e7110b9fSArnaldo Carvalho de Melo  */
58182d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym)
58282d1deb0SDavid Ahern {
58382d1deb0SDavid Ahern 	const char * const idle_symbols[] = {
58482d1deb0SDavid Ahern 		"cpu_idle",
585e0336ed6SArnaldo Carvalho de Melo 		"cpu_startup_entry",
58682d1deb0SDavid Ahern 		"intel_idle",
58782d1deb0SDavid Ahern 		"default_idle",
58882d1deb0SDavid Ahern 		"native_safe_halt",
58982d1deb0SDavid Ahern 		"enter_idle",
59082d1deb0SDavid Ahern 		"exit_idle",
59182d1deb0SDavid Ahern 		"mwait_idle",
59282d1deb0SDavid Ahern 		"mwait_idle_with_hints",
59382d1deb0SDavid Ahern 		"poll_idle",
59482d1deb0SDavid Ahern 		"ppc64_runlatch_off",
59582d1deb0SDavid Ahern 		"pseries_dedicated_idle_sleep",
59682d1deb0SDavid Ahern 		NULL
59782d1deb0SDavid Ahern 	};
59882d1deb0SDavid Ahern 
59982d1deb0SDavid Ahern 	int i;
60082d1deb0SDavid Ahern 
60182d1deb0SDavid Ahern 	if (!sym)
60282d1deb0SDavid Ahern 		return false;
60382d1deb0SDavid Ahern 
60482d1deb0SDavid Ahern 	for (i = 0; idle_symbols[i]; i++) {
60582d1deb0SDavid Ahern 		if (!strcmp(idle_symbols[i], sym->name))
60682d1deb0SDavid Ahern 			return true;
60782d1deb0SDavid Ahern 	}
60882d1deb0SDavid Ahern 
60982d1deb0SDavid Ahern 	return false;
61082d1deb0SDavid Ahern }
61182d1deb0SDavid Ahern 
612682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
61382151520SCody P Schafer 				       char type, u64 start)
614682b335aSArnaldo Carvalho de Melo {
615682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
616682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
617682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
618682b335aSArnaldo Carvalho de Melo 
619682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
620682b335aSArnaldo Carvalho de Melo 		return 0;
621682b335aSArnaldo Carvalho de Melo 
62282151520SCody P Schafer 	/*
62382151520SCody P Schafer 	 * module symbols are not sorted so we add all
62482151520SCody P Schafer 	 * symbols, setting length to 0, and rely on
62582151520SCody P Schafer 	 * symbols__fixup_end() to fix it up.
62682151520SCody P Schafer 	 */
6278e947f1eSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, kallsyms2elf_binding(type), name);
6282e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
629682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
63082164161SArnaldo Carvalho de Melo 	/*
63182164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6324e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
63382164161SArnaldo Carvalho de Melo 	 */
6344e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
635a1645ce1SZhang, Yanmin 
636682b335aSArnaldo Carvalho de Melo 	return 0;
6372e538c4aSArnaldo Carvalho de Melo }
6382e538c4aSArnaldo Carvalho de Melo 
639682b335aSArnaldo Carvalho de Melo /*
640682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
641682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
642682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
643682b335aSArnaldo Carvalho de Melo  */
644aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6459e201442SArnaldo Carvalho de Melo 				  struct map *map)
646682b335aSArnaldo Carvalho de Melo {
647aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6489e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6492e538c4aSArnaldo Carvalho de Melo }
6502e538c4aSArnaldo Carvalho de Melo 
6518e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
6528e0cf965SAdrian Hunter 					 symbol_filter_t filter)
6538e0cf965SAdrian Hunter {
654ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
6558e0cf965SAdrian Hunter 	struct map *curr_map;
6568e0cf965SAdrian Hunter 	struct symbol *pos;
657866548ddSAdrian Hunter 	int count = 0;
658866548ddSAdrian Hunter 	struct rb_root old_root = dso->symbols[map->type];
6598e0cf965SAdrian Hunter 	struct rb_root *root = &dso->symbols[map->type];
6608e0cf965SAdrian Hunter 	struct rb_node *next = rb_first(root);
6618e0cf965SAdrian Hunter 
662ba92732eSWang Nan 	if (!kmaps)
663ba92732eSWang Nan 		return -1;
664ba92732eSWang Nan 
665866548ddSAdrian Hunter 	*root = RB_ROOT;
666866548ddSAdrian Hunter 
6678e0cf965SAdrian Hunter 	while (next) {
6688e0cf965SAdrian Hunter 		char *module;
6698e0cf965SAdrian Hunter 
6708e0cf965SAdrian Hunter 		pos = rb_entry(next, struct symbol, rb_node);
6718e0cf965SAdrian Hunter 		next = rb_next(&pos->rb_node);
6728e0cf965SAdrian Hunter 
673866548ddSAdrian Hunter 		rb_erase_init(&pos->rb_node, &old_root);
674866548ddSAdrian Hunter 
6758e0cf965SAdrian Hunter 		module = strchr(pos->name, '\t');
6768e0cf965SAdrian Hunter 		if (module)
6778e0cf965SAdrian Hunter 			*module = '\0';
6788e0cf965SAdrian Hunter 
6798e0cf965SAdrian Hunter 		curr_map = map_groups__find(kmaps, map->type, pos->start);
6808e0cf965SAdrian Hunter 
6818e0cf965SAdrian Hunter 		if (!curr_map || (filter && filter(curr_map, pos))) {
6828e0cf965SAdrian Hunter 			symbol__delete(pos);
683866548ddSAdrian Hunter 			continue;
684866548ddSAdrian Hunter 		}
685866548ddSAdrian Hunter 
6868e0cf965SAdrian Hunter 		pos->start -= curr_map->start - curr_map->pgoff;
6878e0cf965SAdrian Hunter 		if (pos->end)
6888e0cf965SAdrian Hunter 			pos->end -= curr_map->start - curr_map->pgoff;
689866548ddSAdrian Hunter 		symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
6908e0cf965SAdrian Hunter 		++count;
6918e0cf965SAdrian Hunter 	}
6928e0cf965SAdrian Hunter 
6938e0cf965SAdrian Hunter 	/* Symbols have been adjusted */
6948e0cf965SAdrian Hunter 	dso->adjust_symbols = 1;
6958e0cf965SAdrian Hunter 
696866548ddSAdrian Hunter 	return count;
6978e0cf965SAdrian Hunter }
6988e0cf965SAdrian Hunter 
6992e538c4aSArnaldo Carvalho de Melo /*
7002e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
7012e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
7022e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
7032e538c4aSArnaldo Carvalho de Melo  */
704d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
7059de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
7062e538c4aSArnaldo Carvalho de Melo {
707ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
708ba92732eSWang Nan 	struct machine *machine;
7094e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
7102e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
7118a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
712aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
7134e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
7142e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
7152e538c4aSArnaldo Carvalho de Melo 
716ba92732eSWang Nan 	if (!kmaps)
717ba92732eSWang Nan 		return -1;
718ba92732eSWang Nan 
719ba92732eSWang Nan 	machine = kmaps->machine;
720ba92732eSWang Nan 
7212e538c4aSArnaldo Carvalho de Melo 	while (next) {
7222e538c4aSArnaldo Carvalho de Melo 		char *module;
7232e538c4aSArnaldo Carvalho de Melo 
7242e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
7252e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
7262e538c4aSArnaldo Carvalho de Melo 
7272e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
7282e538c4aSArnaldo Carvalho de Melo 		if (module) {
72975be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
7301de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
7311de8e245SArnaldo Carvalho de Melo 
7322e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
7332e538c4aSArnaldo Carvalho de Melo 
734b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
735a1645ce1SZhang, Yanmin 				if (curr_map != map &&
736aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
73723346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
738a1645ce1SZhang, Yanmin 					/*
739a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
740a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
741a1645ce1SZhang, Yanmin 					 * points to a module and all its
742a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
743a1645ce1SZhang, Yanmin 					 * loaded.
744a1645ce1SZhang, Yanmin 					 */
745a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
746a1645ce1SZhang, Yanmin 							curr_map->type);
747af427bf5SArnaldo Carvalho de Melo 				}
748b7cece76SArnaldo Carvalho de Melo 
749a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
750a1645ce1SZhang, Yanmin 							map->type, module);
751a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7522f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
753a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
754a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
75523346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
756a1645ce1SZhang, Yanmin 					curr_map = map;
757a1645ce1SZhang, Yanmin 					goto discard_symbol;
758a1645ce1SZhang, Yanmin 				}
759a1645ce1SZhang, Yanmin 
760a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
76123346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
762b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
763af427bf5SArnaldo Carvalho de Melo 			}
76486470930SIngo Molnar 			/*
7652e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
7662e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
76786470930SIngo Molnar 			 */
7684e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
7694e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
7704e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
7712e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
772aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
77386470930SIngo Molnar 
774d9b62abaSAdrian Hunter 			if (delta) {
775d9b62abaSAdrian Hunter 				/* Kernel was relocated at boot time */
776d9b62abaSAdrian Hunter 				pos->start -= delta;
777d9b62abaSAdrian Hunter 				pos->end -= delta;
778d9b62abaSAdrian Hunter 			}
779d9b62abaSAdrian Hunter 
7808a953312SArnaldo Carvalho de Melo 			if (count == 0) {
7818a953312SArnaldo Carvalho de Melo 				curr_map = map;
7828a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
7838a953312SArnaldo Carvalho de Melo 			}
7848a953312SArnaldo Carvalho de Melo 
785aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
786a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
787a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
788a1645ce1SZhang, Yanmin 					kernel_range++);
789a1645ce1SZhang, Yanmin 			else
790a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
791a1645ce1SZhang, Yanmin 					"[kernel].%d",
7922e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
79386470930SIngo Molnar 
794aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
795aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
7962e538c4aSArnaldo Carvalho de Melo 				return -1;
7972e538c4aSArnaldo Carvalho de Melo 
798aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
799a1645ce1SZhang, Yanmin 
800aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
80137fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
802d3a7c489SArnaldo Carvalho de Melo 				dso__put(ndso);
8032e538c4aSArnaldo Carvalho de Melo 				return -1;
8042e538c4aSArnaldo Carvalho de Melo 			}
8052e538c4aSArnaldo Carvalho de Melo 
8064e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
8079de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
8082e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
809d9b62abaSAdrian Hunter 		} else if (delta) {
810d9b62abaSAdrian Hunter 			/* Kernel was relocated at boot time */
811d9b62abaSAdrian Hunter 			pos->start -= delta;
812d9b62abaSAdrian Hunter 			pos->end -= delta;
8132e538c4aSArnaldo Carvalho de Melo 		}
8148a953312SArnaldo Carvalho de Melo filter_symbol:
8154e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
8161de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
81700a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
8182e538c4aSArnaldo Carvalho de Melo 		} else {
8194e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
8204e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
8214e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
8228a953312SArnaldo Carvalho de Melo 				++moved;
8238a953312SArnaldo Carvalho de Melo 			} else
8248a953312SArnaldo Carvalho de Melo 				++count;
8259974f496SMike Galbraith 		}
82686470930SIngo Molnar 	}
82786470930SIngo Molnar 
828a1645ce1SZhang, Yanmin 	if (curr_map != map &&
829aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
83023346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
831a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
832a1645ce1SZhang, Yanmin 	}
833a1645ce1SZhang, Yanmin 
8348a953312SArnaldo Carvalho de Melo 	return count + moved;
83586470930SIngo Molnar }
83686470930SIngo Molnar 
8373f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename,
838ec80fde7SArnaldo Carvalho de Melo 				 const char *restricted_filename)
839ec80fde7SArnaldo Carvalho de Melo {
840ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
841ec80fde7SArnaldo Carvalho de Melo 
842ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
843ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
844ec80fde7SArnaldo Carvalho de Melo 
845ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
846ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
847ec80fde7SArnaldo Carvalho de Melo 			free(r);
848ec80fde7SArnaldo Carvalho de Melo 			return restricted;
849ec80fde7SArnaldo Carvalho de Melo 		}
850ec80fde7SArnaldo Carvalho de Melo 	}
851ec80fde7SArnaldo Carvalho de Melo 
852ec80fde7SArnaldo Carvalho de Melo 	return restricted;
853ec80fde7SArnaldo Carvalho de Melo }
854ec80fde7SArnaldo Carvalho de Melo 
85552afdaf9SAdrian Hunter struct module_info {
85652afdaf9SAdrian Hunter 	struct rb_node rb_node;
85752afdaf9SAdrian Hunter 	char *name;
85852afdaf9SAdrian Hunter 	u64 start;
85952afdaf9SAdrian Hunter };
86052afdaf9SAdrian Hunter 
86152afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules)
86252afdaf9SAdrian Hunter {
86352afdaf9SAdrian Hunter 	struct rb_node **p = &modules->rb_node;
86452afdaf9SAdrian Hunter 	struct rb_node *parent = NULL;
86552afdaf9SAdrian Hunter 	struct module_info *m;
86652afdaf9SAdrian Hunter 
86752afdaf9SAdrian Hunter 	while (*p != NULL) {
86852afdaf9SAdrian Hunter 		parent = *p;
86952afdaf9SAdrian Hunter 		m = rb_entry(parent, struct module_info, rb_node);
87052afdaf9SAdrian Hunter 		if (strcmp(mi->name, m->name) < 0)
87152afdaf9SAdrian Hunter 			p = &(*p)->rb_left;
87252afdaf9SAdrian Hunter 		else
87352afdaf9SAdrian Hunter 			p = &(*p)->rb_right;
87452afdaf9SAdrian Hunter 	}
87552afdaf9SAdrian Hunter 	rb_link_node(&mi->rb_node, parent, p);
87652afdaf9SAdrian Hunter 	rb_insert_color(&mi->rb_node, modules);
87752afdaf9SAdrian Hunter }
87852afdaf9SAdrian Hunter 
87952afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules)
88052afdaf9SAdrian Hunter {
88152afdaf9SAdrian Hunter 	struct module_info *mi;
88252afdaf9SAdrian Hunter 	struct rb_node *next = rb_first(modules);
88352afdaf9SAdrian Hunter 
88452afdaf9SAdrian Hunter 	while (next) {
88552afdaf9SAdrian Hunter 		mi = rb_entry(next, struct module_info, rb_node);
88652afdaf9SAdrian Hunter 		next = rb_next(&mi->rb_node);
88752afdaf9SAdrian Hunter 		rb_erase(&mi->rb_node, modules);
88874cf249dSArnaldo Carvalho de Melo 		zfree(&mi->name);
88952afdaf9SAdrian Hunter 		free(mi);
89052afdaf9SAdrian Hunter 	}
89152afdaf9SAdrian Hunter }
89252afdaf9SAdrian Hunter 
89352afdaf9SAdrian Hunter static struct module_info *find_module(const char *name,
89452afdaf9SAdrian Hunter 				       struct rb_root *modules)
89552afdaf9SAdrian Hunter {
89652afdaf9SAdrian Hunter 	struct rb_node *n = modules->rb_node;
89752afdaf9SAdrian Hunter 
89852afdaf9SAdrian Hunter 	while (n) {
89952afdaf9SAdrian Hunter 		struct module_info *m;
90052afdaf9SAdrian Hunter 		int cmp;
90152afdaf9SAdrian Hunter 
90252afdaf9SAdrian Hunter 		m = rb_entry(n, struct module_info, rb_node);
90352afdaf9SAdrian Hunter 		cmp = strcmp(name, m->name);
90452afdaf9SAdrian Hunter 		if (cmp < 0)
90552afdaf9SAdrian Hunter 			n = n->rb_left;
90652afdaf9SAdrian Hunter 		else if (cmp > 0)
90752afdaf9SAdrian Hunter 			n = n->rb_right;
90852afdaf9SAdrian Hunter 		else
90952afdaf9SAdrian Hunter 			return m;
91052afdaf9SAdrian Hunter 	}
91152afdaf9SAdrian Hunter 
91252afdaf9SAdrian Hunter 	return NULL;
91352afdaf9SAdrian Hunter }
91452afdaf9SAdrian Hunter 
91552afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start)
91652afdaf9SAdrian Hunter {
91752afdaf9SAdrian Hunter 	struct rb_root *modules = arg;
91852afdaf9SAdrian Hunter 	struct module_info *mi;
91952afdaf9SAdrian Hunter 
92052afdaf9SAdrian Hunter 	mi = zalloc(sizeof(struct module_info));
92152afdaf9SAdrian Hunter 	if (!mi)
92252afdaf9SAdrian Hunter 		return -ENOMEM;
92352afdaf9SAdrian Hunter 
92452afdaf9SAdrian Hunter 	mi->name = strdup(name);
92552afdaf9SAdrian Hunter 	mi->start = start;
92652afdaf9SAdrian Hunter 
92752afdaf9SAdrian Hunter 	if (!mi->name) {
92852afdaf9SAdrian Hunter 		free(mi);
92952afdaf9SAdrian Hunter 		return -ENOMEM;
93052afdaf9SAdrian Hunter 	}
93152afdaf9SAdrian Hunter 
93252afdaf9SAdrian Hunter 	add_module(mi, modules);
93352afdaf9SAdrian Hunter 
93452afdaf9SAdrian Hunter 	return 0;
93552afdaf9SAdrian Hunter }
93652afdaf9SAdrian Hunter 
93752afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules)
93852afdaf9SAdrian Hunter {
93952afdaf9SAdrian Hunter 	if (symbol__restricted_filename(filename, "/proc/modules"))
94052afdaf9SAdrian Hunter 		return -1;
94152afdaf9SAdrian Hunter 
94252afdaf9SAdrian Hunter 	if (modules__parse(filename, modules, __read_proc_modules)) {
94352afdaf9SAdrian Hunter 		delete_modules(modules);
94452afdaf9SAdrian Hunter 		return -1;
94552afdaf9SAdrian Hunter 	}
94652afdaf9SAdrian Hunter 
94752afdaf9SAdrian Hunter 	return 0;
94852afdaf9SAdrian Hunter }
94952afdaf9SAdrian Hunter 
950fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to)
951fc1b691dSAdrian Hunter {
952fc1b691dSAdrian Hunter 	struct rb_root from_modules = RB_ROOT;
953fc1b691dSAdrian Hunter 	struct rb_root to_modules = RB_ROOT;
954fc1b691dSAdrian Hunter 	struct rb_node *from_node, *to_node;
955fc1b691dSAdrian Hunter 	struct module_info *from_m, *to_m;
956fc1b691dSAdrian Hunter 	int ret = -1;
957fc1b691dSAdrian Hunter 
958fc1b691dSAdrian Hunter 	if (read_proc_modules(from, &from_modules))
959fc1b691dSAdrian Hunter 		return -1;
960fc1b691dSAdrian Hunter 
961fc1b691dSAdrian Hunter 	if (read_proc_modules(to, &to_modules))
962fc1b691dSAdrian Hunter 		goto out_delete_from;
963fc1b691dSAdrian Hunter 
964fc1b691dSAdrian Hunter 	from_node = rb_first(&from_modules);
965fc1b691dSAdrian Hunter 	to_node = rb_first(&to_modules);
966fc1b691dSAdrian Hunter 	while (from_node) {
967fc1b691dSAdrian Hunter 		if (!to_node)
968fc1b691dSAdrian Hunter 			break;
969fc1b691dSAdrian Hunter 
970fc1b691dSAdrian Hunter 		from_m = rb_entry(from_node, struct module_info, rb_node);
971fc1b691dSAdrian Hunter 		to_m = rb_entry(to_node, struct module_info, rb_node);
972fc1b691dSAdrian Hunter 
973fc1b691dSAdrian Hunter 		if (from_m->start != to_m->start ||
974fc1b691dSAdrian Hunter 		    strcmp(from_m->name, to_m->name))
975fc1b691dSAdrian Hunter 			break;
976fc1b691dSAdrian Hunter 
977fc1b691dSAdrian Hunter 		from_node = rb_next(from_node);
978fc1b691dSAdrian Hunter 		to_node = rb_next(to_node);
979fc1b691dSAdrian Hunter 	}
980fc1b691dSAdrian Hunter 
981fc1b691dSAdrian Hunter 	if (!from_node && !to_node)
982fc1b691dSAdrian Hunter 		ret = 0;
983fc1b691dSAdrian Hunter 
984fc1b691dSAdrian Hunter 	delete_modules(&to_modules);
985fc1b691dSAdrian Hunter out_delete_from:
986fc1b691dSAdrian Hunter 	delete_modules(&from_modules);
987fc1b691dSAdrian Hunter 
988fc1b691dSAdrian Hunter 	return ret;
989fc1b691dSAdrian Hunter }
990fc1b691dSAdrian Hunter 
99152afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map,
99252afdaf9SAdrian Hunter 				  struct map_groups *kmaps)
99352afdaf9SAdrian Hunter {
99452afdaf9SAdrian Hunter 	struct rb_root modules = RB_ROOT;
99552afdaf9SAdrian Hunter 	struct map *old_map;
99652afdaf9SAdrian Hunter 	int err;
99752afdaf9SAdrian Hunter 
99852afdaf9SAdrian Hunter 	err = read_proc_modules(filename, &modules);
99952afdaf9SAdrian Hunter 	if (err)
100052afdaf9SAdrian Hunter 		return err;
100152afdaf9SAdrian Hunter 
100252afdaf9SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
100352afdaf9SAdrian Hunter 	while (old_map) {
100452afdaf9SAdrian Hunter 		struct map *next = map_groups__next(old_map);
100552afdaf9SAdrian Hunter 		struct module_info *mi;
100652afdaf9SAdrian Hunter 
100752afdaf9SAdrian Hunter 		if (old_map == map || old_map->start == map->start) {
100852afdaf9SAdrian Hunter 			/* The kernel map */
100952afdaf9SAdrian Hunter 			old_map = next;
101052afdaf9SAdrian Hunter 			continue;
101152afdaf9SAdrian Hunter 		}
101252afdaf9SAdrian Hunter 
101352afdaf9SAdrian Hunter 		/* Module must be in memory at the same address */
101452afdaf9SAdrian Hunter 		mi = find_module(old_map->dso->short_name, &modules);
101552afdaf9SAdrian Hunter 		if (!mi || mi->start != old_map->start) {
101652afdaf9SAdrian Hunter 			err = -EINVAL;
101752afdaf9SAdrian Hunter 			goto out;
101852afdaf9SAdrian Hunter 		}
101952afdaf9SAdrian Hunter 
102052afdaf9SAdrian Hunter 		old_map = next;
102152afdaf9SAdrian Hunter 	}
102252afdaf9SAdrian Hunter out:
102352afdaf9SAdrian Hunter 	delete_modules(&modules);
102452afdaf9SAdrian Hunter 	return err;
102552afdaf9SAdrian Hunter }
102652afdaf9SAdrian Hunter 
102752afdaf9SAdrian Hunter /*
102852afdaf9SAdrian Hunter  * If kallsyms is referenced by name then we look for filename in the same
102952afdaf9SAdrian Hunter  * directory.
103052afdaf9SAdrian Hunter  */
103152afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename,
103252afdaf9SAdrian Hunter 					    const char *base_name,
103352afdaf9SAdrian Hunter 					    const char *kallsyms_filename)
103452afdaf9SAdrian Hunter {
103552afdaf9SAdrian Hunter 	char *name;
103652afdaf9SAdrian Hunter 
103752afdaf9SAdrian Hunter 	strcpy(filename, kallsyms_filename);
103852afdaf9SAdrian Hunter 	name = strrchr(filename, '/');
103952afdaf9SAdrian Hunter 	if (!name)
104052afdaf9SAdrian Hunter 		return false;
104152afdaf9SAdrian Hunter 
104252afdaf9SAdrian Hunter 	name += 1;
104352afdaf9SAdrian Hunter 
104452afdaf9SAdrian Hunter 	if (!strcmp(name, "kallsyms")) {
104552afdaf9SAdrian Hunter 		strcpy(name, base_name);
104652afdaf9SAdrian Hunter 		return true;
104752afdaf9SAdrian Hunter 	}
104852afdaf9SAdrian Hunter 
104952afdaf9SAdrian Hunter 	return false;
105052afdaf9SAdrian Hunter }
105152afdaf9SAdrian Hunter 
105252afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename,
105352afdaf9SAdrian Hunter 				  struct map *map)
105452afdaf9SAdrian Hunter {
1055ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
105652afdaf9SAdrian Hunter 	char modules_filename[PATH_MAX];
105752afdaf9SAdrian Hunter 
1058ba92732eSWang Nan 	if (!kmaps)
1059ba92732eSWang Nan 		return -EINVAL;
1060ba92732eSWang Nan 
106152afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(modules_filename, "modules",
106252afdaf9SAdrian Hunter 					     kallsyms_filename))
106352afdaf9SAdrian Hunter 		return -EINVAL;
106452afdaf9SAdrian Hunter 
106552afdaf9SAdrian Hunter 	if (do_validate_kcore_modules(modules_filename, map, kmaps))
106652afdaf9SAdrian Hunter 		return -EINVAL;
106752afdaf9SAdrian Hunter 
106852afdaf9SAdrian Hunter 	return 0;
106952afdaf9SAdrian Hunter }
107052afdaf9SAdrian Hunter 
1071a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename,
1072a00d28cbSAdrian Hunter 				    struct map *map)
1073a00d28cbSAdrian Hunter {
1074a00d28cbSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1075a00d28cbSAdrian Hunter 
1076ba92732eSWang Nan 	if (!kmap)
1077ba92732eSWang Nan 		return -EINVAL;
1078ba92732eSWang Nan 
1079a00d28cbSAdrian Hunter 	if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1080a00d28cbSAdrian Hunter 		u64 start;
1081a00d28cbSAdrian Hunter 
1082a00d28cbSAdrian Hunter 		start = kallsyms__get_function_start(kallsyms_filename,
1083a00d28cbSAdrian Hunter 						     kmap->ref_reloc_sym->name);
1084a00d28cbSAdrian Hunter 		if (start != kmap->ref_reloc_sym->addr)
1085a00d28cbSAdrian Hunter 			return -EINVAL;
1086a00d28cbSAdrian Hunter 	}
1087a00d28cbSAdrian Hunter 
1088a00d28cbSAdrian Hunter 	return validate_kcore_modules(kallsyms_filename, map);
1089a00d28cbSAdrian Hunter }
1090a00d28cbSAdrian Hunter 
10918e0cf965SAdrian Hunter struct kcore_mapfn_data {
10928e0cf965SAdrian Hunter 	struct dso *dso;
10938e0cf965SAdrian Hunter 	enum map_type type;
10948e0cf965SAdrian Hunter 	struct list_head maps;
10958e0cf965SAdrian Hunter };
10968e0cf965SAdrian Hunter 
10978e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
10988e0cf965SAdrian Hunter {
10998e0cf965SAdrian Hunter 	struct kcore_mapfn_data *md = data;
11008e0cf965SAdrian Hunter 	struct map *map;
11018e0cf965SAdrian Hunter 
11028e0cf965SAdrian Hunter 	map = map__new2(start, md->dso, md->type);
11038e0cf965SAdrian Hunter 	if (map == NULL)
11048e0cf965SAdrian Hunter 		return -ENOMEM;
11058e0cf965SAdrian Hunter 
11068e0cf965SAdrian Hunter 	map->end = map->start + len;
11078e0cf965SAdrian Hunter 	map->pgoff = pgoff;
11088e0cf965SAdrian Hunter 
11098e0cf965SAdrian Hunter 	list_add(&map->node, &md->maps);
11108e0cf965SAdrian Hunter 
11118e0cf965SAdrian Hunter 	return 0;
11128e0cf965SAdrian Hunter }
11138e0cf965SAdrian Hunter 
11148e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map,
11158e0cf965SAdrian Hunter 			   const char *kallsyms_filename)
11168e0cf965SAdrian Hunter {
1117ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
1118ba92732eSWang Nan 	struct machine *machine;
11198e0cf965SAdrian Hunter 	struct kcore_mapfn_data md;
11208e0cf965SAdrian Hunter 	struct map *old_map, *new_map, *replacement_map = NULL;
11218e0cf965SAdrian Hunter 	bool is_64_bit;
11228e0cf965SAdrian Hunter 	int err, fd;
11238e0cf965SAdrian Hunter 	char kcore_filename[PATH_MAX];
11248e0cf965SAdrian Hunter 	struct symbol *sym;
11258e0cf965SAdrian Hunter 
1126ba92732eSWang Nan 	if (!kmaps)
1127ba92732eSWang Nan 		return -EINVAL;
1128ba92732eSWang Nan 
1129ba92732eSWang Nan 	machine = kmaps->machine;
1130ba92732eSWang Nan 
11318e0cf965SAdrian Hunter 	/* This function requires that the map is the kernel map */
11328e0cf965SAdrian Hunter 	if (map != machine->vmlinux_maps[map->type])
11338e0cf965SAdrian Hunter 		return -EINVAL;
11348e0cf965SAdrian Hunter 
113552afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
11368e0cf965SAdrian Hunter 					     kallsyms_filename))
11378e0cf965SAdrian Hunter 		return -EINVAL;
11388e0cf965SAdrian Hunter 
1139a00d28cbSAdrian Hunter 	/* Modules and kernel must be present at their original addresses */
1140a00d28cbSAdrian Hunter 	if (validate_kcore_addresses(kallsyms_filename, map))
114152afdaf9SAdrian Hunter 		return -EINVAL;
114252afdaf9SAdrian Hunter 
11438e0cf965SAdrian Hunter 	md.dso = dso;
11448e0cf965SAdrian Hunter 	md.type = map->type;
11458e0cf965SAdrian Hunter 	INIT_LIST_HEAD(&md.maps);
11468e0cf965SAdrian Hunter 
11478e0cf965SAdrian Hunter 	fd = open(kcore_filename, O_RDONLY);
114836c8bb56SLi Zhang 	if (fd < 0) {
1149133de940SAdrian Hunter 		pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n",
115036c8bb56SLi Zhang 			 kcore_filename);
11518e0cf965SAdrian Hunter 		return -EINVAL;
115236c8bb56SLi Zhang 	}
11538e0cf965SAdrian Hunter 
11548e0cf965SAdrian Hunter 	/* Read new maps into temporary lists */
11558e0cf965SAdrian Hunter 	err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
11568e0cf965SAdrian Hunter 			      &is_64_bit);
11578e0cf965SAdrian Hunter 	if (err)
11588e0cf965SAdrian Hunter 		goto out_err;
1159c6d8f2a4SAdrian Hunter 	dso->is_64_bit = is_64_bit;
11608e0cf965SAdrian Hunter 
11618e0cf965SAdrian Hunter 	if (list_empty(&md.maps)) {
11628e0cf965SAdrian Hunter 		err = -EINVAL;
11638e0cf965SAdrian Hunter 		goto out_err;
11648e0cf965SAdrian Hunter 	}
11658e0cf965SAdrian Hunter 
11668e0cf965SAdrian Hunter 	/* Remove old maps */
11678e0cf965SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
11688e0cf965SAdrian Hunter 	while (old_map) {
11698e0cf965SAdrian Hunter 		struct map *next = map_groups__next(old_map);
11708e0cf965SAdrian Hunter 
11718e0cf965SAdrian Hunter 		if (old_map != map)
11728e0cf965SAdrian Hunter 			map_groups__remove(kmaps, old_map);
11738e0cf965SAdrian Hunter 		old_map = next;
11748e0cf965SAdrian Hunter 	}
11758e0cf965SAdrian Hunter 
11768e0cf965SAdrian Hunter 	/* Find the kernel map using the first symbol */
11778e0cf965SAdrian Hunter 	sym = dso__first_symbol(dso, map->type);
11788e0cf965SAdrian Hunter 	list_for_each_entry(new_map, &md.maps, node) {
11798e0cf965SAdrian Hunter 		if (sym && sym->start >= new_map->start &&
11808e0cf965SAdrian Hunter 		    sym->start < new_map->end) {
11818e0cf965SAdrian Hunter 			replacement_map = new_map;
11828e0cf965SAdrian Hunter 			break;
11838e0cf965SAdrian Hunter 		}
11848e0cf965SAdrian Hunter 	}
11858e0cf965SAdrian Hunter 
11868e0cf965SAdrian Hunter 	if (!replacement_map)
11878e0cf965SAdrian Hunter 		replacement_map = list_entry(md.maps.next, struct map, node);
11888e0cf965SAdrian Hunter 
11898e0cf965SAdrian Hunter 	/* Add new maps */
11908e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
11918e0cf965SAdrian Hunter 		new_map = list_entry(md.maps.next, struct map, node);
1192facf3f06SArnaldo Carvalho de Melo 		list_del_init(&new_map->node);
11938e0cf965SAdrian Hunter 		if (new_map == replacement_map) {
11948e0cf965SAdrian Hunter 			map->start	= new_map->start;
11958e0cf965SAdrian Hunter 			map->end	= new_map->end;
11968e0cf965SAdrian Hunter 			map->pgoff	= new_map->pgoff;
11978e0cf965SAdrian Hunter 			map->map_ip	= new_map->map_ip;
11988e0cf965SAdrian Hunter 			map->unmap_ip	= new_map->unmap_ip;
11998e0cf965SAdrian Hunter 			/* Ensure maps are correctly ordered */
120084c2cafaSArnaldo Carvalho de Melo 			map__get(map);
12018e0cf965SAdrian Hunter 			map_groups__remove(kmaps, map);
12028e0cf965SAdrian Hunter 			map_groups__insert(kmaps, map);
120384c2cafaSArnaldo Carvalho de Melo 			map__put(map);
12048e0cf965SAdrian Hunter 		} else {
12058e0cf965SAdrian Hunter 			map_groups__insert(kmaps, new_map);
12068e0cf965SAdrian Hunter 		}
120784c2cafaSArnaldo Carvalho de Melo 
120884c2cafaSArnaldo Carvalho de Melo 		map__put(new_map);
12098e0cf965SAdrian Hunter 	}
12108e0cf965SAdrian Hunter 
12118e0cf965SAdrian Hunter 	/*
12128e0cf965SAdrian Hunter 	 * Set the data type and long name so that kcore can be read via
12138e0cf965SAdrian Hunter 	 * dso__data_read_addr().
12148e0cf965SAdrian Hunter 	 */
12158e0cf965SAdrian Hunter 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
12165f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
12178e0cf965SAdrian Hunter 	else
12185f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__KCORE;
12197e155d4dSArnaldo Carvalho de Melo 	dso__set_long_name(dso, strdup(kcore_filename), true);
12208e0cf965SAdrian Hunter 
12218e0cf965SAdrian Hunter 	close(fd);
12228e0cf965SAdrian Hunter 
12238e0cf965SAdrian Hunter 	if (map->type == MAP__FUNCTION)
12248e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel object code\n", kcore_filename);
12258e0cf965SAdrian Hunter 	else
12268e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel data\n", kcore_filename);
12278e0cf965SAdrian Hunter 
12288e0cf965SAdrian Hunter 	return 0;
12298e0cf965SAdrian Hunter 
12308e0cf965SAdrian Hunter out_err:
12318e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
12328e0cf965SAdrian Hunter 		map = list_entry(md.maps.next, struct map, node);
1233facf3f06SArnaldo Carvalho de Melo 		list_del_init(&map->node);
123484c2cafaSArnaldo Carvalho de Melo 		map__put(map);
12358e0cf965SAdrian Hunter 	}
12368e0cf965SAdrian Hunter 	close(fd);
12378e0cf965SAdrian Hunter 	return -EINVAL;
12388e0cf965SAdrian Hunter }
12398e0cf965SAdrian Hunter 
1240d9b62abaSAdrian Hunter /*
1241d9b62abaSAdrian Hunter  * If the kernel is relocated at boot time, kallsyms won't match.  Compute the
1242d9b62abaSAdrian Hunter  * delta based on the relocation reference symbol.
1243d9b62abaSAdrian Hunter  */
1244d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1245d9b62abaSAdrian Hunter {
1246d9b62abaSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1247d9b62abaSAdrian Hunter 	u64 addr;
1248d9b62abaSAdrian Hunter 
1249ba92732eSWang Nan 	if (!kmap)
1250ba92732eSWang Nan 		return -1;
1251ba92732eSWang Nan 
1252d9b62abaSAdrian Hunter 	if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1253d9b62abaSAdrian Hunter 		return 0;
1254d9b62abaSAdrian Hunter 
1255d9b62abaSAdrian Hunter 	addr = kallsyms__get_function_start(filename,
1256d9b62abaSAdrian Hunter 					    kmap->ref_reloc_sym->name);
1257d9b62abaSAdrian Hunter 	if (!addr)
1258d9b62abaSAdrian Hunter 		return -1;
1259d9b62abaSAdrian Hunter 
1260d9b62abaSAdrian Hunter 	*delta = addr - kmap->ref_reloc_sym->addr;
1261d9b62abaSAdrian Hunter 	return 0;
1262d9b62abaSAdrian Hunter }
1263d9b62abaSAdrian Hunter 
1264aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
12659de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
12662e538c4aSArnaldo Carvalho de Melo {
1267d9b62abaSAdrian Hunter 	u64 delta = 0;
1268d9b62abaSAdrian Hunter 
1269ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1270ec80fde7SArnaldo Carvalho de Melo 		return -1;
1271ec80fde7SArnaldo Carvalho de Melo 
1272aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
12732e538c4aSArnaldo Carvalho de Melo 		return -1;
12742e538c4aSArnaldo Carvalho de Melo 
1275d9b62abaSAdrian Hunter 	if (kallsyms__delta(map, filename, &delta))
1276d9b62abaSAdrian Hunter 		return -1;
1277d9b62abaSAdrian Hunter 
1278694bf407SAnton Blanchard 	symbols__fixup_duplicate(&dso->symbols[map->type]);
12793f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
12803f5a4272SAnton Blanchard 
1281aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
128244f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1283a1645ce1SZhang, Yanmin 	else
128444f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
12852e538c4aSArnaldo Carvalho de Melo 
12868e0cf965SAdrian Hunter 	if (!dso__load_kcore(dso, map, filename))
12878e0cf965SAdrian Hunter 		return dso__split_kallsyms_for_kcore(dso, map, filter);
12888e0cf965SAdrian Hunter 	else
1289d9b62abaSAdrian Hunter 		return dso__split_kallsyms(dso, map, delta, filter);
1290af427bf5SArnaldo Carvalho de Melo }
1291af427bf5SArnaldo Carvalho de Melo 
1292aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
12936beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
129480d496beSPekka Enberg {
129580d496beSPekka Enberg 	char *line = NULL;
129680d496beSPekka Enberg 	size_t n;
129780d496beSPekka Enberg 	FILE *file;
129880d496beSPekka Enberg 	int nr_syms = 0;
129980d496beSPekka Enberg 
1300aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
130180d496beSPekka Enberg 	if (file == NULL)
130280d496beSPekka Enberg 		goto out_failure;
130380d496beSPekka Enberg 
130480d496beSPekka Enberg 	while (!feof(file)) {
13059cffa8d5SPaul Mackerras 		u64 start, size;
130680d496beSPekka Enberg 		struct symbol *sym;
130780d496beSPekka Enberg 		int line_len, len;
130880d496beSPekka Enberg 
130980d496beSPekka Enberg 		line_len = getline(&line, &n, file);
131080d496beSPekka Enberg 		if (line_len < 0)
131180d496beSPekka Enberg 			break;
131280d496beSPekka Enberg 
131380d496beSPekka Enberg 		if (!line)
131480d496beSPekka Enberg 			goto out_failure;
131580d496beSPekka Enberg 
131680d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
131780d496beSPekka Enberg 
131880d496beSPekka Enberg 		len = hex2u64(line, &start);
131980d496beSPekka Enberg 
132080d496beSPekka Enberg 		len++;
132180d496beSPekka Enberg 		if (len + 2 >= line_len)
132280d496beSPekka Enberg 			continue;
132380d496beSPekka Enberg 
132480d496beSPekka Enberg 		len += hex2u64(line + len, &size);
132580d496beSPekka Enberg 
132680d496beSPekka Enberg 		len++;
132780d496beSPekka Enberg 		if (len + 2 >= line_len)
132880d496beSPekka Enberg 			continue;
132980d496beSPekka Enberg 
1330c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
133180d496beSPekka Enberg 
133280d496beSPekka Enberg 		if (sym == NULL)
133380d496beSPekka Enberg 			goto out_delete_line;
133480d496beSPekka Enberg 
1335439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
133600a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
133780d496beSPekka Enberg 		else {
1338aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
133980d496beSPekka Enberg 			nr_syms++;
134080d496beSPekka Enberg 		}
134180d496beSPekka Enberg 	}
134280d496beSPekka Enberg 
134380d496beSPekka Enberg 	free(line);
134480d496beSPekka Enberg 	fclose(file);
134580d496beSPekka Enberg 
134680d496beSPekka Enberg 	return nr_syms;
134780d496beSPekka Enberg 
134880d496beSPekka Enberg out_delete_line:
134980d496beSPekka Enberg 	free(line);
135080d496beSPekka Enberg out_failure:
135180d496beSPekka Enberg 	return -1;
135280d496beSPekka Enberg }
135380d496beSPekka Enberg 
13541029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
13551029f9feSNamhyung Kim 					   enum dso_binary_type type)
13561029f9feSNamhyung Kim {
13571029f9feSNamhyung Kim 	switch (type) {
13581029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__JAVA_JIT:
13591029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__DEBUGLINK:
13601029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
13611029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
13621029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
13631029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
13641029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
13651029f9feSNamhyung Kim 		return !kmod && dso->kernel == DSO_TYPE_USER;
13661029f9feSNamhyung Kim 
13671029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KALLSYMS:
13681029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__VMLINUX:
13691029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KCORE:
13701029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_KERNEL;
13711029f9feSNamhyung Kim 
13721029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
13731029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
13741029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KCORE:
13751029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
13761029f9feSNamhyung Kim 
13771029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE:
1378c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
13791029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1380c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
13811029f9feSNamhyung Kim 		/*
13821029f9feSNamhyung Kim 		 * kernel modules know their symtab type - it's set when
13839f2de315SArnaldo Carvalho de Melo 		 * creating a module dso in machine__findnew_module_map().
13841029f9feSNamhyung Kim 		 */
13851029f9feSNamhyung Kim 		return kmod && dso->symtab_type == type;
13861029f9feSNamhyung Kim 
13871029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
13881029f9feSNamhyung Kim 		return true;
13891029f9feSNamhyung Kim 
13901029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__NOT_FOUND:
13911029f9feSNamhyung Kim 	default:
13921029f9feSNamhyung Kim 		return false;
13931029f9feSNamhyung Kim 	}
13941029f9feSNamhyung Kim }
13951029f9feSNamhyung Kim 
1396aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
139786470930SIngo Molnar {
1398c338aee8SArnaldo Carvalho de Melo 	char *name;
139986470930SIngo Molnar 	int ret = -1;
140044f24cb3SJiri Olsa 	u_int i;
140123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
140244f24cb3SJiri Olsa 	char *root_dir = (char *) "";
14033aafe5aeSCody P Schafer 	int ss_pos = 0;
14043aafe5aeSCody P Schafer 	struct symsrc ss_[2];
14053aafe5aeSCody P Schafer 	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
14061029f9feSNamhyung Kim 	bool kmod;
14075baecbcdSDima Kogan 	unsigned char build_id[BUILD_ID_SIZE];
140886470930SIngo Molnar 
14094a936edcSNamhyung Kim 	pthread_mutex_lock(&dso->lock);
141066bd8424SArnaldo Carvalho de Melo 
14114a936edcSNamhyung Kim 	/* check again under the dso->lock */
14124a936edcSNamhyung Kim 	if (dso__loaded(dso, map->type)) {
14134a936edcSNamhyung Kim 		ret = 1;
14144a936edcSNamhyung Kim 		goto out;
14154a936edcSNamhyung Kim 	}
14164a936edcSNamhyung Kim 
14174a936edcSNamhyung Kim 	if (dso->kernel) {
1418aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel == DSO_TYPE_KERNEL)
14194a936edcSNamhyung Kim 			ret = dso__load_kernel_sym(dso, map, filter);
1420aeafcbafSArnaldo Carvalho de Melo 		else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
14214a936edcSNamhyung Kim 			ret = dso__load_guest_kernel_sym(dso, map, filter);
14224a936edcSNamhyung Kim 
14234a936edcSNamhyung Kim 		goto out;
14244a936edcSNamhyung Kim 	}
1425a1645ce1SZhang, Yanmin 
142623346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
142723346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1428a1645ce1SZhang, Yanmin 	else
142923346f21SArnaldo Carvalho de Melo 		machine = NULL;
1430c338aee8SArnaldo Carvalho de Melo 
1431aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1432f5812a7aSArnaldo Carvalho de Melo 
1433aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1434981c1252SPekka Enberg 		struct stat st;
1435981c1252SPekka Enberg 
1436e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
14374a936edcSNamhyung Kim 			goto out;
1438981c1252SPekka Enberg 
1439*2059fc7aSArnaldo Carvalho de Melo 		if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
1440981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1441*2059fc7aSArnaldo Carvalho de Melo 				   "ignoring it (use -f to override).\n", dso->name);
14424a936edcSNamhyung Kim 			goto out;
1443981c1252SPekka Enberg 		}
1444981c1252SPekka Enberg 
1445aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
144644f24cb3SJiri Olsa 		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
144744f24cb3SJiri Olsa 					     DSO_BINARY_TYPE__NOT_FOUND;
14484a936edcSNamhyung Kim 		goto out;
144994cb9e38SArnaldo Carvalho de Melo 	}
145094cb9e38SArnaldo Carvalho de Melo 
145144f24cb3SJiri Olsa 	if (machine)
145244f24cb3SJiri Olsa 		root_dir = machine->root_dir;
145344f24cb3SJiri Olsa 
1454164c800eSDavid Ahern 	name = malloc(PATH_MAX);
1455164c800eSDavid Ahern 	if (!name)
14564a936edcSNamhyung Kim 		goto out;
1457164c800eSDavid Ahern 
14581029f9feSNamhyung Kim 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1459c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
1460c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
1461c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
14621029f9feSNamhyung Kim 
14635baecbcdSDima Kogan 
14645baecbcdSDima Kogan 	/*
14655baecbcdSDima Kogan 	 * Read the build id if possible. This is required for
14665baecbcdSDima Kogan 	 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
14675baecbcdSDima Kogan 	 */
14685baecbcdSDima Kogan 	if (filename__read_build_id(dso->name, build_id, BUILD_ID_SIZE) > 0)
14695baecbcdSDima Kogan 		dso__set_build_id(dso, build_id);
14705baecbcdSDima Kogan 
14711029f9feSNamhyung Kim 	/*
14721029f9feSNamhyung Kim 	 * Iterate over candidate debug images.
14733aafe5aeSCody P Schafer 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
14743aafe5aeSCody P Schafer 	 * and/or opd section) for processing.
14756da80ce8SDave Martin 	 */
147644f24cb3SJiri Olsa 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
14773aafe5aeSCody P Schafer 		struct symsrc *ss = &ss_[ss_pos];
14783aafe5aeSCody P Schafer 		bool next_slot = false;
147944f24cb3SJiri Olsa 
1480005f9294SCody P Schafer 		enum dso_binary_type symtab_type = binary_type_symtab[i];
148144f24cb3SJiri Olsa 
14821029f9feSNamhyung Kim 		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
14831029f9feSNamhyung Kim 			continue;
14841029f9feSNamhyung Kim 
1485ee4e9625SArnaldo Carvalho de Melo 		if (dso__read_binary_type_filename(dso, symtab_type,
148644f24cb3SJiri Olsa 						   root_dir, name, PATH_MAX))
14876da80ce8SDave Martin 			continue;
148886470930SIngo Molnar 
14896da80ce8SDave Martin 		/* Name is now the name of the next image to try */
14903aafe5aeSCody P Schafer 		if (symsrc__init(ss, dso, name, symtab_type) < 0)
14916da80ce8SDave Martin 			continue;
14926da80ce8SDave Martin 
14933aafe5aeSCody P Schafer 		if (!syms_ss && symsrc__has_symtab(ss)) {
14943aafe5aeSCody P Schafer 			syms_ss = ss;
14953aafe5aeSCody P Schafer 			next_slot = true;
14960058aef6SAdrian Hunter 			if (!dso->symsrc_filename)
14970058aef6SAdrian Hunter 				dso->symsrc_filename = strdup(name);
1498d26cd12bSCody P Schafer 		}
1499d26cd12bSCody P Schafer 
15003aafe5aeSCody P Schafer 		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
15013aafe5aeSCody P Schafer 			runtime_ss = ss;
15023aafe5aeSCody P Schafer 			next_slot = true;
1503a44f605bSCody P Schafer 		}
150486470930SIngo Molnar 
15053aafe5aeSCody P Schafer 		if (next_slot) {
15063aafe5aeSCody P Schafer 			ss_pos++;
150733ff581eSJiri Olsa 
15083aafe5aeSCody P Schafer 			if (syms_ss && runtime_ss)
15096da80ce8SDave Martin 				break;
151098e9f03bSNamhyung Kim 		} else {
151198e9f03bSNamhyung Kim 			symsrc__destroy(ss);
1512a25e46c4SArnaldo Carvalho de Melo 		}
15133aafe5aeSCody P Schafer 
15146da80ce8SDave Martin 	}
15156da80ce8SDave Martin 
15163aafe5aeSCody P Schafer 	if (!runtime_ss && !syms_ss)
15173aafe5aeSCody P Schafer 		goto out_free;
15183aafe5aeSCody P Schafer 
15193aafe5aeSCody P Schafer 	if (runtime_ss && !syms_ss) {
15203aafe5aeSCody P Schafer 		syms_ss = runtime_ss;
152160e4b10cSArnaldo Carvalho de Melo 	}
152260e4b10cSArnaldo Carvalho de Melo 
15233aafe5aeSCody P Schafer 	/* We'll have to hope for the best */
15243aafe5aeSCody P Schafer 	if (!runtime_ss && syms_ss)
15253aafe5aeSCody P Schafer 		runtime_ss = syms_ss;
15263aafe5aeSCody P Schafer 
15271029f9feSNamhyung Kim 	if (syms_ss)
15281029f9feSNamhyung Kim 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
15291029f9feSNamhyung Kim 	else
15303aafe5aeSCody P Schafer 		ret = -1;
15313aafe5aeSCody P Schafer 
1532f47b58b7SDavid Ahern 	if (ret > 0) {
15333aafe5aeSCody P Schafer 		int nr_plt;
15343aafe5aeSCody P Schafer 
15353aafe5aeSCody P Schafer 		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
15363aafe5aeSCody P Schafer 		if (nr_plt > 0)
15373aafe5aeSCody P Schafer 			ret += nr_plt;
15383aafe5aeSCody P Schafer 	}
15393aafe5aeSCody P Schafer 
15403aafe5aeSCody P Schafer 	for (; ss_pos > 0; ss_pos--)
15413aafe5aeSCody P Schafer 		symsrc__destroy(&ss_[ss_pos - 1]);
15423aafe5aeSCody P Schafer out_free:
154386470930SIngo Molnar 	free(name);
1544aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
15454a936edcSNamhyung Kim 		ret = 0;
15464a936edcSNamhyung Kim out:
15474a936edcSNamhyung Kim 	dso__set_loaded(dso, map->type);
15484a936edcSNamhyung Kim 	pthread_mutex_unlock(&dso->lock);
15494a936edcSNamhyung Kim 
155086470930SIngo Molnar 	return ret;
155186470930SIngo Molnar }
155286470930SIngo Molnar 
1553aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
155479406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1555439d473bSArnaldo Carvalho de Melo {
15561eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
15574bb7123dSArnaldo Carvalho de Melo 	struct map *map;
1558439d473bSArnaldo Carvalho de Melo 
15596a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_rdlock(&maps->lock);
15606a2ffcddSArnaldo Carvalho de Melo 
15614bb7123dSArnaldo Carvalho de Melo 	for (map = maps__first(maps); map; map = map__next(map)) {
1562b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
15636a2ffcddSArnaldo Carvalho de Melo 			goto out_unlock;
1564439d473bSArnaldo Carvalho de Melo 	}
1565439d473bSArnaldo Carvalho de Melo 
15666a2ffcddSArnaldo Carvalho de Melo 	map = NULL;
15676a2ffcddSArnaldo Carvalho de Melo 
15686a2ffcddSArnaldo Carvalho de Melo out_unlock:
15696a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_unlock(&maps->lock);
15706a2ffcddSArnaldo Carvalho de Melo 	return map;
1571439d473bSArnaldo Carvalho de Melo }
1572439d473bSArnaldo Carvalho de Melo 
1573aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
15745230fb7dSArnaldo Carvalho de Melo 		      const char *vmlinux, bool vmlinux_allocated,
15755230fb7dSArnaldo Carvalho de Melo 		      symbol_filter_t filter)
157686470930SIngo Molnar {
1577b68e2f91SCody P Schafer 	int err = -1;
1578b68e2f91SCody P Schafer 	struct symsrc ss;
1579ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
1580005f9294SCody P Schafer 	enum dso_binary_type symtab_type;
158186470930SIngo Molnar 
15825698d2c9SNamhyung Kim 	if (vmlinux[0] == '/')
15835698d2c9SNamhyung Kim 		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
15845698d2c9SNamhyung Kim 	else
1585972f393bSArnaldo Carvalho de Melo 		symbol__join_symfs(symfs_vmlinux, vmlinux);
158686470930SIngo Molnar 
158721ea4539SCody P Schafer 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1588005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
158921ea4539SCody P Schafer 	else
1590005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__VMLINUX;
159121ea4539SCody P Schafer 
1592005f9294SCody P Schafer 	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1593b68e2f91SCody P Schafer 		return -1;
1594b68e2f91SCody P Schafer 
1595261360b6SCody P Schafer 	err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
1596b68e2f91SCody P Schafer 	symsrc__destroy(&ss);
159786470930SIngo Molnar 
1598515850e4SCody P Schafer 	if (err > 0) {
159939b12f78SAdrian Hunter 		if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
16005f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
160139b12f78SAdrian Hunter 		else
16025f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
1603bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, vmlinux, vmlinux_allocated);
1604515850e4SCody P Schafer 		dso__set_loaded(dso, map->type);
1605ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
1606515850e4SCody P Schafer 	}
16073846df2eSArnaldo Carvalho de Melo 
160886470930SIngo Molnar 	return err;
160986470930SIngo Molnar }
161086470930SIngo Molnar 
1611aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
16129de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1613a19afe46SArnaldo Carvalho de Melo {
1614a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
161500dc8657SNamhyung Kim 	char *filename = NULL;
1616a19afe46SArnaldo Carvalho de Melo 
1617dc38218eSArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1618dc38218eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
1619dc38218eSArnaldo Carvalho de Melo 
1620dc38218eSArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1621dc38218eSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
1622dc38218eSArnaldo Carvalho de Melo 		if (err > 0)
1623dc38218eSArnaldo Carvalho de Melo 			goto out;
1624dc38218eSArnaldo Carvalho de Melo 	}
1625dc38218eSArnaldo Carvalho de Melo 
162600dc8657SNamhyung Kim 	if (!symbol_conf.ignore_vmlinux_buildid)
1627aeafcbafSArnaldo Carvalho de Melo 		filename = dso__build_id_filename(dso, NULL, 0);
16285ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
16295230fb7dSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, true, filter);
16305230fb7dSArnaldo Carvalho de Melo 		if (err > 0)
16315ad90e4eSArnaldo Carvalho de Melo 			goto out;
16325ad90e4eSArnaldo Carvalho de Melo 		free(filename);
16335ad90e4eSArnaldo Carvalho de Melo 	}
16345ad90e4eSArnaldo Carvalho de Melo out:
1635a19afe46SArnaldo Carvalho de Melo 	return err;
1636a19afe46SArnaldo Carvalho de Melo }
1637a19afe46SArnaldo Carvalho de Melo 
16380544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
16390544d422SAdrian Hunter {
16400544d422SAdrian Hunter 	char kallsyms_filename[PATH_MAX];
16410544d422SAdrian Hunter 	struct dirent *dent;
16420544d422SAdrian Hunter 	int ret = -1;
16430544d422SAdrian Hunter 	DIR *d;
16440544d422SAdrian Hunter 
16450544d422SAdrian Hunter 	d = opendir(dir);
16460544d422SAdrian Hunter 	if (!d)
16470544d422SAdrian Hunter 		return -1;
16480544d422SAdrian Hunter 
16490544d422SAdrian Hunter 	while (1) {
16500544d422SAdrian Hunter 		dent = readdir(d);
16510544d422SAdrian Hunter 		if (!dent)
16520544d422SAdrian Hunter 			break;
16530544d422SAdrian Hunter 		if (dent->d_type != DT_DIR)
16540544d422SAdrian Hunter 			continue;
16550544d422SAdrian Hunter 		scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
16560544d422SAdrian Hunter 			  "%s/%s/kallsyms", dir, dent->d_name);
1657a00d28cbSAdrian Hunter 		if (!validate_kcore_addresses(kallsyms_filename, map)) {
16580544d422SAdrian Hunter 			strlcpy(dir, kallsyms_filename, dir_sz);
16590544d422SAdrian Hunter 			ret = 0;
16600544d422SAdrian Hunter 			break;
16610544d422SAdrian Hunter 		}
16620544d422SAdrian Hunter 	}
16630544d422SAdrian Hunter 
16640544d422SAdrian Hunter 	closedir(d);
16650544d422SAdrian Hunter 
16660544d422SAdrian Hunter 	return ret;
16670544d422SAdrian Hunter }
16680544d422SAdrian Hunter 
16690544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map)
16700544d422SAdrian Hunter {
16710544d422SAdrian Hunter 	u8 host_build_id[BUILD_ID_SIZE];
16720544d422SAdrian Hunter 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
16730544d422SAdrian Hunter 	bool is_host = false;
16740544d422SAdrian Hunter 	char path[PATH_MAX];
16750544d422SAdrian Hunter 
16760544d422SAdrian Hunter 	if (!dso->has_build_id) {
16770544d422SAdrian Hunter 		/*
16780544d422SAdrian Hunter 		 * Last resort, if we don't have a build-id and couldn't find
16790544d422SAdrian Hunter 		 * any vmlinux file, try the running kernel kallsyms table.
16800544d422SAdrian Hunter 		 */
16810544d422SAdrian Hunter 		goto proc_kallsyms;
16820544d422SAdrian Hunter 	}
16830544d422SAdrian Hunter 
16840544d422SAdrian Hunter 	if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
16850544d422SAdrian Hunter 				 sizeof(host_build_id)) == 0)
16860544d422SAdrian Hunter 		is_host = dso__build_id_equal(dso, host_build_id);
16870544d422SAdrian Hunter 
16880544d422SAdrian Hunter 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
16890544d422SAdrian Hunter 
1690449867e3SAdrian Hunter 	scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
1691449867e3SAdrian Hunter 		  sbuild_id);
1692449867e3SAdrian Hunter 
16930544d422SAdrian Hunter 	/* Use /proc/kallsyms if possible */
16940544d422SAdrian Hunter 	if (is_host) {
16950544d422SAdrian Hunter 		DIR *d;
16960544d422SAdrian Hunter 		int fd;
16970544d422SAdrian Hunter 
16980544d422SAdrian Hunter 		/* If no cached kcore go with /proc/kallsyms */
16990544d422SAdrian Hunter 		d = opendir(path);
17000544d422SAdrian Hunter 		if (!d)
17010544d422SAdrian Hunter 			goto proc_kallsyms;
17020544d422SAdrian Hunter 		closedir(d);
17030544d422SAdrian Hunter 
17040544d422SAdrian Hunter 		/*
17050544d422SAdrian Hunter 		 * Do not check the build-id cache, until we know we cannot use
17060544d422SAdrian Hunter 		 * /proc/kcore.
17070544d422SAdrian Hunter 		 */
17080544d422SAdrian Hunter 		fd = open("/proc/kcore", O_RDONLY);
17090544d422SAdrian Hunter 		if (fd != -1) {
17100544d422SAdrian Hunter 			close(fd);
17110544d422SAdrian Hunter 			/* If module maps match go with /proc/kallsyms */
1712a00d28cbSAdrian Hunter 			if (!validate_kcore_addresses("/proc/kallsyms", map))
17130544d422SAdrian Hunter 				goto proc_kallsyms;
17140544d422SAdrian Hunter 		}
17150544d422SAdrian Hunter 
17160544d422SAdrian Hunter 		/* Find kallsyms in build-id cache with kcore */
17170544d422SAdrian Hunter 		if (!find_matching_kcore(map, path, sizeof(path)))
17180544d422SAdrian Hunter 			return strdup(path);
17190544d422SAdrian Hunter 
17200544d422SAdrian Hunter 		goto proc_kallsyms;
17210544d422SAdrian Hunter 	}
17220544d422SAdrian Hunter 
1723449867e3SAdrian Hunter 	/* Find kallsyms in build-id cache with kcore */
1724449867e3SAdrian Hunter 	if (!find_matching_kcore(map, path, sizeof(path)))
1725449867e3SAdrian Hunter 		return strdup(path);
1726449867e3SAdrian Hunter 
17270544d422SAdrian Hunter 	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
17280544d422SAdrian Hunter 		  buildid_dir, sbuild_id);
17290544d422SAdrian Hunter 
17300544d422SAdrian Hunter 	if (access(path, F_OK)) {
17310544d422SAdrian Hunter 		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
17320544d422SAdrian Hunter 		       sbuild_id);
17330544d422SAdrian Hunter 		return NULL;
17340544d422SAdrian Hunter 	}
17350544d422SAdrian Hunter 
17360544d422SAdrian Hunter 	return strdup(path);
17370544d422SAdrian Hunter 
17380544d422SAdrian Hunter proc_kallsyms:
17390544d422SAdrian Hunter 	return strdup("/proc/kallsyms");
17400544d422SAdrian Hunter }
17410544d422SAdrian Hunter 
1742aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
17439de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
174486470930SIngo Molnar {
1745cc612d81SArnaldo Carvalho de Melo 	int err;
17469e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
17479e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1748dc8d6ab2SArnaldo Carvalho de Melo 	/*
1749b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1750b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1751dc8d6ab2SArnaldo Carvalho de Melo 	 *
1752dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1753dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1754dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1755dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1756dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1757dc8d6ab2SArnaldo Carvalho de Melo 	 *
1758dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1759dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1760dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1761dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1762dc8d6ab2SArnaldo Carvalho de Melo 	 */
1763b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1764b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1765b226a5a7SDavid Ahern 		goto do_kallsyms;
1766b226a5a7SDavid Ahern 	}
1767b226a5a7SDavid Ahern 
1768fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
17695230fb7dSArnaldo Carvalho de Melo 		return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
17705230fb7dSArnaldo Carvalho de Melo 					 false, filter);
1771dc8d6ab2SArnaldo Carvalho de Melo 	}
1772439d473bSArnaldo Carvalho de Melo 
1773fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
1774aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
1775a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
177639b12f78SAdrian Hunter 			return err;
1777cc612d81SArnaldo Carvalho de Melo 	}
1778cc612d81SArnaldo Carvalho de Melo 
1779ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1780ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1781ec5761eaSDavid Ahern 		return -1;
1782ec5761eaSDavid Ahern 
17830544d422SAdrian Hunter 	kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
17840544d422SAdrian Hunter 	if (!kallsyms_allocated_filename)
17858d0591f6SArnaldo Carvalho de Melo 		return -1;
17868d0591f6SArnaldo Carvalho de Melo 
178719fc2dedSArnaldo Carvalho de Melo 	kallsyms_filename = kallsyms_allocated_filename;
178819fc2dedSArnaldo Carvalho de Melo 
1789dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
1790aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
17913846df2eSArnaldo Carvalho de Melo 	if (err > 0)
17923846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1793dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1794dc8d6ab2SArnaldo Carvalho de Melo 
17958e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1796bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
1797bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, "[kernel.kallsyms]", false);
17986a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
17996a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1800439d473bSArnaldo Carvalho de Melo 	}
180194cb9e38SArnaldo Carvalho de Melo 
180286470930SIngo Molnar 	return err;
180386470930SIngo Molnar }
180486470930SIngo Molnar 
1805aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1806a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
1807a1645ce1SZhang, Yanmin {
1808a1645ce1SZhang, Yanmin 	int err;
1809a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
181023346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1811a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1812a1645ce1SZhang, Yanmin 
1813a1645ce1SZhang, Yanmin 	if (!map->groups) {
1814a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1815a1645ce1SZhang, Yanmin 		return -1;
1816a1645ce1SZhang, Yanmin 	}
181723346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1818a1645ce1SZhang, Yanmin 
181923346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1820a1645ce1SZhang, Yanmin 		/*
1821a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1822a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1823a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1824a1645ce1SZhang, Yanmin 		 */
1825a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1826aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
18275230fb7dSArnaldo Carvalho de Melo 						symbol_conf.default_guest_vmlinux_name,
18285230fb7dSArnaldo Carvalho de Melo 						false, filter);
182939b12f78SAdrian Hunter 			return err;
1830a1645ce1SZhang, Yanmin 		}
1831a1645ce1SZhang, Yanmin 
1832a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1833a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1834a1645ce1SZhang, Yanmin 			return -1;
1835a1645ce1SZhang, Yanmin 	} else {
183623346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1837a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1838a1645ce1SZhang, Yanmin 	}
1839a1645ce1SZhang, Yanmin 
1840aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
18418e0cf965SAdrian Hunter 	if (err > 0)
184239b12f78SAdrian Hunter 		pr_debug("Using %s for symbols\n", kallsyms_filename);
18438e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1844bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
184548ea8f54SArnaldo Carvalho de Melo 		machine__mmap_name(machine, path, sizeof(path));
18467e155d4dSArnaldo Carvalho de Melo 		dso__set_long_name(dso, strdup(path), true);
1847a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1848a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1849a1645ce1SZhang, Yanmin 	}
1850a1645ce1SZhang, Yanmin 
1851a1645ce1SZhang, Yanmin 	return err;
1852a1645ce1SZhang, Yanmin }
1853cd84c2acSFrederic Weisbecker 
1854cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
18552446042cSArnaldo Carvalho de Melo {
185604662523SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0)
185704662523SArnaldo Carvalho de Melo 		zfree(&vmlinux_path[vmlinux_path__nr_entries]);
1858c4f03547SWang Nan 	vmlinux_path__nr_entries = 0;
1859cc612d81SArnaldo Carvalho de Melo 
186004662523SArnaldo Carvalho de Melo 	zfree(&vmlinux_path);
1861cc612d81SArnaldo Carvalho de Melo }
1862cc612d81SArnaldo Carvalho de Melo 
1863ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env)
1864cc612d81SArnaldo Carvalho de Melo {
1865cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1866cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
18670a7e6d1bSNamhyung Kim 	char *kernel_version;
1868cc612d81SArnaldo Carvalho de Melo 
1869c657f423SAnton Blanchard 	vmlinux_path = malloc(sizeof(char *) * 6);
1870cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1871cc612d81SArnaldo Carvalho de Melo 		return -1;
1872cc612d81SArnaldo Carvalho de Melo 
1873cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1874cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1875cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1876cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1877cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1878cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1879cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1880cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1881ec5761eaSDavid Ahern 
18820a7e6d1bSNamhyung Kim 	/* only try kernel version if no symfs was given */
1883ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1884ec5761eaSDavid Ahern 		return 0;
1885ec5761eaSDavid Ahern 
18860a7e6d1bSNamhyung Kim 	if (env) {
18870a7e6d1bSNamhyung Kim 		kernel_version = env->os_release;
18880a7e6d1bSNamhyung Kim 	} else {
1889ec5761eaSDavid Ahern 		if (uname(&uts) < 0)
1890e96c674fSNamhyung Kim 			goto out_fail;
1891ec5761eaSDavid Ahern 
18920a7e6d1bSNamhyung Kim 		kernel_version = uts.release;
18930a7e6d1bSNamhyung Kim 	}
18940a7e6d1bSNamhyung Kim 
18950a7e6d1bSNamhyung Kim 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
1896cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1897cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1898cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1899cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1900c657f423SAnton Blanchard 	snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
1901c657f423SAnton Blanchard 		 kernel_version);
1902c657f423SAnton Blanchard 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1903c657f423SAnton Blanchard 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1904c657f423SAnton Blanchard 		goto out_fail;
1905c657f423SAnton Blanchard         ++vmlinux_path__nr_entries;
19060a7e6d1bSNamhyung Kim 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
1907cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1908cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1909cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1910cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1911cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
19120a7e6d1bSNamhyung Kim 		 kernel_version);
1913cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1914cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1915cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1916cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1917cc612d81SArnaldo Carvalho de Melo 
1918cc612d81SArnaldo Carvalho de Melo 	return 0;
1919cc612d81SArnaldo Carvalho de Melo 
1920cc612d81SArnaldo Carvalho de Melo out_fail:
1921cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1922cc612d81SArnaldo Carvalho de Melo 	return -1;
1923cc612d81SArnaldo Carvalho de Melo }
1924cc612d81SArnaldo Carvalho de Melo 
19253bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str,
1926655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
1927655000e7SArnaldo Carvalho de Melo {
1928655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
1929655000e7SArnaldo Carvalho de Melo 		return 0;
1930655000e7SArnaldo Carvalho de Melo 
19314a77e218SArnaldo Carvalho de Melo 	*list = strlist__new(list_str, NULL);
1932655000e7SArnaldo Carvalho de Melo 	if (!*list) {
1933655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
1934655000e7SArnaldo Carvalho de Melo 		return -1;
1935655000e7SArnaldo Carvalho de Melo 	}
19360bc2f2f7SArnaldo Carvalho de Melo 
19370bc2f2f7SArnaldo Carvalho de Melo 	symbol_conf.has_filter = true;
1938655000e7SArnaldo Carvalho de Melo 	return 0;
1939655000e7SArnaldo Carvalho de Melo }
1940655000e7SArnaldo Carvalho de Melo 
1941e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str,
1942e03eaa40SDavid Ahern 		  const char *list_name)
1943e03eaa40SDavid Ahern {
1944e03eaa40SDavid Ahern 	if (list_str == NULL)
1945e03eaa40SDavid Ahern 		return 0;
1946e03eaa40SDavid Ahern 
1947e03eaa40SDavid Ahern 	*list = intlist__new(list_str);
1948e03eaa40SDavid Ahern 	if (!*list) {
1949e03eaa40SDavid Ahern 		pr_err("problems parsing %s list\n", list_name);
1950e03eaa40SDavid Ahern 		return -1;
1951e03eaa40SDavid Ahern 	}
1952e03eaa40SDavid Ahern 	return 0;
1953e03eaa40SDavid Ahern }
1954e03eaa40SDavid Ahern 
1955ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
1956ec80fde7SArnaldo Carvalho de Melo {
1957ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
1958ec80fde7SArnaldo Carvalho de Melo 
1959ec80fde7SArnaldo Carvalho de Melo 	if (geteuid() != 0) {
1960ec80fde7SArnaldo Carvalho de Melo 		FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
1961ec80fde7SArnaldo Carvalho de Melo 		if (fp != NULL) {
1962ec80fde7SArnaldo Carvalho de Melo 			char line[8];
1963ec80fde7SArnaldo Carvalho de Melo 
1964ec80fde7SArnaldo Carvalho de Melo 			if (fgets(line, sizeof(line), fp) != NULL)
1965ec80fde7SArnaldo Carvalho de Melo 				value = atoi(line) != 0;
1966ec80fde7SArnaldo Carvalho de Melo 
1967ec80fde7SArnaldo Carvalho de Melo 			fclose(fp);
1968ec80fde7SArnaldo Carvalho de Melo 		}
1969ec80fde7SArnaldo Carvalho de Melo 	}
1970ec80fde7SArnaldo Carvalho de Melo 
1971ec80fde7SArnaldo Carvalho de Melo 	return value;
1972ec80fde7SArnaldo Carvalho de Melo }
1973ec80fde7SArnaldo Carvalho de Melo 
1974ce80d3beSKan Liang int symbol__init(struct perf_env *env)
1975cc612d81SArnaldo Carvalho de Melo {
1976ec5761eaSDavid Ahern 	const char *symfs;
1977ec5761eaSDavid Ahern 
197885e00b55SJovi Zhang 	if (symbol_conf.initialized)
197985e00b55SJovi Zhang 		return 0;
198085e00b55SJovi Zhang 
19819ac3e487SIrina Tirdea 	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
19824d439517SDavid S. Miller 
1983166ccc9cSNamhyung Kim 	symbol__elf_init();
1984166ccc9cSNamhyung Kim 
198575be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
198675be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
198779406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
1988b32d133aSArnaldo Carvalho de Melo 
19890a7e6d1bSNamhyung Kim 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
1990cc612d81SArnaldo Carvalho de Melo 		return -1;
1991cc612d81SArnaldo Carvalho de Melo 
1992c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1993c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
1994c410a338SArnaldo Carvalho de Melo 		return -1;
1995c410a338SArnaldo Carvalho de Melo 	}
1996c410a338SArnaldo Carvalho de Melo 
1997655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
1998655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
1999655000e7SArnaldo Carvalho de Melo 		return -1;
2000655000e7SArnaldo Carvalho de Melo 
2001655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2002655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2003655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2004655000e7SArnaldo Carvalho de Melo 
2005e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.pid_list,
2006e03eaa40SDavid Ahern 		       symbol_conf.pid_list_str, "pid") < 0)
2007e03eaa40SDavid Ahern 		goto out_free_comm_list;
2008e03eaa40SDavid Ahern 
2009e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.tid_list,
2010e03eaa40SDavid Ahern 		       symbol_conf.tid_list_str, "tid") < 0)
2011e03eaa40SDavid Ahern 		goto out_free_pid_list;
2012e03eaa40SDavid Ahern 
2013655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2014655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2015e03eaa40SDavid Ahern 		goto out_free_tid_list;
2016655000e7SArnaldo Carvalho de Melo 
2017ec5761eaSDavid Ahern 	/*
2018ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2019ec5761eaSDavid Ahern 	 * reset here for simplicity.
2020ec5761eaSDavid Ahern 	 */
2021ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2022ec5761eaSDavid Ahern 	if (symfs == NULL)
2023ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2024ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2025ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2026ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2027ec5761eaSDavid Ahern 		free((void *)symfs);
2028ec5761eaSDavid Ahern 
2029ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2030ec80fde7SArnaldo Carvalho de Melo 
203185e00b55SJovi Zhang 	symbol_conf.initialized = true;
20324aa65636SArnaldo Carvalho de Melo 	return 0;
2033655000e7SArnaldo Carvalho de Melo 
2034e03eaa40SDavid Ahern out_free_tid_list:
2035e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2036e03eaa40SDavid Ahern out_free_pid_list:
2037e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2038655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2039655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2040d74c896bSNamhyung Kim out_free_dso_list:
2041d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2042655000e7SArnaldo Carvalho de Melo 	return -1;
2043cc612d81SArnaldo Carvalho de Melo }
2044cc612d81SArnaldo Carvalho de Melo 
2045d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2046d65a458bSArnaldo Carvalho de Melo {
204785e00b55SJovi Zhang 	if (!symbol_conf.initialized)
204885e00b55SJovi Zhang 		return;
2049d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2050d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2051d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2052e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2053e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2054d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2055d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
205685e00b55SJovi Zhang 	symbol_conf.initialized = false;
2057d65a458bSArnaldo Carvalho de Melo }
2058