xref: /linux/tools/perf/util/symbol.c (revision 0a7c74eae307894c6c95316c382f118aef8481e8)
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>
6877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
75aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
85aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
95aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
105aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
115aab621bSArnaldo Carvalho de Melo #include <unistd.h>
129486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
13b01141f4SArnaldo Carvalho de Melo #include "annotate.h"
14b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
15e334c726SNamhyung Kim #include "util.h"
168a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1769d2591aSArnaldo Carvalho de Melo #include "machine.h"
1886470930SIngo Molnar #include "symbol.h"
195aab621bSArnaldo Carvalho de Melo #include "strlist.h"
20e03eaa40SDavid Ahern #include "intlist.h"
21843ff37bSKrister Johansen #include "namespaces.h"
220a7e6d1bSNamhyung Kim #include "header.h"
239a3993d4SArnaldo Carvalho de Melo #include "path.h"
243d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h"
2586470930SIngo Molnar 
2686470930SIngo Molnar #include <elf.h>
27f1617b40SArnaldo Carvalho de Melo #include <limits.h>
28c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h>
29439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
302cdbc46dSPeter Zijlstra 
31be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map);
32be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map);
33608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name);
34608c34deSArnaldo Carvalho de Melo 
353f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries;
363f067dcaSArnaldo Carvalho de Melo char **vmlinux_path;
37439d473bSArnaldo Carvalho de Melo 
3875be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
39b32d133aSArnaldo Carvalho de Melo 	.use_modules		= true,
40b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path	= true,
413e6a2a7fSStephane Eranian 	.annotate_src		= true,
42328ccdacSNamhyung Kim 	.demangle		= true,
43763122adSAvi Kivity 	.demangle_kernel	= false,
44e511db5eSNamhyung Kim 	.cumulate_callchain	= true,
45c8302367SJiri Olsa 	.show_hist_headers	= true,
46ec5761eaSDavid Ahern 	.symfs			= "",
471e9abf8bSNamhyung Kim 	.event_group		= true,
48b32d133aSArnaldo Carvalho de Melo };
49b32d133aSArnaldo Carvalho de Melo 
5044f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = {
5144f24cb3SJiri Olsa 	DSO_BINARY_TYPE__KALLSYMS,
5244f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KALLSYMS,
5344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__JAVA_JIT,
5444f24cb3SJiri Olsa 	DSO_BINARY_TYPE__DEBUGLINK,
5544f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
56d2396999SKrister Johansen 	DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO,
5744f24cb3SJiri Olsa 	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
5844f24cb3SJiri Olsa 	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
5944f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
6044f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
6144f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KMODULE,
62c00c48fcSNamhyung Kim 	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
6344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
64c00c48fcSNamhyung Kim 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
659cd00941SRicardo Ribalda Delgado 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
6644f24cb3SJiri Olsa 	DSO_BINARY_TYPE__NOT_FOUND,
6744f24cb3SJiri Olsa };
6844f24cb3SJiri Olsa 
69028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
7044f24cb3SJiri Olsa 
7136a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
726893d4eeSArnaldo Carvalho de Melo {
7331877908SAnton Blanchard 	symbol_type = toupper(symbol_type);
7431877908SAnton Blanchard 
756893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
766893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
776893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
78f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
7931877908SAnton Blanchard 		return symbol_type == 'D';
806893d4eeSArnaldo Carvalho de Melo 	default:
816893d4eeSArnaldo Carvalho de Melo 		return false;
826893d4eeSArnaldo Carvalho de Melo 	}
836893d4eeSArnaldo Carvalho de Melo }
846893d4eeSArnaldo Carvalho de Melo 
85694bf407SAnton Blanchard static int prefix_underscores_count(const char *str)
86694bf407SAnton Blanchard {
87694bf407SAnton Blanchard 	const char *tail = str;
88694bf407SAnton Blanchard 
89694bf407SAnton Blanchard 	while (*tail == '_')
90694bf407SAnton Blanchard 		tail++;
91694bf407SAnton Blanchard 
92694bf407SAnton Blanchard 	return tail - str;
93694bf407SAnton Blanchard }
94694bf407SAnton Blanchard 
95d8040645SPaul Clarke int __weak arch__compare_symbol_names(const char *namea, const char *nameb)
96d8040645SPaul Clarke {
97d8040645SPaul Clarke 	return strcmp(namea, nameb);
98d8040645SPaul Clarke }
99d8040645SPaul Clarke 
100d8040645SPaul Clarke int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb,
101d8040645SPaul Clarke 					unsigned int n)
102d8040645SPaul Clarke {
103d8040645SPaul Clarke 	return strncmp(namea, nameb, n);
104d8040645SPaul Clarke }
105d8040645SPaul Clarke 
106fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma,
107fb6d5942SNaveen N. Rao 				    struct symbol *symb __maybe_unused)
108fb6d5942SNaveen N. Rao {
109fb6d5942SNaveen N. Rao 	/* Avoid "SyS" kernel syscall aliases */
110fb6d5942SNaveen N. Rao 	if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
111fb6d5942SNaveen N. Rao 		return SYMBOL_B;
112fb6d5942SNaveen N. Rao 	if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
113fb6d5942SNaveen N. Rao 		return SYMBOL_B;
114fb6d5942SNaveen N. Rao 
115fb6d5942SNaveen N. Rao 	return SYMBOL_A;
116fb6d5942SNaveen N. Rao }
117694bf407SAnton Blanchard 
118694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
119694bf407SAnton Blanchard {
120694bf407SAnton Blanchard 	s64 a;
121694bf407SAnton Blanchard 	s64 b;
1223445432bSAdrian Hunter 	size_t na, nb;
123694bf407SAnton Blanchard 
124694bf407SAnton Blanchard 	/* Prefer a symbol with non zero length */
125694bf407SAnton Blanchard 	a = syma->end - syma->start;
126694bf407SAnton Blanchard 	b = symb->end - symb->start;
127694bf407SAnton Blanchard 	if ((b == 0) && (a > 0))
128694bf407SAnton Blanchard 		return SYMBOL_A;
129694bf407SAnton Blanchard 	else if ((a == 0) && (b > 0))
130694bf407SAnton Blanchard 		return SYMBOL_B;
131694bf407SAnton Blanchard 
132694bf407SAnton Blanchard 	/* Prefer a non weak symbol over a weak one */
133694bf407SAnton Blanchard 	a = syma->binding == STB_WEAK;
134694bf407SAnton Blanchard 	b = symb->binding == STB_WEAK;
135694bf407SAnton Blanchard 	if (b && !a)
136694bf407SAnton Blanchard 		return SYMBOL_A;
137694bf407SAnton Blanchard 	if (a && !b)
138694bf407SAnton Blanchard 		return SYMBOL_B;
139694bf407SAnton Blanchard 
140694bf407SAnton Blanchard 	/* Prefer a global symbol over a non global one */
141694bf407SAnton Blanchard 	a = syma->binding == STB_GLOBAL;
142694bf407SAnton Blanchard 	b = symb->binding == STB_GLOBAL;
143694bf407SAnton Blanchard 	if (a && !b)
144694bf407SAnton Blanchard 		return SYMBOL_A;
145694bf407SAnton Blanchard 	if (b && !a)
146694bf407SAnton Blanchard 		return SYMBOL_B;
147694bf407SAnton Blanchard 
148694bf407SAnton Blanchard 	/* Prefer a symbol with less underscores */
149694bf407SAnton Blanchard 	a = prefix_underscores_count(syma->name);
150694bf407SAnton Blanchard 	b = prefix_underscores_count(symb->name);
151694bf407SAnton Blanchard 	if (b > a)
152694bf407SAnton Blanchard 		return SYMBOL_A;
153694bf407SAnton Blanchard 	else if (a > b)
154694bf407SAnton Blanchard 		return SYMBOL_B;
155694bf407SAnton Blanchard 
1563445432bSAdrian Hunter 	/* Choose the symbol with the longest name */
1573445432bSAdrian Hunter 	na = strlen(syma->name);
1583445432bSAdrian Hunter 	nb = strlen(symb->name);
1593445432bSAdrian Hunter 	if (na > nb)
160694bf407SAnton Blanchard 		return SYMBOL_A;
1613445432bSAdrian Hunter 	else if (na < nb)
162694bf407SAnton Blanchard 		return SYMBOL_B;
1633445432bSAdrian Hunter 
164fb6d5942SNaveen N. Rao 	return arch__choose_best_symbol(syma, symb);
165694bf407SAnton Blanchard }
166694bf407SAnton Blanchard 
167e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols)
168694bf407SAnton Blanchard {
169694bf407SAnton Blanchard 	struct rb_node *nd;
170694bf407SAnton Blanchard 	struct symbol *curr, *next;
171694bf407SAnton Blanchard 
172c97b40e4SArnaldo Carvalho de Melo 	if (symbol_conf.allow_aliases)
173c97b40e4SArnaldo Carvalho de Melo 		return;
174c97b40e4SArnaldo Carvalho de Melo 
175694bf407SAnton Blanchard 	nd = rb_first(symbols);
176694bf407SAnton Blanchard 
177694bf407SAnton Blanchard 	while (nd) {
178694bf407SAnton Blanchard 		curr = rb_entry(nd, struct symbol, rb_node);
179694bf407SAnton Blanchard again:
180694bf407SAnton Blanchard 		nd = rb_next(&curr->rb_node);
181694bf407SAnton Blanchard 		next = rb_entry(nd, struct symbol, rb_node);
182694bf407SAnton Blanchard 
183694bf407SAnton Blanchard 		if (!nd)
184694bf407SAnton Blanchard 			break;
185694bf407SAnton Blanchard 
186694bf407SAnton Blanchard 		if (curr->start != next->start)
187694bf407SAnton Blanchard 			continue;
188694bf407SAnton Blanchard 
189694bf407SAnton Blanchard 		if (choose_best_symbol(curr, next) == SYMBOL_A) {
190694bf407SAnton Blanchard 			rb_erase(&next->rb_node, symbols);
191d4f74eb8SChenggang Qin 			symbol__delete(next);
192694bf407SAnton Blanchard 			goto again;
193694bf407SAnton Blanchard 		} else {
194694bf407SAnton Blanchard 			nd = rb_next(&curr->rb_node);
195694bf407SAnton Blanchard 			rb_erase(&curr->rb_node, symbols);
196d4f74eb8SChenggang Qin 			symbol__delete(curr);
197694bf407SAnton Blanchard 		}
198694bf407SAnton Blanchard 	}
199694bf407SAnton Blanchard }
200694bf407SAnton Blanchard 
201e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols)
202af427bf5SArnaldo Carvalho de Melo {
203aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(symbols);
2042e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
205af427bf5SArnaldo Carvalho de Melo 
206af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
207af427bf5SArnaldo Carvalho de Melo 		return;
208af427bf5SArnaldo Carvalho de Melo 
2092e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
2102e538c4aSArnaldo Carvalho de Melo 
211af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
2122e538c4aSArnaldo Carvalho de Melo 		prev = curr;
2132e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
214af427bf5SArnaldo Carvalho de Melo 
2153b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
2162c241bd3SArnaldo Carvalho de Melo 			prev->end = curr->start;
217af427bf5SArnaldo Carvalho de Melo 	}
218af427bf5SArnaldo Carvalho de Melo 
2192e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
2202e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
221e7ede72aSDaniel Borkmann 		curr->end = roundup(curr->start, 4096) + 4096;
2222e538c4aSArnaldo Carvalho de Melo }
2232e538c4aSArnaldo Carvalho de Melo 
224e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
225af427bf5SArnaldo Carvalho de Melo {
2261eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
2274bb7123dSArnaldo Carvalho de Melo 	struct map *next, *curr;
228af427bf5SArnaldo Carvalho de Melo 
229*0a7c74eaSArnaldo Carvalho de Melo 	down_write(&maps->lock);
2306a2ffcddSArnaldo Carvalho de Melo 
2314bb7123dSArnaldo Carvalho de Melo 	curr = maps__first(maps);
2324bb7123dSArnaldo Carvalho de Melo 	if (curr == NULL)
2336a2ffcddSArnaldo Carvalho de Melo 		goto out_unlock;
234af427bf5SArnaldo Carvalho de Melo 
2354bb7123dSArnaldo Carvalho de Melo 	for (next = map__next(curr); next; next = map__next(curr)) {
2369ad4652bSThomas Richter 		if (!curr->end)
2374bb7123dSArnaldo Carvalho de Melo 			curr->end = next->start;
2384bb7123dSArnaldo Carvalho de Melo 		curr = next;
2392e538c4aSArnaldo Carvalho de Melo 	}
24090c83218SArnaldo Carvalho de Melo 
24190c83218SArnaldo Carvalho de Melo 	/*
24290c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
24390c83218SArnaldo Carvalho de Melo 	 * last map final address.
24490c83218SArnaldo Carvalho de Melo 	 */
2459ad4652bSThomas Richter 	if (!curr->end)
2469d1faba5SIan Munsie 		curr->end = ~0ULL;
2476a2ffcddSArnaldo Carvalho de Melo 
2486a2ffcddSArnaldo Carvalho de Melo out_unlock:
249*0a7c74eaSArnaldo Carvalho de Melo 	up_write(&maps->lock);
250af427bf5SArnaldo Carvalho de Melo }
251af427bf5SArnaldo Carvalho de Melo 
252e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
25386470930SIngo Molnar {
25486470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
255aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
256aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
257aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
25886470930SIngo Molnar 		return NULL;
25986470930SIngo Molnar 
260b01141f4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size) {
261b01141f4SArnaldo Carvalho de Melo 		if (symbol_conf.init_annotation) {
262b01141f4SArnaldo Carvalho de Melo 			struct annotation *notes = (void *)sym;
263b01141f4SArnaldo Carvalho de Melo 			pthread_mutex_init(&notes->lock, NULL);
264b01141f4SArnaldo Carvalho de Melo 		}
265aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
266b01141f4SArnaldo Carvalho de Melo 	}
26736479484SArnaldo Carvalho de Melo 
268aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
2692c241bd3SArnaldo Carvalho de Melo 	sym->end     = len ? start + len : start;
270aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
271aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
272e4204992SArnaldo Carvalho de Melo 
273aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
274aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
275aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
276e4204992SArnaldo Carvalho de Melo 
277aeafcbafSArnaldo Carvalho de Melo 	return sym;
27886470930SIngo Molnar }
27986470930SIngo Molnar 
280aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
28186470930SIngo Molnar {
282aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
28386470930SIngo Molnar }
28486470930SIngo Molnar 
285cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols)
28686470930SIngo Molnar {
28786470930SIngo Molnar 	struct symbol *pos;
288aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
28986470930SIngo Molnar 
29086470930SIngo Molnar 	while (next) {
29186470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
29286470930SIngo Molnar 		next = rb_next(&pos->rb_node);
293aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
29400a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
29586470930SIngo Molnar 	}
29686470930SIngo Molnar }
29786470930SIngo Molnar 
298608c34deSArnaldo Carvalho de Melo void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel)
29986470930SIngo Molnar {
300aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
30186470930SIngo Molnar 	struct rb_node *parent = NULL;
3029cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
30386470930SIngo Molnar 	struct symbol *s;
30486470930SIngo Molnar 
305608c34deSArnaldo Carvalho de Melo 	if (kernel) {
306608c34deSArnaldo Carvalho de Melo 		const char *name = sym->name;
307608c34deSArnaldo Carvalho de Melo 		/*
308608c34deSArnaldo Carvalho de Melo 		 * ppc64 uses function descriptors and appends a '.' to the
309608c34deSArnaldo Carvalho de Melo 		 * start of every instruction address. Remove it.
310608c34deSArnaldo Carvalho de Melo 		 */
311608c34deSArnaldo Carvalho de Melo 		if (name[0] == '.')
312608c34deSArnaldo Carvalho de Melo 			name++;
313608c34deSArnaldo Carvalho de Melo 		sym->idle = symbol__is_idle(name);
314608c34deSArnaldo Carvalho de Melo 	}
315608c34deSArnaldo Carvalho de Melo 
31686470930SIngo Molnar 	while (*p != NULL) {
31786470930SIngo Molnar 		parent = *p;
31886470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
31986470930SIngo Molnar 		if (ip < s->start)
32086470930SIngo Molnar 			p = &(*p)->rb_left;
32186470930SIngo Molnar 		else
32286470930SIngo Molnar 			p = &(*p)->rb_right;
32386470930SIngo Molnar 	}
32486470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
325aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
32686470930SIngo Molnar }
32786470930SIngo Molnar 
328608c34deSArnaldo Carvalho de Melo void symbols__insert(struct rb_root *symbols, struct symbol *sym)
329608c34deSArnaldo Carvalho de Melo {
330608c34deSArnaldo Carvalho de Melo 	__symbols__insert(symbols, sym, false);
331608c34deSArnaldo Carvalho de Melo }
332608c34deSArnaldo Carvalho de Melo 
333aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
33486470930SIngo Molnar {
33586470930SIngo Molnar 	struct rb_node *n;
33686470930SIngo Molnar 
337aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
33886470930SIngo Molnar 		return NULL;
33986470930SIngo Molnar 
340aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
34186470930SIngo Molnar 
34286470930SIngo Molnar 	while (n) {
34386470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
34486470930SIngo Molnar 
34586470930SIngo Molnar 		if (ip < s->start)
34686470930SIngo Molnar 			n = n->rb_left;
3479c7b37cdSChris Phlipot 		else if (ip > s->end || (ip == s->end && ip != s->start))
34886470930SIngo Molnar 			n = n->rb_right;
34986470930SIngo Molnar 		else
35086470930SIngo Molnar 			return s;
35186470930SIngo Molnar 	}
35286470930SIngo Molnar 
35386470930SIngo Molnar 	return NULL;
35486470930SIngo Molnar }
35586470930SIngo Molnar 
3568e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols)
3578e0cf965SAdrian Hunter {
3588e0cf965SAdrian Hunter 	struct rb_node *n = rb_first(symbols);
3598e0cf965SAdrian Hunter 
3608e0cf965SAdrian Hunter 	if (n)
3618e0cf965SAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3628e0cf965SAdrian Hunter 
3638e0cf965SAdrian Hunter 	return NULL;
3648e0cf965SAdrian Hunter }
3658e0cf965SAdrian Hunter 
366cd67f99fSAdrian Hunter static struct symbol *symbols__last(struct rb_root *symbols)
367cd67f99fSAdrian Hunter {
368cd67f99fSAdrian Hunter 	struct rb_node *n = rb_last(symbols);
369cd67f99fSAdrian Hunter 
370cd67f99fSAdrian Hunter 	if (n)
371cd67f99fSAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
372cd67f99fSAdrian Hunter 
373cd67f99fSAdrian Hunter 	return NULL;
374cd67f99fSAdrian Hunter }
375cd67f99fSAdrian Hunter 
3769c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym)
3779c00a81bSAdrian Hunter {
3789c00a81bSAdrian Hunter 	struct rb_node *n = rb_next(&sym->rb_node);
3799c00a81bSAdrian Hunter 
3809c00a81bSAdrian Hunter 	if (n)
3819c00a81bSAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3829c00a81bSAdrian Hunter 
3839c00a81bSAdrian Hunter 	return NULL;
3849c00a81bSAdrian Hunter }
3859c00a81bSAdrian Hunter 
386aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
38779406cd7SArnaldo Carvalho de Melo {
388aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
38979406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
39002a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
39102a9d037SRabin Vincent 
39202a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
39379406cd7SArnaldo Carvalho de Melo 
39479406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
39579406cd7SArnaldo Carvalho de Melo 		parent = *p;
39679406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
39779406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
39879406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
39979406cd7SArnaldo Carvalho de Melo 		else
40079406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
40179406cd7SArnaldo Carvalho de Melo 	}
40279406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
403aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
40479406cd7SArnaldo Carvalho de Melo }
40579406cd7SArnaldo Carvalho de Melo 
406aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
407aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
40879406cd7SArnaldo Carvalho de Melo {
40979406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
41079406cd7SArnaldo Carvalho de Melo 
41179406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
41279406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
413aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
41479406cd7SArnaldo Carvalho de Melo 	}
41579406cd7SArnaldo Carvalho de Melo }
41679406cd7SArnaldo Carvalho de Melo 
417d8040645SPaul Clarke int symbol__match_symbol_name(const char *name, const char *str,
418d8040645SPaul Clarke 			      enum symbol_tag_include includes)
419d8040645SPaul Clarke {
420d8040645SPaul Clarke 	const char *versioning;
421d8040645SPaul Clarke 
422d8040645SPaul Clarke 	if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY &&
423d8040645SPaul Clarke 	    (versioning = strstr(name, "@@"))) {
424d8040645SPaul Clarke 		int len = strlen(str);
425d8040645SPaul Clarke 
426d8040645SPaul Clarke 		if (len < versioning - name)
427d8040645SPaul Clarke 			len = versioning - name;
428d8040645SPaul Clarke 
429d8040645SPaul Clarke 		return arch__compare_symbol_names_n(name, str, len);
430d8040645SPaul Clarke 	} else
431d8040645SPaul Clarke 		return arch__compare_symbol_names(name, str);
432d8040645SPaul Clarke }
433d8040645SPaul Clarke 
434aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
435d8040645SPaul Clarke 					    const char *name,
436d8040645SPaul Clarke 					    enum symbol_tag_include includes)
43779406cd7SArnaldo Carvalho de Melo {
43879406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
4395bcaaca3SMartin Liška 	struct symbol_name_rb_node *s = NULL;
44079406cd7SArnaldo Carvalho de Melo 
441aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
44279406cd7SArnaldo Carvalho de Melo 		return NULL;
44379406cd7SArnaldo Carvalho de Melo 
444aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
44579406cd7SArnaldo Carvalho de Melo 
44679406cd7SArnaldo Carvalho de Melo 	while (n) {
44779406cd7SArnaldo Carvalho de Melo 		int cmp;
44879406cd7SArnaldo Carvalho de Melo 
44979406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
450d8040645SPaul Clarke 		cmp = symbol__match_symbol_name(s->sym.name, name, includes);
45179406cd7SArnaldo Carvalho de Melo 
452d8040645SPaul Clarke 		if (cmp > 0)
45379406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
454d8040645SPaul Clarke 		else if (cmp < 0)
45579406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
45679406cd7SArnaldo Carvalho de Melo 		else
457de480999SNamhyung Kim 			break;
45879406cd7SArnaldo Carvalho de Melo 	}
45979406cd7SArnaldo Carvalho de Melo 
460de480999SNamhyung Kim 	if (n == NULL)
46179406cd7SArnaldo Carvalho de Melo 		return NULL;
462de480999SNamhyung Kim 
463d8040645SPaul Clarke 	if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY)
464de480999SNamhyung Kim 		/* return first symbol that has same name (if any) */
465de480999SNamhyung Kim 		for (n = rb_prev(n); n; n = rb_prev(n)) {
466de480999SNamhyung Kim 			struct symbol_name_rb_node *tmp;
467de480999SNamhyung Kim 
468de480999SNamhyung Kim 			tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
469031b84c4SNaveen N. Rao 			if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
470de480999SNamhyung Kim 				break;
471de480999SNamhyung Kim 
472de480999SNamhyung Kim 			s = tmp;
473de480999SNamhyung Kim 		}
474de480999SNamhyung Kim 
475de480999SNamhyung Kim 	return &s->sym;
47679406cd7SArnaldo Carvalho de Melo }
47779406cd7SArnaldo Carvalho de Melo 
478c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso)
479c0b4dffbSArnaldo Carvalho de Melo {
480c0b4dffbSArnaldo Carvalho de Melo 	enum map_type type;
481c0b4dffbSArnaldo Carvalho de Melo 
482c0b4dffbSArnaldo Carvalho de Melo 	for (type = MAP__FUNCTION; type <= MAP__VARIABLE; ++type) {
483c0b4dffbSArnaldo Carvalho de Melo 		dso->last_find_result[type].addr   = 0;
484c0b4dffbSArnaldo Carvalho de Melo 		dso->last_find_result[type].symbol = NULL;
485c0b4dffbSArnaldo Carvalho de Melo 	}
486c0b4dffbSArnaldo Carvalho de Melo }
487c0b4dffbSArnaldo Carvalho de Melo 
488ae93a6c7SChris Phlipot void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym)
489ae93a6c7SChris Phlipot {
490608c34deSArnaldo Carvalho de Melo 	__symbols__insert(&dso->symbols[type], sym, dso->kernel);
491ae93a6c7SChris Phlipot 
492ae93a6c7SChris Phlipot 	/* update the symbol cache if necessary */
493ae93a6c7SChris Phlipot 	if (dso->last_find_result[type].addr >= sym->start &&
494ae93a6c7SChris Phlipot 	    (dso->last_find_result[type].addr < sym->end ||
495ae93a6c7SChris Phlipot 	    sym->start == sym->end)) {
496ae93a6c7SChris Phlipot 		dso->last_find_result[type].symbol = sym;
497ae93a6c7SChris Phlipot 	}
498ae93a6c7SChris Phlipot }
499ae93a6c7SChris Phlipot 
500aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
50179406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
502fcf1203aSArnaldo Carvalho de Melo {
503b843f62aSArnaldo Carvalho de Melo 	if (dso->last_find_result[type].addr != addr || dso->last_find_result[type].symbol == NULL) {
504b685ac22SArnaldo Carvalho de Melo 		dso->last_find_result[type].addr   = addr;
505b685ac22SArnaldo Carvalho de Melo 		dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr);
506b685ac22SArnaldo Carvalho de Melo 	}
507b685ac22SArnaldo Carvalho de Melo 
508b685ac22SArnaldo Carvalho de Melo 	return dso->last_find_result[type].symbol;
509fcf1203aSArnaldo Carvalho de Melo }
510fcf1203aSArnaldo Carvalho de Melo 
5119c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
5128e0cf965SAdrian Hunter {
5138e0cf965SAdrian Hunter 	return symbols__first(&dso->symbols[type]);
5148e0cf965SAdrian Hunter }
5158e0cf965SAdrian Hunter 
516cd67f99fSAdrian Hunter struct symbol *dso__last_symbol(struct dso *dso, enum map_type type)
517cd67f99fSAdrian Hunter {
518cd67f99fSAdrian Hunter 	return symbols__last(&dso->symbols[type]);
519cd67f99fSAdrian Hunter }
520cd67f99fSAdrian Hunter 
5219c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym)
5229c00a81bSAdrian Hunter {
5239c00a81bSAdrian Hunter 	return symbols__next(sym);
5249c00a81bSAdrian Hunter }
5259c00a81bSAdrian Hunter 
52618bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym)
52718bd7264SArnaldo Carvalho de Melo {
52818bd7264SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
52918bd7264SArnaldo Carvalho de Melo 	struct rb_node *n = rb_next(&s->rb_node);
53018bd7264SArnaldo Carvalho de Melo 
53118bd7264SArnaldo Carvalho de Melo 	return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
53218bd7264SArnaldo Carvalho de Melo }
53318bd7264SArnaldo Carvalho de Melo 
53418bd7264SArnaldo Carvalho de Melo  /*
53518bd7264SArnaldo Carvalho de Melo   * Teturns first symbol that matched with @name.
53618bd7264SArnaldo Carvalho de Melo   */
537aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
53879406cd7SArnaldo Carvalho de Melo 					const char *name)
53979406cd7SArnaldo Carvalho de Melo {
540d8040645SPaul Clarke 	struct symbol *s = symbols__find_by_name(&dso->symbol_names[type], name,
541d8040645SPaul Clarke 						 SYMBOL_TAG_INCLUDE__NONE);
542d8040645SPaul Clarke 	if (!s)
543d8040645SPaul Clarke 		s = symbols__find_by_name(&dso->symbol_names[type], name,
544d8040645SPaul Clarke 					  SYMBOL_TAG_INCLUDE__DEFAULT_ONLY);
545d8040645SPaul Clarke 	return s;
54679406cd7SArnaldo Carvalho de Melo }
54779406cd7SArnaldo Carvalho de Melo 
548aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
54979406cd7SArnaldo Carvalho de Melo {
550aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
551aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
552aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
55379406cd7SArnaldo Carvalho de Melo }
55479406cd7SArnaldo Carvalho de Melo 
555316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg,
556316d70d6SAdrian Hunter 		   int (*process_module)(void *arg, const char *name,
5579ad4652bSThomas Richter 					 u64 start, u64 size))
558316d70d6SAdrian Hunter {
559316d70d6SAdrian Hunter 	char *line = NULL;
560316d70d6SAdrian Hunter 	size_t n;
561316d70d6SAdrian Hunter 	FILE *file;
562316d70d6SAdrian Hunter 	int err = 0;
563316d70d6SAdrian Hunter 
564316d70d6SAdrian Hunter 	file = fopen(filename, "r");
565316d70d6SAdrian Hunter 	if (file == NULL)
566316d70d6SAdrian Hunter 		return -1;
567316d70d6SAdrian Hunter 
568316d70d6SAdrian Hunter 	while (1) {
569316d70d6SAdrian Hunter 		char name[PATH_MAX];
5709ad4652bSThomas Richter 		u64 start, size;
5719ad4652bSThomas Richter 		char *sep, *endptr;
572316d70d6SAdrian Hunter 		ssize_t line_len;
573316d70d6SAdrian Hunter 
574316d70d6SAdrian Hunter 		line_len = getline(&line, &n, file);
575316d70d6SAdrian Hunter 		if (line_len < 0) {
576316d70d6SAdrian Hunter 			if (feof(file))
577316d70d6SAdrian Hunter 				break;
578316d70d6SAdrian Hunter 			err = -1;
579316d70d6SAdrian Hunter 			goto out;
580316d70d6SAdrian Hunter 		}
581316d70d6SAdrian Hunter 
582316d70d6SAdrian Hunter 		if (!line) {
583316d70d6SAdrian Hunter 			err = -1;
584316d70d6SAdrian Hunter 			goto out;
585316d70d6SAdrian Hunter 		}
586316d70d6SAdrian Hunter 
587316d70d6SAdrian Hunter 		line[--line_len] = '\0'; /* \n */
588316d70d6SAdrian Hunter 
589316d70d6SAdrian Hunter 		sep = strrchr(line, 'x');
590316d70d6SAdrian Hunter 		if (sep == NULL)
591316d70d6SAdrian Hunter 			continue;
592316d70d6SAdrian Hunter 
593316d70d6SAdrian Hunter 		hex2u64(sep + 1, &start);
594316d70d6SAdrian Hunter 
595316d70d6SAdrian Hunter 		sep = strchr(line, ' ');
596316d70d6SAdrian Hunter 		if (sep == NULL)
597316d70d6SAdrian Hunter 			continue;
598316d70d6SAdrian Hunter 
599316d70d6SAdrian Hunter 		*sep = '\0';
600316d70d6SAdrian Hunter 
601316d70d6SAdrian Hunter 		scnprintf(name, sizeof(name), "[%s]", line);
602316d70d6SAdrian Hunter 
6039ad4652bSThomas Richter 		size = strtoul(sep + 1, &endptr, 0);
6049ad4652bSThomas Richter 		if (*endptr != ' ' && *endptr != '\t')
6059ad4652bSThomas Richter 			continue;
6069ad4652bSThomas Richter 
6079ad4652bSThomas Richter 		err = process_module(arg, name, start, size);
608316d70d6SAdrian Hunter 		if (err)
609316d70d6SAdrian Hunter 			break;
610316d70d6SAdrian Hunter 	}
611316d70d6SAdrian Hunter out:
612316d70d6SAdrian Hunter 	free(line);
613316d70d6SAdrian Hunter 	fclose(file);
614316d70d6SAdrian Hunter 	return err;
615316d70d6SAdrian Hunter }
616316d70d6SAdrian Hunter 
617682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
618682b335aSArnaldo Carvalho de Melo 	struct map *map;
619682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
620682b335aSArnaldo Carvalho de Melo };
621682b335aSArnaldo Carvalho de Melo 
622e7110b9fSArnaldo Carvalho de Melo /*
623e7110b9fSArnaldo Carvalho de Melo  * These are symbols in the kernel image, so make sure that
624e7110b9fSArnaldo Carvalho de Melo  * sym is from a kernel DSO.
625e7110b9fSArnaldo Carvalho de Melo  */
626608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name)
62782d1deb0SDavid Ahern {
62882d1deb0SDavid Ahern 	const char * const idle_symbols[] = {
62982d1deb0SDavid Ahern 		"cpu_idle",
630e0336ed6SArnaldo Carvalho de Melo 		"cpu_startup_entry",
63182d1deb0SDavid Ahern 		"intel_idle",
63282d1deb0SDavid Ahern 		"default_idle",
63382d1deb0SDavid Ahern 		"native_safe_halt",
63482d1deb0SDavid Ahern 		"enter_idle",
63582d1deb0SDavid Ahern 		"exit_idle",
63682d1deb0SDavid Ahern 		"mwait_idle",
63782d1deb0SDavid Ahern 		"mwait_idle_with_hints",
63882d1deb0SDavid Ahern 		"poll_idle",
63982d1deb0SDavid Ahern 		"ppc64_runlatch_off",
64082d1deb0SDavid Ahern 		"pseries_dedicated_idle_sleep",
64182d1deb0SDavid Ahern 		NULL
64282d1deb0SDavid Ahern 	};
64382d1deb0SDavid Ahern 	int i;
64482d1deb0SDavid Ahern 
64582d1deb0SDavid Ahern 	for (i = 0; idle_symbols[i]; i++) {
646608c34deSArnaldo Carvalho de Melo 		if (!strcmp(idle_symbols[i], name))
64782d1deb0SDavid Ahern 			return true;
64882d1deb0SDavid Ahern 	}
64982d1deb0SDavid Ahern 
65082d1deb0SDavid Ahern 	return false;
65182d1deb0SDavid Ahern }
65282d1deb0SDavid Ahern 
653682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
65482151520SCody P Schafer 				       char type, u64 start)
655682b335aSArnaldo Carvalho de Melo {
656682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
657682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
658682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
659682b335aSArnaldo Carvalho de Melo 
660682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
661682b335aSArnaldo Carvalho de Melo 		return 0;
662682b335aSArnaldo Carvalho de Melo 
66382151520SCody P Schafer 	/*
66482151520SCody P Schafer 	 * module symbols are not sorted so we add all
66582151520SCody P Schafer 	 * symbols, setting length to 0, and rely on
66682151520SCody P Schafer 	 * symbols__fixup_end() to fix it up.
66782151520SCody P Schafer 	 */
6688e947f1eSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, kallsyms2elf_binding(type), name);
6692e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
670682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
67182164161SArnaldo Carvalho de Melo 	/*
67282164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6734e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
67482164161SArnaldo Carvalho de Melo 	 */
675608c34deSArnaldo Carvalho de Melo 	__symbols__insert(root, sym, !strchr(name, '['));
676a1645ce1SZhang, Yanmin 
677682b335aSArnaldo Carvalho de Melo 	return 0;
6782e538c4aSArnaldo Carvalho de Melo }
6792e538c4aSArnaldo Carvalho de Melo 
680682b335aSArnaldo Carvalho de Melo /*
681682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
682682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
683682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
684682b335aSArnaldo Carvalho de Melo  */
685aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6869e201442SArnaldo Carvalho de Melo 				  struct map *map)
687682b335aSArnaldo Carvalho de Melo {
688aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6899e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6902e538c4aSArnaldo Carvalho de Melo }
6912e538c4aSArnaldo Carvalho de Melo 
692be39db9fSArnaldo Carvalho de Melo static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map)
6938e0cf965SAdrian Hunter {
694ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
6958e0cf965SAdrian Hunter 	struct map *curr_map;
6968e0cf965SAdrian Hunter 	struct symbol *pos;
697866548ddSAdrian Hunter 	int count = 0;
698866548ddSAdrian Hunter 	struct rb_root old_root = dso->symbols[map->type];
6998e0cf965SAdrian Hunter 	struct rb_root *root = &dso->symbols[map->type];
7008e0cf965SAdrian Hunter 	struct rb_node *next = rb_first(root);
7018e0cf965SAdrian Hunter 
702ba92732eSWang Nan 	if (!kmaps)
703ba92732eSWang Nan 		return -1;
704ba92732eSWang Nan 
705866548ddSAdrian Hunter 	*root = RB_ROOT;
706866548ddSAdrian Hunter 
7078e0cf965SAdrian Hunter 	while (next) {
7088e0cf965SAdrian Hunter 		char *module;
7098e0cf965SAdrian Hunter 
7108e0cf965SAdrian Hunter 		pos = rb_entry(next, struct symbol, rb_node);
7118e0cf965SAdrian Hunter 		next = rb_next(&pos->rb_node);
7128e0cf965SAdrian Hunter 
713866548ddSAdrian Hunter 		rb_erase_init(&pos->rb_node, &old_root);
714866548ddSAdrian Hunter 
7158e0cf965SAdrian Hunter 		module = strchr(pos->name, '\t');
7168e0cf965SAdrian Hunter 		if (module)
7178e0cf965SAdrian Hunter 			*module = '\0';
7188e0cf965SAdrian Hunter 
7198e0cf965SAdrian Hunter 		curr_map = map_groups__find(kmaps, map->type, pos->start);
7208e0cf965SAdrian Hunter 
721be39db9fSArnaldo Carvalho de Melo 		if (!curr_map) {
7228e0cf965SAdrian Hunter 			symbol__delete(pos);
723866548ddSAdrian Hunter 			continue;
724866548ddSAdrian Hunter 		}
725866548ddSAdrian Hunter 
7268e0cf965SAdrian Hunter 		pos->start -= curr_map->start - curr_map->pgoff;
7278e0cf965SAdrian Hunter 		if (pos->end)
7288e0cf965SAdrian Hunter 			pos->end -= curr_map->start - curr_map->pgoff;
729866548ddSAdrian Hunter 		symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
7308e0cf965SAdrian Hunter 		++count;
7318e0cf965SAdrian Hunter 	}
7328e0cf965SAdrian Hunter 
7338e0cf965SAdrian Hunter 	/* Symbols have been adjusted */
7348e0cf965SAdrian Hunter 	dso->adjust_symbols = 1;
7358e0cf965SAdrian Hunter 
736866548ddSAdrian Hunter 	return count;
7378e0cf965SAdrian Hunter }
7388e0cf965SAdrian Hunter 
7392e538c4aSArnaldo Carvalho de Melo /*
7402e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
7412e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
7422e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
7432e538c4aSArnaldo Carvalho de Melo  */
744be39db9fSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
7452e538c4aSArnaldo Carvalho de Melo {
746ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
747ba92732eSWang Nan 	struct machine *machine;
7484e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
7492e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
7508a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
751aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
7524e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
7532e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
7542e538c4aSArnaldo Carvalho de Melo 
755ba92732eSWang Nan 	if (!kmaps)
756ba92732eSWang Nan 		return -1;
757ba92732eSWang Nan 
758ba92732eSWang Nan 	machine = kmaps->machine;
759ba92732eSWang Nan 
7602e538c4aSArnaldo Carvalho de Melo 	while (next) {
7612e538c4aSArnaldo Carvalho de Melo 		char *module;
7622e538c4aSArnaldo Carvalho de Melo 
7632e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
7642e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
7652e538c4aSArnaldo Carvalho de Melo 
7662e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
7672e538c4aSArnaldo Carvalho de Melo 		if (module) {
76875be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
7691de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
7701de8e245SArnaldo Carvalho de Melo 
7712e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
7722e538c4aSArnaldo Carvalho de Melo 
773b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
774a1645ce1SZhang, Yanmin 				if (curr_map != map &&
775aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
77623346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
777a1645ce1SZhang, Yanmin 					/*
778a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
779a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
780a1645ce1SZhang, Yanmin 					 * points to a module and all its
781a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
782a1645ce1SZhang, Yanmin 					 * loaded.
783a1645ce1SZhang, Yanmin 					 */
784a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
785a1645ce1SZhang, Yanmin 							curr_map->type);
786af427bf5SArnaldo Carvalho de Melo 				}
787b7cece76SArnaldo Carvalho de Melo 
788a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
789a1645ce1SZhang, Yanmin 							map->type, module);
790a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7912f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
792a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
793a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
79423346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
795a1645ce1SZhang, Yanmin 					curr_map = map;
796a1645ce1SZhang, Yanmin 					goto discard_symbol;
797a1645ce1SZhang, Yanmin 				}
798a1645ce1SZhang, Yanmin 
799a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
80023346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
801b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
802af427bf5SArnaldo Carvalho de Melo 			}
80386470930SIngo Molnar 			/*
8042e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
8052e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
80686470930SIngo Molnar 			 */
8074e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
8084e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
8094e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
8102e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
811aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
81286470930SIngo Molnar 
813d9b62abaSAdrian Hunter 			if (delta) {
814d9b62abaSAdrian Hunter 				/* Kernel was relocated at boot time */
815d9b62abaSAdrian Hunter 				pos->start -= delta;
816d9b62abaSAdrian Hunter 				pos->end -= delta;
817d9b62abaSAdrian Hunter 			}
818d9b62abaSAdrian Hunter 
8198a953312SArnaldo Carvalho de Melo 			if (count == 0) {
8208a953312SArnaldo Carvalho de Melo 				curr_map = map;
821be39db9fSArnaldo Carvalho de Melo 				goto add_symbol;
8228a953312SArnaldo Carvalho de Melo 			}
8238a953312SArnaldo Carvalho de Melo 
824aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
825a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
826a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
827a1645ce1SZhang, Yanmin 					kernel_range++);
828a1645ce1SZhang, Yanmin 			else
829a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
830a1645ce1SZhang, Yanmin 					"[kernel].%d",
8312e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
83286470930SIngo Molnar 
833aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
834aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
8352e538c4aSArnaldo Carvalho de Melo 				return -1;
8362e538c4aSArnaldo Carvalho de Melo 
837aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
838a1645ce1SZhang, Yanmin 
839aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
84037fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
841d3a7c489SArnaldo Carvalho de Melo 				dso__put(ndso);
8422e538c4aSArnaldo Carvalho de Melo 				return -1;
8432e538c4aSArnaldo Carvalho de Melo 			}
8442e538c4aSArnaldo Carvalho de Melo 
8454e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
8469de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
8472e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
848d9b62abaSAdrian Hunter 		} else if (delta) {
849d9b62abaSAdrian Hunter 			/* Kernel was relocated at boot time */
850d9b62abaSAdrian Hunter 			pos->start -= delta;
851d9b62abaSAdrian Hunter 			pos->end -= delta;
8522e538c4aSArnaldo Carvalho de Melo 		}
853be39db9fSArnaldo Carvalho de Melo add_symbol:
8544e06255fSArnaldo Carvalho de Melo 		if (curr_map != map) {
8554e06255fSArnaldo Carvalho de Melo 			rb_erase(&pos->rb_node, root);
8564e06255fSArnaldo Carvalho de Melo 			symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
8578a953312SArnaldo Carvalho de Melo 			++moved;
8588a953312SArnaldo Carvalho de Melo 		} else
8598a953312SArnaldo Carvalho de Melo 			++count;
860be39db9fSArnaldo Carvalho de Melo 
861be39db9fSArnaldo Carvalho de Melo 		continue;
862be39db9fSArnaldo Carvalho de Melo discard_symbol:
863be39db9fSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, root);
864be39db9fSArnaldo Carvalho de Melo 		symbol__delete(pos);
86586470930SIngo Molnar 	}
86686470930SIngo Molnar 
867a1645ce1SZhang, Yanmin 	if (curr_map != map &&
868aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
86923346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
870a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
871a1645ce1SZhang, Yanmin 	}
872a1645ce1SZhang, Yanmin 
8738a953312SArnaldo Carvalho de Melo 	return count + moved;
87486470930SIngo Molnar }
87586470930SIngo Molnar 
8763f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename,
877ec80fde7SArnaldo Carvalho de Melo 				 const char *restricted_filename)
878ec80fde7SArnaldo Carvalho de Melo {
879ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
880ec80fde7SArnaldo Carvalho de Melo 
881ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
882ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
883ec80fde7SArnaldo Carvalho de Melo 
884ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
885ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
886ec80fde7SArnaldo Carvalho de Melo 			free(r);
887ec80fde7SArnaldo Carvalho de Melo 			return restricted;
888ec80fde7SArnaldo Carvalho de Melo 		}
889ec80fde7SArnaldo Carvalho de Melo 	}
890ec80fde7SArnaldo Carvalho de Melo 
891ec80fde7SArnaldo Carvalho de Melo 	return restricted;
892ec80fde7SArnaldo Carvalho de Melo }
893ec80fde7SArnaldo Carvalho de Melo 
89452afdaf9SAdrian Hunter struct module_info {
89552afdaf9SAdrian Hunter 	struct rb_node rb_node;
89652afdaf9SAdrian Hunter 	char *name;
89752afdaf9SAdrian Hunter 	u64 start;
89852afdaf9SAdrian Hunter };
89952afdaf9SAdrian Hunter 
90052afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules)
90152afdaf9SAdrian Hunter {
90252afdaf9SAdrian Hunter 	struct rb_node **p = &modules->rb_node;
90352afdaf9SAdrian Hunter 	struct rb_node *parent = NULL;
90452afdaf9SAdrian Hunter 	struct module_info *m;
90552afdaf9SAdrian Hunter 
90652afdaf9SAdrian Hunter 	while (*p != NULL) {
90752afdaf9SAdrian Hunter 		parent = *p;
90852afdaf9SAdrian Hunter 		m = rb_entry(parent, struct module_info, rb_node);
90952afdaf9SAdrian Hunter 		if (strcmp(mi->name, m->name) < 0)
91052afdaf9SAdrian Hunter 			p = &(*p)->rb_left;
91152afdaf9SAdrian Hunter 		else
91252afdaf9SAdrian Hunter 			p = &(*p)->rb_right;
91352afdaf9SAdrian Hunter 	}
91452afdaf9SAdrian Hunter 	rb_link_node(&mi->rb_node, parent, p);
91552afdaf9SAdrian Hunter 	rb_insert_color(&mi->rb_node, modules);
91652afdaf9SAdrian Hunter }
91752afdaf9SAdrian Hunter 
91852afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules)
91952afdaf9SAdrian Hunter {
92052afdaf9SAdrian Hunter 	struct module_info *mi;
92152afdaf9SAdrian Hunter 	struct rb_node *next = rb_first(modules);
92252afdaf9SAdrian Hunter 
92352afdaf9SAdrian Hunter 	while (next) {
92452afdaf9SAdrian Hunter 		mi = rb_entry(next, struct module_info, rb_node);
92552afdaf9SAdrian Hunter 		next = rb_next(&mi->rb_node);
92652afdaf9SAdrian Hunter 		rb_erase(&mi->rb_node, modules);
92774cf249dSArnaldo Carvalho de Melo 		zfree(&mi->name);
92852afdaf9SAdrian Hunter 		free(mi);
92952afdaf9SAdrian Hunter 	}
93052afdaf9SAdrian Hunter }
93152afdaf9SAdrian Hunter 
93252afdaf9SAdrian Hunter static struct module_info *find_module(const char *name,
93352afdaf9SAdrian Hunter 				       struct rb_root *modules)
93452afdaf9SAdrian Hunter {
93552afdaf9SAdrian Hunter 	struct rb_node *n = modules->rb_node;
93652afdaf9SAdrian Hunter 
93752afdaf9SAdrian Hunter 	while (n) {
93852afdaf9SAdrian Hunter 		struct module_info *m;
93952afdaf9SAdrian Hunter 		int cmp;
94052afdaf9SAdrian Hunter 
94152afdaf9SAdrian Hunter 		m = rb_entry(n, struct module_info, rb_node);
94252afdaf9SAdrian Hunter 		cmp = strcmp(name, m->name);
94352afdaf9SAdrian Hunter 		if (cmp < 0)
94452afdaf9SAdrian Hunter 			n = n->rb_left;
94552afdaf9SAdrian Hunter 		else if (cmp > 0)
94652afdaf9SAdrian Hunter 			n = n->rb_right;
94752afdaf9SAdrian Hunter 		else
94852afdaf9SAdrian Hunter 			return m;
94952afdaf9SAdrian Hunter 	}
95052afdaf9SAdrian Hunter 
95152afdaf9SAdrian Hunter 	return NULL;
95252afdaf9SAdrian Hunter }
95352afdaf9SAdrian Hunter 
9549ad4652bSThomas Richter static int __read_proc_modules(void *arg, const char *name, u64 start,
9559ad4652bSThomas Richter 			       u64 size __maybe_unused)
95652afdaf9SAdrian Hunter {
95752afdaf9SAdrian Hunter 	struct rb_root *modules = arg;
95852afdaf9SAdrian Hunter 	struct module_info *mi;
95952afdaf9SAdrian Hunter 
96052afdaf9SAdrian Hunter 	mi = zalloc(sizeof(struct module_info));
96152afdaf9SAdrian Hunter 	if (!mi)
96252afdaf9SAdrian Hunter 		return -ENOMEM;
96352afdaf9SAdrian Hunter 
96452afdaf9SAdrian Hunter 	mi->name = strdup(name);
96552afdaf9SAdrian Hunter 	mi->start = start;
96652afdaf9SAdrian Hunter 
96752afdaf9SAdrian Hunter 	if (!mi->name) {
96852afdaf9SAdrian Hunter 		free(mi);
96952afdaf9SAdrian Hunter 		return -ENOMEM;
97052afdaf9SAdrian Hunter 	}
97152afdaf9SAdrian Hunter 
97252afdaf9SAdrian Hunter 	add_module(mi, modules);
97352afdaf9SAdrian Hunter 
97452afdaf9SAdrian Hunter 	return 0;
97552afdaf9SAdrian Hunter }
97652afdaf9SAdrian Hunter 
97752afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules)
97852afdaf9SAdrian Hunter {
97952afdaf9SAdrian Hunter 	if (symbol__restricted_filename(filename, "/proc/modules"))
98052afdaf9SAdrian Hunter 		return -1;
98152afdaf9SAdrian Hunter 
98252afdaf9SAdrian Hunter 	if (modules__parse(filename, modules, __read_proc_modules)) {
98352afdaf9SAdrian Hunter 		delete_modules(modules);
98452afdaf9SAdrian Hunter 		return -1;
98552afdaf9SAdrian Hunter 	}
98652afdaf9SAdrian Hunter 
98752afdaf9SAdrian Hunter 	return 0;
98852afdaf9SAdrian Hunter }
98952afdaf9SAdrian Hunter 
990fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to)
991fc1b691dSAdrian Hunter {
992fc1b691dSAdrian Hunter 	struct rb_root from_modules = RB_ROOT;
993fc1b691dSAdrian Hunter 	struct rb_root to_modules = RB_ROOT;
994fc1b691dSAdrian Hunter 	struct rb_node *from_node, *to_node;
995fc1b691dSAdrian Hunter 	struct module_info *from_m, *to_m;
996fc1b691dSAdrian Hunter 	int ret = -1;
997fc1b691dSAdrian Hunter 
998fc1b691dSAdrian Hunter 	if (read_proc_modules(from, &from_modules))
999fc1b691dSAdrian Hunter 		return -1;
1000fc1b691dSAdrian Hunter 
1001fc1b691dSAdrian Hunter 	if (read_proc_modules(to, &to_modules))
1002fc1b691dSAdrian Hunter 		goto out_delete_from;
1003fc1b691dSAdrian Hunter 
1004fc1b691dSAdrian Hunter 	from_node = rb_first(&from_modules);
1005fc1b691dSAdrian Hunter 	to_node = rb_first(&to_modules);
1006fc1b691dSAdrian Hunter 	while (from_node) {
1007fc1b691dSAdrian Hunter 		if (!to_node)
1008fc1b691dSAdrian Hunter 			break;
1009fc1b691dSAdrian Hunter 
1010fc1b691dSAdrian Hunter 		from_m = rb_entry(from_node, struct module_info, rb_node);
1011fc1b691dSAdrian Hunter 		to_m = rb_entry(to_node, struct module_info, rb_node);
1012fc1b691dSAdrian Hunter 
1013fc1b691dSAdrian Hunter 		if (from_m->start != to_m->start ||
1014fc1b691dSAdrian Hunter 		    strcmp(from_m->name, to_m->name))
1015fc1b691dSAdrian Hunter 			break;
1016fc1b691dSAdrian Hunter 
1017fc1b691dSAdrian Hunter 		from_node = rb_next(from_node);
1018fc1b691dSAdrian Hunter 		to_node = rb_next(to_node);
1019fc1b691dSAdrian Hunter 	}
1020fc1b691dSAdrian Hunter 
1021fc1b691dSAdrian Hunter 	if (!from_node && !to_node)
1022fc1b691dSAdrian Hunter 		ret = 0;
1023fc1b691dSAdrian Hunter 
1024fc1b691dSAdrian Hunter 	delete_modules(&to_modules);
1025fc1b691dSAdrian Hunter out_delete_from:
1026fc1b691dSAdrian Hunter 	delete_modules(&from_modules);
1027fc1b691dSAdrian Hunter 
1028fc1b691dSAdrian Hunter 	return ret;
1029fc1b691dSAdrian Hunter }
1030fc1b691dSAdrian Hunter 
103152afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map,
103252afdaf9SAdrian Hunter 				  struct map_groups *kmaps)
103352afdaf9SAdrian Hunter {
103452afdaf9SAdrian Hunter 	struct rb_root modules = RB_ROOT;
103552afdaf9SAdrian Hunter 	struct map *old_map;
103652afdaf9SAdrian Hunter 	int err;
103752afdaf9SAdrian Hunter 
103852afdaf9SAdrian Hunter 	err = read_proc_modules(filename, &modules);
103952afdaf9SAdrian Hunter 	if (err)
104052afdaf9SAdrian Hunter 		return err;
104152afdaf9SAdrian Hunter 
104252afdaf9SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
104352afdaf9SAdrian Hunter 	while (old_map) {
104452afdaf9SAdrian Hunter 		struct map *next = map_groups__next(old_map);
104552afdaf9SAdrian Hunter 		struct module_info *mi;
104652afdaf9SAdrian Hunter 
104752afdaf9SAdrian Hunter 		if (old_map == map || old_map->start == map->start) {
104852afdaf9SAdrian Hunter 			/* The kernel map */
104952afdaf9SAdrian Hunter 			old_map = next;
105052afdaf9SAdrian Hunter 			continue;
105152afdaf9SAdrian Hunter 		}
105252afdaf9SAdrian Hunter 
105352afdaf9SAdrian Hunter 		/* Module must be in memory at the same address */
105452afdaf9SAdrian Hunter 		mi = find_module(old_map->dso->short_name, &modules);
105552afdaf9SAdrian Hunter 		if (!mi || mi->start != old_map->start) {
105652afdaf9SAdrian Hunter 			err = -EINVAL;
105752afdaf9SAdrian Hunter 			goto out;
105852afdaf9SAdrian Hunter 		}
105952afdaf9SAdrian Hunter 
106052afdaf9SAdrian Hunter 		old_map = next;
106152afdaf9SAdrian Hunter 	}
106252afdaf9SAdrian Hunter out:
106352afdaf9SAdrian Hunter 	delete_modules(&modules);
106452afdaf9SAdrian Hunter 	return err;
106552afdaf9SAdrian Hunter }
106652afdaf9SAdrian Hunter 
106752afdaf9SAdrian Hunter /*
106852afdaf9SAdrian Hunter  * If kallsyms is referenced by name then we look for filename in the same
106952afdaf9SAdrian Hunter  * directory.
107052afdaf9SAdrian Hunter  */
107152afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename,
107252afdaf9SAdrian Hunter 					    const char *base_name,
107352afdaf9SAdrian Hunter 					    const char *kallsyms_filename)
107452afdaf9SAdrian Hunter {
107552afdaf9SAdrian Hunter 	char *name;
107652afdaf9SAdrian Hunter 
107752afdaf9SAdrian Hunter 	strcpy(filename, kallsyms_filename);
107852afdaf9SAdrian Hunter 	name = strrchr(filename, '/');
107952afdaf9SAdrian Hunter 	if (!name)
108052afdaf9SAdrian Hunter 		return false;
108152afdaf9SAdrian Hunter 
108252afdaf9SAdrian Hunter 	name += 1;
108352afdaf9SAdrian Hunter 
108452afdaf9SAdrian Hunter 	if (!strcmp(name, "kallsyms")) {
108552afdaf9SAdrian Hunter 		strcpy(name, base_name);
108652afdaf9SAdrian Hunter 		return true;
108752afdaf9SAdrian Hunter 	}
108852afdaf9SAdrian Hunter 
108952afdaf9SAdrian Hunter 	return false;
109052afdaf9SAdrian Hunter }
109152afdaf9SAdrian Hunter 
109252afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename,
109352afdaf9SAdrian Hunter 				  struct map *map)
109452afdaf9SAdrian Hunter {
1095ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
109652afdaf9SAdrian Hunter 	char modules_filename[PATH_MAX];
109752afdaf9SAdrian Hunter 
1098ba92732eSWang Nan 	if (!kmaps)
1099ba92732eSWang Nan 		return -EINVAL;
1100ba92732eSWang Nan 
110152afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(modules_filename, "modules",
110252afdaf9SAdrian Hunter 					     kallsyms_filename))
110352afdaf9SAdrian Hunter 		return -EINVAL;
110452afdaf9SAdrian Hunter 
110552afdaf9SAdrian Hunter 	if (do_validate_kcore_modules(modules_filename, map, kmaps))
110652afdaf9SAdrian Hunter 		return -EINVAL;
110752afdaf9SAdrian Hunter 
110852afdaf9SAdrian Hunter 	return 0;
110952afdaf9SAdrian Hunter }
111052afdaf9SAdrian Hunter 
1111a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename,
1112a00d28cbSAdrian Hunter 				    struct map *map)
1113a00d28cbSAdrian Hunter {
1114a00d28cbSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1115a00d28cbSAdrian Hunter 
1116ba92732eSWang Nan 	if (!kmap)
1117ba92732eSWang Nan 		return -EINVAL;
1118ba92732eSWang Nan 
1119a00d28cbSAdrian Hunter 	if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1120a00d28cbSAdrian Hunter 		u64 start;
1121a00d28cbSAdrian Hunter 
1122b843f62aSArnaldo Carvalho de Melo 		if (kallsyms__get_function_start(kallsyms_filename,
1123b843f62aSArnaldo Carvalho de Melo 						 kmap->ref_reloc_sym->name, &start))
1124b843f62aSArnaldo Carvalho de Melo 			return -ENOENT;
1125a00d28cbSAdrian Hunter 		if (start != kmap->ref_reloc_sym->addr)
1126a00d28cbSAdrian Hunter 			return -EINVAL;
1127a00d28cbSAdrian Hunter 	}
1128a00d28cbSAdrian Hunter 
1129a00d28cbSAdrian Hunter 	return validate_kcore_modules(kallsyms_filename, map);
1130a00d28cbSAdrian Hunter }
1131a00d28cbSAdrian Hunter 
11328e0cf965SAdrian Hunter struct kcore_mapfn_data {
11338e0cf965SAdrian Hunter 	struct dso *dso;
11348e0cf965SAdrian Hunter 	enum map_type type;
11358e0cf965SAdrian Hunter 	struct list_head maps;
11368e0cf965SAdrian Hunter };
11378e0cf965SAdrian Hunter 
11388e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
11398e0cf965SAdrian Hunter {
11408e0cf965SAdrian Hunter 	struct kcore_mapfn_data *md = data;
11418e0cf965SAdrian Hunter 	struct map *map;
11428e0cf965SAdrian Hunter 
11438e0cf965SAdrian Hunter 	map = map__new2(start, md->dso, md->type);
11448e0cf965SAdrian Hunter 	if (map == NULL)
11458e0cf965SAdrian Hunter 		return -ENOMEM;
11468e0cf965SAdrian Hunter 
11478e0cf965SAdrian Hunter 	map->end = map->start + len;
11488e0cf965SAdrian Hunter 	map->pgoff = pgoff;
11498e0cf965SAdrian Hunter 
11508e0cf965SAdrian Hunter 	list_add(&map->node, &md->maps);
11518e0cf965SAdrian Hunter 
11528e0cf965SAdrian Hunter 	return 0;
11538e0cf965SAdrian Hunter }
11548e0cf965SAdrian Hunter 
11558e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map,
11568e0cf965SAdrian Hunter 			   const char *kallsyms_filename)
11578e0cf965SAdrian Hunter {
1158ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
1159ba92732eSWang Nan 	struct machine *machine;
11608e0cf965SAdrian Hunter 	struct kcore_mapfn_data md;
11618e0cf965SAdrian Hunter 	struct map *old_map, *new_map, *replacement_map = NULL;
11628e0cf965SAdrian Hunter 	bool is_64_bit;
11638e0cf965SAdrian Hunter 	int err, fd;
11648e0cf965SAdrian Hunter 	char kcore_filename[PATH_MAX];
11658e0cf965SAdrian Hunter 	struct symbol *sym;
11668e0cf965SAdrian Hunter 
1167ba92732eSWang Nan 	if (!kmaps)
1168ba92732eSWang Nan 		return -EINVAL;
1169ba92732eSWang Nan 
1170ba92732eSWang Nan 	machine = kmaps->machine;
1171ba92732eSWang Nan 
11728e0cf965SAdrian Hunter 	/* This function requires that the map is the kernel map */
11738e0cf965SAdrian Hunter 	if (map != machine->vmlinux_maps[map->type])
11748e0cf965SAdrian Hunter 		return -EINVAL;
11758e0cf965SAdrian Hunter 
117652afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
11778e0cf965SAdrian Hunter 					     kallsyms_filename))
11788e0cf965SAdrian Hunter 		return -EINVAL;
11798e0cf965SAdrian Hunter 
1180a00d28cbSAdrian Hunter 	/* Modules and kernel must be present at their original addresses */
1181a00d28cbSAdrian Hunter 	if (validate_kcore_addresses(kallsyms_filename, map))
118252afdaf9SAdrian Hunter 		return -EINVAL;
118352afdaf9SAdrian Hunter 
11848e0cf965SAdrian Hunter 	md.dso = dso;
11858e0cf965SAdrian Hunter 	md.type = map->type;
11868e0cf965SAdrian Hunter 	INIT_LIST_HEAD(&md.maps);
11878e0cf965SAdrian Hunter 
11888e0cf965SAdrian Hunter 	fd = open(kcore_filename, O_RDONLY);
118936c8bb56SLi Zhang 	if (fd < 0) {
1190133de940SAdrian Hunter 		pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n",
119136c8bb56SLi Zhang 			 kcore_filename);
11928e0cf965SAdrian Hunter 		return -EINVAL;
119336c8bb56SLi Zhang 	}
11948e0cf965SAdrian Hunter 
11958e0cf965SAdrian Hunter 	/* Read new maps into temporary lists */
11968e0cf965SAdrian Hunter 	err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
11978e0cf965SAdrian Hunter 			      &is_64_bit);
11988e0cf965SAdrian Hunter 	if (err)
11998e0cf965SAdrian Hunter 		goto out_err;
1200c6d8f2a4SAdrian Hunter 	dso->is_64_bit = is_64_bit;
12018e0cf965SAdrian Hunter 
12028e0cf965SAdrian Hunter 	if (list_empty(&md.maps)) {
12038e0cf965SAdrian Hunter 		err = -EINVAL;
12048e0cf965SAdrian Hunter 		goto out_err;
12058e0cf965SAdrian Hunter 	}
12068e0cf965SAdrian Hunter 
12078e0cf965SAdrian Hunter 	/* Remove old maps */
12088e0cf965SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
12098e0cf965SAdrian Hunter 	while (old_map) {
12108e0cf965SAdrian Hunter 		struct map *next = map_groups__next(old_map);
12118e0cf965SAdrian Hunter 
12128e0cf965SAdrian Hunter 		if (old_map != map)
12138e0cf965SAdrian Hunter 			map_groups__remove(kmaps, old_map);
12148e0cf965SAdrian Hunter 		old_map = next;
12158e0cf965SAdrian Hunter 	}
12168e0cf965SAdrian Hunter 
12178e0cf965SAdrian Hunter 	/* Find the kernel map using the first symbol */
12188e0cf965SAdrian Hunter 	sym = dso__first_symbol(dso, map->type);
12198e0cf965SAdrian Hunter 	list_for_each_entry(new_map, &md.maps, node) {
12208e0cf965SAdrian Hunter 		if (sym && sym->start >= new_map->start &&
12218e0cf965SAdrian Hunter 		    sym->start < new_map->end) {
12228e0cf965SAdrian Hunter 			replacement_map = new_map;
12238e0cf965SAdrian Hunter 			break;
12248e0cf965SAdrian Hunter 		}
12258e0cf965SAdrian Hunter 	}
12268e0cf965SAdrian Hunter 
12278e0cf965SAdrian Hunter 	if (!replacement_map)
12288e0cf965SAdrian Hunter 		replacement_map = list_entry(md.maps.next, struct map, node);
12298e0cf965SAdrian Hunter 
12308e0cf965SAdrian Hunter 	/* Add new maps */
12318e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
12328e0cf965SAdrian Hunter 		new_map = list_entry(md.maps.next, struct map, node);
1233facf3f06SArnaldo Carvalho de Melo 		list_del_init(&new_map->node);
12348e0cf965SAdrian Hunter 		if (new_map == replacement_map) {
12358e0cf965SAdrian Hunter 			map->start	= new_map->start;
12368e0cf965SAdrian Hunter 			map->end	= new_map->end;
12378e0cf965SAdrian Hunter 			map->pgoff	= new_map->pgoff;
12388e0cf965SAdrian Hunter 			map->map_ip	= new_map->map_ip;
12398e0cf965SAdrian Hunter 			map->unmap_ip	= new_map->unmap_ip;
12408e0cf965SAdrian Hunter 			/* Ensure maps are correctly ordered */
124184c2cafaSArnaldo Carvalho de Melo 			map__get(map);
12428e0cf965SAdrian Hunter 			map_groups__remove(kmaps, map);
12438e0cf965SAdrian Hunter 			map_groups__insert(kmaps, map);
124484c2cafaSArnaldo Carvalho de Melo 			map__put(map);
12458e0cf965SAdrian Hunter 		} else {
12468e0cf965SAdrian Hunter 			map_groups__insert(kmaps, new_map);
12478e0cf965SAdrian Hunter 		}
124884c2cafaSArnaldo Carvalho de Melo 
124984c2cafaSArnaldo Carvalho de Melo 		map__put(new_map);
12508e0cf965SAdrian Hunter 	}
12518e0cf965SAdrian Hunter 
12528e0cf965SAdrian Hunter 	/*
12538e0cf965SAdrian Hunter 	 * Set the data type and long name so that kcore can be read via
12548e0cf965SAdrian Hunter 	 * dso__data_read_addr().
12558e0cf965SAdrian Hunter 	 */
12568e0cf965SAdrian Hunter 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
12575f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
12588e0cf965SAdrian Hunter 	else
12595f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__KCORE;
12607e155d4dSArnaldo Carvalho de Melo 	dso__set_long_name(dso, strdup(kcore_filename), true);
12618e0cf965SAdrian Hunter 
12628e0cf965SAdrian Hunter 	close(fd);
12638e0cf965SAdrian Hunter 
12648e0cf965SAdrian Hunter 	if (map->type == MAP__FUNCTION)
12658e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel object code\n", kcore_filename);
12668e0cf965SAdrian Hunter 	else
12678e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel data\n", kcore_filename);
12688e0cf965SAdrian Hunter 
12698e0cf965SAdrian Hunter 	return 0;
12708e0cf965SAdrian Hunter 
12718e0cf965SAdrian Hunter out_err:
12728e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
12738e0cf965SAdrian Hunter 		map = list_entry(md.maps.next, struct map, node);
1274facf3f06SArnaldo Carvalho de Melo 		list_del_init(&map->node);
127584c2cafaSArnaldo Carvalho de Melo 		map__put(map);
12768e0cf965SAdrian Hunter 	}
12778e0cf965SAdrian Hunter 	close(fd);
12788e0cf965SAdrian Hunter 	return -EINVAL;
12798e0cf965SAdrian Hunter }
12808e0cf965SAdrian Hunter 
1281d9b62abaSAdrian Hunter /*
1282d9b62abaSAdrian Hunter  * If the kernel is relocated at boot time, kallsyms won't match.  Compute the
1283d9b62abaSAdrian Hunter  * delta based on the relocation reference symbol.
1284d9b62abaSAdrian Hunter  */
1285d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1286d9b62abaSAdrian Hunter {
1287d9b62abaSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1288d9b62abaSAdrian Hunter 	u64 addr;
1289d9b62abaSAdrian Hunter 
1290ba92732eSWang Nan 	if (!kmap)
1291ba92732eSWang Nan 		return -1;
1292ba92732eSWang Nan 
1293d9b62abaSAdrian Hunter 	if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1294d9b62abaSAdrian Hunter 		return 0;
1295d9b62abaSAdrian Hunter 
1296b843f62aSArnaldo Carvalho de Melo 	if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr))
1297d9b62abaSAdrian Hunter 		return -1;
1298d9b62abaSAdrian Hunter 
1299d9b62abaSAdrian Hunter 	*delta = addr - kmap->ref_reloc_sym->addr;
1300d9b62abaSAdrian Hunter 	return 0;
1301d9b62abaSAdrian Hunter }
1302d9b62abaSAdrian Hunter 
1303e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename,
1304be39db9fSArnaldo Carvalho de Melo 			 struct map *map, bool no_kcore)
13052e538c4aSArnaldo Carvalho de Melo {
1306d9b62abaSAdrian Hunter 	u64 delta = 0;
1307d9b62abaSAdrian Hunter 
1308ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1309ec80fde7SArnaldo Carvalho de Melo 		return -1;
1310ec80fde7SArnaldo Carvalho de Melo 
1311aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
13122e538c4aSArnaldo Carvalho de Melo 		return -1;
13132e538c4aSArnaldo Carvalho de Melo 
1314d9b62abaSAdrian Hunter 	if (kallsyms__delta(map, filename, &delta))
1315d9b62abaSAdrian Hunter 		return -1;
1316d9b62abaSAdrian Hunter 
13173f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
1318432746f8SArnaldo Carvalho de Melo 	symbols__fixup_duplicate(&dso->symbols[map->type]);
13193f5a4272SAnton Blanchard 
1320aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
132144f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1322a1645ce1SZhang, Yanmin 	else
132344f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
13242e538c4aSArnaldo Carvalho de Melo 
1325e02092b9SArnaldo Carvalho de Melo 	if (!no_kcore && !dso__load_kcore(dso, map, filename))
1326be39db9fSArnaldo Carvalho de Melo 		return dso__split_kallsyms_for_kcore(dso, map);
13278e0cf965SAdrian Hunter 	else
1328be39db9fSArnaldo Carvalho de Melo 		return dso__split_kallsyms(dso, map, delta);
1329af427bf5SArnaldo Carvalho de Melo }
1330af427bf5SArnaldo Carvalho de Melo 
1331e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
1332be39db9fSArnaldo Carvalho de Melo 		       struct map *map)
1333e02092b9SArnaldo Carvalho de Melo {
1334be39db9fSArnaldo Carvalho de Melo 	return __dso__load_kallsyms(dso, filename, map, false);
1335e02092b9SArnaldo Carvalho de Melo }
1336e02092b9SArnaldo Carvalho de Melo 
1337bf2e710bSKrister Johansen static int dso__load_perf_map(const char *map_path, struct dso *dso,
1338bf2e710bSKrister Johansen 			      struct map *map)
133980d496beSPekka Enberg {
134080d496beSPekka Enberg 	char *line = NULL;
134180d496beSPekka Enberg 	size_t n;
134280d496beSPekka Enberg 	FILE *file;
134380d496beSPekka Enberg 	int nr_syms = 0;
134480d496beSPekka Enberg 
1345bf2e710bSKrister Johansen 	file = fopen(map_path, "r");
134680d496beSPekka Enberg 	if (file == NULL)
134780d496beSPekka Enberg 		goto out_failure;
134880d496beSPekka Enberg 
134980d496beSPekka Enberg 	while (!feof(file)) {
13509cffa8d5SPaul Mackerras 		u64 start, size;
135180d496beSPekka Enberg 		struct symbol *sym;
135280d496beSPekka Enberg 		int line_len, len;
135380d496beSPekka Enberg 
135480d496beSPekka Enberg 		line_len = getline(&line, &n, file);
135580d496beSPekka Enberg 		if (line_len < 0)
135680d496beSPekka Enberg 			break;
135780d496beSPekka Enberg 
135880d496beSPekka Enberg 		if (!line)
135980d496beSPekka Enberg 			goto out_failure;
136080d496beSPekka Enberg 
136180d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
136280d496beSPekka Enberg 
136380d496beSPekka Enberg 		len = hex2u64(line, &start);
136480d496beSPekka Enberg 
136580d496beSPekka Enberg 		len++;
136680d496beSPekka Enberg 		if (len + 2 >= line_len)
136780d496beSPekka Enberg 			continue;
136880d496beSPekka Enberg 
136980d496beSPekka Enberg 		len += hex2u64(line + len, &size);
137080d496beSPekka Enberg 
137180d496beSPekka Enberg 		len++;
137280d496beSPekka Enberg 		if (len + 2 >= line_len)
137380d496beSPekka Enberg 			continue;
137480d496beSPekka Enberg 
1375c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
137680d496beSPekka Enberg 
137780d496beSPekka Enberg 		if (sym == NULL)
137880d496beSPekka Enberg 			goto out_delete_line;
137980d496beSPekka Enberg 
1380aeafcbafSArnaldo Carvalho de Melo 		symbols__insert(&dso->symbols[map->type], sym);
138180d496beSPekka Enberg 		nr_syms++;
138280d496beSPekka Enberg 	}
138380d496beSPekka Enberg 
138480d496beSPekka Enberg 	free(line);
138580d496beSPekka Enberg 	fclose(file);
138680d496beSPekka Enberg 
138780d496beSPekka Enberg 	return nr_syms;
138880d496beSPekka Enberg 
138980d496beSPekka Enberg out_delete_line:
139080d496beSPekka Enberg 	free(line);
139180d496beSPekka Enberg out_failure:
139280d496beSPekka Enberg 	return -1;
139380d496beSPekka Enberg }
139480d496beSPekka Enberg 
13951029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
13961029f9feSNamhyung Kim 					   enum dso_binary_type type)
13971029f9feSNamhyung Kim {
13981029f9feSNamhyung Kim 	switch (type) {
13991029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__JAVA_JIT:
14001029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__DEBUGLINK:
14011029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
14021029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
14031029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
14041029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
14051029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
14061029f9feSNamhyung Kim 		return !kmod && dso->kernel == DSO_TYPE_USER;
14071029f9feSNamhyung Kim 
14081029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KALLSYMS:
14091029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__VMLINUX:
14101029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KCORE:
14111029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_KERNEL;
14121029f9feSNamhyung Kim 
14131029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
14141029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
14151029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KCORE:
14161029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
14171029f9feSNamhyung Kim 
14181029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE:
1419c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
14201029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1421c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
14221029f9feSNamhyung Kim 		/*
14231029f9feSNamhyung Kim 		 * kernel modules know their symtab type - it's set when
14249f2de315SArnaldo Carvalho de Melo 		 * creating a module dso in machine__findnew_module_map().
14251029f9feSNamhyung Kim 		 */
14261029f9feSNamhyung Kim 		return kmod && dso->symtab_type == type;
14271029f9feSNamhyung Kim 
14281029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
1429d2396999SKrister Johansen 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
14301029f9feSNamhyung Kim 		return true;
14311029f9feSNamhyung Kim 
14321029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__NOT_FOUND:
14331029f9feSNamhyung Kim 	default:
14341029f9feSNamhyung Kim 		return false;
14351029f9feSNamhyung Kim 	}
14361029f9feSNamhyung Kim }
14371029f9feSNamhyung Kim 
1438bf2e710bSKrister Johansen /* Checks for the existence of the perf-<pid>.map file in two different
1439bf2e710bSKrister Johansen  * locations.  First, if the process is a separate mount namespace, check in
1440bf2e710bSKrister Johansen  * that namespace using the pid of the innermost pid namespace.  If's not in a
1441bf2e710bSKrister Johansen  * namespace, or the file can't be found there, try in the mount namespace of
1442bf2e710bSKrister Johansen  * the tracing process using our view of its pid.
1443bf2e710bSKrister Johansen  */
1444bf2e710bSKrister Johansen static int dso__find_perf_map(char *filebuf, size_t bufsz,
1445bf2e710bSKrister Johansen 			      struct nsinfo **nsip)
1446bf2e710bSKrister Johansen {
1447bf2e710bSKrister Johansen 	struct nscookie nsc;
1448bf2e710bSKrister Johansen 	struct nsinfo *nsi;
1449bf2e710bSKrister Johansen 	struct nsinfo *nnsi;
1450bf2e710bSKrister Johansen 	int rc = -1;
1451bf2e710bSKrister Johansen 
1452bf2e710bSKrister Johansen 	nsi = *nsip;
1453bf2e710bSKrister Johansen 
1454bf2e710bSKrister Johansen 	if (nsi->need_setns) {
1455bf2e710bSKrister Johansen 		snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsi->nstgid);
1456bf2e710bSKrister Johansen 		nsinfo__mountns_enter(nsi, &nsc);
1457bf2e710bSKrister Johansen 		rc = access(filebuf, R_OK);
1458bf2e710bSKrister Johansen 		nsinfo__mountns_exit(&nsc);
1459bf2e710bSKrister Johansen 		if (rc == 0)
1460bf2e710bSKrister Johansen 			return rc;
1461bf2e710bSKrister Johansen 	}
1462bf2e710bSKrister Johansen 
1463bf2e710bSKrister Johansen 	nnsi = nsinfo__copy(nsi);
1464bf2e710bSKrister Johansen 	if (nnsi) {
1465bf2e710bSKrister Johansen 		nsinfo__put(nsi);
1466bf2e710bSKrister Johansen 
1467bf2e710bSKrister Johansen 		nnsi->need_setns = false;
1468bf2e710bSKrister Johansen 		snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nnsi->tgid);
1469bf2e710bSKrister Johansen 		*nsip = nnsi;
1470bf2e710bSKrister Johansen 		rc = 0;
1471bf2e710bSKrister Johansen 	}
1472bf2e710bSKrister Johansen 
1473bf2e710bSKrister Johansen 	return rc;
1474bf2e710bSKrister Johansen }
1475bf2e710bSKrister Johansen 
1476be39db9fSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map)
147786470930SIngo Molnar {
1478c338aee8SArnaldo Carvalho de Melo 	char *name;
147986470930SIngo Molnar 	int ret = -1;
148044f24cb3SJiri Olsa 	u_int i;
148123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
148244f24cb3SJiri Olsa 	char *root_dir = (char *) "";
14833aafe5aeSCody P Schafer 	int ss_pos = 0;
14843aafe5aeSCody P Schafer 	struct symsrc ss_[2];
14853aafe5aeSCody P Schafer 	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
14861029f9feSNamhyung Kim 	bool kmod;
1487bf2e710bSKrister Johansen 	bool perfmap;
14885baecbcdSDima Kogan 	unsigned char build_id[BUILD_ID_SIZE];
1489843ff37bSKrister Johansen 	struct nscookie nsc;
1490bf2e710bSKrister Johansen 	char newmapname[PATH_MAX];
1491bf2e710bSKrister Johansen 	const char *map_path = dso->long_name;
1492bf2e710bSKrister Johansen 
1493bf2e710bSKrister Johansen 	perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0;
1494bf2e710bSKrister Johansen 	if (perfmap) {
1495bf2e710bSKrister Johansen 		if (dso->nsinfo && (dso__find_perf_map(newmapname,
1496bf2e710bSKrister Johansen 		    sizeof(newmapname), &dso->nsinfo) == 0)) {
1497bf2e710bSKrister Johansen 			map_path = newmapname;
1498bf2e710bSKrister Johansen 		}
1499bf2e710bSKrister Johansen 	}
150086470930SIngo Molnar 
1501843ff37bSKrister Johansen 	nsinfo__mountns_enter(dso->nsinfo, &nsc);
15024a936edcSNamhyung Kim 	pthread_mutex_lock(&dso->lock);
150366bd8424SArnaldo Carvalho de Melo 
15044a936edcSNamhyung Kim 	/* check again under the dso->lock */
15054a936edcSNamhyung Kim 	if (dso__loaded(dso, map->type)) {
15064a936edcSNamhyung Kim 		ret = 1;
15074a936edcSNamhyung Kim 		goto out;
15084a936edcSNamhyung Kim 	}
15094a936edcSNamhyung Kim 
15104a936edcSNamhyung Kim 	if (dso->kernel) {
1511aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel == DSO_TYPE_KERNEL)
1512be39db9fSArnaldo Carvalho de Melo 			ret = dso__load_kernel_sym(dso, map);
1513aeafcbafSArnaldo Carvalho de Melo 		else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1514be39db9fSArnaldo Carvalho de Melo 			ret = dso__load_guest_kernel_sym(dso, map);
15154a936edcSNamhyung Kim 
15164a936edcSNamhyung Kim 		goto out;
15174a936edcSNamhyung Kim 	}
1518a1645ce1SZhang, Yanmin 
151923346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
152023346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1521a1645ce1SZhang, Yanmin 	else
152223346f21SArnaldo Carvalho de Melo 		machine = NULL;
1523c338aee8SArnaldo Carvalho de Melo 
1524aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1525f5812a7aSArnaldo Carvalho de Melo 
1526bf2e710bSKrister Johansen 	if (perfmap) {
1527981c1252SPekka Enberg 		struct stat st;
1528981c1252SPekka Enberg 
1529bf2e710bSKrister Johansen 		if (lstat(map_path, &st) < 0)
15304a936edcSNamhyung Kim 			goto out;
1531981c1252SPekka Enberg 
15322059fc7aSArnaldo Carvalho de Melo 		if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
1533981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1534bf2e710bSKrister Johansen 				   "ignoring it (use -f to override).\n", map_path);
15354a936edcSNamhyung Kim 			goto out;
1536981c1252SPekka Enberg 		}
1537981c1252SPekka Enberg 
1538bf2e710bSKrister Johansen 		ret = dso__load_perf_map(map_path, dso, map);
153944f24cb3SJiri Olsa 		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
154044f24cb3SJiri Olsa 					     DSO_BINARY_TYPE__NOT_FOUND;
15414a936edcSNamhyung Kim 		goto out;
154294cb9e38SArnaldo Carvalho de Melo 	}
154394cb9e38SArnaldo Carvalho de Melo 
154444f24cb3SJiri Olsa 	if (machine)
154544f24cb3SJiri Olsa 		root_dir = machine->root_dir;
154644f24cb3SJiri Olsa 
1547164c800eSDavid Ahern 	name = malloc(PATH_MAX);
1548164c800eSDavid Ahern 	if (!name)
15494a936edcSNamhyung Kim 		goto out;
1550164c800eSDavid Ahern 
15511029f9feSNamhyung Kim 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1552c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
1553c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
1554c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
15551029f9feSNamhyung Kim 
15565baecbcdSDima Kogan 
15575baecbcdSDima Kogan 	/*
15585baecbcdSDima Kogan 	 * Read the build id if possible. This is required for
15595baecbcdSDima Kogan 	 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
15605baecbcdSDima Kogan 	 */
1561ed6c166cSKan Liang 	if (!dso->has_build_id &&
15629b200653SVictor Kamensky 	    is_regular_file(dso->long_name)) {
15639b200653SVictor Kamensky 	    __symbol__join_symfs(name, PATH_MAX, dso->long_name);
15649b200653SVictor Kamensky 	    if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0)
15655baecbcdSDima Kogan 		dso__set_build_id(dso, build_id);
15669b200653SVictor Kamensky 	}
15675baecbcdSDima Kogan 
15681029f9feSNamhyung Kim 	/*
15691029f9feSNamhyung Kim 	 * Iterate over candidate debug images.
15703aafe5aeSCody P Schafer 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
15713aafe5aeSCody P Schafer 	 * and/or opd section) for processing.
15726da80ce8SDave Martin 	 */
157344f24cb3SJiri Olsa 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
15743aafe5aeSCody P Schafer 		struct symsrc *ss = &ss_[ss_pos];
15753aafe5aeSCody P Schafer 		bool next_slot = false;
1576f045b8c4SKrister Johansen 		bool is_reg;
1577d2396999SKrister Johansen 		bool nsexit;
1578f045b8c4SKrister Johansen 		int sirc;
157944f24cb3SJiri Olsa 
1580005f9294SCody P Schafer 		enum dso_binary_type symtab_type = binary_type_symtab[i];
158144f24cb3SJiri Olsa 
1582d2396999SKrister Johansen 		nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE ||
1583d2396999SKrister Johansen 		    symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO);
1584d2396999SKrister Johansen 
15851029f9feSNamhyung Kim 		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
15861029f9feSNamhyung Kim 			continue;
15871029f9feSNamhyung Kim 
1588ee4e9625SArnaldo Carvalho de Melo 		if (dso__read_binary_type_filename(dso, symtab_type,
158944f24cb3SJiri Olsa 						   root_dir, name, PATH_MAX))
15906da80ce8SDave Martin 			continue;
159186470930SIngo Molnar 
1592d2396999SKrister Johansen 		if (nsexit)
1593f045b8c4SKrister Johansen 			nsinfo__mountns_exit(&nsc);
159440356721SJiri Olsa 
1595f045b8c4SKrister Johansen 		is_reg = is_regular_file(name);
1596f045b8c4SKrister Johansen 		sirc = symsrc__init(ss, dso, name, symtab_type);
1597f045b8c4SKrister Johansen 
1598d2396999SKrister Johansen 		if (nsexit)
1599f045b8c4SKrister Johansen 			nsinfo__mountns_enter(dso->nsinfo, &nsc);
1600f045b8c4SKrister Johansen 
1601f045b8c4SKrister Johansen 		if (!is_reg || sirc < 0) {
1602f045b8c4SKrister Johansen 			if (sirc >= 0)
1603f045b8c4SKrister Johansen 				symsrc__destroy(ss);
16046da80ce8SDave Martin 			continue;
1605f045b8c4SKrister Johansen 		}
16066da80ce8SDave Martin 
16073aafe5aeSCody P Schafer 		if (!syms_ss && symsrc__has_symtab(ss)) {
16083aafe5aeSCody P Schafer 			syms_ss = ss;
16093aafe5aeSCody P Schafer 			next_slot = true;
16100058aef6SAdrian Hunter 			if (!dso->symsrc_filename)
16110058aef6SAdrian Hunter 				dso->symsrc_filename = strdup(name);
1612d26cd12bSCody P Schafer 		}
1613d26cd12bSCody P Schafer 
16143aafe5aeSCody P Schafer 		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
16153aafe5aeSCody P Schafer 			runtime_ss = ss;
16163aafe5aeSCody P Schafer 			next_slot = true;
1617a44f605bSCody P Schafer 		}
161886470930SIngo Molnar 
16193aafe5aeSCody P Schafer 		if (next_slot) {
16203aafe5aeSCody P Schafer 			ss_pos++;
162133ff581eSJiri Olsa 
16223aafe5aeSCody P Schafer 			if (syms_ss && runtime_ss)
16236da80ce8SDave Martin 				break;
162498e9f03bSNamhyung Kim 		} else {
162598e9f03bSNamhyung Kim 			symsrc__destroy(ss);
1626a25e46c4SArnaldo Carvalho de Melo 		}
16273aafe5aeSCody P Schafer 
16286da80ce8SDave Martin 	}
16296da80ce8SDave Martin 
16303aafe5aeSCody P Schafer 	if (!runtime_ss && !syms_ss)
16313aafe5aeSCody P Schafer 		goto out_free;
16323aafe5aeSCody P Schafer 
16333aafe5aeSCody P Schafer 	if (runtime_ss && !syms_ss) {
16343aafe5aeSCody P Schafer 		syms_ss = runtime_ss;
163560e4b10cSArnaldo Carvalho de Melo 	}
163660e4b10cSArnaldo Carvalho de Melo 
16373aafe5aeSCody P Schafer 	/* We'll have to hope for the best */
16383aafe5aeSCody P Schafer 	if (!runtime_ss && syms_ss)
16393aafe5aeSCody P Schafer 		runtime_ss = syms_ss;
16403aafe5aeSCody P Schafer 
16411029f9feSNamhyung Kim 	if (syms_ss)
1642be39db9fSArnaldo Carvalho de Melo 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod);
16431029f9feSNamhyung Kim 	else
16443aafe5aeSCody P Schafer 		ret = -1;
16453aafe5aeSCody P Schafer 
1646f47b58b7SDavid Ahern 	if (ret > 0) {
16473aafe5aeSCody P Schafer 		int nr_plt;
16483aafe5aeSCody P Schafer 
1649be39db9fSArnaldo Carvalho de Melo 		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map);
16503aafe5aeSCody P Schafer 		if (nr_plt > 0)
16513aafe5aeSCody P Schafer 			ret += nr_plt;
16523aafe5aeSCody P Schafer 	}
16533aafe5aeSCody P Schafer 
16543aafe5aeSCody P Schafer 	for (; ss_pos > 0; ss_pos--)
16553aafe5aeSCody P Schafer 		symsrc__destroy(&ss_[ss_pos - 1]);
16563aafe5aeSCody P Schafer out_free:
165786470930SIngo Molnar 	free(name);
1658aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
16594a936edcSNamhyung Kim 		ret = 0;
16604a936edcSNamhyung Kim out:
16614a936edcSNamhyung Kim 	dso__set_loaded(dso, map->type);
16624a936edcSNamhyung Kim 	pthread_mutex_unlock(&dso->lock);
1663843ff37bSKrister Johansen 	nsinfo__mountns_exit(&nsc);
16644a936edcSNamhyung Kim 
166586470930SIngo Molnar 	return ret;
166686470930SIngo Molnar }
166786470930SIngo Molnar 
1668aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
166979406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1670439d473bSArnaldo Carvalho de Melo {
16711eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
16724bb7123dSArnaldo Carvalho de Melo 	struct map *map;
1673439d473bSArnaldo Carvalho de Melo 
1674*0a7c74eaSArnaldo Carvalho de Melo 	down_read(&maps->lock);
16756a2ffcddSArnaldo Carvalho de Melo 
16764bb7123dSArnaldo Carvalho de Melo 	for (map = maps__first(maps); map; map = map__next(map)) {
1677b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
16786a2ffcddSArnaldo Carvalho de Melo 			goto out_unlock;
1679439d473bSArnaldo Carvalho de Melo 	}
1680439d473bSArnaldo Carvalho de Melo 
16816a2ffcddSArnaldo Carvalho de Melo 	map = NULL;
16826a2ffcddSArnaldo Carvalho de Melo 
16836a2ffcddSArnaldo Carvalho de Melo out_unlock:
1684*0a7c74eaSArnaldo Carvalho de Melo 	up_read(&maps->lock);
16856a2ffcddSArnaldo Carvalho de Melo 	return map;
1686439d473bSArnaldo Carvalho de Melo }
1687439d473bSArnaldo Carvalho de Melo 
1688aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
1689be39db9fSArnaldo Carvalho de Melo 		      const char *vmlinux, bool vmlinux_allocated)
169086470930SIngo Molnar {
1691b68e2f91SCody P Schafer 	int err = -1;
1692b68e2f91SCody P Schafer 	struct symsrc ss;
1693ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
1694005f9294SCody P Schafer 	enum dso_binary_type symtab_type;
169586470930SIngo Molnar 
16965698d2c9SNamhyung Kim 	if (vmlinux[0] == '/')
16975698d2c9SNamhyung Kim 		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
16985698d2c9SNamhyung Kim 	else
1699972f393bSArnaldo Carvalho de Melo 		symbol__join_symfs(symfs_vmlinux, vmlinux);
170086470930SIngo Molnar 
170121ea4539SCody P Schafer 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1702005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
170321ea4539SCody P Schafer 	else
1704005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__VMLINUX;
170521ea4539SCody P Schafer 
1706005f9294SCody P Schafer 	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1707b68e2f91SCody P Schafer 		return -1;
1708b68e2f91SCody P Schafer 
1709be39db9fSArnaldo Carvalho de Melo 	err = dso__load_sym(dso, map, &ss, &ss, 0);
1710b68e2f91SCody P Schafer 	symsrc__destroy(&ss);
171186470930SIngo Molnar 
1712515850e4SCody P Schafer 	if (err > 0) {
171339b12f78SAdrian Hunter 		if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
17145f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
171539b12f78SAdrian Hunter 		else
17165f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
1717bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, vmlinux, vmlinux_allocated);
1718515850e4SCody P Schafer 		dso__set_loaded(dso, map->type);
1719ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
1720515850e4SCody P Schafer 	}
17213846df2eSArnaldo Carvalho de Melo 
172286470930SIngo Molnar 	return err;
172386470930SIngo Molnar }
172486470930SIngo Molnar 
1725be39db9fSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map)
1726a19afe46SArnaldo Carvalho de Melo {
1727a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
172800dc8657SNamhyung Kim 	char *filename = NULL;
1729a19afe46SArnaldo Carvalho de Melo 
1730dc38218eSArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1731dc38218eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
1732dc38218eSArnaldo Carvalho de Melo 
1733dc38218eSArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1734be39db9fSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false);
1735dc38218eSArnaldo Carvalho de Melo 		if (err > 0)
1736dc38218eSArnaldo Carvalho de Melo 			goto out;
1737dc38218eSArnaldo Carvalho de Melo 	}
1738dc38218eSArnaldo Carvalho de Melo 
173900dc8657SNamhyung Kim 	if (!symbol_conf.ignore_vmlinux_buildid)
1740d2396999SKrister Johansen 		filename = dso__build_id_filename(dso, NULL, 0, false);
17415ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
1742be39db9fSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, true);
17435230fb7dSArnaldo Carvalho de Melo 		if (err > 0)
17445ad90e4eSArnaldo Carvalho de Melo 			goto out;
17455ad90e4eSArnaldo Carvalho de Melo 		free(filename);
17465ad90e4eSArnaldo Carvalho de Melo 	}
17475ad90e4eSArnaldo Carvalho de Melo out:
1748a19afe46SArnaldo Carvalho de Melo 	return err;
1749a19afe46SArnaldo Carvalho de Melo }
1750a19afe46SArnaldo Carvalho de Melo 
1751c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d)
1752c48903b8SMasami Hiramatsu {
1753c48903b8SMasami Hiramatsu 	if (d->d_type != DT_DIR)
1754c48903b8SMasami Hiramatsu 		return false;
1755c48903b8SMasami Hiramatsu 	return lsdir_no_dot_filter(name, d);
1756c48903b8SMasami Hiramatsu }
1757c48903b8SMasami Hiramatsu 
17580544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
17590544d422SAdrian Hunter {
17600544d422SAdrian Hunter 	char kallsyms_filename[PATH_MAX];
17610544d422SAdrian Hunter 	int ret = -1;
1762c48903b8SMasami Hiramatsu 	struct strlist *dirs;
1763c48903b8SMasami Hiramatsu 	struct str_node *nd;
17640544d422SAdrian Hunter 
1765c48903b8SMasami Hiramatsu 	dirs = lsdir(dir, visible_dir_filter);
1766c48903b8SMasami Hiramatsu 	if (!dirs)
17670544d422SAdrian Hunter 		return -1;
17680544d422SAdrian Hunter 
1769602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(nd, dirs) {
17700544d422SAdrian Hunter 		scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1771c48903b8SMasami Hiramatsu 			  "%s/%s/kallsyms", dir, nd->s);
1772a00d28cbSAdrian Hunter 		if (!validate_kcore_addresses(kallsyms_filename, map)) {
17730544d422SAdrian Hunter 			strlcpy(dir, kallsyms_filename, dir_sz);
17740544d422SAdrian Hunter 			ret = 0;
17750544d422SAdrian Hunter 			break;
17760544d422SAdrian Hunter 		}
17770544d422SAdrian Hunter 	}
17780544d422SAdrian Hunter 
1779c48903b8SMasami Hiramatsu 	strlist__delete(dirs);
17800544d422SAdrian Hunter 
17810544d422SAdrian Hunter 	return ret;
17820544d422SAdrian Hunter }
17830544d422SAdrian Hunter 
178411870d71SMasami Hiramatsu /*
178511870d71SMasami Hiramatsu  * Use open(O_RDONLY) to check readability directly instead of access(R_OK)
178611870d71SMasami Hiramatsu  * since access(R_OK) only checks with real UID/GID but open() use effective
178711870d71SMasami Hiramatsu  * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO).
178811870d71SMasami Hiramatsu  */
178911870d71SMasami Hiramatsu static bool filename__readable(const char *file)
179011870d71SMasami Hiramatsu {
179111870d71SMasami Hiramatsu 	int fd = open(file, O_RDONLY);
179211870d71SMasami Hiramatsu 	if (fd < 0)
179311870d71SMasami Hiramatsu 		return false;
179411870d71SMasami Hiramatsu 	close(fd);
179511870d71SMasami Hiramatsu 	return true;
179611870d71SMasami Hiramatsu }
179711870d71SMasami Hiramatsu 
17980544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map)
17990544d422SAdrian Hunter {
18000544d422SAdrian Hunter 	u8 host_build_id[BUILD_ID_SIZE];
1801b5d8bbe8SMasami Hiramatsu 	char sbuild_id[SBUILD_ID_SIZE];
18020544d422SAdrian Hunter 	bool is_host = false;
18030544d422SAdrian Hunter 	char path[PATH_MAX];
18040544d422SAdrian Hunter 
18050544d422SAdrian Hunter 	if (!dso->has_build_id) {
18060544d422SAdrian Hunter 		/*
18070544d422SAdrian Hunter 		 * Last resort, if we don't have a build-id and couldn't find
18080544d422SAdrian Hunter 		 * any vmlinux file, try the running kernel kallsyms table.
18090544d422SAdrian Hunter 		 */
18100544d422SAdrian Hunter 		goto proc_kallsyms;
18110544d422SAdrian Hunter 	}
18120544d422SAdrian Hunter 
18130544d422SAdrian Hunter 	if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
18140544d422SAdrian Hunter 				 sizeof(host_build_id)) == 0)
18150544d422SAdrian Hunter 		is_host = dso__build_id_equal(dso, host_build_id);
18160544d422SAdrian Hunter 
18174e4b6c06SMasami Hiramatsu 	/* Try a fast path for /proc/kallsyms if possible */
18180544d422SAdrian Hunter 	if (is_host) {
18190544d422SAdrian Hunter 		/*
182011870d71SMasami Hiramatsu 		 * Do not check the build-id cache, unless we know we cannot use
182111870d71SMasami Hiramatsu 		 * /proc/kcore or module maps don't match to /proc/kallsyms.
182211870d71SMasami Hiramatsu 		 * To check readability of /proc/kcore, do not use access(R_OK)
182311870d71SMasami Hiramatsu 		 * since /proc/kcore requires CAP_SYS_RAWIO to read and access
182411870d71SMasami Hiramatsu 		 * can't check it.
18250544d422SAdrian Hunter 		 */
182611870d71SMasami Hiramatsu 		if (filename__readable("/proc/kcore") &&
182711870d71SMasami Hiramatsu 		    !validate_kcore_addresses("/proc/kallsyms", map))
18280544d422SAdrian Hunter 			goto proc_kallsyms;
18290544d422SAdrian Hunter 	}
18300544d422SAdrian Hunter 
18314e4b6c06SMasami Hiramatsu 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
18324e4b6c06SMasami Hiramatsu 
1833449867e3SAdrian Hunter 	/* Find kallsyms in build-id cache with kcore */
18344e4b6c06SMasami Hiramatsu 	scnprintf(path, sizeof(path), "%s/%s/%s",
18354e4b6c06SMasami Hiramatsu 		  buildid_dir, DSO__NAME_KCORE, sbuild_id);
18364e4b6c06SMasami Hiramatsu 
1837449867e3SAdrian Hunter 	if (!find_matching_kcore(map, path, sizeof(path)))
1838449867e3SAdrian Hunter 		return strdup(path);
1839449867e3SAdrian Hunter 
18404e4b6c06SMasami Hiramatsu 	/* Use current /proc/kallsyms if possible */
18414e4b6c06SMasami Hiramatsu 	if (is_host) {
18424e4b6c06SMasami Hiramatsu proc_kallsyms:
18434e4b6c06SMasami Hiramatsu 		return strdup("/proc/kallsyms");
18444e4b6c06SMasami Hiramatsu 	}
18454e4b6c06SMasami Hiramatsu 
18464e4b6c06SMasami Hiramatsu 	/* Finally, find a cache of kallsyms */
184701412261SMasami Hiramatsu 	if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) {
18480544d422SAdrian Hunter 		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
18490544d422SAdrian Hunter 		       sbuild_id);
18500544d422SAdrian Hunter 		return NULL;
18510544d422SAdrian Hunter 	}
18520544d422SAdrian Hunter 
18530544d422SAdrian Hunter 	return strdup(path);
18540544d422SAdrian Hunter }
18550544d422SAdrian Hunter 
1856be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map)
185786470930SIngo Molnar {
1858cc612d81SArnaldo Carvalho de Melo 	int err;
18599e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
18609e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1861dc8d6ab2SArnaldo Carvalho de Melo 	/*
1862b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1863b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1864dc8d6ab2SArnaldo Carvalho de Melo 	 *
1865dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1866dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1867dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1868dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1869dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1870dc8d6ab2SArnaldo Carvalho de Melo 	 *
1871dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1872dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1873dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1874dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1875dc8d6ab2SArnaldo Carvalho de Melo 	 */
1876b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1877b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1878b226a5a7SDavid Ahern 		goto do_kallsyms;
1879b226a5a7SDavid Ahern 	}
1880b226a5a7SDavid Ahern 
1881fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
1882be39db9fSArnaldo Carvalho de Melo 		return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false);
1883dc8d6ab2SArnaldo Carvalho de Melo 	}
1884439d473bSArnaldo Carvalho de Melo 
1885fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
1886be39db9fSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map);
1887a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
188839b12f78SAdrian Hunter 			return err;
1889cc612d81SArnaldo Carvalho de Melo 	}
1890cc612d81SArnaldo Carvalho de Melo 
1891ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1892ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1893ec5761eaSDavid Ahern 		return -1;
1894ec5761eaSDavid Ahern 
18950544d422SAdrian Hunter 	kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
18960544d422SAdrian Hunter 	if (!kallsyms_allocated_filename)
18978d0591f6SArnaldo Carvalho de Melo 		return -1;
18988d0591f6SArnaldo Carvalho de Melo 
189919fc2dedSArnaldo Carvalho de Melo 	kallsyms_filename = kallsyms_allocated_filename;
190019fc2dedSArnaldo Carvalho de Melo 
1901dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
1902be39db9fSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map);
19033846df2eSArnaldo Carvalho de Melo 	if (err > 0)
19043846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1905dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1906dc8d6ab2SArnaldo Carvalho de Melo 
19078e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1908bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
19090a77582fSMasami Hiramatsu 		dso__set_long_name(dso, DSO__NAME_KALLSYMS, false);
19106a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
19116a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1912439d473bSArnaldo Carvalho de Melo 	}
191394cb9e38SArnaldo Carvalho de Melo 
191486470930SIngo Molnar 	return err;
191586470930SIngo Molnar }
191686470930SIngo Molnar 
1917be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map)
1918a1645ce1SZhang, Yanmin {
1919a1645ce1SZhang, Yanmin 	int err;
1920a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
192123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1922a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1923a1645ce1SZhang, Yanmin 
1924a1645ce1SZhang, Yanmin 	if (!map->groups) {
1925a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1926a1645ce1SZhang, Yanmin 		return -1;
1927a1645ce1SZhang, Yanmin 	}
192823346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1929a1645ce1SZhang, Yanmin 
193023346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1931a1645ce1SZhang, Yanmin 		/*
1932a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1933a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1934a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1935a1645ce1SZhang, Yanmin 		 */
1936a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1937aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
19385230fb7dSArnaldo Carvalho de Melo 						symbol_conf.default_guest_vmlinux_name,
1939be39db9fSArnaldo Carvalho de Melo 						false);
194039b12f78SAdrian Hunter 			return err;
1941a1645ce1SZhang, Yanmin 		}
1942a1645ce1SZhang, Yanmin 
1943a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1944a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1945a1645ce1SZhang, Yanmin 			return -1;
1946a1645ce1SZhang, Yanmin 	} else {
194723346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1948a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1949a1645ce1SZhang, Yanmin 	}
1950a1645ce1SZhang, Yanmin 
1951be39db9fSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map);
19528e0cf965SAdrian Hunter 	if (err > 0)
195339b12f78SAdrian Hunter 		pr_debug("Using %s for symbols\n", kallsyms_filename);
19548e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1955bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
195648ea8f54SArnaldo Carvalho de Melo 		machine__mmap_name(machine, path, sizeof(path));
19577e155d4dSArnaldo Carvalho de Melo 		dso__set_long_name(dso, strdup(path), true);
1958a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1959a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1960a1645ce1SZhang, Yanmin 	}
1961a1645ce1SZhang, Yanmin 
1962a1645ce1SZhang, Yanmin 	return err;
1963a1645ce1SZhang, Yanmin }
1964cd84c2acSFrederic Weisbecker 
1965cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
19662446042cSArnaldo Carvalho de Melo {
196704662523SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0)
196804662523SArnaldo Carvalho de Melo 		zfree(&vmlinux_path[vmlinux_path__nr_entries]);
1969c4f03547SWang Nan 	vmlinux_path__nr_entries = 0;
1970cc612d81SArnaldo Carvalho de Melo 
197104662523SArnaldo Carvalho de Melo 	zfree(&vmlinux_path);
1972cc612d81SArnaldo Carvalho de Melo }
1973cc612d81SArnaldo Carvalho de Melo 
1974aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = {
1975aac48647SEkaterina Tumanova 	"vmlinux",
1976aac48647SEkaterina Tumanova 	"/boot/vmlinux"
1977aac48647SEkaterina Tumanova };
1978aac48647SEkaterina Tumanova 
1979aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = {
1980aac48647SEkaterina Tumanova 	"/boot/vmlinux-%s",
1981aac48647SEkaterina Tumanova 	"/usr/lib/debug/boot/vmlinux-%s",
1982aac48647SEkaterina Tumanova 	"/lib/modules/%s/build/vmlinux",
1983f55ae954SEkaterina Tumanova 	"/usr/lib/debug/lib/modules/%s/vmlinux",
1984f55ae954SEkaterina Tumanova 	"/usr/lib/debug/boot/vmlinux-%s.debug"
1985aac48647SEkaterina Tumanova };
1986aac48647SEkaterina Tumanova 
1987aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry)
1988aac48647SEkaterina Tumanova {
1989aac48647SEkaterina Tumanova 	vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
1990aac48647SEkaterina Tumanova 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1991aac48647SEkaterina Tumanova 		return -1;
1992aac48647SEkaterina Tumanova 	++vmlinux_path__nr_entries;
1993aac48647SEkaterina Tumanova 
1994aac48647SEkaterina Tumanova 	return 0;
1995aac48647SEkaterina Tumanova }
1996aac48647SEkaterina Tumanova 
1997ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env)
1998cc612d81SArnaldo Carvalho de Melo {
1999cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2000cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
20010a7e6d1bSNamhyung Kim 	char *kernel_version;
2002aac48647SEkaterina Tumanova 	unsigned int i;
2003cc612d81SArnaldo Carvalho de Melo 
2004aac48647SEkaterina Tumanova 	vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
2005aac48647SEkaterina Tumanova 			      ARRAY_SIZE(vmlinux_paths_upd)));
2006cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2007cc612d81SArnaldo Carvalho de Melo 		return -1;
2008cc612d81SArnaldo Carvalho de Melo 
2009aac48647SEkaterina Tumanova 	for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
2010aac48647SEkaterina Tumanova 		if (vmlinux_path__add(vmlinux_paths[i]) < 0)
2011cc612d81SArnaldo Carvalho de Melo 			goto out_fail;
2012ec5761eaSDavid Ahern 
20130a7e6d1bSNamhyung Kim 	/* only try kernel version if no symfs was given */
2014ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2015ec5761eaSDavid Ahern 		return 0;
2016ec5761eaSDavid Ahern 
20170a7e6d1bSNamhyung Kim 	if (env) {
20180a7e6d1bSNamhyung Kim 		kernel_version = env->os_release;
20190a7e6d1bSNamhyung Kim 	} else {
2020ec5761eaSDavid Ahern 		if (uname(&uts) < 0)
2021e96c674fSNamhyung Kim 			goto out_fail;
2022ec5761eaSDavid Ahern 
20230a7e6d1bSNamhyung Kim 		kernel_version = uts.release;
20240a7e6d1bSNamhyung Kim 	}
20250a7e6d1bSNamhyung Kim 
2026aac48647SEkaterina Tumanova 	for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
2027aac48647SEkaterina Tumanova 		snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
2028aac48647SEkaterina Tumanova 		if (vmlinux_path__add(bf) < 0)
2029cc612d81SArnaldo Carvalho de Melo 			goto out_fail;
2030aac48647SEkaterina Tumanova 	}
2031cc612d81SArnaldo Carvalho de Melo 
2032cc612d81SArnaldo Carvalho de Melo 	return 0;
2033cc612d81SArnaldo Carvalho de Melo 
2034cc612d81SArnaldo Carvalho de Melo out_fail:
2035cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2036cc612d81SArnaldo Carvalho de Melo 	return -1;
2037cc612d81SArnaldo Carvalho de Melo }
2038cc612d81SArnaldo Carvalho de Melo 
20393bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str,
2040655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2041655000e7SArnaldo Carvalho de Melo {
2042655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2043655000e7SArnaldo Carvalho de Melo 		return 0;
2044655000e7SArnaldo Carvalho de Melo 
20454a77e218SArnaldo Carvalho de Melo 	*list = strlist__new(list_str, NULL);
2046655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2047655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2048655000e7SArnaldo Carvalho de Melo 		return -1;
2049655000e7SArnaldo Carvalho de Melo 	}
20500bc2f2f7SArnaldo Carvalho de Melo 
20510bc2f2f7SArnaldo Carvalho de Melo 	symbol_conf.has_filter = true;
2052655000e7SArnaldo Carvalho de Melo 	return 0;
2053655000e7SArnaldo Carvalho de Melo }
2054655000e7SArnaldo Carvalho de Melo 
2055e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str,
2056e03eaa40SDavid Ahern 		  const char *list_name)
2057e03eaa40SDavid Ahern {
2058e03eaa40SDavid Ahern 	if (list_str == NULL)
2059e03eaa40SDavid Ahern 		return 0;
2060e03eaa40SDavid Ahern 
2061e03eaa40SDavid Ahern 	*list = intlist__new(list_str);
2062e03eaa40SDavid Ahern 	if (!*list) {
2063e03eaa40SDavid Ahern 		pr_err("problems parsing %s list\n", list_name);
2064e03eaa40SDavid Ahern 		return -1;
2065e03eaa40SDavid Ahern 	}
2066e03eaa40SDavid Ahern 	return 0;
2067e03eaa40SDavid Ahern }
2068e03eaa40SDavid Ahern 
2069ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
2070ec80fde7SArnaldo Carvalho de Melo {
2071ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
2072ec80fde7SArnaldo Carvalho de Melo 	FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
207338272dc4SWang Nan 
2074ec80fde7SArnaldo Carvalho de Melo 	if (fp != NULL) {
2075ec80fde7SArnaldo Carvalho de Melo 		char line[8];
2076ec80fde7SArnaldo Carvalho de Melo 
2077ec80fde7SArnaldo Carvalho de Melo 		if (fgets(line, sizeof(line), fp) != NULL)
20783dbe46c5SWang Nan 			value = ((geteuid() != 0) || (getuid() != 0)) ?
207938272dc4SWang Nan 					(atoi(line) != 0) :
208038272dc4SWang Nan 					(atoi(line) == 2);
2081ec80fde7SArnaldo Carvalho de Melo 
2082ec80fde7SArnaldo Carvalho de Melo 		fclose(fp);
2083ec80fde7SArnaldo Carvalho de Melo 	}
2084ec80fde7SArnaldo Carvalho de Melo 
2085ec80fde7SArnaldo Carvalho de Melo 	return value;
2086ec80fde7SArnaldo Carvalho de Melo }
2087ec80fde7SArnaldo Carvalho de Melo 
2088b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void)
2089b01141f4SArnaldo Carvalho de Melo {
2090b01141f4SArnaldo Carvalho de Melo 	if (symbol_conf.initialized) {
2091b01141f4SArnaldo Carvalho de Melo 		pr_err("Annotation needs to be init before symbol__init()\n");
2092b01141f4SArnaldo Carvalho de Melo 		return -1;
2093b01141f4SArnaldo Carvalho de Melo 	}
2094b01141f4SArnaldo Carvalho de Melo 
2095b01141f4SArnaldo Carvalho de Melo 	if (symbol_conf.init_annotation) {
2096b01141f4SArnaldo Carvalho de Melo 		pr_warning("Annotation being initialized multiple times\n");
2097b01141f4SArnaldo Carvalho de Melo 		return 0;
2098b01141f4SArnaldo Carvalho de Melo 	}
2099b01141f4SArnaldo Carvalho de Melo 
2100b01141f4SArnaldo Carvalho de Melo 	symbol_conf.priv_size += sizeof(struct annotation);
2101b01141f4SArnaldo Carvalho de Melo 	symbol_conf.init_annotation = true;
2102b01141f4SArnaldo Carvalho de Melo 	return 0;
2103b01141f4SArnaldo Carvalho de Melo }
2104b01141f4SArnaldo Carvalho de Melo 
2105ce80d3beSKan Liang int symbol__init(struct perf_env *env)
2106cc612d81SArnaldo Carvalho de Melo {
2107ec5761eaSDavid Ahern 	const char *symfs;
2108ec5761eaSDavid Ahern 
210985e00b55SJovi Zhang 	if (symbol_conf.initialized)
211085e00b55SJovi Zhang 		return 0;
211185e00b55SJovi Zhang 
21129ac3e487SIrina Tirdea 	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
21134d439517SDavid S. Miller 
2114166ccc9cSNamhyung Kim 	symbol__elf_init();
2115166ccc9cSNamhyung Kim 
211675be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
211775be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
211879406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2119b32d133aSArnaldo Carvalho de Melo 
21200a7e6d1bSNamhyung Kim 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
2121cc612d81SArnaldo Carvalho de Melo 		return -1;
2122cc612d81SArnaldo Carvalho de Melo 
2123c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2124c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2125c410a338SArnaldo Carvalho de Melo 		return -1;
2126c410a338SArnaldo Carvalho de Melo 	}
2127c410a338SArnaldo Carvalho de Melo 
2128655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2129655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2130655000e7SArnaldo Carvalho de Melo 		return -1;
2131655000e7SArnaldo Carvalho de Melo 
2132655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2133655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2134655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2135655000e7SArnaldo Carvalho de Melo 
2136e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.pid_list,
2137e03eaa40SDavid Ahern 		       symbol_conf.pid_list_str, "pid") < 0)
2138e03eaa40SDavid Ahern 		goto out_free_comm_list;
2139e03eaa40SDavid Ahern 
2140e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.tid_list,
2141e03eaa40SDavid Ahern 		       symbol_conf.tid_list_str, "tid") < 0)
2142e03eaa40SDavid Ahern 		goto out_free_pid_list;
2143e03eaa40SDavid Ahern 
2144655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2145655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2146e03eaa40SDavid Ahern 		goto out_free_tid_list;
2147655000e7SArnaldo Carvalho de Melo 
214864eff7d9SDavid Ahern 	if (setup_list(&symbol_conf.bt_stop_list,
214964eff7d9SDavid Ahern 		       symbol_conf.bt_stop_list_str, "symbol") < 0)
215064eff7d9SDavid Ahern 		goto out_free_sym_list;
215164eff7d9SDavid Ahern 
2152ec5761eaSDavid Ahern 	/*
2153ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2154ec5761eaSDavid Ahern 	 * reset here for simplicity.
2155ec5761eaSDavid Ahern 	 */
2156ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2157ec5761eaSDavid Ahern 	if (symfs == NULL)
2158ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2159ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2160ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2161ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2162ec5761eaSDavid Ahern 		free((void *)symfs);
2163ec5761eaSDavid Ahern 
2164ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2165ec80fde7SArnaldo Carvalho de Melo 
216685e00b55SJovi Zhang 	symbol_conf.initialized = true;
21674aa65636SArnaldo Carvalho de Melo 	return 0;
2168655000e7SArnaldo Carvalho de Melo 
216964eff7d9SDavid Ahern out_free_sym_list:
217064eff7d9SDavid Ahern 	strlist__delete(symbol_conf.sym_list);
2171e03eaa40SDavid Ahern out_free_tid_list:
2172e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2173e03eaa40SDavid Ahern out_free_pid_list:
2174e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2175655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2176655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2177d74c896bSNamhyung Kim out_free_dso_list:
2178d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2179655000e7SArnaldo Carvalho de Melo 	return -1;
2180cc612d81SArnaldo Carvalho de Melo }
2181cc612d81SArnaldo Carvalho de Melo 
2182d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2183d65a458bSArnaldo Carvalho de Melo {
218485e00b55SJovi Zhang 	if (!symbol_conf.initialized)
218585e00b55SJovi Zhang 		return;
218664eff7d9SDavid Ahern 	strlist__delete(symbol_conf.bt_stop_list);
2187d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2188d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2189d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2190e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2191e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2192d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2193d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
219464eff7d9SDavid Ahern 	symbol_conf.bt_stop_list = NULL;
219585e00b55SJovi Zhang 	symbol_conf.initialized = false;
2196d65a458bSArnaldo Carvalho de Melo }
2197a7066709SHe Kuang 
2198a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused,
2199a7066709SHe Kuang 			 const char *dir, int unset __maybe_unused)
2200a7066709SHe Kuang {
2201a7066709SHe Kuang 	char *bf = NULL;
2202a7066709SHe Kuang 	int ret;
2203a7066709SHe Kuang 
2204a7066709SHe Kuang 	symbol_conf.symfs = strdup(dir);
2205a7066709SHe Kuang 	if (symbol_conf.symfs == NULL)
2206a7066709SHe Kuang 		return -ENOMEM;
2207a7066709SHe Kuang 
2208a7066709SHe Kuang 	/* skip the locally configured cache if a symfs is given, and
2209a7066709SHe Kuang 	 * config buildid dir to symfs/.debug
2210a7066709SHe Kuang 	 */
2211a7066709SHe Kuang 	ret = asprintf(&bf, "%s/%s", dir, ".debug");
2212a7066709SHe Kuang 	if (ret < 0)
2213a7066709SHe Kuang 		return -ENOMEM;
2214a7066709SHe Kuang 
2215a7066709SHe Kuang 	set_buildid_dir(bf);
2216a7066709SHe Kuang 
2217a7066709SHe Kuang 	free(bf);
2218a7066709SHe Kuang 	return 0;
2219a7066709SHe Kuang }
2220