xref: /linux/tools/perf/util/symbol.c (revision 0bc2f2f7d080561cc484d2d0a162a9396bed3383)
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 
444aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
44579406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
446fcf1203aSArnaldo Carvalho de Melo {
447aeafcbafSArnaldo Carvalho de Melo 	return symbols__find(&dso->symbols[type], addr);
448fcf1203aSArnaldo Carvalho de Melo }
449fcf1203aSArnaldo Carvalho de Melo 
4509c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
4518e0cf965SAdrian Hunter {
4528e0cf965SAdrian Hunter 	return symbols__first(&dso->symbols[type]);
4538e0cf965SAdrian Hunter }
4548e0cf965SAdrian Hunter 
4559c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym)
4569c00a81bSAdrian Hunter {
4579c00a81bSAdrian Hunter 	return symbols__next(sym);
4589c00a81bSAdrian Hunter }
4599c00a81bSAdrian Hunter 
46018bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym)
46118bd7264SArnaldo Carvalho de Melo {
46218bd7264SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
46318bd7264SArnaldo Carvalho de Melo 	struct rb_node *n = rb_next(&s->rb_node);
46418bd7264SArnaldo Carvalho de Melo 
46518bd7264SArnaldo Carvalho de Melo 	return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
46618bd7264SArnaldo Carvalho de Melo }
46718bd7264SArnaldo Carvalho de Melo 
46818bd7264SArnaldo Carvalho de Melo  /*
46918bd7264SArnaldo Carvalho de Melo   * Teturns first symbol that matched with @name.
47018bd7264SArnaldo Carvalho de Melo   */
471aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
47279406cd7SArnaldo Carvalho de Melo 					const char *name)
47379406cd7SArnaldo Carvalho de Melo {
474aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
47579406cd7SArnaldo Carvalho de Melo }
47679406cd7SArnaldo Carvalho de Melo 
477aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
47879406cd7SArnaldo Carvalho de Melo {
479aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
480aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
481aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
48279406cd7SArnaldo Carvalho de Melo }
48379406cd7SArnaldo Carvalho de Melo 
484aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso,
485aeafcbafSArnaldo Carvalho de Melo 				    enum map_type type, FILE *fp)
48690f18e63SSrikar Dronamraju {
48790f18e63SSrikar Dronamraju 	size_t ret = 0;
48890f18e63SSrikar Dronamraju 	struct rb_node *nd;
48990f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
49090f18e63SSrikar Dronamraju 
491aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
49290f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
49390f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
49490f18e63SSrikar Dronamraju 	}
49590f18e63SSrikar Dronamraju 
49690f18e63SSrikar Dronamraju 	return ret;
49790f18e63SSrikar Dronamraju }
49890f18e63SSrikar Dronamraju 
499316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg,
500316d70d6SAdrian Hunter 		   int (*process_module)(void *arg, const char *name,
501316d70d6SAdrian Hunter 					 u64 start))
502316d70d6SAdrian Hunter {
503316d70d6SAdrian Hunter 	char *line = NULL;
504316d70d6SAdrian Hunter 	size_t n;
505316d70d6SAdrian Hunter 	FILE *file;
506316d70d6SAdrian Hunter 	int err = 0;
507316d70d6SAdrian Hunter 
508316d70d6SAdrian Hunter 	file = fopen(filename, "r");
509316d70d6SAdrian Hunter 	if (file == NULL)
510316d70d6SAdrian Hunter 		return -1;
511316d70d6SAdrian Hunter 
512316d70d6SAdrian Hunter 	while (1) {
513316d70d6SAdrian Hunter 		char name[PATH_MAX];
514316d70d6SAdrian Hunter 		u64 start;
515316d70d6SAdrian Hunter 		char *sep;
516316d70d6SAdrian Hunter 		ssize_t line_len;
517316d70d6SAdrian Hunter 
518316d70d6SAdrian Hunter 		line_len = getline(&line, &n, file);
519316d70d6SAdrian Hunter 		if (line_len < 0) {
520316d70d6SAdrian Hunter 			if (feof(file))
521316d70d6SAdrian Hunter 				break;
522316d70d6SAdrian Hunter 			err = -1;
523316d70d6SAdrian Hunter 			goto out;
524316d70d6SAdrian Hunter 		}
525316d70d6SAdrian Hunter 
526316d70d6SAdrian Hunter 		if (!line) {
527316d70d6SAdrian Hunter 			err = -1;
528316d70d6SAdrian Hunter 			goto out;
529316d70d6SAdrian Hunter 		}
530316d70d6SAdrian Hunter 
531316d70d6SAdrian Hunter 		line[--line_len] = '\0'; /* \n */
532316d70d6SAdrian Hunter 
533316d70d6SAdrian Hunter 		sep = strrchr(line, 'x');
534316d70d6SAdrian Hunter 		if (sep == NULL)
535316d70d6SAdrian Hunter 			continue;
536316d70d6SAdrian Hunter 
537316d70d6SAdrian Hunter 		hex2u64(sep + 1, &start);
538316d70d6SAdrian Hunter 
539316d70d6SAdrian Hunter 		sep = strchr(line, ' ');
540316d70d6SAdrian Hunter 		if (sep == NULL)
541316d70d6SAdrian Hunter 			continue;
542316d70d6SAdrian Hunter 
543316d70d6SAdrian Hunter 		*sep = '\0';
544316d70d6SAdrian Hunter 
545316d70d6SAdrian Hunter 		scnprintf(name, sizeof(name), "[%s]", line);
546316d70d6SAdrian Hunter 
547316d70d6SAdrian Hunter 		err = process_module(arg, name, start);
548316d70d6SAdrian Hunter 		if (err)
549316d70d6SAdrian Hunter 			break;
550316d70d6SAdrian Hunter 	}
551316d70d6SAdrian Hunter out:
552316d70d6SAdrian Hunter 	free(line);
553316d70d6SAdrian Hunter 	fclose(file);
554316d70d6SAdrian Hunter 	return err;
555316d70d6SAdrian Hunter }
556316d70d6SAdrian Hunter 
557682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
558682b335aSArnaldo Carvalho de Melo 	struct map *map;
559682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
560682b335aSArnaldo Carvalho de Melo };
561682b335aSArnaldo Carvalho de Melo 
562e7110b9fSArnaldo Carvalho de Melo /*
563e7110b9fSArnaldo Carvalho de Melo  * These are symbols in the kernel image, so make sure that
564e7110b9fSArnaldo Carvalho de Melo  * sym is from a kernel DSO.
565e7110b9fSArnaldo Carvalho de Melo  */
56682d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym)
56782d1deb0SDavid Ahern {
56882d1deb0SDavid Ahern 	const char * const idle_symbols[] = {
56982d1deb0SDavid Ahern 		"cpu_idle",
570e0336ed6SArnaldo Carvalho de Melo 		"cpu_startup_entry",
57182d1deb0SDavid Ahern 		"intel_idle",
57282d1deb0SDavid Ahern 		"default_idle",
57382d1deb0SDavid Ahern 		"native_safe_halt",
57482d1deb0SDavid Ahern 		"enter_idle",
57582d1deb0SDavid Ahern 		"exit_idle",
57682d1deb0SDavid Ahern 		"mwait_idle",
57782d1deb0SDavid Ahern 		"mwait_idle_with_hints",
57882d1deb0SDavid Ahern 		"poll_idle",
57982d1deb0SDavid Ahern 		"ppc64_runlatch_off",
58082d1deb0SDavid Ahern 		"pseries_dedicated_idle_sleep",
58182d1deb0SDavid Ahern 		NULL
58282d1deb0SDavid Ahern 	};
58382d1deb0SDavid Ahern 
58482d1deb0SDavid Ahern 	int i;
58582d1deb0SDavid Ahern 
58682d1deb0SDavid Ahern 	if (!sym)
58782d1deb0SDavid Ahern 		return false;
58882d1deb0SDavid Ahern 
58982d1deb0SDavid Ahern 	for (i = 0; idle_symbols[i]; i++) {
59082d1deb0SDavid Ahern 		if (!strcmp(idle_symbols[i], sym->name))
59182d1deb0SDavid Ahern 			return true;
59282d1deb0SDavid Ahern 	}
59382d1deb0SDavid Ahern 
59482d1deb0SDavid Ahern 	return false;
59582d1deb0SDavid Ahern }
59682d1deb0SDavid Ahern 
597682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
59882151520SCody P Schafer 				       char type, u64 start)
599682b335aSArnaldo Carvalho de Melo {
600682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
601682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
602682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
603682b335aSArnaldo Carvalho de Melo 
604682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
605682b335aSArnaldo Carvalho de Melo 		return 0;
606682b335aSArnaldo Carvalho de Melo 
60782151520SCody P Schafer 	/*
60882151520SCody P Schafer 	 * module symbols are not sorted so we add all
60982151520SCody P Schafer 	 * symbols, setting length to 0, and rely on
61082151520SCody P Schafer 	 * symbols__fixup_end() to fix it up.
61182151520SCody P Schafer 	 */
61282151520SCody P Schafer 	sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
6132e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
614682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
61582164161SArnaldo Carvalho de Melo 	/*
61682164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6174e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
61882164161SArnaldo Carvalho de Melo 	 */
6194e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
620a1645ce1SZhang, Yanmin 
621682b335aSArnaldo Carvalho de Melo 	return 0;
6222e538c4aSArnaldo Carvalho de Melo }
6232e538c4aSArnaldo Carvalho de Melo 
624682b335aSArnaldo Carvalho de Melo /*
625682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
626682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
627682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
628682b335aSArnaldo Carvalho de Melo  */
629aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6309e201442SArnaldo Carvalho de Melo 				  struct map *map)
631682b335aSArnaldo Carvalho de Melo {
632aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6339e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6342e538c4aSArnaldo Carvalho de Melo }
6352e538c4aSArnaldo Carvalho de Melo 
6368e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
6378e0cf965SAdrian Hunter 					 symbol_filter_t filter)
6388e0cf965SAdrian Hunter {
639ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
6408e0cf965SAdrian Hunter 	struct map *curr_map;
6418e0cf965SAdrian Hunter 	struct symbol *pos;
6428e0cf965SAdrian Hunter 	int count = 0, moved = 0;
6438e0cf965SAdrian Hunter 	struct rb_root *root = &dso->symbols[map->type];
6448e0cf965SAdrian Hunter 	struct rb_node *next = rb_first(root);
6458e0cf965SAdrian Hunter 
646ba92732eSWang Nan 	if (!kmaps)
647ba92732eSWang Nan 		return -1;
648ba92732eSWang Nan 
6498e0cf965SAdrian Hunter 	while (next) {
6508e0cf965SAdrian Hunter 		char *module;
6518e0cf965SAdrian Hunter 
6528e0cf965SAdrian Hunter 		pos = rb_entry(next, struct symbol, rb_node);
6538e0cf965SAdrian Hunter 		next = rb_next(&pos->rb_node);
6548e0cf965SAdrian Hunter 
6558e0cf965SAdrian Hunter 		module = strchr(pos->name, '\t');
6568e0cf965SAdrian Hunter 		if (module)
6578e0cf965SAdrian Hunter 			*module = '\0';
6588e0cf965SAdrian Hunter 
6598e0cf965SAdrian Hunter 		curr_map = map_groups__find(kmaps, map->type, pos->start);
6608e0cf965SAdrian Hunter 
6618e0cf965SAdrian Hunter 		if (!curr_map || (filter && filter(curr_map, pos))) {
662facf3f06SArnaldo Carvalho de Melo 			rb_erase_init(&pos->rb_node, root);
6638e0cf965SAdrian Hunter 			symbol__delete(pos);
6648e0cf965SAdrian Hunter 		} else {
6658e0cf965SAdrian Hunter 			pos->start -= curr_map->start - curr_map->pgoff;
6668e0cf965SAdrian Hunter 			if (pos->end)
6678e0cf965SAdrian Hunter 				pos->end -= curr_map->start - curr_map->pgoff;
6688e0cf965SAdrian Hunter 			if (curr_map != map) {
669facf3f06SArnaldo Carvalho de Melo 				rb_erase_init(&pos->rb_node, root);
6708e0cf965SAdrian Hunter 				symbols__insert(
6718e0cf965SAdrian Hunter 					&curr_map->dso->symbols[curr_map->type],
6728e0cf965SAdrian Hunter 					pos);
6738e0cf965SAdrian Hunter 				++moved;
6748e0cf965SAdrian Hunter 			} else {
6758e0cf965SAdrian Hunter 				++count;
6768e0cf965SAdrian Hunter 			}
6778e0cf965SAdrian Hunter 		}
6788e0cf965SAdrian Hunter 	}
6798e0cf965SAdrian Hunter 
6808e0cf965SAdrian Hunter 	/* Symbols have been adjusted */
6818e0cf965SAdrian Hunter 	dso->adjust_symbols = 1;
6828e0cf965SAdrian Hunter 
6838e0cf965SAdrian Hunter 	return count + moved;
6848e0cf965SAdrian Hunter }
6858e0cf965SAdrian Hunter 
6862e538c4aSArnaldo Carvalho de Melo /*
6872e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
6882e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
6892e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
6902e538c4aSArnaldo Carvalho de Melo  */
691d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
6929de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
6932e538c4aSArnaldo Carvalho de Melo {
694ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
695ba92732eSWang Nan 	struct machine *machine;
6964e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
6972e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
6988a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
699aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
7004e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
7012e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
7022e538c4aSArnaldo Carvalho de Melo 
703ba92732eSWang Nan 	if (!kmaps)
704ba92732eSWang Nan 		return -1;
705ba92732eSWang Nan 
706ba92732eSWang Nan 	machine = kmaps->machine;
707ba92732eSWang Nan 
7082e538c4aSArnaldo Carvalho de Melo 	while (next) {
7092e538c4aSArnaldo Carvalho de Melo 		char *module;
7102e538c4aSArnaldo Carvalho de Melo 
7112e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
7122e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
7132e538c4aSArnaldo Carvalho de Melo 
7142e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
7152e538c4aSArnaldo Carvalho de Melo 		if (module) {
71675be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
7171de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
7181de8e245SArnaldo Carvalho de Melo 
7192e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
7202e538c4aSArnaldo Carvalho de Melo 
721b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
722a1645ce1SZhang, Yanmin 				if (curr_map != map &&
723aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
72423346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
725a1645ce1SZhang, Yanmin 					/*
726a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
727a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
728a1645ce1SZhang, Yanmin 					 * points to a module and all its
729a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
730a1645ce1SZhang, Yanmin 					 * loaded.
731a1645ce1SZhang, Yanmin 					 */
732a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
733a1645ce1SZhang, Yanmin 							curr_map->type);
734af427bf5SArnaldo Carvalho de Melo 				}
735b7cece76SArnaldo Carvalho de Melo 
736a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
737a1645ce1SZhang, Yanmin 							map->type, module);
738a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7392f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
740a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
741a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
74223346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
743a1645ce1SZhang, Yanmin 					curr_map = map;
744a1645ce1SZhang, Yanmin 					goto discard_symbol;
745a1645ce1SZhang, Yanmin 				}
746a1645ce1SZhang, Yanmin 
747a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
74823346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
749b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
750af427bf5SArnaldo Carvalho de Melo 			}
75186470930SIngo Molnar 			/*
7522e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
7532e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
75486470930SIngo Molnar 			 */
7554e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
7564e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
7574e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
7582e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
759aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
76086470930SIngo Molnar 
761d9b62abaSAdrian Hunter 			if (delta) {
762d9b62abaSAdrian Hunter 				/* Kernel was relocated at boot time */
763d9b62abaSAdrian Hunter 				pos->start -= delta;
764d9b62abaSAdrian Hunter 				pos->end -= delta;
765d9b62abaSAdrian Hunter 			}
766d9b62abaSAdrian Hunter 
7678a953312SArnaldo Carvalho de Melo 			if (count == 0) {
7688a953312SArnaldo Carvalho de Melo 				curr_map = map;
7698a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
7708a953312SArnaldo Carvalho de Melo 			}
7718a953312SArnaldo Carvalho de Melo 
772aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
773a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
774a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
775a1645ce1SZhang, Yanmin 					kernel_range++);
776a1645ce1SZhang, Yanmin 			else
777a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
778a1645ce1SZhang, Yanmin 					"[kernel].%d",
7792e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
78086470930SIngo Molnar 
781aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
782aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
7832e538c4aSArnaldo Carvalho de Melo 				return -1;
7842e538c4aSArnaldo Carvalho de Melo 
785aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
786a1645ce1SZhang, Yanmin 
787aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
78837fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
789d3a7c489SArnaldo Carvalho de Melo 				dso__put(ndso);
7902e538c4aSArnaldo Carvalho de Melo 				return -1;
7912e538c4aSArnaldo Carvalho de Melo 			}
7922e538c4aSArnaldo Carvalho de Melo 
7934e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
7949de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
7952e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
796d9b62abaSAdrian Hunter 		} else if (delta) {
797d9b62abaSAdrian Hunter 			/* Kernel was relocated at boot time */
798d9b62abaSAdrian Hunter 			pos->start -= delta;
799d9b62abaSAdrian Hunter 			pos->end -= delta;
8002e538c4aSArnaldo Carvalho de Melo 		}
8018a953312SArnaldo Carvalho de Melo filter_symbol:
8024e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
8031de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
80400a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
8052e538c4aSArnaldo Carvalho de Melo 		} else {
8064e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
8074e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
8084e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
8098a953312SArnaldo Carvalho de Melo 				++moved;
8108a953312SArnaldo Carvalho de Melo 			} else
8118a953312SArnaldo Carvalho de Melo 				++count;
8129974f496SMike Galbraith 		}
81386470930SIngo Molnar 	}
81486470930SIngo Molnar 
815a1645ce1SZhang, Yanmin 	if (curr_map != map &&
816aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
81723346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
818a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
819a1645ce1SZhang, Yanmin 	}
820a1645ce1SZhang, Yanmin 
8218a953312SArnaldo Carvalho de Melo 	return count + moved;
82286470930SIngo Molnar }
82386470930SIngo Molnar 
8243f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename,
825ec80fde7SArnaldo Carvalho de Melo 				 const char *restricted_filename)
826ec80fde7SArnaldo Carvalho de Melo {
827ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
828ec80fde7SArnaldo Carvalho de Melo 
829ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
830ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
831ec80fde7SArnaldo Carvalho de Melo 
832ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
833ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
834ec80fde7SArnaldo Carvalho de Melo 			free(r);
835ec80fde7SArnaldo Carvalho de Melo 			return restricted;
836ec80fde7SArnaldo Carvalho de Melo 		}
837ec80fde7SArnaldo Carvalho de Melo 	}
838ec80fde7SArnaldo Carvalho de Melo 
839ec80fde7SArnaldo Carvalho de Melo 	return restricted;
840ec80fde7SArnaldo Carvalho de Melo }
841ec80fde7SArnaldo Carvalho de Melo 
84252afdaf9SAdrian Hunter struct module_info {
84352afdaf9SAdrian Hunter 	struct rb_node rb_node;
84452afdaf9SAdrian Hunter 	char *name;
84552afdaf9SAdrian Hunter 	u64 start;
84652afdaf9SAdrian Hunter };
84752afdaf9SAdrian Hunter 
84852afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules)
84952afdaf9SAdrian Hunter {
85052afdaf9SAdrian Hunter 	struct rb_node **p = &modules->rb_node;
85152afdaf9SAdrian Hunter 	struct rb_node *parent = NULL;
85252afdaf9SAdrian Hunter 	struct module_info *m;
85352afdaf9SAdrian Hunter 
85452afdaf9SAdrian Hunter 	while (*p != NULL) {
85552afdaf9SAdrian Hunter 		parent = *p;
85652afdaf9SAdrian Hunter 		m = rb_entry(parent, struct module_info, rb_node);
85752afdaf9SAdrian Hunter 		if (strcmp(mi->name, m->name) < 0)
85852afdaf9SAdrian Hunter 			p = &(*p)->rb_left;
85952afdaf9SAdrian Hunter 		else
86052afdaf9SAdrian Hunter 			p = &(*p)->rb_right;
86152afdaf9SAdrian Hunter 	}
86252afdaf9SAdrian Hunter 	rb_link_node(&mi->rb_node, parent, p);
86352afdaf9SAdrian Hunter 	rb_insert_color(&mi->rb_node, modules);
86452afdaf9SAdrian Hunter }
86552afdaf9SAdrian Hunter 
86652afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules)
86752afdaf9SAdrian Hunter {
86852afdaf9SAdrian Hunter 	struct module_info *mi;
86952afdaf9SAdrian Hunter 	struct rb_node *next = rb_first(modules);
87052afdaf9SAdrian Hunter 
87152afdaf9SAdrian Hunter 	while (next) {
87252afdaf9SAdrian Hunter 		mi = rb_entry(next, struct module_info, rb_node);
87352afdaf9SAdrian Hunter 		next = rb_next(&mi->rb_node);
87452afdaf9SAdrian Hunter 		rb_erase(&mi->rb_node, modules);
87574cf249dSArnaldo Carvalho de Melo 		zfree(&mi->name);
87652afdaf9SAdrian Hunter 		free(mi);
87752afdaf9SAdrian Hunter 	}
87852afdaf9SAdrian Hunter }
87952afdaf9SAdrian Hunter 
88052afdaf9SAdrian Hunter static struct module_info *find_module(const char *name,
88152afdaf9SAdrian Hunter 				       struct rb_root *modules)
88252afdaf9SAdrian Hunter {
88352afdaf9SAdrian Hunter 	struct rb_node *n = modules->rb_node;
88452afdaf9SAdrian Hunter 
88552afdaf9SAdrian Hunter 	while (n) {
88652afdaf9SAdrian Hunter 		struct module_info *m;
88752afdaf9SAdrian Hunter 		int cmp;
88852afdaf9SAdrian Hunter 
88952afdaf9SAdrian Hunter 		m = rb_entry(n, struct module_info, rb_node);
89052afdaf9SAdrian Hunter 		cmp = strcmp(name, m->name);
89152afdaf9SAdrian Hunter 		if (cmp < 0)
89252afdaf9SAdrian Hunter 			n = n->rb_left;
89352afdaf9SAdrian Hunter 		else if (cmp > 0)
89452afdaf9SAdrian Hunter 			n = n->rb_right;
89552afdaf9SAdrian Hunter 		else
89652afdaf9SAdrian Hunter 			return m;
89752afdaf9SAdrian Hunter 	}
89852afdaf9SAdrian Hunter 
89952afdaf9SAdrian Hunter 	return NULL;
90052afdaf9SAdrian Hunter }
90152afdaf9SAdrian Hunter 
90252afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start)
90352afdaf9SAdrian Hunter {
90452afdaf9SAdrian Hunter 	struct rb_root *modules = arg;
90552afdaf9SAdrian Hunter 	struct module_info *mi;
90652afdaf9SAdrian Hunter 
90752afdaf9SAdrian Hunter 	mi = zalloc(sizeof(struct module_info));
90852afdaf9SAdrian Hunter 	if (!mi)
90952afdaf9SAdrian Hunter 		return -ENOMEM;
91052afdaf9SAdrian Hunter 
91152afdaf9SAdrian Hunter 	mi->name = strdup(name);
91252afdaf9SAdrian Hunter 	mi->start = start;
91352afdaf9SAdrian Hunter 
91452afdaf9SAdrian Hunter 	if (!mi->name) {
91552afdaf9SAdrian Hunter 		free(mi);
91652afdaf9SAdrian Hunter 		return -ENOMEM;
91752afdaf9SAdrian Hunter 	}
91852afdaf9SAdrian Hunter 
91952afdaf9SAdrian Hunter 	add_module(mi, modules);
92052afdaf9SAdrian Hunter 
92152afdaf9SAdrian Hunter 	return 0;
92252afdaf9SAdrian Hunter }
92352afdaf9SAdrian Hunter 
92452afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules)
92552afdaf9SAdrian Hunter {
92652afdaf9SAdrian Hunter 	if (symbol__restricted_filename(filename, "/proc/modules"))
92752afdaf9SAdrian Hunter 		return -1;
92852afdaf9SAdrian Hunter 
92952afdaf9SAdrian Hunter 	if (modules__parse(filename, modules, __read_proc_modules)) {
93052afdaf9SAdrian Hunter 		delete_modules(modules);
93152afdaf9SAdrian Hunter 		return -1;
93252afdaf9SAdrian Hunter 	}
93352afdaf9SAdrian Hunter 
93452afdaf9SAdrian Hunter 	return 0;
93552afdaf9SAdrian Hunter }
93652afdaf9SAdrian Hunter 
937fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to)
938fc1b691dSAdrian Hunter {
939fc1b691dSAdrian Hunter 	struct rb_root from_modules = RB_ROOT;
940fc1b691dSAdrian Hunter 	struct rb_root to_modules = RB_ROOT;
941fc1b691dSAdrian Hunter 	struct rb_node *from_node, *to_node;
942fc1b691dSAdrian Hunter 	struct module_info *from_m, *to_m;
943fc1b691dSAdrian Hunter 	int ret = -1;
944fc1b691dSAdrian Hunter 
945fc1b691dSAdrian Hunter 	if (read_proc_modules(from, &from_modules))
946fc1b691dSAdrian Hunter 		return -1;
947fc1b691dSAdrian Hunter 
948fc1b691dSAdrian Hunter 	if (read_proc_modules(to, &to_modules))
949fc1b691dSAdrian Hunter 		goto out_delete_from;
950fc1b691dSAdrian Hunter 
951fc1b691dSAdrian Hunter 	from_node = rb_first(&from_modules);
952fc1b691dSAdrian Hunter 	to_node = rb_first(&to_modules);
953fc1b691dSAdrian Hunter 	while (from_node) {
954fc1b691dSAdrian Hunter 		if (!to_node)
955fc1b691dSAdrian Hunter 			break;
956fc1b691dSAdrian Hunter 
957fc1b691dSAdrian Hunter 		from_m = rb_entry(from_node, struct module_info, rb_node);
958fc1b691dSAdrian Hunter 		to_m = rb_entry(to_node, struct module_info, rb_node);
959fc1b691dSAdrian Hunter 
960fc1b691dSAdrian Hunter 		if (from_m->start != to_m->start ||
961fc1b691dSAdrian Hunter 		    strcmp(from_m->name, to_m->name))
962fc1b691dSAdrian Hunter 			break;
963fc1b691dSAdrian Hunter 
964fc1b691dSAdrian Hunter 		from_node = rb_next(from_node);
965fc1b691dSAdrian Hunter 		to_node = rb_next(to_node);
966fc1b691dSAdrian Hunter 	}
967fc1b691dSAdrian Hunter 
968fc1b691dSAdrian Hunter 	if (!from_node && !to_node)
969fc1b691dSAdrian Hunter 		ret = 0;
970fc1b691dSAdrian Hunter 
971fc1b691dSAdrian Hunter 	delete_modules(&to_modules);
972fc1b691dSAdrian Hunter out_delete_from:
973fc1b691dSAdrian Hunter 	delete_modules(&from_modules);
974fc1b691dSAdrian Hunter 
975fc1b691dSAdrian Hunter 	return ret;
976fc1b691dSAdrian Hunter }
977fc1b691dSAdrian Hunter 
97852afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map,
97952afdaf9SAdrian Hunter 				  struct map_groups *kmaps)
98052afdaf9SAdrian Hunter {
98152afdaf9SAdrian Hunter 	struct rb_root modules = RB_ROOT;
98252afdaf9SAdrian Hunter 	struct map *old_map;
98352afdaf9SAdrian Hunter 	int err;
98452afdaf9SAdrian Hunter 
98552afdaf9SAdrian Hunter 	err = read_proc_modules(filename, &modules);
98652afdaf9SAdrian Hunter 	if (err)
98752afdaf9SAdrian Hunter 		return err;
98852afdaf9SAdrian Hunter 
98952afdaf9SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
99052afdaf9SAdrian Hunter 	while (old_map) {
99152afdaf9SAdrian Hunter 		struct map *next = map_groups__next(old_map);
99252afdaf9SAdrian Hunter 		struct module_info *mi;
99352afdaf9SAdrian Hunter 
99452afdaf9SAdrian Hunter 		if (old_map == map || old_map->start == map->start) {
99552afdaf9SAdrian Hunter 			/* The kernel map */
99652afdaf9SAdrian Hunter 			old_map = next;
99752afdaf9SAdrian Hunter 			continue;
99852afdaf9SAdrian Hunter 		}
99952afdaf9SAdrian Hunter 
100052afdaf9SAdrian Hunter 		/* Module must be in memory at the same address */
100152afdaf9SAdrian Hunter 		mi = find_module(old_map->dso->short_name, &modules);
100252afdaf9SAdrian Hunter 		if (!mi || mi->start != old_map->start) {
100352afdaf9SAdrian Hunter 			err = -EINVAL;
100452afdaf9SAdrian Hunter 			goto out;
100552afdaf9SAdrian Hunter 		}
100652afdaf9SAdrian Hunter 
100752afdaf9SAdrian Hunter 		old_map = next;
100852afdaf9SAdrian Hunter 	}
100952afdaf9SAdrian Hunter out:
101052afdaf9SAdrian Hunter 	delete_modules(&modules);
101152afdaf9SAdrian Hunter 	return err;
101252afdaf9SAdrian Hunter }
101352afdaf9SAdrian Hunter 
101452afdaf9SAdrian Hunter /*
101552afdaf9SAdrian Hunter  * If kallsyms is referenced by name then we look for filename in the same
101652afdaf9SAdrian Hunter  * directory.
101752afdaf9SAdrian Hunter  */
101852afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename,
101952afdaf9SAdrian Hunter 					    const char *base_name,
102052afdaf9SAdrian Hunter 					    const char *kallsyms_filename)
102152afdaf9SAdrian Hunter {
102252afdaf9SAdrian Hunter 	char *name;
102352afdaf9SAdrian Hunter 
102452afdaf9SAdrian Hunter 	strcpy(filename, kallsyms_filename);
102552afdaf9SAdrian Hunter 	name = strrchr(filename, '/');
102652afdaf9SAdrian Hunter 	if (!name)
102752afdaf9SAdrian Hunter 		return false;
102852afdaf9SAdrian Hunter 
102952afdaf9SAdrian Hunter 	name += 1;
103052afdaf9SAdrian Hunter 
103152afdaf9SAdrian Hunter 	if (!strcmp(name, "kallsyms")) {
103252afdaf9SAdrian Hunter 		strcpy(name, base_name);
103352afdaf9SAdrian Hunter 		return true;
103452afdaf9SAdrian Hunter 	}
103552afdaf9SAdrian Hunter 
103652afdaf9SAdrian Hunter 	return false;
103752afdaf9SAdrian Hunter }
103852afdaf9SAdrian Hunter 
103952afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename,
104052afdaf9SAdrian Hunter 				  struct map *map)
104152afdaf9SAdrian Hunter {
1042ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
104352afdaf9SAdrian Hunter 	char modules_filename[PATH_MAX];
104452afdaf9SAdrian Hunter 
1045ba92732eSWang Nan 	if (!kmaps)
1046ba92732eSWang Nan 		return -EINVAL;
1047ba92732eSWang Nan 
104852afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(modules_filename, "modules",
104952afdaf9SAdrian Hunter 					     kallsyms_filename))
105052afdaf9SAdrian Hunter 		return -EINVAL;
105152afdaf9SAdrian Hunter 
105252afdaf9SAdrian Hunter 	if (do_validate_kcore_modules(modules_filename, map, kmaps))
105352afdaf9SAdrian Hunter 		return -EINVAL;
105452afdaf9SAdrian Hunter 
105552afdaf9SAdrian Hunter 	return 0;
105652afdaf9SAdrian Hunter }
105752afdaf9SAdrian Hunter 
1058a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename,
1059a00d28cbSAdrian Hunter 				    struct map *map)
1060a00d28cbSAdrian Hunter {
1061a00d28cbSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1062a00d28cbSAdrian Hunter 
1063ba92732eSWang Nan 	if (!kmap)
1064ba92732eSWang Nan 		return -EINVAL;
1065ba92732eSWang Nan 
1066a00d28cbSAdrian Hunter 	if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1067a00d28cbSAdrian Hunter 		u64 start;
1068a00d28cbSAdrian Hunter 
1069a00d28cbSAdrian Hunter 		start = kallsyms__get_function_start(kallsyms_filename,
1070a00d28cbSAdrian Hunter 						     kmap->ref_reloc_sym->name);
1071a00d28cbSAdrian Hunter 		if (start != kmap->ref_reloc_sym->addr)
1072a00d28cbSAdrian Hunter 			return -EINVAL;
1073a00d28cbSAdrian Hunter 	}
1074a00d28cbSAdrian Hunter 
1075a00d28cbSAdrian Hunter 	return validate_kcore_modules(kallsyms_filename, map);
1076a00d28cbSAdrian Hunter }
1077a00d28cbSAdrian Hunter 
10788e0cf965SAdrian Hunter struct kcore_mapfn_data {
10798e0cf965SAdrian Hunter 	struct dso *dso;
10808e0cf965SAdrian Hunter 	enum map_type type;
10818e0cf965SAdrian Hunter 	struct list_head maps;
10828e0cf965SAdrian Hunter };
10838e0cf965SAdrian Hunter 
10848e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
10858e0cf965SAdrian Hunter {
10868e0cf965SAdrian Hunter 	struct kcore_mapfn_data *md = data;
10878e0cf965SAdrian Hunter 	struct map *map;
10888e0cf965SAdrian Hunter 
10898e0cf965SAdrian Hunter 	map = map__new2(start, md->dso, md->type);
10908e0cf965SAdrian Hunter 	if (map == NULL)
10918e0cf965SAdrian Hunter 		return -ENOMEM;
10928e0cf965SAdrian Hunter 
10938e0cf965SAdrian Hunter 	map->end = map->start + len;
10948e0cf965SAdrian Hunter 	map->pgoff = pgoff;
10958e0cf965SAdrian Hunter 
10968e0cf965SAdrian Hunter 	list_add(&map->node, &md->maps);
10978e0cf965SAdrian Hunter 
10988e0cf965SAdrian Hunter 	return 0;
10998e0cf965SAdrian Hunter }
11008e0cf965SAdrian Hunter 
11018e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map,
11028e0cf965SAdrian Hunter 			   const char *kallsyms_filename)
11038e0cf965SAdrian Hunter {
1104ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
1105ba92732eSWang Nan 	struct machine *machine;
11068e0cf965SAdrian Hunter 	struct kcore_mapfn_data md;
11078e0cf965SAdrian Hunter 	struct map *old_map, *new_map, *replacement_map = NULL;
11088e0cf965SAdrian Hunter 	bool is_64_bit;
11098e0cf965SAdrian Hunter 	int err, fd;
11108e0cf965SAdrian Hunter 	char kcore_filename[PATH_MAX];
11118e0cf965SAdrian Hunter 	struct symbol *sym;
11128e0cf965SAdrian Hunter 
1113ba92732eSWang Nan 	if (!kmaps)
1114ba92732eSWang Nan 		return -EINVAL;
1115ba92732eSWang Nan 
1116ba92732eSWang Nan 	machine = kmaps->machine;
1117ba92732eSWang Nan 
11188e0cf965SAdrian Hunter 	/* This function requires that the map is the kernel map */
11198e0cf965SAdrian Hunter 	if (map != machine->vmlinux_maps[map->type])
11208e0cf965SAdrian Hunter 		return -EINVAL;
11218e0cf965SAdrian Hunter 
112252afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
11238e0cf965SAdrian Hunter 					     kallsyms_filename))
11248e0cf965SAdrian Hunter 		return -EINVAL;
11258e0cf965SAdrian Hunter 
1126a00d28cbSAdrian Hunter 	/* Modules and kernel must be present at their original addresses */
1127a00d28cbSAdrian Hunter 	if (validate_kcore_addresses(kallsyms_filename, map))
112852afdaf9SAdrian Hunter 		return -EINVAL;
112952afdaf9SAdrian Hunter 
11308e0cf965SAdrian Hunter 	md.dso = dso;
11318e0cf965SAdrian Hunter 	md.type = map->type;
11328e0cf965SAdrian Hunter 	INIT_LIST_HEAD(&md.maps);
11338e0cf965SAdrian Hunter 
11348e0cf965SAdrian Hunter 	fd = open(kcore_filename, O_RDONLY);
113536c8bb56SLi Zhang 	if (fd < 0) {
113636c8bb56SLi Zhang 		pr_err("%s requires CAP_SYS_RAWIO capability to access.\n",
113736c8bb56SLi Zhang 			kcore_filename);
11388e0cf965SAdrian Hunter 		return -EINVAL;
113936c8bb56SLi Zhang 	}
11408e0cf965SAdrian Hunter 
11418e0cf965SAdrian Hunter 	/* Read new maps into temporary lists */
11428e0cf965SAdrian Hunter 	err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
11438e0cf965SAdrian Hunter 			      &is_64_bit);
11448e0cf965SAdrian Hunter 	if (err)
11458e0cf965SAdrian Hunter 		goto out_err;
1146c6d8f2a4SAdrian Hunter 	dso->is_64_bit = is_64_bit;
11478e0cf965SAdrian Hunter 
11488e0cf965SAdrian Hunter 	if (list_empty(&md.maps)) {
11498e0cf965SAdrian Hunter 		err = -EINVAL;
11508e0cf965SAdrian Hunter 		goto out_err;
11518e0cf965SAdrian Hunter 	}
11528e0cf965SAdrian Hunter 
11538e0cf965SAdrian Hunter 	/* Remove old maps */
11548e0cf965SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
11558e0cf965SAdrian Hunter 	while (old_map) {
11568e0cf965SAdrian Hunter 		struct map *next = map_groups__next(old_map);
11578e0cf965SAdrian Hunter 
11588e0cf965SAdrian Hunter 		if (old_map != map)
11598e0cf965SAdrian Hunter 			map_groups__remove(kmaps, old_map);
11608e0cf965SAdrian Hunter 		old_map = next;
11618e0cf965SAdrian Hunter 	}
11628e0cf965SAdrian Hunter 
11638e0cf965SAdrian Hunter 	/* Find the kernel map using the first symbol */
11648e0cf965SAdrian Hunter 	sym = dso__first_symbol(dso, map->type);
11658e0cf965SAdrian Hunter 	list_for_each_entry(new_map, &md.maps, node) {
11668e0cf965SAdrian Hunter 		if (sym && sym->start >= new_map->start &&
11678e0cf965SAdrian Hunter 		    sym->start < new_map->end) {
11688e0cf965SAdrian Hunter 			replacement_map = new_map;
11698e0cf965SAdrian Hunter 			break;
11708e0cf965SAdrian Hunter 		}
11718e0cf965SAdrian Hunter 	}
11728e0cf965SAdrian Hunter 
11738e0cf965SAdrian Hunter 	if (!replacement_map)
11748e0cf965SAdrian Hunter 		replacement_map = list_entry(md.maps.next, struct map, node);
11758e0cf965SAdrian Hunter 
11768e0cf965SAdrian Hunter 	/* Add new maps */
11778e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
11788e0cf965SAdrian Hunter 		new_map = list_entry(md.maps.next, struct map, node);
1179facf3f06SArnaldo Carvalho de Melo 		list_del_init(&new_map->node);
11808e0cf965SAdrian Hunter 		if (new_map == replacement_map) {
11818e0cf965SAdrian Hunter 			map->start	= new_map->start;
11828e0cf965SAdrian Hunter 			map->end	= new_map->end;
11838e0cf965SAdrian Hunter 			map->pgoff	= new_map->pgoff;
11848e0cf965SAdrian Hunter 			map->map_ip	= new_map->map_ip;
11858e0cf965SAdrian Hunter 			map->unmap_ip	= new_map->unmap_ip;
11868e0cf965SAdrian Hunter 			/* Ensure maps are correctly ordered */
118784c2cafaSArnaldo Carvalho de Melo 			map__get(map);
11888e0cf965SAdrian Hunter 			map_groups__remove(kmaps, map);
11898e0cf965SAdrian Hunter 			map_groups__insert(kmaps, map);
119084c2cafaSArnaldo Carvalho de Melo 			map__put(map);
11918e0cf965SAdrian Hunter 		} else {
11928e0cf965SAdrian Hunter 			map_groups__insert(kmaps, new_map);
11938e0cf965SAdrian Hunter 		}
119484c2cafaSArnaldo Carvalho de Melo 
119584c2cafaSArnaldo Carvalho de Melo 		map__put(new_map);
11968e0cf965SAdrian Hunter 	}
11978e0cf965SAdrian Hunter 
11988e0cf965SAdrian Hunter 	/*
11998e0cf965SAdrian Hunter 	 * Set the data type and long name so that kcore can be read via
12008e0cf965SAdrian Hunter 	 * dso__data_read_addr().
12018e0cf965SAdrian Hunter 	 */
12028e0cf965SAdrian Hunter 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
12035f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
12048e0cf965SAdrian Hunter 	else
12055f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__KCORE;
12067e155d4dSArnaldo Carvalho de Melo 	dso__set_long_name(dso, strdup(kcore_filename), true);
12078e0cf965SAdrian Hunter 
12088e0cf965SAdrian Hunter 	close(fd);
12098e0cf965SAdrian Hunter 
12108e0cf965SAdrian Hunter 	if (map->type == MAP__FUNCTION)
12118e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel object code\n", kcore_filename);
12128e0cf965SAdrian Hunter 	else
12138e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel data\n", kcore_filename);
12148e0cf965SAdrian Hunter 
12158e0cf965SAdrian Hunter 	return 0;
12168e0cf965SAdrian Hunter 
12178e0cf965SAdrian Hunter out_err:
12188e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
12198e0cf965SAdrian Hunter 		map = list_entry(md.maps.next, struct map, node);
1220facf3f06SArnaldo Carvalho de Melo 		list_del_init(&map->node);
122184c2cafaSArnaldo Carvalho de Melo 		map__put(map);
12228e0cf965SAdrian Hunter 	}
12238e0cf965SAdrian Hunter 	close(fd);
12248e0cf965SAdrian Hunter 	return -EINVAL;
12258e0cf965SAdrian Hunter }
12268e0cf965SAdrian Hunter 
1227d9b62abaSAdrian Hunter /*
1228d9b62abaSAdrian Hunter  * If the kernel is relocated at boot time, kallsyms won't match.  Compute the
1229d9b62abaSAdrian Hunter  * delta based on the relocation reference symbol.
1230d9b62abaSAdrian Hunter  */
1231d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1232d9b62abaSAdrian Hunter {
1233d9b62abaSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1234d9b62abaSAdrian Hunter 	u64 addr;
1235d9b62abaSAdrian Hunter 
1236ba92732eSWang Nan 	if (!kmap)
1237ba92732eSWang Nan 		return -1;
1238ba92732eSWang Nan 
1239d9b62abaSAdrian Hunter 	if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1240d9b62abaSAdrian Hunter 		return 0;
1241d9b62abaSAdrian Hunter 
1242d9b62abaSAdrian Hunter 	addr = kallsyms__get_function_start(filename,
1243d9b62abaSAdrian Hunter 					    kmap->ref_reloc_sym->name);
1244d9b62abaSAdrian Hunter 	if (!addr)
1245d9b62abaSAdrian Hunter 		return -1;
1246d9b62abaSAdrian Hunter 
1247d9b62abaSAdrian Hunter 	*delta = addr - kmap->ref_reloc_sym->addr;
1248d9b62abaSAdrian Hunter 	return 0;
1249d9b62abaSAdrian Hunter }
1250d9b62abaSAdrian Hunter 
1251aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
12529de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
12532e538c4aSArnaldo Carvalho de Melo {
1254d9b62abaSAdrian Hunter 	u64 delta = 0;
1255d9b62abaSAdrian Hunter 
1256ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1257ec80fde7SArnaldo Carvalho de Melo 		return -1;
1258ec80fde7SArnaldo Carvalho de Melo 
1259aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
12602e538c4aSArnaldo Carvalho de Melo 		return -1;
12612e538c4aSArnaldo Carvalho de Melo 
1262d9b62abaSAdrian Hunter 	if (kallsyms__delta(map, filename, &delta))
1263d9b62abaSAdrian Hunter 		return -1;
1264d9b62abaSAdrian Hunter 
1265694bf407SAnton Blanchard 	symbols__fixup_duplicate(&dso->symbols[map->type]);
12663f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
12673f5a4272SAnton Blanchard 
1268aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
126944f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1270a1645ce1SZhang, Yanmin 	else
127144f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
12722e538c4aSArnaldo Carvalho de Melo 
12738e0cf965SAdrian Hunter 	if (!dso__load_kcore(dso, map, filename))
12748e0cf965SAdrian Hunter 		return dso__split_kallsyms_for_kcore(dso, map, filter);
12758e0cf965SAdrian Hunter 	else
1276d9b62abaSAdrian Hunter 		return dso__split_kallsyms(dso, map, delta, filter);
1277af427bf5SArnaldo Carvalho de Melo }
1278af427bf5SArnaldo Carvalho de Melo 
1279aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
12806beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
128180d496beSPekka Enberg {
128280d496beSPekka Enberg 	char *line = NULL;
128380d496beSPekka Enberg 	size_t n;
128480d496beSPekka Enberg 	FILE *file;
128580d496beSPekka Enberg 	int nr_syms = 0;
128680d496beSPekka Enberg 
1287aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
128880d496beSPekka Enberg 	if (file == NULL)
128980d496beSPekka Enberg 		goto out_failure;
129080d496beSPekka Enberg 
129180d496beSPekka Enberg 	while (!feof(file)) {
12929cffa8d5SPaul Mackerras 		u64 start, size;
129380d496beSPekka Enberg 		struct symbol *sym;
129480d496beSPekka Enberg 		int line_len, len;
129580d496beSPekka Enberg 
129680d496beSPekka Enberg 		line_len = getline(&line, &n, file);
129780d496beSPekka Enberg 		if (line_len < 0)
129880d496beSPekka Enberg 			break;
129980d496beSPekka Enberg 
130080d496beSPekka Enberg 		if (!line)
130180d496beSPekka Enberg 			goto out_failure;
130280d496beSPekka Enberg 
130380d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
130480d496beSPekka Enberg 
130580d496beSPekka Enberg 		len = hex2u64(line, &start);
130680d496beSPekka Enberg 
130780d496beSPekka Enberg 		len++;
130880d496beSPekka Enberg 		if (len + 2 >= line_len)
130980d496beSPekka Enberg 			continue;
131080d496beSPekka Enberg 
131180d496beSPekka Enberg 		len += hex2u64(line + len, &size);
131280d496beSPekka Enberg 
131380d496beSPekka Enberg 		len++;
131480d496beSPekka Enberg 		if (len + 2 >= line_len)
131580d496beSPekka Enberg 			continue;
131680d496beSPekka Enberg 
1317c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
131880d496beSPekka Enberg 
131980d496beSPekka Enberg 		if (sym == NULL)
132080d496beSPekka Enberg 			goto out_delete_line;
132180d496beSPekka Enberg 
1322439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
132300a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
132480d496beSPekka Enberg 		else {
1325aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
132680d496beSPekka Enberg 			nr_syms++;
132780d496beSPekka Enberg 		}
132880d496beSPekka Enberg 	}
132980d496beSPekka Enberg 
133080d496beSPekka Enberg 	free(line);
133180d496beSPekka Enberg 	fclose(file);
133280d496beSPekka Enberg 
133380d496beSPekka Enberg 	return nr_syms;
133480d496beSPekka Enberg 
133580d496beSPekka Enberg out_delete_line:
133680d496beSPekka Enberg 	free(line);
133780d496beSPekka Enberg out_failure:
133880d496beSPekka Enberg 	return -1;
133980d496beSPekka Enberg }
134080d496beSPekka Enberg 
13411029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
13421029f9feSNamhyung Kim 					   enum dso_binary_type type)
13431029f9feSNamhyung Kim {
13441029f9feSNamhyung Kim 	switch (type) {
13451029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__JAVA_JIT:
13461029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__DEBUGLINK:
13471029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
13481029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
13491029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
13501029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
13511029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
13521029f9feSNamhyung Kim 		return !kmod && dso->kernel == DSO_TYPE_USER;
13531029f9feSNamhyung Kim 
13541029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KALLSYMS:
13551029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__VMLINUX:
13561029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KCORE:
13571029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_KERNEL;
13581029f9feSNamhyung Kim 
13591029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
13601029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
13611029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KCORE:
13621029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
13631029f9feSNamhyung Kim 
13641029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE:
1365c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
13661029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1367c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
13681029f9feSNamhyung Kim 		/*
13691029f9feSNamhyung Kim 		 * kernel modules know their symtab type - it's set when
13709f2de315SArnaldo Carvalho de Melo 		 * creating a module dso in machine__findnew_module_map().
13711029f9feSNamhyung Kim 		 */
13721029f9feSNamhyung Kim 		return kmod && dso->symtab_type == type;
13731029f9feSNamhyung Kim 
13741029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
13751029f9feSNamhyung Kim 		return true;
13761029f9feSNamhyung Kim 
13771029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__NOT_FOUND:
13781029f9feSNamhyung Kim 	default:
13791029f9feSNamhyung Kim 		return false;
13801029f9feSNamhyung Kim 	}
13811029f9feSNamhyung Kim }
13821029f9feSNamhyung Kim 
1383aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
138486470930SIngo Molnar {
1385c338aee8SArnaldo Carvalho de Melo 	char *name;
138686470930SIngo Molnar 	int ret = -1;
138744f24cb3SJiri Olsa 	u_int i;
138823346f21SArnaldo Carvalho de Melo 	struct machine *machine;
138944f24cb3SJiri Olsa 	char *root_dir = (char *) "";
13903aafe5aeSCody P Schafer 	int ss_pos = 0;
13913aafe5aeSCody P Schafer 	struct symsrc ss_[2];
13923aafe5aeSCody P Schafer 	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
13931029f9feSNamhyung Kim 	bool kmod;
139486470930SIngo Molnar 
13954a936edcSNamhyung Kim 	pthread_mutex_lock(&dso->lock);
139666bd8424SArnaldo Carvalho de Melo 
13974a936edcSNamhyung Kim 	/* check again under the dso->lock */
13984a936edcSNamhyung Kim 	if (dso__loaded(dso, map->type)) {
13994a936edcSNamhyung Kim 		ret = 1;
14004a936edcSNamhyung Kim 		goto out;
14014a936edcSNamhyung Kim 	}
14024a936edcSNamhyung Kim 
14034a936edcSNamhyung Kim 	if (dso->kernel) {
1404aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel == DSO_TYPE_KERNEL)
14054a936edcSNamhyung Kim 			ret = dso__load_kernel_sym(dso, map, filter);
1406aeafcbafSArnaldo Carvalho de Melo 		else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
14074a936edcSNamhyung Kim 			ret = dso__load_guest_kernel_sym(dso, map, filter);
14084a936edcSNamhyung Kim 
14094a936edcSNamhyung Kim 		goto out;
14104a936edcSNamhyung Kim 	}
1411a1645ce1SZhang, Yanmin 
141223346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
141323346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1414a1645ce1SZhang, Yanmin 	else
141523346f21SArnaldo Carvalho de Melo 		machine = NULL;
1416c338aee8SArnaldo Carvalho de Melo 
1417aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1418f5812a7aSArnaldo Carvalho de Melo 
1419aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1420981c1252SPekka Enberg 		struct stat st;
1421981c1252SPekka Enberg 
1422e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
14234a936edcSNamhyung Kim 			goto out;
1424981c1252SPekka Enberg 
1425981c1252SPekka Enberg 		if (st.st_uid && (st.st_uid != geteuid())) {
1426981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1427981c1252SPekka Enberg 				"ignoring it.\n", dso->name);
14284a936edcSNamhyung Kim 			goto out;
1429981c1252SPekka Enberg 		}
1430981c1252SPekka Enberg 
1431aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
143244f24cb3SJiri Olsa 		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
143344f24cb3SJiri Olsa 					     DSO_BINARY_TYPE__NOT_FOUND;
14344a936edcSNamhyung Kim 		goto out;
143594cb9e38SArnaldo Carvalho de Melo 	}
143694cb9e38SArnaldo Carvalho de Melo 
143744f24cb3SJiri Olsa 	if (machine)
143844f24cb3SJiri Olsa 		root_dir = machine->root_dir;
143944f24cb3SJiri Olsa 
1440164c800eSDavid Ahern 	name = malloc(PATH_MAX);
1441164c800eSDavid Ahern 	if (!name)
14424a936edcSNamhyung Kim 		goto out;
1443164c800eSDavid Ahern 
14441029f9feSNamhyung Kim 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1445c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
1446c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
1447c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
14481029f9feSNamhyung Kim 
14491029f9feSNamhyung Kim 	/*
14501029f9feSNamhyung Kim 	 * Iterate over candidate debug images.
14513aafe5aeSCody P Schafer 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
14523aafe5aeSCody P Schafer 	 * and/or opd section) for processing.
14536da80ce8SDave Martin 	 */
145444f24cb3SJiri Olsa 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
14553aafe5aeSCody P Schafer 		struct symsrc *ss = &ss_[ss_pos];
14563aafe5aeSCody P Schafer 		bool next_slot = false;
145744f24cb3SJiri Olsa 
1458005f9294SCody P Schafer 		enum dso_binary_type symtab_type = binary_type_symtab[i];
145944f24cb3SJiri Olsa 
14601029f9feSNamhyung Kim 		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
14611029f9feSNamhyung Kim 			continue;
14621029f9feSNamhyung Kim 
1463ee4e9625SArnaldo Carvalho de Melo 		if (dso__read_binary_type_filename(dso, symtab_type,
146444f24cb3SJiri Olsa 						   root_dir, name, PATH_MAX))
14656da80ce8SDave Martin 			continue;
146686470930SIngo Molnar 
14676da80ce8SDave Martin 		/* Name is now the name of the next image to try */
14683aafe5aeSCody P Schafer 		if (symsrc__init(ss, dso, name, symtab_type) < 0)
14696da80ce8SDave Martin 			continue;
14706da80ce8SDave Martin 
14713aafe5aeSCody P Schafer 		if (!syms_ss && symsrc__has_symtab(ss)) {
14723aafe5aeSCody P Schafer 			syms_ss = ss;
14733aafe5aeSCody P Schafer 			next_slot = true;
14740058aef6SAdrian Hunter 			if (!dso->symsrc_filename)
14750058aef6SAdrian Hunter 				dso->symsrc_filename = strdup(name);
1476d26cd12bSCody P Schafer 		}
1477d26cd12bSCody P Schafer 
14783aafe5aeSCody P Schafer 		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
14793aafe5aeSCody P Schafer 			runtime_ss = ss;
14803aafe5aeSCody P Schafer 			next_slot = true;
1481a44f605bSCody P Schafer 		}
148286470930SIngo Molnar 
14833aafe5aeSCody P Schafer 		if (next_slot) {
14843aafe5aeSCody P Schafer 			ss_pos++;
148533ff581eSJiri Olsa 
14863aafe5aeSCody P Schafer 			if (syms_ss && runtime_ss)
14876da80ce8SDave Martin 				break;
148898e9f03bSNamhyung Kim 		} else {
148998e9f03bSNamhyung Kim 			symsrc__destroy(ss);
1490a25e46c4SArnaldo Carvalho de Melo 		}
14913aafe5aeSCody P Schafer 
14926da80ce8SDave Martin 	}
14936da80ce8SDave Martin 
14943aafe5aeSCody P Schafer 	if (!runtime_ss && !syms_ss)
14953aafe5aeSCody P Schafer 		goto out_free;
14963aafe5aeSCody P Schafer 
14973aafe5aeSCody P Schafer 	if (runtime_ss && !syms_ss) {
14983aafe5aeSCody P Schafer 		syms_ss = runtime_ss;
149960e4b10cSArnaldo Carvalho de Melo 	}
150060e4b10cSArnaldo Carvalho de Melo 
15013aafe5aeSCody P Schafer 	/* We'll have to hope for the best */
15023aafe5aeSCody P Schafer 	if (!runtime_ss && syms_ss)
15033aafe5aeSCody P Schafer 		runtime_ss = syms_ss;
15043aafe5aeSCody P Schafer 
15051029f9feSNamhyung Kim 	if (syms_ss)
15061029f9feSNamhyung Kim 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
15071029f9feSNamhyung Kim 	else
15083aafe5aeSCody P Schafer 		ret = -1;
15093aafe5aeSCody P Schafer 
1510f47b58b7SDavid Ahern 	if (ret > 0) {
15113aafe5aeSCody P Schafer 		int nr_plt;
15123aafe5aeSCody P Schafer 
15133aafe5aeSCody P Schafer 		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
15143aafe5aeSCody P Schafer 		if (nr_plt > 0)
15153aafe5aeSCody P Schafer 			ret += nr_plt;
15163aafe5aeSCody P Schafer 	}
15173aafe5aeSCody P Schafer 
15183aafe5aeSCody P Schafer 	for (; ss_pos > 0; ss_pos--)
15193aafe5aeSCody P Schafer 		symsrc__destroy(&ss_[ss_pos - 1]);
15203aafe5aeSCody P Schafer out_free:
152186470930SIngo Molnar 	free(name);
1522aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
15234a936edcSNamhyung Kim 		ret = 0;
15244a936edcSNamhyung Kim out:
15254a936edcSNamhyung Kim 	dso__set_loaded(dso, map->type);
15264a936edcSNamhyung Kim 	pthread_mutex_unlock(&dso->lock);
15274a936edcSNamhyung Kim 
152886470930SIngo Molnar 	return ret;
152986470930SIngo Molnar }
153086470930SIngo Molnar 
1531aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
153279406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1533439d473bSArnaldo Carvalho de Melo {
15341eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
15354bb7123dSArnaldo Carvalho de Melo 	struct map *map;
1536439d473bSArnaldo Carvalho de Melo 
15376a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_rdlock(&maps->lock);
15386a2ffcddSArnaldo Carvalho de Melo 
15394bb7123dSArnaldo Carvalho de Melo 	for (map = maps__first(maps); map; map = map__next(map)) {
1540b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
15416a2ffcddSArnaldo Carvalho de Melo 			goto out_unlock;
1542439d473bSArnaldo Carvalho de Melo 	}
1543439d473bSArnaldo Carvalho de Melo 
15446a2ffcddSArnaldo Carvalho de Melo 	map = NULL;
15456a2ffcddSArnaldo Carvalho de Melo 
15466a2ffcddSArnaldo Carvalho de Melo out_unlock:
15476a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_unlock(&maps->lock);
15486a2ffcddSArnaldo Carvalho de Melo 	return map;
1549439d473bSArnaldo Carvalho de Melo }
1550439d473bSArnaldo Carvalho de Melo 
1551aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
15525230fb7dSArnaldo Carvalho de Melo 		      const char *vmlinux, bool vmlinux_allocated,
15535230fb7dSArnaldo Carvalho de Melo 		      symbol_filter_t filter)
155486470930SIngo Molnar {
1555b68e2f91SCody P Schafer 	int err = -1;
1556b68e2f91SCody P Schafer 	struct symsrc ss;
1557ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
1558005f9294SCody P Schafer 	enum dso_binary_type symtab_type;
155986470930SIngo Molnar 
15605698d2c9SNamhyung Kim 	if (vmlinux[0] == '/')
15615698d2c9SNamhyung Kim 		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
15625698d2c9SNamhyung Kim 	else
1563972f393bSArnaldo Carvalho de Melo 		symbol__join_symfs(symfs_vmlinux, vmlinux);
156486470930SIngo Molnar 
156521ea4539SCody P Schafer 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1566005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
156721ea4539SCody P Schafer 	else
1568005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__VMLINUX;
156921ea4539SCody P Schafer 
1570005f9294SCody P Schafer 	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1571b68e2f91SCody P Schafer 		return -1;
1572b68e2f91SCody P Schafer 
1573261360b6SCody P Schafer 	err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
1574b68e2f91SCody P Schafer 	symsrc__destroy(&ss);
157586470930SIngo Molnar 
1576515850e4SCody P Schafer 	if (err > 0) {
157739b12f78SAdrian Hunter 		if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
15785f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
157939b12f78SAdrian Hunter 		else
15805f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
1581bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, vmlinux, vmlinux_allocated);
1582515850e4SCody P Schafer 		dso__set_loaded(dso, map->type);
1583ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
1584515850e4SCody P Schafer 	}
15853846df2eSArnaldo Carvalho de Melo 
158686470930SIngo Molnar 	return err;
158786470930SIngo Molnar }
158886470930SIngo Molnar 
1589aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
15909de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1591a19afe46SArnaldo Carvalho de Melo {
1592a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
159300dc8657SNamhyung Kim 	char *filename = NULL;
1594a19afe46SArnaldo Carvalho de Melo 
159500dc8657SNamhyung Kim 	if (!symbol_conf.ignore_vmlinux_buildid)
1596aeafcbafSArnaldo Carvalho de Melo 		filename = dso__build_id_filename(dso, NULL, 0);
15975ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
15985230fb7dSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, true, filter);
15995230fb7dSArnaldo Carvalho de Melo 		if (err > 0)
16005ad90e4eSArnaldo Carvalho de Melo 			goto out;
16015ad90e4eSArnaldo Carvalho de Melo 		free(filename);
16025ad90e4eSArnaldo Carvalho de Melo 	}
1603a19afe46SArnaldo Carvalho de Melo 
160400dc8657SNamhyung Kim 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
160500dc8657SNamhyung Kim 		 vmlinux_path__nr_entries + 1);
160600dc8657SNamhyung Kim 
1607a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
16085230fb7dSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
16095230fb7dSArnaldo Carvalho de Melo 		if (err > 0)
1610a19afe46SArnaldo Carvalho de Melo 			break;
1611a19afe46SArnaldo Carvalho de Melo 	}
16125ad90e4eSArnaldo Carvalho de Melo out:
1613a19afe46SArnaldo Carvalho de Melo 	return err;
1614a19afe46SArnaldo Carvalho de Melo }
1615a19afe46SArnaldo Carvalho de Melo 
16160544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
16170544d422SAdrian Hunter {
16180544d422SAdrian Hunter 	char kallsyms_filename[PATH_MAX];
16190544d422SAdrian Hunter 	struct dirent *dent;
16200544d422SAdrian Hunter 	int ret = -1;
16210544d422SAdrian Hunter 	DIR *d;
16220544d422SAdrian Hunter 
16230544d422SAdrian Hunter 	d = opendir(dir);
16240544d422SAdrian Hunter 	if (!d)
16250544d422SAdrian Hunter 		return -1;
16260544d422SAdrian Hunter 
16270544d422SAdrian Hunter 	while (1) {
16280544d422SAdrian Hunter 		dent = readdir(d);
16290544d422SAdrian Hunter 		if (!dent)
16300544d422SAdrian Hunter 			break;
16310544d422SAdrian Hunter 		if (dent->d_type != DT_DIR)
16320544d422SAdrian Hunter 			continue;
16330544d422SAdrian Hunter 		scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
16340544d422SAdrian Hunter 			  "%s/%s/kallsyms", dir, dent->d_name);
1635a00d28cbSAdrian Hunter 		if (!validate_kcore_addresses(kallsyms_filename, map)) {
16360544d422SAdrian Hunter 			strlcpy(dir, kallsyms_filename, dir_sz);
16370544d422SAdrian Hunter 			ret = 0;
16380544d422SAdrian Hunter 			break;
16390544d422SAdrian Hunter 		}
16400544d422SAdrian Hunter 	}
16410544d422SAdrian Hunter 
16420544d422SAdrian Hunter 	closedir(d);
16430544d422SAdrian Hunter 
16440544d422SAdrian Hunter 	return ret;
16450544d422SAdrian Hunter }
16460544d422SAdrian Hunter 
16470544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map)
16480544d422SAdrian Hunter {
16490544d422SAdrian Hunter 	u8 host_build_id[BUILD_ID_SIZE];
16500544d422SAdrian Hunter 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
16510544d422SAdrian Hunter 	bool is_host = false;
16520544d422SAdrian Hunter 	char path[PATH_MAX];
16530544d422SAdrian Hunter 
16540544d422SAdrian Hunter 	if (!dso->has_build_id) {
16550544d422SAdrian Hunter 		/*
16560544d422SAdrian Hunter 		 * Last resort, if we don't have a build-id and couldn't find
16570544d422SAdrian Hunter 		 * any vmlinux file, try the running kernel kallsyms table.
16580544d422SAdrian Hunter 		 */
16590544d422SAdrian Hunter 		goto proc_kallsyms;
16600544d422SAdrian Hunter 	}
16610544d422SAdrian Hunter 
16620544d422SAdrian Hunter 	if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
16630544d422SAdrian Hunter 				 sizeof(host_build_id)) == 0)
16640544d422SAdrian Hunter 		is_host = dso__build_id_equal(dso, host_build_id);
16650544d422SAdrian Hunter 
16660544d422SAdrian Hunter 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
16670544d422SAdrian Hunter 
1668449867e3SAdrian Hunter 	scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
1669449867e3SAdrian Hunter 		  sbuild_id);
1670449867e3SAdrian Hunter 
16710544d422SAdrian Hunter 	/* Use /proc/kallsyms if possible */
16720544d422SAdrian Hunter 	if (is_host) {
16730544d422SAdrian Hunter 		DIR *d;
16740544d422SAdrian Hunter 		int fd;
16750544d422SAdrian Hunter 
16760544d422SAdrian Hunter 		/* If no cached kcore go with /proc/kallsyms */
16770544d422SAdrian Hunter 		d = opendir(path);
16780544d422SAdrian Hunter 		if (!d)
16790544d422SAdrian Hunter 			goto proc_kallsyms;
16800544d422SAdrian Hunter 		closedir(d);
16810544d422SAdrian Hunter 
16820544d422SAdrian Hunter 		/*
16830544d422SAdrian Hunter 		 * Do not check the build-id cache, until we know we cannot use
16840544d422SAdrian Hunter 		 * /proc/kcore.
16850544d422SAdrian Hunter 		 */
16860544d422SAdrian Hunter 		fd = open("/proc/kcore", O_RDONLY);
16870544d422SAdrian Hunter 		if (fd != -1) {
16880544d422SAdrian Hunter 			close(fd);
16890544d422SAdrian Hunter 			/* If module maps match go with /proc/kallsyms */
1690a00d28cbSAdrian Hunter 			if (!validate_kcore_addresses("/proc/kallsyms", map))
16910544d422SAdrian Hunter 				goto proc_kallsyms;
16920544d422SAdrian Hunter 		}
16930544d422SAdrian Hunter 
16940544d422SAdrian Hunter 		/* Find kallsyms in build-id cache with kcore */
16950544d422SAdrian Hunter 		if (!find_matching_kcore(map, path, sizeof(path)))
16960544d422SAdrian Hunter 			return strdup(path);
16970544d422SAdrian Hunter 
16980544d422SAdrian Hunter 		goto proc_kallsyms;
16990544d422SAdrian Hunter 	}
17000544d422SAdrian Hunter 
1701449867e3SAdrian Hunter 	/* Find kallsyms in build-id cache with kcore */
1702449867e3SAdrian Hunter 	if (!find_matching_kcore(map, path, sizeof(path)))
1703449867e3SAdrian Hunter 		return strdup(path);
1704449867e3SAdrian Hunter 
17050544d422SAdrian Hunter 	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
17060544d422SAdrian Hunter 		  buildid_dir, sbuild_id);
17070544d422SAdrian Hunter 
17080544d422SAdrian Hunter 	if (access(path, F_OK)) {
17090544d422SAdrian Hunter 		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
17100544d422SAdrian Hunter 		       sbuild_id);
17110544d422SAdrian Hunter 		return NULL;
17120544d422SAdrian Hunter 	}
17130544d422SAdrian Hunter 
17140544d422SAdrian Hunter 	return strdup(path);
17150544d422SAdrian Hunter 
17160544d422SAdrian Hunter proc_kallsyms:
17170544d422SAdrian Hunter 	return strdup("/proc/kallsyms");
17180544d422SAdrian Hunter }
17190544d422SAdrian Hunter 
1720aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
17219de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
172286470930SIngo Molnar {
1723cc612d81SArnaldo Carvalho de Melo 	int err;
17249e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
17259e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1726dc8d6ab2SArnaldo Carvalho de Melo 	/*
1727b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1728b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1729dc8d6ab2SArnaldo Carvalho de Melo 	 *
1730dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1731dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1732dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1733dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1734dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1735dc8d6ab2SArnaldo Carvalho de Melo 	 *
1736dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1737dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1738dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1739dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1740dc8d6ab2SArnaldo Carvalho de Melo 	 */
1741b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1742b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1743b226a5a7SDavid Ahern 		goto do_kallsyms;
1744b226a5a7SDavid Ahern 	}
1745b226a5a7SDavid Ahern 
1746fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
17475230fb7dSArnaldo Carvalho de Melo 		return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
17485230fb7dSArnaldo Carvalho de Melo 					 false, filter);
1749dc8d6ab2SArnaldo Carvalho de Melo 	}
1750439d473bSArnaldo Carvalho de Melo 
1751fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
1752aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
1753a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
175439b12f78SAdrian Hunter 			return err;
1755cc612d81SArnaldo Carvalho de Melo 	}
1756cc612d81SArnaldo Carvalho de Melo 
1757ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1758ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1759ec5761eaSDavid Ahern 		return -1;
1760ec5761eaSDavid Ahern 
17610544d422SAdrian Hunter 	kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
17620544d422SAdrian Hunter 	if (!kallsyms_allocated_filename)
17638d0591f6SArnaldo Carvalho de Melo 		return -1;
17648d0591f6SArnaldo Carvalho de Melo 
176519fc2dedSArnaldo Carvalho de Melo 	kallsyms_filename = kallsyms_allocated_filename;
176619fc2dedSArnaldo Carvalho de Melo 
1767dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
1768aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
17693846df2eSArnaldo Carvalho de Melo 	if (err > 0)
17703846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1771dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1772dc8d6ab2SArnaldo Carvalho de Melo 
17738e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1774bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
1775bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, "[kernel.kallsyms]", false);
17766a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
17776a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1778439d473bSArnaldo Carvalho de Melo 	}
177994cb9e38SArnaldo Carvalho de Melo 
178086470930SIngo Molnar 	return err;
178186470930SIngo Molnar }
178286470930SIngo Molnar 
1783aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1784a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
1785a1645ce1SZhang, Yanmin {
1786a1645ce1SZhang, Yanmin 	int err;
1787a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
178823346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1789a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1790a1645ce1SZhang, Yanmin 
1791a1645ce1SZhang, Yanmin 	if (!map->groups) {
1792a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1793a1645ce1SZhang, Yanmin 		return -1;
1794a1645ce1SZhang, Yanmin 	}
179523346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1796a1645ce1SZhang, Yanmin 
179723346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1798a1645ce1SZhang, Yanmin 		/*
1799a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1800a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1801a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1802a1645ce1SZhang, Yanmin 		 */
1803a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1804aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
18055230fb7dSArnaldo Carvalho de Melo 						symbol_conf.default_guest_vmlinux_name,
18065230fb7dSArnaldo Carvalho de Melo 						false, filter);
180739b12f78SAdrian Hunter 			return err;
1808a1645ce1SZhang, Yanmin 		}
1809a1645ce1SZhang, Yanmin 
1810a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1811a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1812a1645ce1SZhang, Yanmin 			return -1;
1813a1645ce1SZhang, Yanmin 	} else {
181423346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1815a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1816a1645ce1SZhang, Yanmin 	}
1817a1645ce1SZhang, Yanmin 
1818aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
18198e0cf965SAdrian Hunter 	if (err > 0)
182039b12f78SAdrian Hunter 		pr_debug("Using %s for symbols\n", kallsyms_filename);
18218e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1822bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
182348ea8f54SArnaldo Carvalho de Melo 		machine__mmap_name(machine, path, sizeof(path));
18247e155d4dSArnaldo Carvalho de Melo 		dso__set_long_name(dso, strdup(path), true);
1825a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1826a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1827a1645ce1SZhang, Yanmin 	}
1828a1645ce1SZhang, Yanmin 
1829a1645ce1SZhang, Yanmin 	return err;
1830a1645ce1SZhang, Yanmin }
1831cd84c2acSFrederic Weisbecker 
1832cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
18332446042cSArnaldo Carvalho de Melo {
183404662523SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0)
183504662523SArnaldo Carvalho de Melo 		zfree(&vmlinux_path[vmlinux_path__nr_entries]);
1836c4f03547SWang Nan 	vmlinux_path__nr_entries = 0;
1837cc612d81SArnaldo Carvalho de Melo 
183804662523SArnaldo Carvalho de Melo 	zfree(&vmlinux_path);
1839cc612d81SArnaldo Carvalho de Melo }
1840cc612d81SArnaldo Carvalho de Melo 
18410a7e6d1bSNamhyung Kim static int vmlinux_path__init(struct perf_session_env *env)
1842cc612d81SArnaldo Carvalho de Melo {
1843cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1844cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
18450a7e6d1bSNamhyung Kim 	char *kernel_version;
1846cc612d81SArnaldo Carvalho de Melo 
1847c657f423SAnton Blanchard 	vmlinux_path = malloc(sizeof(char *) * 6);
1848cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1849cc612d81SArnaldo Carvalho de Melo 		return -1;
1850cc612d81SArnaldo Carvalho de Melo 
1851cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1852cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1853cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1854cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1855cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1856cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1857cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1858cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1859ec5761eaSDavid Ahern 
18600a7e6d1bSNamhyung Kim 	/* only try kernel version if no symfs was given */
1861ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1862ec5761eaSDavid Ahern 		return 0;
1863ec5761eaSDavid Ahern 
18640a7e6d1bSNamhyung Kim 	if (env) {
18650a7e6d1bSNamhyung Kim 		kernel_version = env->os_release;
18660a7e6d1bSNamhyung Kim 	} else {
1867ec5761eaSDavid Ahern 		if (uname(&uts) < 0)
1868e96c674fSNamhyung Kim 			goto out_fail;
1869ec5761eaSDavid Ahern 
18700a7e6d1bSNamhyung Kim 		kernel_version = uts.release;
18710a7e6d1bSNamhyung Kim 	}
18720a7e6d1bSNamhyung Kim 
18730a7e6d1bSNamhyung Kim 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
1874cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1875cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1876cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1877cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1878c657f423SAnton Blanchard 	snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
1879c657f423SAnton Blanchard 		 kernel_version);
1880c657f423SAnton Blanchard 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1881c657f423SAnton Blanchard 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1882c657f423SAnton Blanchard 		goto out_fail;
1883c657f423SAnton Blanchard         ++vmlinux_path__nr_entries;
18840a7e6d1bSNamhyung Kim 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
1885cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1886cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1887cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1888cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1889cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
18900a7e6d1bSNamhyung Kim 		 kernel_version);
1891cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1892cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1893cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1894cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1895cc612d81SArnaldo Carvalho de Melo 
1896cc612d81SArnaldo Carvalho de Melo 	return 0;
1897cc612d81SArnaldo Carvalho de Melo 
1898cc612d81SArnaldo Carvalho de Melo out_fail:
1899cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1900cc612d81SArnaldo Carvalho de Melo 	return -1;
1901cc612d81SArnaldo Carvalho de Melo }
1902cc612d81SArnaldo Carvalho de Melo 
19033bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str,
1904655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
1905655000e7SArnaldo Carvalho de Melo {
1906655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
1907655000e7SArnaldo Carvalho de Melo 		return 0;
1908655000e7SArnaldo Carvalho de Melo 
1909655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
1910655000e7SArnaldo Carvalho de Melo 	if (!*list) {
1911655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
1912655000e7SArnaldo Carvalho de Melo 		return -1;
1913655000e7SArnaldo Carvalho de Melo 	}
1914*0bc2f2f7SArnaldo Carvalho de Melo 
1915*0bc2f2f7SArnaldo Carvalho de Melo 	symbol_conf.has_filter = true;
1916655000e7SArnaldo Carvalho de Melo 	return 0;
1917655000e7SArnaldo Carvalho de Melo }
1918655000e7SArnaldo Carvalho de Melo 
1919e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str,
1920e03eaa40SDavid Ahern 		  const char *list_name)
1921e03eaa40SDavid Ahern {
1922e03eaa40SDavid Ahern 	if (list_str == NULL)
1923e03eaa40SDavid Ahern 		return 0;
1924e03eaa40SDavid Ahern 
1925e03eaa40SDavid Ahern 	*list = intlist__new(list_str);
1926e03eaa40SDavid Ahern 	if (!*list) {
1927e03eaa40SDavid Ahern 		pr_err("problems parsing %s list\n", list_name);
1928e03eaa40SDavid Ahern 		return -1;
1929e03eaa40SDavid Ahern 	}
1930e03eaa40SDavid Ahern 	return 0;
1931e03eaa40SDavid Ahern }
1932e03eaa40SDavid Ahern 
1933ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
1934ec80fde7SArnaldo Carvalho de Melo {
1935ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
1936ec80fde7SArnaldo Carvalho de Melo 
1937ec80fde7SArnaldo Carvalho de Melo 	if (geteuid() != 0) {
1938ec80fde7SArnaldo Carvalho de Melo 		FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
1939ec80fde7SArnaldo Carvalho de Melo 		if (fp != NULL) {
1940ec80fde7SArnaldo Carvalho de Melo 			char line[8];
1941ec80fde7SArnaldo Carvalho de Melo 
1942ec80fde7SArnaldo Carvalho de Melo 			if (fgets(line, sizeof(line), fp) != NULL)
1943ec80fde7SArnaldo Carvalho de Melo 				value = atoi(line) != 0;
1944ec80fde7SArnaldo Carvalho de Melo 
1945ec80fde7SArnaldo Carvalho de Melo 			fclose(fp);
1946ec80fde7SArnaldo Carvalho de Melo 		}
1947ec80fde7SArnaldo Carvalho de Melo 	}
1948ec80fde7SArnaldo Carvalho de Melo 
1949ec80fde7SArnaldo Carvalho de Melo 	return value;
1950ec80fde7SArnaldo Carvalho de Melo }
1951ec80fde7SArnaldo Carvalho de Melo 
19520a7e6d1bSNamhyung Kim int symbol__init(struct perf_session_env *env)
1953cc612d81SArnaldo Carvalho de Melo {
1954ec5761eaSDavid Ahern 	const char *symfs;
1955ec5761eaSDavid Ahern 
195685e00b55SJovi Zhang 	if (symbol_conf.initialized)
195785e00b55SJovi Zhang 		return 0;
195885e00b55SJovi Zhang 
19599ac3e487SIrina Tirdea 	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
19604d439517SDavid S. Miller 
1961166ccc9cSNamhyung Kim 	symbol__elf_init();
1962166ccc9cSNamhyung Kim 
196375be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
196475be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
196579406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
1966b32d133aSArnaldo Carvalho de Melo 
19670a7e6d1bSNamhyung Kim 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
1968cc612d81SArnaldo Carvalho de Melo 		return -1;
1969cc612d81SArnaldo Carvalho de Melo 
1970c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1971c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
1972c410a338SArnaldo Carvalho de Melo 		return -1;
1973c410a338SArnaldo Carvalho de Melo 	}
1974c410a338SArnaldo Carvalho de Melo 
1975655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
1976655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
1977655000e7SArnaldo Carvalho de Melo 		return -1;
1978655000e7SArnaldo Carvalho de Melo 
1979655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
1980655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
1981655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
1982655000e7SArnaldo Carvalho de Melo 
1983e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.pid_list,
1984e03eaa40SDavid Ahern 		       symbol_conf.pid_list_str, "pid") < 0)
1985e03eaa40SDavid Ahern 		goto out_free_comm_list;
1986e03eaa40SDavid Ahern 
1987e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.tid_list,
1988e03eaa40SDavid Ahern 		       symbol_conf.tid_list_str, "tid") < 0)
1989e03eaa40SDavid Ahern 		goto out_free_pid_list;
1990e03eaa40SDavid Ahern 
1991655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
1992655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
1993e03eaa40SDavid Ahern 		goto out_free_tid_list;
1994655000e7SArnaldo Carvalho de Melo 
1995ec5761eaSDavid Ahern 	/*
1996ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
1997ec5761eaSDavid Ahern 	 * reset here for simplicity.
1998ec5761eaSDavid Ahern 	 */
1999ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2000ec5761eaSDavid Ahern 	if (symfs == NULL)
2001ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2002ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2003ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2004ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2005ec5761eaSDavid Ahern 		free((void *)symfs);
2006ec5761eaSDavid Ahern 
2007ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2008ec80fde7SArnaldo Carvalho de Melo 
200985e00b55SJovi Zhang 	symbol_conf.initialized = true;
20104aa65636SArnaldo Carvalho de Melo 	return 0;
2011655000e7SArnaldo Carvalho de Melo 
2012e03eaa40SDavid Ahern out_free_tid_list:
2013e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2014e03eaa40SDavid Ahern out_free_pid_list:
2015e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2016655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2017655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2018d74c896bSNamhyung Kim out_free_dso_list:
2019d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2020655000e7SArnaldo Carvalho de Melo 	return -1;
2021cc612d81SArnaldo Carvalho de Melo }
2022cc612d81SArnaldo Carvalho de Melo 
2023d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2024d65a458bSArnaldo Carvalho de Melo {
202585e00b55SJovi Zhang 	if (!symbol_conf.initialized)
202685e00b55SJovi Zhang 		return;
2027d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2028d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2029d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2030e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2031e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2032d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2033d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
203485e00b55SJovi Zhang 	symbol_conf.initialized = false;
2035d65a458bSArnaldo Carvalho de Melo }
2036