xref: /linux/tools/perf/util/symbol.c (revision 432746f8e0b6a82ba832b771afe31abd51af6752)
15aab621bSArnaldo Carvalho de Melo #include <dirent.h>
25aab621bSArnaldo Carvalho de Melo #include <errno.h>
35aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
45aab621bSArnaldo Carvalho de Melo #include <stdio.h>
55aab621bSArnaldo Carvalho de Melo #include <string.h>
65aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
85aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
95aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
105aab621bSArnaldo Carvalho de Melo #include <unistd.h>
119486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
12b01141f4SArnaldo Carvalho de Melo #include "annotate.h"
13b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
14e334c726SNamhyung Kim #include "util.h"
158a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1669d2591aSArnaldo Carvalho de Melo #include "machine.h"
1786470930SIngo Molnar #include "symbol.h"
185aab621bSArnaldo Carvalho de Melo #include "strlist.h"
19e03eaa40SDavid Ahern #include "intlist.h"
200a7e6d1bSNamhyung Kim #include "header.h"
2186470930SIngo Molnar 
2286470930SIngo Molnar #include <elf.h>
23f1617b40SArnaldo Carvalho de Melo #include <limits.h>
24c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h>
25439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
262cdbc46dSPeter Zijlstra 
27aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
289de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
29aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
30a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
313f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries;
323f067dcaSArnaldo Carvalho de Melo char **vmlinux_path;
33439d473bSArnaldo Carvalho de Melo 
3475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
35b32d133aSArnaldo Carvalho de Melo 	.use_modules		= true,
36b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path	= true,
373e6a2a7fSStephane Eranian 	.annotate_src		= true,
38328ccdacSNamhyung Kim 	.demangle		= true,
39763122adSAvi Kivity 	.demangle_kernel	= false,
40e511db5eSNamhyung Kim 	.cumulate_callchain	= true,
41c8302367SJiri Olsa 	.show_hist_headers	= true,
42ec5761eaSDavid Ahern 	.symfs			= "",
431e9abf8bSNamhyung Kim 	.event_group		= true,
44b32d133aSArnaldo Carvalho de Melo };
45b32d133aSArnaldo Carvalho de Melo 
4644f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = {
4744f24cb3SJiri Olsa 	DSO_BINARY_TYPE__KALLSYMS,
4844f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KALLSYMS,
4944f24cb3SJiri Olsa 	DSO_BINARY_TYPE__JAVA_JIT,
5044f24cb3SJiri Olsa 	DSO_BINARY_TYPE__DEBUGLINK,
5144f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
5244f24cb3SJiri Olsa 	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
5344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
5444f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
5544f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
5644f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KMODULE,
57c00c48fcSNamhyung Kim 	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
5844f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
59c00c48fcSNamhyung Kim 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
609cd00941SRicardo Ribalda Delgado 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
6144f24cb3SJiri Olsa 	DSO_BINARY_TYPE__NOT_FOUND,
6244f24cb3SJiri Olsa };
6344f24cb3SJiri Olsa 
64028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
6544f24cb3SJiri Olsa 
6636a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
676893d4eeSArnaldo Carvalho de Melo {
6831877908SAnton Blanchard 	symbol_type = toupper(symbol_type);
6931877908SAnton Blanchard 
706893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
716893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
726893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
73f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
7431877908SAnton Blanchard 		return symbol_type == 'D';
756893d4eeSArnaldo Carvalho de Melo 	default:
766893d4eeSArnaldo Carvalho de Melo 		return false;
776893d4eeSArnaldo Carvalho de Melo 	}
786893d4eeSArnaldo Carvalho de Melo }
796893d4eeSArnaldo Carvalho de Melo 
80694bf407SAnton Blanchard static int prefix_underscores_count(const char *str)
81694bf407SAnton Blanchard {
82694bf407SAnton Blanchard 	const char *tail = str;
83694bf407SAnton Blanchard 
84694bf407SAnton Blanchard 	while (*tail == '_')
85694bf407SAnton Blanchard 		tail++;
86694bf407SAnton Blanchard 
87694bf407SAnton Blanchard 	return tail - str;
88694bf407SAnton Blanchard }
89694bf407SAnton Blanchard 
90fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma,
91fb6d5942SNaveen N. Rao 				    struct symbol *symb __maybe_unused)
92fb6d5942SNaveen N. Rao {
93fb6d5942SNaveen N. Rao 	/* Avoid "SyS" kernel syscall aliases */
94fb6d5942SNaveen N. Rao 	if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
95fb6d5942SNaveen N. Rao 		return SYMBOL_B;
96fb6d5942SNaveen N. Rao 	if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
97fb6d5942SNaveen N. Rao 		return SYMBOL_B;
98fb6d5942SNaveen N. Rao 
99fb6d5942SNaveen N. Rao 	return SYMBOL_A;
100fb6d5942SNaveen N. Rao }
101694bf407SAnton Blanchard 
102694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
103694bf407SAnton Blanchard {
104694bf407SAnton Blanchard 	s64 a;
105694bf407SAnton Blanchard 	s64 b;
1063445432bSAdrian Hunter 	size_t na, nb;
107694bf407SAnton Blanchard 
108694bf407SAnton Blanchard 	/* Prefer a symbol with non zero length */
109694bf407SAnton Blanchard 	a = syma->end - syma->start;
110694bf407SAnton Blanchard 	b = symb->end - symb->start;
111694bf407SAnton Blanchard 	if ((b == 0) && (a > 0))
112694bf407SAnton Blanchard 		return SYMBOL_A;
113694bf407SAnton Blanchard 	else if ((a == 0) && (b > 0))
114694bf407SAnton Blanchard 		return SYMBOL_B;
115694bf407SAnton Blanchard 
116694bf407SAnton Blanchard 	/* Prefer a non weak symbol over a weak one */
117694bf407SAnton Blanchard 	a = syma->binding == STB_WEAK;
118694bf407SAnton Blanchard 	b = symb->binding == STB_WEAK;
119694bf407SAnton Blanchard 	if (b && !a)
120694bf407SAnton Blanchard 		return SYMBOL_A;
121694bf407SAnton Blanchard 	if (a && !b)
122694bf407SAnton Blanchard 		return SYMBOL_B;
123694bf407SAnton Blanchard 
124694bf407SAnton Blanchard 	/* Prefer a global symbol over a non global one */
125694bf407SAnton Blanchard 	a = syma->binding == STB_GLOBAL;
126694bf407SAnton Blanchard 	b = symb->binding == STB_GLOBAL;
127694bf407SAnton Blanchard 	if (a && !b)
128694bf407SAnton Blanchard 		return SYMBOL_A;
129694bf407SAnton Blanchard 	if (b && !a)
130694bf407SAnton Blanchard 		return SYMBOL_B;
131694bf407SAnton Blanchard 
132694bf407SAnton Blanchard 	/* Prefer a symbol with less underscores */
133694bf407SAnton Blanchard 	a = prefix_underscores_count(syma->name);
134694bf407SAnton Blanchard 	b = prefix_underscores_count(symb->name);
135694bf407SAnton Blanchard 	if (b > a)
136694bf407SAnton Blanchard 		return SYMBOL_A;
137694bf407SAnton Blanchard 	else if (a > b)
138694bf407SAnton Blanchard 		return SYMBOL_B;
139694bf407SAnton Blanchard 
1403445432bSAdrian Hunter 	/* Choose the symbol with the longest name */
1413445432bSAdrian Hunter 	na = strlen(syma->name);
1423445432bSAdrian Hunter 	nb = strlen(symb->name);
1433445432bSAdrian Hunter 	if (na > nb)
144694bf407SAnton Blanchard 		return SYMBOL_A;
1453445432bSAdrian Hunter 	else if (na < nb)
146694bf407SAnton Blanchard 		return SYMBOL_B;
1473445432bSAdrian Hunter 
148fb6d5942SNaveen N. Rao 	return arch__choose_best_symbol(syma, symb);
149694bf407SAnton Blanchard }
150694bf407SAnton Blanchard 
151e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols)
152694bf407SAnton Blanchard {
153694bf407SAnton Blanchard 	struct rb_node *nd;
154694bf407SAnton Blanchard 	struct symbol *curr, *next;
155694bf407SAnton Blanchard 
156c97b40e4SArnaldo Carvalho de Melo 	if (symbol_conf.allow_aliases)
157c97b40e4SArnaldo Carvalho de Melo 		return;
158c97b40e4SArnaldo Carvalho de Melo 
159694bf407SAnton Blanchard 	nd = rb_first(symbols);
160694bf407SAnton Blanchard 
161694bf407SAnton Blanchard 	while (nd) {
162694bf407SAnton Blanchard 		curr = rb_entry(nd, struct symbol, rb_node);
163694bf407SAnton Blanchard again:
164694bf407SAnton Blanchard 		nd = rb_next(&curr->rb_node);
165694bf407SAnton Blanchard 		next = rb_entry(nd, struct symbol, rb_node);
166694bf407SAnton Blanchard 
167694bf407SAnton Blanchard 		if (!nd)
168694bf407SAnton Blanchard 			break;
169694bf407SAnton Blanchard 
170694bf407SAnton Blanchard 		if (curr->start != next->start)
171694bf407SAnton Blanchard 			continue;
172694bf407SAnton Blanchard 
173694bf407SAnton Blanchard 		if (choose_best_symbol(curr, next) == SYMBOL_A) {
174694bf407SAnton Blanchard 			rb_erase(&next->rb_node, symbols);
175d4f74eb8SChenggang Qin 			symbol__delete(next);
176694bf407SAnton Blanchard 			goto again;
177694bf407SAnton Blanchard 		} else {
178694bf407SAnton Blanchard 			nd = rb_next(&curr->rb_node);
179694bf407SAnton Blanchard 			rb_erase(&curr->rb_node, symbols);
180d4f74eb8SChenggang Qin 			symbol__delete(curr);
181694bf407SAnton Blanchard 		}
182694bf407SAnton Blanchard 	}
183694bf407SAnton Blanchard }
184694bf407SAnton Blanchard 
185e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols)
186af427bf5SArnaldo Carvalho de Melo {
187aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(symbols);
1882e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
189af427bf5SArnaldo Carvalho de Melo 
190af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
191af427bf5SArnaldo Carvalho de Melo 		return;
192af427bf5SArnaldo Carvalho de Melo 
1932e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
1942e538c4aSArnaldo Carvalho de Melo 
195af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
1962e538c4aSArnaldo Carvalho de Melo 		prev = curr;
1972e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
198af427bf5SArnaldo Carvalho de Melo 
1993b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
2002c241bd3SArnaldo Carvalho de Melo 			prev->end = curr->start;
201af427bf5SArnaldo Carvalho de Melo 	}
202af427bf5SArnaldo Carvalho de Melo 
2032e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
2042e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
2052e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
2062e538c4aSArnaldo Carvalho de Melo }
2072e538c4aSArnaldo Carvalho de Melo 
208e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
209af427bf5SArnaldo Carvalho de Melo {
2101eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
2114bb7123dSArnaldo Carvalho de Melo 	struct map *next, *curr;
212af427bf5SArnaldo Carvalho de Melo 
2136a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_wrlock(&maps->lock);
2146a2ffcddSArnaldo Carvalho de Melo 
2154bb7123dSArnaldo Carvalho de Melo 	curr = maps__first(maps);
2164bb7123dSArnaldo Carvalho de Melo 	if (curr == NULL)
2176a2ffcddSArnaldo Carvalho de Melo 		goto out_unlock;
218af427bf5SArnaldo Carvalho de Melo 
2194bb7123dSArnaldo Carvalho de Melo 	for (next = map__next(curr); next; next = map__next(curr)) {
2204bb7123dSArnaldo Carvalho de Melo 		curr->end = next->start;
2214bb7123dSArnaldo Carvalho de Melo 		curr = next;
2222e538c4aSArnaldo Carvalho de Melo 	}
22390c83218SArnaldo Carvalho de Melo 
22490c83218SArnaldo Carvalho de Melo 	/*
22590c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
22690c83218SArnaldo Carvalho de Melo 	 * last map final address.
22790c83218SArnaldo Carvalho de Melo 	 */
2289d1faba5SIan Munsie 	curr->end = ~0ULL;
2296a2ffcddSArnaldo Carvalho de Melo 
2306a2ffcddSArnaldo Carvalho de Melo out_unlock:
2316a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_unlock(&maps->lock);
232af427bf5SArnaldo Carvalho de Melo }
233af427bf5SArnaldo Carvalho de Melo 
234e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
23586470930SIngo Molnar {
23686470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
237aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
238aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
239aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
24086470930SIngo Molnar 		return NULL;
24186470930SIngo Molnar 
242b01141f4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size) {
243b01141f4SArnaldo Carvalho de Melo 		if (symbol_conf.init_annotation) {
244b01141f4SArnaldo Carvalho de Melo 			struct annotation *notes = (void *)sym;
245b01141f4SArnaldo Carvalho de Melo 			pthread_mutex_init(&notes->lock, NULL);
246b01141f4SArnaldo Carvalho de Melo 		}
247aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
248b01141f4SArnaldo Carvalho de Melo 	}
24936479484SArnaldo Carvalho de Melo 
250aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
2512c241bd3SArnaldo Carvalho de Melo 	sym->end     = len ? start + len : start;
252aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
253aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
254e4204992SArnaldo Carvalho de Melo 
255aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
256aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
257aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
258e4204992SArnaldo Carvalho de Melo 
259aeafcbafSArnaldo Carvalho de Melo 	return sym;
26086470930SIngo Molnar }
26186470930SIngo Molnar 
262aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
26386470930SIngo Molnar {
264aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
26586470930SIngo Molnar }
26686470930SIngo Molnar 
267cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols)
26886470930SIngo Molnar {
26986470930SIngo Molnar 	struct symbol *pos;
270aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
27186470930SIngo Molnar 
27286470930SIngo Molnar 	while (next) {
27386470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
27486470930SIngo Molnar 		next = rb_next(&pos->rb_node);
275aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
27600a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
27786470930SIngo Molnar 	}
27886470930SIngo Molnar }
27986470930SIngo Molnar 
280e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym)
28186470930SIngo Molnar {
282aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
28386470930SIngo Molnar 	struct rb_node *parent = NULL;
2849cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
28586470930SIngo Molnar 	struct symbol *s;
28686470930SIngo Molnar 
28786470930SIngo Molnar 	while (*p != NULL) {
28886470930SIngo Molnar 		parent = *p;
28986470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
29086470930SIngo Molnar 		if (ip < s->start)
29186470930SIngo Molnar 			p = &(*p)->rb_left;
29286470930SIngo Molnar 		else
29386470930SIngo Molnar 			p = &(*p)->rb_right;
29486470930SIngo Molnar 	}
29586470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
296aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
29786470930SIngo Molnar }
29886470930SIngo Molnar 
299aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
30086470930SIngo Molnar {
30186470930SIngo Molnar 	struct rb_node *n;
30286470930SIngo Molnar 
303aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
30486470930SIngo Molnar 		return NULL;
30586470930SIngo Molnar 
306aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
30786470930SIngo Molnar 
30886470930SIngo Molnar 	while (n) {
30986470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
31086470930SIngo Molnar 
31186470930SIngo Molnar 		if (ip < s->start)
31286470930SIngo Molnar 			n = n->rb_left;
3139c7b37cdSChris Phlipot 		else if (ip > s->end || (ip == s->end && ip != s->start))
31486470930SIngo Molnar 			n = n->rb_right;
31586470930SIngo Molnar 		else
31686470930SIngo Molnar 			return s;
31786470930SIngo Molnar 	}
31886470930SIngo Molnar 
31986470930SIngo Molnar 	return NULL;
32086470930SIngo Molnar }
32186470930SIngo Molnar 
3228e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols)
3238e0cf965SAdrian Hunter {
3248e0cf965SAdrian Hunter 	struct rb_node *n = rb_first(symbols);
3258e0cf965SAdrian Hunter 
3268e0cf965SAdrian Hunter 	if (n)
3278e0cf965SAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3288e0cf965SAdrian Hunter 
3298e0cf965SAdrian Hunter 	return NULL;
3308e0cf965SAdrian Hunter }
3318e0cf965SAdrian Hunter 
3329c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym)
3339c00a81bSAdrian Hunter {
3349c00a81bSAdrian Hunter 	struct rb_node *n = rb_next(&sym->rb_node);
3359c00a81bSAdrian Hunter 
3369c00a81bSAdrian Hunter 	if (n)
3379c00a81bSAdrian Hunter 		return rb_entry(n, struct symbol, rb_node);
3389c00a81bSAdrian Hunter 
3399c00a81bSAdrian Hunter 	return NULL;
3409c00a81bSAdrian Hunter }
3419c00a81bSAdrian Hunter 
342aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
34379406cd7SArnaldo Carvalho de Melo {
344aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
34579406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
34602a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
34702a9d037SRabin Vincent 
34802a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
34979406cd7SArnaldo Carvalho de Melo 
35079406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
35179406cd7SArnaldo Carvalho de Melo 		parent = *p;
35279406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
35379406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
35479406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
35579406cd7SArnaldo Carvalho de Melo 		else
35679406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
35779406cd7SArnaldo Carvalho de Melo 	}
35879406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
359aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
36079406cd7SArnaldo Carvalho de Melo }
36179406cd7SArnaldo Carvalho de Melo 
362aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
363aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
36479406cd7SArnaldo Carvalho de Melo {
36579406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
36679406cd7SArnaldo Carvalho de Melo 
36779406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
36879406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
369aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
37079406cd7SArnaldo Carvalho de Melo 	}
37179406cd7SArnaldo Carvalho de Melo }
37279406cd7SArnaldo Carvalho de Melo 
373aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
374aeafcbafSArnaldo Carvalho de Melo 					    const char *name)
37579406cd7SArnaldo Carvalho de Melo {
37679406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
3775bcaaca3SMartin Liška 	struct symbol_name_rb_node *s = NULL;
37879406cd7SArnaldo Carvalho de Melo 
379aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
38079406cd7SArnaldo Carvalho de Melo 		return NULL;
38179406cd7SArnaldo Carvalho de Melo 
382aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
38379406cd7SArnaldo Carvalho de Melo 
38479406cd7SArnaldo Carvalho de Melo 	while (n) {
38579406cd7SArnaldo Carvalho de Melo 		int cmp;
38679406cd7SArnaldo Carvalho de Melo 
38779406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
388031b84c4SNaveen N. Rao 		cmp = arch__compare_symbol_names(name, s->sym.name);
38979406cd7SArnaldo Carvalho de Melo 
39079406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
39179406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
39279406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
39379406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
39479406cd7SArnaldo Carvalho de Melo 		else
395de480999SNamhyung Kim 			break;
39679406cd7SArnaldo Carvalho de Melo 	}
39779406cd7SArnaldo Carvalho de Melo 
398de480999SNamhyung Kim 	if (n == NULL)
39979406cd7SArnaldo Carvalho de Melo 		return NULL;
400de480999SNamhyung Kim 
401de480999SNamhyung Kim 	/* return first symbol that has same name (if any) */
402de480999SNamhyung Kim 	for (n = rb_prev(n); n; n = rb_prev(n)) {
403de480999SNamhyung Kim 		struct symbol_name_rb_node *tmp;
404de480999SNamhyung Kim 
405de480999SNamhyung Kim 		tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
406031b84c4SNaveen N. Rao 		if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
407de480999SNamhyung Kim 			break;
408de480999SNamhyung Kim 
409de480999SNamhyung Kim 		s = tmp;
410de480999SNamhyung Kim 	}
411de480999SNamhyung Kim 
412de480999SNamhyung Kim 	return &s->sym;
41379406cd7SArnaldo Carvalho de Melo }
41479406cd7SArnaldo Carvalho de Melo 
415c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso)
416c0b4dffbSArnaldo Carvalho de Melo {
417c0b4dffbSArnaldo Carvalho de Melo 	enum map_type type;
418c0b4dffbSArnaldo Carvalho de Melo 
419c0b4dffbSArnaldo Carvalho de Melo 	for (type = MAP__FUNCTION; type <= MAP__VARIABLE; ++type) {
420c0b4dffbSArnaldo Carvalho de Melo 		dso->last_find_result[type].addr   = 0;
421c0b4dffbSArnaldo Carvalho de Melo 		dso->last_find_result[type].symbol = NULL;
422c0b4dffbSArnaldo Carvalho de Melo 	}
423c0b4dffbSArnaldo Carvalho de Melo }
424c0b4dffbSArnaldo Carvalho de Melo 
425ae93a6c7SChris Phlipot void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym)
426ae93a6c7SChris Phlipot {
427ae93a6c7SChris Phlipot 	symbols__insert(&dso->symbols[type], sym);
428ae93a6c7SChris Phlipot 
429ae93a6c7SChris Phlipot 	/* update the symbol cache if necessary */
430ae93a6c7SChris Phlipot 	if (dso->last_find_result[type].addr >= sym->start &&
431ae93a6c7SChris Phlipot 	    (dso->last_find_result[type].addr < sym->end ||
432ae93a6c7SChris Phlipot 	    sym->start == sym->end)) {
433ae93a6c7SChris Phlipot 		dso->last_find_result[type].symbol = sym;
434ae93a6c7SChris Phlipot 	}
435ae93a6c7SChris Phlipot }
436ae93a6c7SChris Phlipot 
437aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
43879406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
439fcf1203aSArnaldo Carvalho de Melo {
440b685ac22SArnaldo Carvalho de Melo 	if (dso->last_find_result[type].addr != addr) {
441b685ac22SArnaldo Carvalho de Melo 		dso->last_find_result[type].addr   = addr;
442b685ac22SArnaldo Carvalho de Melo 		dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr);
443b685ac22SArnaldo Carvalho de Melo 	}
444b685ac22SArnaldo Carvalho de Melo 
445b685ac22SArnaldo Carvalho de Melo 	return dso->last_find_result[type].symbol;
446fcf1203aSArnaldo Carvalho de Melo }
447fcf1203aSArnaldo Carvalho de Melo 
4489c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
4498e0cf965SAdrian Hunter {
4508e0cf965SAdrian Hunter 	return symbols__first(&dso->symbols[type]);
4518e0cf965SAdrian Hunter }
4528e0cf965SAdrian Hunter 
4539c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym)
4549c00a81bSAdrian Hunter {
4559c00a81bSAdrian Hunter 	return symbols__next(sym);
4569c00a81bSAdrian Hunter }
4579c00a81bSAdrian Hunter 
45818bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym)
45918bd7264SArnaldo Carvalho de Melo {
46018bd7264SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
46118bd7264SArnaldo Carvalho de Melo 	struct rb_node *n = rb_next(&s->rb_node);
46218bd7264SArnaldo Carvalho de Melo 
46318bd7264SArnaldo Carvalho de Melo 	return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
46418bd7264SArnaldo Carvalho de Melo }
46518bd7264SArnaldo Carvalho de Melo 
46618bd7264SArnaldo Carvalho de Melo  /*
46718bd7264SArnaldo Carvalho de Melo   * Teturns first symbol that matched with @name.
46818bd7264SArnaldo Carvalho de Melo   */
469aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
47079406cd7SArnaldo Carvalho de Melo 					const char *name)
47179406cd7SArnaldo Carvalho de Melo {
472aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
47379406cd7SArnaldo Carvalho de Melo }
47479406cd7SArnaldo Carvalho de Melo 
475aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
47679406cd7SArnaldo Carvalho de Melo {
477aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
478aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
479aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
48079406cd7SArnaldo Carvalho de Melo }
48179406cd7SArnaldo Carvalho de Melo 
482316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg,
483316d70d6SAdrian Hunter 		   int (*process_module)(void *arg, const char *name,
484316d70d6SAdrian Hunter 					 u64 start))
485316d70d6SAdrian Hunter {
486316d70d6SAdrian Hunter 	char *line = NULL;
487316d70d6SAdrian Hunter 	size_t n;
488316d70d6SAdrian Hunter 	FILE *file;
489316d70d6SAdrian Hunter 	int err = 0;
490316d70d6SAdrian Hunter 
491316d70d6SAdrian Hunter 	file = fopen(filename, "r");
492316d70d6SAdrian Hunter 	if (file == NULL)
493316d70d6SAdrian Hunter 		return -1;
494316d70d6SAdrian Hunter 
495316d70d6SAdrian Hunter 	while (1) {
496316d70d6SAdrian Hunter 		char name[PATH_MAX];
497316d70d6SAdrian Hunter 		u64 start;
498316d70d6SAdrian Hunter 		char *sep;
499316d70d6SAdrian Hunter 		ssize_t line_len;
500316d70d6SAdrian Hunter 
501316d70d6SAdrian Hunter 		line_len = getline(&line, &n, file);
502316d70d6SAdrian Hunter 		if (line_len < 0) {
503316d70d6SAdrian Hunter 			if (feof(file))
504316d70d6SAdrian Hunter 				break;
505316d70d6SAdrian Hunter 			err = -1;
506316d70d6SAdrian Hunter 			goto out;
507316d70d6SAdrian Hunter 		}
508316d70d6SAdrian Hunter 
509316d70d6SAdrian Hunter 		if (!line) {
510316d70d6SAdrian Hunter 			err = -1;
511316d70d6SAdrian Hunter 			goto out;
512316d70d6SAdrian Hunter 		}
513316d70d6SAdrian Hunter 
514316d70d6SAdrian Hunter 		line[--line_len] = '\0'; /* \n */
515316d70d6SAdrian Hunter 
516316d70d6SAdrian Hunter 		sep = strrchr(line, 'x');
517316d70d6SAdrian Hunter 		if (sep == NULL)
518316d70d6SAdrian Hunter 			continue;
519316d70d6SAdrian Hunter 
520316d70d6SAdrian Hunter 		hex2u64(sep + 1, &start);
521316d70d6SAdrian Hunter 
522316d70d6SAdrian Hunter 		sep = strchr(line, ' ');
523316d70d6SAdrian Hunter 		if (sep == NULL)
524316d70d6SAdrian Hunter 			continue;
525316d70d6SAdrian Hunter 
526316d70d6SAdrian Hunter 		*sep = '\0';
527316d70d6SAdrian Hunter 
528316d70d6SAdrian Hunter 		scnprintf(name, sizeof(name), "[%s]", line);
529316d70d6SAdrian Hunter 
530316d70d6SAdrian Hunter 		err = process_module(arg, name, start);
531316d70d6SAdrian Hunter 		if (err)
532316d70d6SAdrian Hunter 			break;
533316d70d6SAdrian Hunter 	}
534316d70d6SAdrian Hunter out:
535316d70d6SAdrian Hunter 	free(line);
536316d70d6SAdrian Hunter 	fclose(file);
537316d70d6SAdrian Hunter 	return err;
538316d70d6SAdrian Hunter }
539316d70d6SAdrian Hunter 
540682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
541682b335aSArnaldo Carvalho de Melo 	struct map *map;
542682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
543682b335aSArnaldo Carvalho de Melo };
544682b335aSArnaldo Carvalho de Melo 
545e7110b9fSArnaldo Carvalho de Melo /*
546e7110b9fSArnaldo Carvalho de Melo  * These are symbols in the kernel image, so make sure that
547e7110b9fSArnaldo Carvalho de Melo  * sym is from a kernel DSO.
548e7110b9fSArnaldo Carvalho de Melo  */
54982d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym)
55082d1deb0SDavid Ahern {
55182d1deb0SDavid Ahern 	const char * const idle_symbols[] = {
55282d1deb0SDavid Ahern 		"cpu_idle",
553e0336ed6SArnaldo Carvalho de Melo 		"cpu_startup_entry",
55482d1deb0SDavid Ahern 		"intel_idle",
55582d1deb0SDavid Ahern 		"default_idle",
55682d1deb0SDavid Ahern 		"native_safe_halt",
55782d1deb0SDavid Ahern 		"enter_idle",
55882d1deb0SDavid Ahern 		"exit_idle",
55982d1deb0SDavid Ahern 		"mwait_idle",
56082d1deb0SDavid Ahern 		"mwait_idle_with_hints",
56182d1deb0SDavid Ahern 		"poll_idle",
56282d1deb0SDavid Ahern 		"ppc64_runlatch_off",
56382d1deb0SDavid Ahern 		"pseries_dedicated_idle_sleep",
56482d1deb0SDavid Ahern 		NULL
56582d1deb0SDavid Ahern 	};
56682d1deb0SDavid Ahern 
56782d1deb0SDavid Ahern 	int i;
56882d1deb0SDavid Ahern 
56982d1deb0SDavid Ahern 	if (!sym)
57082d1deb0SDavid Ahern 		return false;
57182d1deb0SDavid Ahern 
57282d1deb0SDavid Ahern 	for (i = 0; idle_symbols[i]; i++) {
57382d1deb0SDavid Ahern 		if (!strcmp(idle_symbols[i], sym->name))
57482d1deb0SDavid Ahern 			return true;
57582d1deb0SDavid Ahern 	}
57682d1deb0SDavid Ahern 
57782d1deb0SDavid Ahern 	return false;
57882d1deb0SDavid Ahern }
57982d1deb0SDavid Ahern 
580682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
58182151520SCody P Schafer 				       char type, u64 start)
582682b335aSArnaldo Carvalho de Melo {
583682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
584682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
585682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
586682b335aSArnaldo Carvalho de Melo 
587682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
588682b335aSArnaldo Carvalho de Melo 		return 0;
589682b335aSArnaldo Carvalho de Melo 
59082151520SCody P Schafer 	/*
59182151520SCody P Schafer 	 * module symbols are not sorted so we add all
59282151520SCody P Schafer 	 * symbols, setting length to 0, and rely on
59382151520SCody P Schafer 	 * symbols__fixup_end() to fix it up.
59482151520SCody P Schafer 	 */
5958e947f1eSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, kallsyms2elf_binding(type), name);
5962e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
597682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
59882164161SArnaldo Carvalho de Melo 	/*
59982164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6004e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
60182164161SArnaldo Carvalho de Melo 	 */
6024e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
603a1645ce1SZhang, Yanmin 
604682b335aSArnaldo Carvalho de Melo 	return 0;
6052e538c4aSArnaldo Carvalho de Melo }
6062e538c4aSArnaldo Carvalho de Melo 
607682b335aSArnaldo Carvalho de Melo /*
608682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
609682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
610682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
611682b335aSArnaldo Carvalho de Melo  */
612aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6139e201442SArnaldo Carvalho de Melo 				  struct map *map)
614682b335aSArnaldo Carvalho de Melo {
615aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6169e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6172e538c4aSArnaldo Carvalho de Melo }
6182e538c4aSArnaldo Carvalho de Melo 
6198e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
6208e0cf965SAdrian Hunter 					 symbol_filter_t filter)
6218e0cf965SAdrian Hunter {
622ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
6238e0cf965SAdrian Hunter 	struct map *curr_map;
6248e0cf965SAdrian Hunter 	struct symbol *pos;
625866548ddSAdrian Hunter 	int count = 0;
626866548ddSAdrian Hunter 	struct rb_root old_root = dso->symbols[map->type];
6278e0cf965SAdrian Hunter 	struct rb_root *root = &dso->symbols[map->type];
6288e0cf965SAdrian Hunter 	struct rb_node *next = rb_first(root);
6298e0cf965SAdrian Hunter 
630ba92732eSWang Nan 	if (!kmaps)
631ba92732eSWang Nan 		return -1;
632ba92732eSWang Nan 
633866548ddSAdrian Hunter 	*root = RB_ROOT;
634866548ddSAdrian Hunter 
6358e0cf965SAdrian Hunter 	while (next) {
6368e0cf965SAdrian Hunter 		char *module;
6378e0cf965SAdrian Hunter 
6388e0cf965SAdrian Hunter 		pos = rb_entry(next, struct symbol, rb_node);
6398e0cf965SAdrian Hunter 		next = rb_next(&pos->rb_node);
6408e0cf965SAdrian Hunter 
641866548ddSAdrian Hunter 		rb_erase_init(&pos->rb_node, &old_root);
642866548ddSAdrian Hunter 
6438e0cf965SAdrian Hunter 		module = strchr(pos->name, '\t');
6448e0cf965SAdrian Hunter 		if (module)
6458e0cf965SAdrian Hunter 			*module = '\0';
6468e0cf965SAdrian Hunter 
6478e0cf965SAdrian Hunter 		curr_map = map_groups__find(kmaps, map->type, pos->start);
6488e0cf965SAdrian Hunter 
6498e0cf965SAdrian Hunter 		if (!curr_map || (filter && filter(curr_map, pos))) {
6508e0cf965SAdrian Hunter 			symbol__delete(pos);
651866548ddSAdrian Hunter 			continue;
652866548ddSAdrian Hunter 		}
653866548ddSAdrian Hunter 
6548e0cf965SAdrian Hunter 		pos->start -= curr_map->start - curr_map->pgoff;
6558e0cf965SAdrian Hunter 		if (pos->end)
6568e0cf965SAdrian Hunter 			pos->end -= curr_map->start - curr_map->pgoff;
657866548ddSAdrian Hunter 		symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
6588e0cf965SAdrian Hunter 		++count;
6598e0cf965SAdrian Hunter 	}
6608e0cf965SAdrian Hunter 
6618e0cf965SAdrian Hunter 	/* Symbols have been adjusted */
6628e0cf965SAdrian Hunter 	dso->adjust_symbols = 1;
6638e0cf965SAdrian Hunter 
664866548ddSAdrian Hunter 	return count;
6658e0cf965SAdrian Hunter }
6668e0cf965SAdrian Hunter 
6672e538c4aSArnaldo Carvalho de Melo /*
6682e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
6692e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
6702e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
6712e538c4aSArnaldo Carvalho de Melo  */
672d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
6739de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
6742e538c4aSArnaldo Carvalho de Melo {
675ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
676ba92732eSWang Nan 	struct machine *machine;
6774e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
6782e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
6798a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
680aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
6814e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
6822e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
6832e538c4aSArnaldo Carvalho de Melo 
684ba92732eSWang Nan 	if (!kmaps)
685ba92732eSWang Nan 		return -1;
686ba92732eSWang Nan 
687ba92732eSWang Nan 	machine = kmaps->machine;
688ba92732eSWang Nan 
6892e538c4aSArnaldo Carvalho de Melo 	while (next) {
6902e538c4aSArnaldo Carvalho de Melo 		char *module;
6912e538c4aSArnaldo Carvalho de Melo 
6922e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
6932e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
6942e538c4aSArnaldo Carvalho de Melo 
6952e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
6962e538c4aSArnaldo Carvalho de Melo 		if (module) {
69775be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
6981de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
6991de8e245SArnaldo Carvalho de Melo 
7002e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
7012e538c4aSArnaldo Carvalho de Melo 
702b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
703a1645ce1SZhang, Yanmin 				if (curr_map != map &&
704aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
70523346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
706a1645ce1SZhang, Yanmin 					/*
707a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
708a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
709a1645ce1SZhang, Yanmin 					 * points to a module and all its
710a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
711a1645ce1SZhang, Yanmin 					 * loaded.
712a1645ce1SZhang, Yanmin 					 */
713a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
714a1645ce1SZhang, Yanmin 							curr_map->type);
715af427bf5SArnaldo Carvalho de Melo 				}
716b7cece76SArnaldo Carvalho de Melo 
717a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
718a1645ce1SZhang, Yanmin 							map->type, module);
719a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7202f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
721a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
722a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
72323346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
724a1645ce1SZhang, Yanmin 					curr_map = map;
725a1645ce1SZhang, Yanmin 					goto discard_symbol;
726a1645ce1SZhang, Yanmin 				}
727a1645ce1SZhang, Yanmin 
728a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
72923346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
730b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
731af427bf5SArnaldo Carvalho de Melo 			}
73286470930SIngo Molnar 			/*
7332e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
7342e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
73586470930SIngo Molnar 			 */
7364e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
7374e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
7384e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
7392e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
740aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
74186470930SIngo Molnar 
742d9b62abaSAdrian Hunter 			if (delta) {
743d9b62abaSAdrian Hunter 				/* Kernel was relocated at boot time */
744d9b62abaSAdrian Hunter 				pos->start -= delta;
745d9b62abaSAdrian Hunter 				pos->end -= delta;
746d9b62abaSAdrian Hunter 			}
747d9b62abaSAdrian Hunter 
7488a953312SArnaldo Carvalho de Melo 			if (count == 0) {
7498a953312SArnaldo Carvalho de Melo 				curr_map = map;
7508a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
7518a953312SArnaldo Carvalho de Melo 			}
7528a953312SArnaldo Carvalho de Melo 
753aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
754a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
755a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
756a1645ce1SZhang, Yanmin 					kernel_range++);
757a1645ce1SZhang, Yanmin 			else
758a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
759a1645ce1SZhang, Yanmin 					"[kernel].%d",
7602e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
76186470930SIngo Molnar 
762aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
763aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
7642e538c4aSArnaldo Carvalho de Melo 				return -1;
7652e538c4aSArnaldo Carvalho de Melo 
766aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
767a1645ce1SZhang, Yanmin 
768aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
76937fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
770d3a7c489SArnaldo Carvalho de Melo 				dso__put(ndso);
7712e538c4aSArnaldo Carvalho de Melo 				return -1;
7722e538c4aSArnaldo Carvalho de Melo 			}
7732e538c4aSArnaldo Carvalho de Melo 
7744e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
7759de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
7762e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
777d9b62abaSAdrian Hunter 		} else if (delta) {
778d9b62abaSAdrian Hunter 			/* Kernel was relocated at boot time */
779d9b62abaSAdrian Hunter 			pos->start -= delta;
780d9b62abaSAdrian Hunter 			pos->end -= delta;
7812e538c4aSArnaldo Carvalho de Melo 		}
7828a953312SArnaldo Carvalho de Melo filter_symbol:
7834e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
7841de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
78500a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
7862e538c4aSArnaldo Carvalho de Melo 		} else {
7874e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
7884e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
7894e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
7908a953312SArnaldo Carvalho de Melo 				++moved;
7918a953312SArnaldo Carvalho de Melo 			} else
7928a953312SArnaldo Carvalho de Melo 				++count;
7939974f496SMike Galbraith 		}
79486470930SIngo Molnar 	}
79586470930SIngo Molnar 
796a1645ce1SZhang, Yanmin 	if (curr_map != map &&
797aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
79823346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
799a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
800a1645ce1SZhang, Yanmin 	}
801a1645ce1SZhang, Yanmin 
8028a953312SArnaldo Carvalho de Melo 	return count + moved;
80386470930SIngo Molnar }
80486470930SIngo Molnar 
8053f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename,
806ec80fde7SArnaldo Carvalho de Melo 				 const char *restricted_filename)
807ec80fde7SArnaldo Carvalho de Melo {
808ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
809ec80fde7SArnaldo Carvalho de Melo 
810ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
811ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
812ec80fde7SArnaldo Carvalho de Melo 
813ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
814ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
815ec80fde7SArnaldo Carvalho de Melo 			free(r);
816ec80fde7SArnaldo Carvalho de Melo 			return restricted;
817ec80fde7SArnaldo Carvalho de Melo 		}
818ec80fde7SArnaldo Carvalho de Melo 	}
819ec80fde7SArnaldo Carvalho de Melo 
820ec80fde7SArnaldo Carvalho de Melo 	return restricted;
821ec80fde7SArnaldo Carvalho de Melo }
822ec80fde7SArnaldo Carvalho de Melo 
82352afdaf9SAdrian Hunter struct module_info {
82452afdaf9SAdrian Hunter 	struct rb_node rb_node;
82552afdaf9SAdrian Hunter 	char *name;
82652afdaf9SAdrian Hunter 	u64 start;
82752afdaf9SAdrian Hunter };
82852afdaf9SAdrian Hunter 
82952afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules)
83052afdaf9SAdrian Hunter {
83152afdaf9SAdrian Hunter 	struct rb_node **p = &modules->rb_node;
83252afdaf9SAdrian Hunter 	struct rb_node *parent = NULL;
83352afdaf9SAdrian Hunter 	struct module_info *m;
83452afdaf9SAdrian Hunter 
83552afdaf9SAdrian Hunter 	while (*p != NULL) {
83652afdaf9SAdrian Hunter 		parent = *p;
83752afdaf9SAdrian Hunter 		m = rb_entry(parent, struct module_info, rb_node);
83852afdaf9SAdrian Hunter 		if (strcmp(mi->name, m->name) < 0)
83952afdaf9SAdrian Hunter 			p = &(*p)->rb_left;
84052afdaf9SAdrian Hunter 		else
84152afdaf9SAdrian Hunter 			p = &(*p)->rb_right;
84252afdaf9SAdrian Hunter 	}
84352afdaf9SAdrian Hunter 	rb_link_node(&mi->rb_node, parent, p);
84452afdaf9SAdrian Hunter 	rb_insert_color(&mi->rb_node, modules);
84552afdaf9SAdrian Hunter }
84652afdaf9SAdrian Hunter 
84752afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules)
84852afdaf9SAdrian Hunter {
84952afdaf9SAdrian Hunter 	struct module_info *mi;
85052afdaf9SAdrian Hunter 	struct rb_node *next = rb_first(modules);
85152afdaf9SAdrian Hunter 
85252afdaf9SAdrian Hunter 	while (next) {
85352afdaf9SAdrian Hunter 		mi = rb_entry(next, struct module_info, rb_node);
85452afdaf9SAdrian Hunter 		next = rb_next(&mi->rb_node);
85552afdaf9SAdrian Hunter 		rb_erase(&mi->rb_node, modules);
85674cf249dSArnaldo Carvalho de Melo 		zfree(&mi->name);
85752afdaf9SAdrian Hunter 		free(mi);
85852afdaf9SAdrian Hunter 	}
85952afdaf9SAdrian Hunter }
86052afdaf9SAdrian Hunter 
86152afdaf9SAdrian Hunter static struct module_info *find_module(const char *name,
86252afdaf9SAdrian Hunter 				       struct rb_root *modules)
86352afdaf9SAdrian Hunter {
86452afdaf9SAdrian Hunter 	struct rb_node *n = modules->rb_node;
86552afdaf9SAdrian Hunter 
86652afdaf9SAdrian Hunter 	while (n) {
86752afdaf9SAdrian Hunter 		struct module_info *m;
86852afdaf9SAdrian Hunter 		int cmp;
86952afdaf9SAdrian Hunter 
87052afdaf9SAdrian Hunter 		m = rb_entry(n, struct module_info, rb_node);
87152afdaf9SAdrian Hunter 		cmp = strcmp(name, m->name);
87252afdaf9SAdrian Hunter 		if (cmp < 0)
87352afdaf9SAdrian Hunter 			n = n->rb_left;
87452afdaf9SAdrian Hunter 		else if (cmp > 0)
87552afdaf9SAdrian Hunter 			n = n->rb_right;
87652afdaf9SAdrian Hunter 		else
87752afdaf9SAdrian Hunter 			return m;
87852afdaf9SAdrian Hunter 	}
87952afdaf9SAdrian Hunter 
88052afdaf9SAdrian Hunter 	return NULL;
88152afdaf9SAdrian Hunter }
88252afdaf9SAdrian Hunter 
88352afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start)
88452afdaf9SAdrian Hunter {
88552afdaf9SAdrian Hunter 	struct rb_root *modules = arg;
88652afdaf9SAdrian Hunter 	struct module_info *mi;
88752afdaf9SAdrian Hunter 
88852afdaf9SAdrian Hunter 	mi = zalloc(sizeof(struct module_info));
88952afdaf9SAdrian Hunter 	if (!mi)
89052afdaf9SAdrian Hunter 		return -ENOMEM;
89152afdaf9SAdrian Hunter 
89252afdaf9SAdrian Hunter 	mi->name = strdup(name);
89352afdaf9SAdrian Hunter 	mi->start = start;
89452afdaf9SAdrian Hunter 
89552afdaf9SAdrian Hunter 	if (!mi->name) {
89652afdaf9SAdrian Hunter 		free(mi);
89752afdaf9SAdrian Hunter 		return -ENOMEM;
89852afdaf9SAdrian Hunter 	}
89952afdaf9SAdrian Hunter 
90052afdaf9SAdrian Hunter 	add_module(mi, modules);
90152afdaf9SAdrian Hunter 
90252afdaf9SAdrian Hunter 	return 0;
90352afdaf9SAdrian Hunter }
90452afdaf9SAdrian Hunter 
90552afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules)
90652afdaf9SAdrian Hunter {
90752afdaf9SAdrian Hunter 	if (symbol__restricted_filename(filename, "/proc/modules"))
90852afdaf9SAdrian Hunter 		return -1;
90952afdaf9SAdrian Hunter 
91052afdaf9SAdrian Hunter 	if (modules__parse(filename, modules, __read_proc_modules)) {
91152afdaf9SAdrian Hunter 		delete_modules(modules);
91252afdaf9SAdrian Hunter 		return -1;
91352afdaf9SAdrian Hunter 	}
91452afdaf9SAdrian Hunter 
91552afdaf9SAdrian Hunter 	return 0;
91652afdaf9SAdrian Hunter }
91752afdaf9SAdrian Hunter 
918fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to)
919fc1b691dSAdrian Hunter {
920fc1b691dSAdrian Hunter 	struct rb_root from_modules = RB_ROOT;
921fc1b691dSAdrian Hunter 	struct rb_root to_modules = RB_ROOT;
922fc1b691dSAdrian Hunter 	struct rb_node *from_node, *to_node;
923fc1b691dSAdrian Hunter 	struct module_info *from_m, *to_m;
924fc1b691dSAdrian Hunter 	int ret = -1;
925fc1b691dSAdrian Hunter 
926fc1b691dSAdrian Hunter 	if (read_proc_modules(from, &from_modules))
927fc1b691dSAdrian Hunter 		return -1;
928fc1b691dSAdrian Hunter 
929fc1b691dSAdrian Hunter 	if (read_proc_modules(to, &to_modules))
930fc1b691dSAdrian Hunter 		goto out_delete_from;
931fc1b691dSAdrian Hunter 
932fc1b691dSAdrian Hunter 	from_node = rb_first(&from_modules);
933fc1b691dSAdrian Hunter 	to_node = rb_first(&to_modules);
934fc1b691dSAdrian Hunter 	while (from_node) {
935fc1b691dSAdrian Hunter 		if (!to_node)
936fc1b691dSAdrian Hunter 			break;
937fc1b691dSAdrian Hunter 
938fc1b691dSAdrian Hunter 		from_m = rb_entry(from_node, struct module_info, rb_node);
939fc1b691dSAdrian Hunter 		to_m = rb_entry(to_node, struct module_info, rb_node);
940fc1b691dSAdrian Hunter 
941fc1b691dSAdrian Hunter 		if (from_m->start != to_m->start ||
942fc1b691dSAdrian Hunter 		    strcmp(from_m->name, to_m->name))
943fc1b691dSAdrian Hunter 			break;
944fc1b691dSAdrian Hunter 
945fc1b691dSAdrian Hunter 		from_node = rb_next(from_node);
946fc1b691dSAdrian Hunter 		to_node = rb_next(to_node);
947fc1b691dSAdrian Hunter 	}
948fc1b691dSAdrian Hunter 
949fc1b691dSAdrian Hunter 	if (!from_node && !to_node)
950fc1b691dSAdrian Hunter 		ret = 0;
951fc1b691dSAdrian Hunter 
952fc1b691dSAdrian Hunter 	delete_modules(&to_modules);
953fc1b691dSAdrian Hunter out_delete_from:
954fc1b691dSAdrian Hunter 	delete_modules(&from_modules);
955fc1b691dSAdrian Hunter 
956fc1b691dSAdrian Hunter 	return ret;
957fc1b691dSAdrian Hunter }
958fc1b691dSAdrian Hunter 
95952afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map,
96052afdaf9SAdrian Hunter 				  struct map_groups *kmaps)
96152afdaf9SAdrian Hunter {
96252afdaf9SAdrian Hunter 	struct rb_root modules = RB_ROOT;
96352afdaf9SAdrian Hunter 	struct map *old_map;
96452afdaf9SAdrian Hunter 	int err;
96552afdaf9SAdrian Hunter 
96652afdaf9SAdrian Hunter 	err = read_proc_modules(filename, &modules);
96752afdaf9SAdrian Hunter 	if (err)
96852afdaf9SAdrian Hunter 		return err;
96952afdaf9SAdrian Hunter 
97052afdaf9SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
97152afdaf9SAdrian Hunter 	while (old_map) {
97252afdaf9SAdrian Hunter 		struct map *next = map_groups__next(old_map);
97352afdaf9SAdrian Hunter 		struct module_info *mi;
97452afdaf9SAdrian Hunter 
97552afdaf9SAdrian Hunter 		if (old_map == map || old_map->start == map->start) {
97652afdaf9SAdrian Hunter 			/* The kernel map */
97752afdaf9SAdrian Hunter 			old_map = next;
97852afdaf9SAdrian Hunter 			continue;
97952afdaf9SAdrian Hunter 		}
98052afdaf9SAdrian Hunter 
98152afdaf9SAdrian Hunter 		/* Module must be in memory at the same address */
98252afdaf9SAdrian Hunter 		mi = find_module(old_map->dso->short_name, &modules);
98352afdaf9SAdrian Hunter 		if (!mi || mi->start != old_map->start) {
98452afdaf9SAdrian Hunter 			err = -EINVAL;
98552afdaf9SAdrian Hunter 			goto out;
98652afdaf9SAdrian Hunter 		}
98752afdaf9SAdrian Hunter 
98852afdaf9SAdrian Hunter 		old_map = next;
98952afdaf9SAdrian Hunter 	}
99052afdaf9SAdrian Hunter out:
99152afdaf9SAdrian Hunter 	delete_modules(&modules);
99252afdaf9SAdrian Hunter 	return err;
99352afdaf9SAdrian Hunter }
99452afdaf9SAdrian Hunter 
99552afdaf9SAdrian Hunter /*
99652afdaf9SAdrian Hunter  * If kallsyms is referenced by name then we look for filename in the same
99752afdaf9SAdrian Hunter  * directory.
99852afdaf9SAdrian Hunter  */
99952afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename,
100052afdaf9SAdrian Hunter 					    const char *base_name,
100152afdaf9SAdrian Hunter 					    const char *kallsyms_filename)
100252afdaf9SAdrian Hunter {
100352afdaf9SAdrian Hunter 	char *name;
100452afdaf9SAdrian Hunter 
100552afdaf9SAdrian Hunter 	strcpy(filename, kallsyms_filename);
100652afdaf9SAdrian Hunter 	name = strrchr(filename, '/');
100752afdaf9SAdrian Hunter 	if (!name)
100852afdaf9SAdrian Hunter 		return false;
100952afdaf9SAdrian Hunter 
101052afdaf9SAdrian Hunter 	name += 1;
101152afdaf9SAdrian Hunter 
101252afdaf9SAdrian Hunter 	if (!strcmp(name, "kallsyms")) {
101352afdaf9SAdrian Hunter 		strcpy(name, base_name);
101452afdaf9SAdrian Hunter 		return true;
101552afdaf9SAdrian Hunter 	}
101652afdaf9SAdrian Hunter 
101752afdaf9SAdrian Hunter 	return false;
101852afdaf9SAdrian Hunter }
101952afdaf9SAdrian Hunter 
102052afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename,
102152afdaf9SAdrian Hunter 				  struct map *map)
102252afdaf9SAdrian Hunter {
1023ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
102452afdaf9SAdrian Hunter 	char modules_filename[PATH_MAX];
102552afdaf9SAdrian Hunter 
1026ba92732eSWang Nan 	if (!kmaps)
1027ba92732eSWang Nan 		return -EINVAL;
1028ba92732eSWang Nan 
102952afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(modules_filename, "modules",
103052afdaf9SAdrian Hunter 					     kallsyms_filename))
103152afdaf9SAdrian Hunter 		return -EINVAL;
103252afdaf9SAdrian Hunter 
103352afdaf9SAdrian Hunter 	if (do_validate_kcore_modules(modules_filename, map, kmaps))
103452afdaf9SAdrian Hunter 		return -EINVAL;
103552afdaf9SAdrian Hunter 
103652afdaf9SAdrian Hunter 	return 0;
103752afdaf9SAdrian Hunter }
103852afdaf9SAdrian Hunter 
1039a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename,
1040a00d28cbSAdrian Hunter 				    struct map *map)
1041a00d28cbSAdrian Hunter {
1042a00d28cbSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1043a00d28cbSAdrian Hunter 
1044ba92732eSWang Nan 	if (!kmap)
1045ba92732eSWang Nan 		return -EINVAL;
1046ba92732eSWang Nan 
1047a00d28cbSAdrian Hunter 	if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1048a00d28cbSAdrian Hunter 		u64 start;
1049a00d28cbSAdrian Hunter 
1050a00d28cbSAdrian Hunter 		start = kallsyms__get_function_start(kallsyms_filename,
1051a00d28cbSAdrian Hunter 						     kmap->ref_reloc_sym->name);
1052a00d28cbSAdrian Hunter 		if (start != kmap->ref_reloc_sym->addr)
1053a00d28cbSAdrian Hunter 			return -EINVAL;
1054a00d28cbSAdrian Hunter 	}
1055a00d28cbSAdrian Hunter 
1056a00d28cbSAdrian Hunter 	return validate_kcore_modules(kallsyms_filename, map);
1057a00d28cbSAdrian Hunter }
1058a00d28cbSAdrian Hunter 
10598e0cf965SAdrian Hunter struct kcore_mapfn_data {
10608e0cf965SAdrian Hunter 	struct dso *dso;
10618e0cf965SAdrian Hunter 	enum map_type type;
10628e0cf965SAdrian Hunter 	struct list_head maps;
10638e0cf965SAdrian Hunter };
10648e0cf965SAdrian Hunter 
10658e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
10668e0cf965SAdrian Hunter {
10678e0cf965SAdrian Hunter 	struct kcore_mapfn_data *md = data;
10688e0cf965SAdrian Hunter 	struct map *map;
10698e0cf965SAdrian Hunter 
10708e0cf965SAdrian Hunter 	map = map__new2(start, md->dso, md->type);
10718e0cf965SAdrian Hunter 	if (map == NULL)
10728e0cf965SAdrian Hunter 		return -ENOMEM;
10738e0cf965SAdrian Hunter 
10748e0cf965SAdrian Hunter 	map->end = map->start + len;
10758e0cf965SAdrian Hunter 	map->pgoff = pgoff;
10768e0cf965SAdrian Hunter 
10778e0cf965SAdrian Hunter 	list_add(&map->node, &md->maps);
10788e0cf965SAdrian Hunter 
10798e0cf965SAdrian Hunter 	return 0;
10808e0cf965SAdrian Hunter }
10818e0cf965SAdrian Hunter 
10828e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map,
10838e0cf965SAdrian Hunter 			   const char *kallsyms_filename)
10848e0cf965SAdrian Hunter {
1085ba92732eSWang Nan 	struct map_groups *kmaps = map__kmaps(map);
1086ba92732eSWang Nan 	struct machine *machine;
10878e0cf965SAdrian Hunter 	struct kcore_mapfn_data md;
10888e0cf965SAdrian Hunter 	struct map *old_map, *new_map, *replacement_map = NULL;
10898e0cf965SAdrian Hunter 	bool is_64_bit;
10908e0cf965SAdrian Hunter 	int err, fd;
10918e0cf965SAdrian Hunter 	char kcore_filename[PATH_MAX];
10928e0cf965SAdrian Hunter 	struct symbol *sym;
10938e0cf965SAdrian Hunter 
1094ba92732eSWang Nan 	if (!kmaps)
1095ba92732eSWang Nan 		return -EINVAL;
1096ba92732eSWang Nan 
1097ba92732eSWang Nan 	machine = kmaps->machine;
1098ba92732eSWang Nan 
10998e0cf965SAdrian Hunter 	/* This function requires that the map is the kernel map */
11008e0cf965SAdrian Hunter 	if (map != machine->vmlinux_maps[map->type])
11018e0cf965SAdrian Hunter 		return -EINVAL;
11028e0cf965SAdrian Hunter 
110352afdaf9SAdrian Hunter 	if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
11048e0cf965SAdrian Hunter 					     kallsyms_filename))
11058e0cf965SAdrian Hunter 		return -EINVAL;
11068e0cf965SAdrian Hunter 
1107a00d28cbSAdrian Hunter 	/* Modules and kernel must be present at their original addresses */
1108a00d28cbSAdrian Hunter 	if (validate_kcore_addresses(kallsyms_filename, map))
110952afdaf9SAdrian Hunter 		return -EINVAL;
111052afdaf9SAdrian Hunter 
11118e0cf965SAdrian Hunter 	md.dso = dso;
11128e0cf965SAdrian Hunter 	md.type = map->type;
11138e0cf965SAdrian Hunter 	INIT_LIST_HEAD(&md.maps);
11148e0cf965SAdrian Hunter 
11158e0cf965SAdrian Hunter 	fd = open(kcore_filename, O_RDONLY);
111636c8bb56SLi Zhang 	if (fd < 0) {
1117133de940SAdrian Hunter 		pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n",
111836c8bb56SLi Zhang 			 kcore_filename);
11198e0cf965SAdrian Hunter 		return -EINVAL;
112036c8bb56SLi Zhang 	}
11218e0cf965SAdrian Hunter 
11228e0cf965SAdrian Hunter 	/* Read new maps into temporary lists */
11238e0cf965SAdrian Hunter 	err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
11248e0cf965SAdrian Hunter 			      &is_64_bit);
11258e0cf965SAdrian Hunter 	if (err)
11268e0cf965SAdrian Hunter 		goto out_err;
1127c6d8f2a4SAdrian Hunter 	dso->is_64_bit = is_64_bit;
11288e0cf965SAdrian Hunter 
11298e0cf965SAdrian Hunter 	if (list_empty(&md.maps)) {
11308e0cf965SAdrian Hunter 		err = -EINVAL;
11318e0cf965SAdrian Hunter 		goto out_err;
11328e0cf965SAdrian Hunter 	}
11338e0cf965SAdrian Hunter 
11348e0cf965SAdrian Hunter 	/* Remove old maps */
11358e0cf965SAdrian Hunter 	old_map = map_groups__first(kmaps, map->type);
11368e0cf965SAdrian Hunter 	while (old_map) {
11378e0cf965SAdrian Hunter 		struct map *next = map_groups__next(old_map);
11388e0cf965SAdrian Hunter 
11398e0cf965SAdrian Hunter 		if (old_map != map)
11408e0cf965SAdrian Hunter 			map_groups__remove(kmaps, old_map);
11418e0cf965SAdrian Hunter 		old_map = next;
11428e0cf965SAdrian Hunter 	}
11438e0cf965SAdrian Hunter 
11448e0cf965SAdrian Hunter 	/* Find the kernel map using the first symbol */
11458e0cf965SAdrian Hunter 	sym = dso__first_symbol(dso, map->type);
11468e0cf965SAdrian Hunter 	list_for_each_entry(new_map, &md.maps, node) {
11478e0cf965SAdrian Hunter 		if (sym && sym->start >= new_map->start &&
11488e0cf965SAdrian Hunter 		    sym->start < new_map->end) {
11498e0cf965SAdrian Hunter 			replacement_map = new_map;
11508e0cf965SAdrian Hunter 			break;
11518e0cf965SAdrian Hunter 		}
11528e0cf965SAdrian Hunter 	}
11538e0cf965SAdrian Hunter 
11548e0cf965SAdrian Hunter 	if (!replacement_map)
11558e0cf965SAdrian Hunter 		replacement_map = list_entry(md.maps.next, struct map, node);
11568e0cf965SAdrian Hunter 
11578e0cf965SAdrian Hunter 	/* Add new maps */
11588e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
11598e0cf965SAdrian Hunter 		new_map = list_entry(md.maps.next, struct map, node);
1160facf3f06SArnaldo Carvalho de Melo 		list_del_init(&new_map->node);
11618e0cf965SAdrian Hunter 		if (new_map == replacement_map) {
11628e0cf965SAdrian Hunter 			map->start	= new_map->start;
11638e0cf965SAdrian Hunter 			map->end	= new_map->end;
11648e0cf965SAdrian Hunter 			map->pgoff	= new_map->pgoff;
11658e0cf965SAdrian Hunter 			map->map_ip	= new_map->map_ip;
11668e0cf965SAdrian Hunter 			map->unmap_ip	= new_map->unmap_ip;
11678e0cf965SAdrian Hunter 			/* Ensure maps are correctly ordered */
116884c2cafaSArnaldo Carvalho de Melo 			map__get(map);
11698e0cf965SAdrian Hunter 			map_groups__remove(kmaps, map);
11708e0cf965SAdrian Hunter 			map_groups__insert(kmaps, map);
117184c2cafaSArnaldo Carvalho de Melo 			map__put(map);
11728e0cf965SAdrian Hunter 		} else {
11738e0cf965SAdrian Hunter 			map_groups__insert(kmaps, new_map);
11748e0cf965SAdrian Hunter 		}
117584c2cafaSArnaldo Carvalho de Melo 
117684c2cafaSArnaldo Carvalho de Melo 		map__put(new_map);
11778e0cf965SAdrian Hunter 	}
11788e0cf965SAdrian Hunter 
11798e0cf965SAdrian Hunter 	/*
11808e0cf965SAdrian Hunter 	 * Set the data type and long name so that kcore can be read via
11818e0cf965SAdrian Hunter 	 * dso__data_read_addr().
11828e0cf965SAdrian Hunter 	 */
11838e0cf965SAdrian Hunter 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
11845f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
11858e0cf965SAdrian Hunter 	else
11865f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__KCORE;
11877e155d4dSArnaldo Carvalho de Melo 	dso__set_long_name(dso, strdup(kcore_filename), true);
11888e0cf965SAdrian Hunter 
11898e0cf965SAdrian Hunter 	close(fd);
11908e0cf965SAdrian Hunter 
11918e0cf965SAdrian Hunter 	if (map->type == MAP__FUNCTION)
11928e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel object code\n", kcore_filename);
11938e0cf965SAdrian Hunter 	else
11948e0cf965SAdrian Hunter 		pr_debug("Using %s for kernel data\n", kcore_filename);
11958e0cf965SAdrian Hunter 
11968e0cf965SAdrian Hunter 	return 0;
11978e0cf965SAdrian Hunter 
11988e0cf965SAdrian Hunter out_err:
11998e0cf965SAdrian Hunter 	while (!list_empty(&md.maps)) {
12008e0cf965SAdrian Hunter 		map = list_entry(md.maps.next, struct map, node);
1201facf3f06SArnaldo Carvalho de Melo 		list_del_init(&map->node);
120284c2cafaSArnaldo Carvalho de Melo 		map__put(map);
12038e0cf965SAdrian Hunter 	}
12048e0cf965SAdrian Hunter 	close(fd);
12058e0cf965SAdrian Hunter 	return -EINVAL;
12068e0cf965SAdrian Hunter }
12078e0cf965SAdrian Hunter 
1208d9b62abaSAdrian Hunter /*
1209d9b62abaSAdrian Hunter  * If the kernel is relocated at boot time, kallsyms won't match.  Compute the
1210d9b62abaSAdrian Hunter  * delta based on the relocation reference symbol.
1211d9b62abaSAdrian Hunter  */
1212d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1213d9b62abaSAdrian Hunter {
1214d9b62abaSAdrian Hunter 	struct kmap *kmap = map__kmap(map);
1215d9b62abaSAdrian Hunter 	u64 addr;
1216d9b62abaSAdrian Hunter 
1217ba92732eSWang Nan 	if (!kmap)
1218ba92732eSWang Nan 		return -1;
1219ba92732eSWang Nan 
1220d9b62abaSAdrian Hunter 	if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1221d9b62abaSAdrian Hunter 		return 0;
1222d9b62abaSAdrian Hunter 
1223d9b62abaSAdrian Hunter 	addr = kallsyms__get_function_start(filename,
1224d9b62abaSAdrian Hunter 					    kmap->ref_reloc_sym->name);
1225d9b62abaSAdrian Hunter 	if (!addr)
1226d9b62abaSAdrian Hunter 		return -1;
1227d9b62abaSAdrian Hunter 
1228d9b62abaSAdrian Hunter 	*delta = addr - kmap->ref_reloc_sym->addr;
1229d9b62abaSAdrian Hunter 	return 0;
1230d9b62abaSAdrian Hunter }
1231d9b62abaSAdrian Hunter 
1232e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename,
1233e02092b9SArnaldo Carvalho de Melo 			 struct map *map, bool no_kcore, symbol_filter_t filter)
12342e538c4aSArnaldo Carvalho de Melo {
1235d9b62abaSAdrian Hunter 	u64 delta = 0;
1236d9b62abaSAdrian Hunter 
1237ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1238ec80fde7SArnaldo Carvalho de Melo 		return -1;
1239ec80fde7SArnaldo Carvalho de Melo 
1240aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
12412e538c4aSArnaldo Carvalho de Melo 		return -1;
12422e538c4aSArnaldo Carvalho de Melo 
1243d9b62abaSAdrian Hunter 	if (kallsyms__delta(map, filename, &delta))
1244d9b62abaSAdrian Hunter 		return -1;
1245d9b62abaSAdrian Hunter 
12463f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
1247*432746f8SArnaldo Carvalho de Melo 	symbols__fixup_duplicate(&dso->symbols[map->type]);
12483f5a4272SAnton Blanchard 
1249aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
125044f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1251a1645ce1SZhang, Yanmin 	else
125244f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
12532e538c4aSArnaldo Carvalho de Melo 
1254e02092b9SArnaldo Carvalho de Melo 	if (!no_kcore && !dso__load_kcore(dso, map, filename))
12558e0cf965SAdrian Hunter 		return dso__split_kallsyms_for_kcore(dso, map, filter);
12568e0cf965SAdrian Hunter 	else
1257d9b62abaSAdrian Hunter 		return dso__split_kallsyms(dso, map, delta, filter);
1258af427bf5SArnaldo Carvalho de Melo }
1259af427bf5SArnaldo Carvalho de Melo 
1260e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
1261e02092b9SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
1262e02092b9SArnaldo Carvalho de Melo {
1263e02092b9SArnaldo Carvalho de Melo 	return __dso__load_kallsyms(dso, filename, map, false, filter);
1264e02092b9SArnaldo Carvalho de Melo }
1265e02092b9SArnaldo Carvalho de Melo 
1266aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
12676beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
126880d496beSPekka Enberg {
126980d496beSPekka Enberg 	char *line = NULL;
127080d496beSPekka Enberg 	size_t n;
127180d496beSPekka Enberg 	FILE *file;
127280d496beSPekka Enberg 	int nr_syms = 0;
127380d496beSPekka Enberg 
1274aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
127580d496beSPekka Enberg 	if (file == NULL)
127680d496beSPekka Enberg 		goto out_failure;
127780d496beSPekka Enberg 
127880d496beSPekka Enberg 	while (!feof(file)) {
12799cffa8d5SPaul Mackerras 		u64 start, size;
128080d496beSPekka Enberg 		struct symbol *sym;
128180d496beSPekka Enberg 		int line_len, len;
128280d496beSPekka Enberg 
128380d496beSPekka Enberg 		line_len = getline(&line, &n, file);
128480d496beSPekka Enberg 		if (line_len < 0)
128580d496beSPekka Enberg 			break;
128680d496beSPekka Enberg 
128780d496beSPekka Enberg 		if (!line)
128880d496beSPekka Enberg 			goto out_failure;
128980d496beSPekka Enberg 
129080d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
129180d496beSPekka Enberg 
129280d496beSPekka Enberg 		len = hex2u64(line, &start);
129380d496beSPekka Enberg 
129480d496beSPekka Enberg 		len++;
129580d496beSPekka Enberg 		if (len + 2 >= line_len)
129680d496beSPekka Enberg 			continue;
129780d496beSPekka Enberg 
129880d496beSPekka Enberg 		len += hex2u64(line + len, &size);
129980d496beSPekka Enberg 
130080d496beSPekka Enberg 		len++;
130180d496beSPekka Enberg 		if (len + 2 >= line_len)
130280d496beSPekka Enberg 			continue;
130380d496beSPekka Enberg 
1304c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
130580d496beSPekka Enberg 
130680d496beSPekka Enberg 		if (sym == NULL)
130780d496beSPekka Enberg 			goto out_delete_line;
130880d496beSPekka Enberg 
1309439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
131000a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
131180d496beSPekka Enberg 		else {
1312aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
131380d496beSPekka Enberg 			nr_syms++;
131480d496beSPekka Enberg 		}
131580d496beSPekka Enberg 	}
131680d496beSPekka Enberg 
131780d496beSPekka Enberg 	free(line);
131880d496beSPekka Enberg 	fclose(file);
131980d496beSPekka Enberg 
132080d496beSPekka Enberg 	return nr_syms;
132180d496beSPekka Enberg 
132280d496beSPekka Enberg out_delete_line:
132380d496beSPekka Enberg 	free(line);
132480d496beSPekka Enberg out_failure:
132580d496beSPekka Enberg 	return -1;
132680d496beSPekka Enberg }
132780d496beSPekka Enberg 
13281029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
13291029f9feSNamhyung Kim 					   enum dso_binary_type type)
13301029f9feSNamhyung Kim {
13311029f9feSNamhyung Kim 	switch (type) {
13321029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__JAVA_JIT:
13331029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__DEBUGLINK:
13341029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
13351029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
13361029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
13371029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
13381029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
13391029f9feSNamhyung Kim 		return !kmod && dso->kernel == DSO_TYPE_USER;
13401029f9feSNamhyung Kim 
13411029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KALLSYMS:
13421029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__VMLINUX:
13431029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__KCORE:
13441029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_KERNEL;
13451029f9feSNamhyung Kim 
13461029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
13471029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
13481029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KCORE:
13491029f9feSNamhyung Kim 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
13501029f9feSNamhyung Kim 
13511029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE:
1352c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
13531029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1354c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
13551029f9feSNamhyung Kim 		/*
13561029f9feSNamhyung Kim 		 * kernel modules know their symtab type - it's set when
13579f2de315SArnaldo Carvalho de Melo 		 * creating a module dso in machine__findnew_module_map().
13581029f9feSNamhyung Kim 		 */
13591029f9feSNamhyung Kim 		return kmod && dso->symtab_type == type;
13601029f9feSNamhyung Kim 
13611029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
13621029f9feSNamhyung Kim 		return true;
13631029f9feSNamhyung Kim 
13641029f9feSNamhyung Kim 	case DSO_BINARY_TYPE__NOT_FOUND:
13651029f9feSNamhyung Kim 	default:
13661029f9feSNamhyung Kim 		return false;
13671029f9feSNamhyung Kim 	}
13681029f9feSNamhyung Kim }
13691029f9feSNamhyung Kim 
1370aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
137186470930SIngo Molnar {
1372c338aee8SArnaldo Carvalho de Melo 	char *name;
137386470930SIngo Molnar 	int ret = -1;
137444f24cb3SJiri Olsa 	u_int i;
137523346f21SArnaldo Carvalho de Melo 	struct machine *machine;
137644f24cb3SJiri Olsa 	char *root_dir = (char *) "";
13773aafe5aeSCody P Schafer 	int ss_pos = 0;
13783aafe5aeSCody P Schafer 	struct symsrc ss_[2];
13793aafe5aeSCody P Schafer 	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
13801029f9feSNamhyung Kim 	bool kmod;
13815baecbcdSDima Kogan 	unsigned char build_id[BUILD_ID_SIZE];
138286470930SIngo Molnar 
13834a936edcSNamhyung Kim 	pthread_mutex_lock(&dso->lock);
138466bd8424SArnaldo Carvalho de Melo 
13854a936edcSNamhyung Kim 	/* check again under the dso->lock */
13864a936edcSNamhyung Kim 	if (dso__loaded(dso, map->type)) {
13874a936edcSNamhyung Kim 		ret = 1;
13884a936edcSNamhyung Kim 		goto out;
13894a936edcSNamhyung Kim 	}
13904a936edcSNamhyung Kim 
13914a936edcSNamhyung Kim 	if (dso->kernel) {
1392aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel == DSO_TYPE_KERNEL)
13934a936edcSNamhyung Kim 			ret = dso__load_kernel_sym(dso, map, filter);
1394aeafcbafSArnaldo Carvalho de Melo 		else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
13954a936edcSNamhyung Kim 			ret = dso__load_guest_kernel_sym(dso, map, filter);
13964a936edcSNamhyung Kim 
13974a936edcSNamhyung Kim 		goto out;
13984a936edcSNamhyung Kim 	}
1399a1645ce1SZhang, Yanmin 
140023346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
140123346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1402a1645ce1SZhang, Yanmin 	else
140323346f21SArnaldo Carvalho de Melo 		machine = NULL;
1404c338aee8SArnaldo Carvalho de Melo 
1405aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1406f5812a7aSArnaldo Carvalho de Melo 
1407aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1408981c1252SPekka Enberg 		struct stat st;
1409981c1252SPekka Enberg 
1410e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
14114a936edcSNamhyung Kim 			goto out;
1412981c1252SPekka Enberg 
14132059fc7aSArnaldo Carvalho de Melo 		if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
1414981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
14152059fc7aSArnaldo Carvalho de Melo 				   "ignoring it (use -f to override).\n", dso->name);
14164a936edcSNamhyung Kim 			goto out;
1417981c1252SPekka Enberg 		}
1418981c1252SPekka Enberg 
1419aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
142044f24cb3SJiri Olsa 		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
142144f24cb3SJiri Olsa 					     DSO_BINARY_TYPE__NOT_FOUND;
14224a936edcSNamhyung Kim 		goto out;
142394cb9e38SArnaldo Carvalho de Melo 	}
142494cb9e38SArnaldo Carvalho de Melo 
142544f24cb3SJiri Olsa 	if (machine)
142644f24cb3SJiri Olsa 		root_dir = machine->root_dir;
142744f24cb3SJiri Olsa 
1428164c800eSDavid Ahern 	name = malloc(PATH_MAX);
1429164c800eSDavid Ahern 	if (!name)
14304a936edcSNamhyung Kim 		goto out;
1431164c800eSDavid Ahern 
14321029f9feSNamhyung Kim 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1433c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
1434c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
1435c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
14361029f9feSNamhyung Kim 
14375baecbcdSDima Kogan 
14385baecbcdSDima Kogan 	/*
14395baecbcdSDima Kogan 	 * Read the build id if possible. This is required for
14405baecbcdSDima Kogan 	 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
14415baecbcdSDima Kogan 	 */
1442ed7b630bSJiri Olsa 	if (is_regular_file(dso->long_name) &&
144340356721SJiri Olsa 	    filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
14445baecbcdSDima Kogan 		dso__set_build_id(dso, build_id);
14455baecbcdSDima Kogan 
14461029f9feSNamhyung Kim 	/*
14471029f9feSNamhyung Kim 	 * Iterate over candidate debug images.
14483aafe5aeSCody P Schafer 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
14493aafe5aeSCody P Schafer 	 * and/or opd section) for processing.
14506da80ce8SDave Martin 	 */
145144f24cb3SJiri Olsa 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
14523aafe5aeSCody P Schafer 		struct symsrc *ss = &ss_[ss_pos];
14533aafe5aeSCody P Schafer 		bool next_slot = false;
145444f24cb3SJiri Olsa 
1455005f9294SCody P Schafer 		enum dso_binary_type symtab_type = binary_type_symtab[i];
145644f24cb3SJiri Olsa 
14571029f9feSNamhyung Kim 		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
14581029f9feSNamhyung Kim 			continue;
14591029f9feSNamhyung Kim 
1460ee4e9625SArnaldo Carvalho de Melo 		if (dso__read_binary_type_filename(dso, symtab_type,
146144f24cb3SJiri Olsa 						   root_dir, name, PATH_MAX))
14626da80ce8SDave Martin 			continue;
146386470930SIngo Molnar 
146440356721SJiri Olsa 		if (!is_regular_file(name))
146540356721SJiri Olsa 			continue;
146640356721SJiri Olsa 
14676da80ce8SDave Martin 		/* Name is now the name of the next image to try */
14683aafe5aeSCody P Schafer 		if (symsrc__init(ss, dso, name, symtab_type) < 0)
14696da80ce8SDave Martin 			continue;
14706da80ce8SDave Martin 
14713aafe5aeSCody P Schafer 		if (!syms_ss && symsrc__has_symtab(ss)) {
14723aafe5aeSCody P Schafer 			syms_ss = ss;
14733aafe5aeSCody P Schafer 			next_slot = true;
14740058aef6SAdrian Hunter 			if (!dso->symsrc_filename)
14750058aef6SAdrian Hunter 				dso->symsrc_filename = strdup(name);
1476d26cd12bSCody P Schafer 		}
1477d26cd12bSCody P Schafer 
14783aafe5aeSCody P Schafer 		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
14793aafe5aeSCody P Schafer 			runtime_ss = ss;
14803aafe5aeSCody P Schafer 			next_slot = true;
1481a44f605bSCody P Schafer 		}
148286470930SIngo Molnar 
14833aafe5aeSCody P Schafer 		if (next_slot) {
14843aafe5aeSCody P Schafer 			ss_pos++;
148533ff581eSJiri Olsa 
14863aafe5aeSCody P Schafer 			if (syms_ss && runtime_ss)
14876da80ce8SDave Martin 				break;
148898e9f03bSNamhyung Kim 		} else {
148998e9f03bSNamhyung Kim 			symsrc__destroy(ss);
1490a25e46c4SArnaldo Carvalho de Melo 		}
14913aafe5aeSCody P Schafer 
14926da80ce8SDave Martin 	}
14936da80ce8SDave Martin 
14943aafe5aeSCody P Schafer 	if (!runtime_ss && !syms_ss)
14953aafe5aeSCody P Schafer 		goto out_free;
14963aafe5aeSCody P Schafer 
14973aafe5aeSCody P Schafer 	if (runtime_ss && !syms_ss) {
14983aafe5aeSCody P Schafer 		syms_ss = runtime_ss;
149960e4b10cSArnaldo Carvalho de Melo 	}
150060e4b10cSArnaldo Carvalho de Melo 
15013aafe5aeSCody P Schafer 	/* We'll have to hope for the best */
15023aafe5aeSCody P Schafer 	if (!runtime_ss && syms_ss)
15033aafe5aeSCody P Schafer 		runtime_ss = syms_ss;
15043aafe5aeSCody P Schafer 
1505e7ee4047SWang Nan 	if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
1506e7ee4047SWang Nan 		if (dso__build_id_is_kmod(dso, name, PATH_MAX))
1507e7ee4047SWang Nan 			kmod = true;
1508e7ee4047SWang Nan 
15091029f9feSNamhyung Kim 	if (syms_ss)
15101029f9feSNamhyung Kim 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
15111029f9feSNamhyung Kim 	else
15123aafe5aeSCody P Schafer 		ret = -1;
15133aafe5aeSCody P Schafer 
1514f47b58b7SDavid Ahern 	if (ret > 0) {
15153aafe5aeSCody P Schafer 		int nr_plt;
15163aafe5aeSCody P Schafer 
15173aafe5aeSCody P Schafer 		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
15183aafe5aeSCody P Schafer 		if (nr_plt > 0)
15193aafe5aeSCody P Schafer 			ret += nr_plt;
15203aafe5aeSCody P Schafer 	}
15213aafe5aeSCody P Schafer 
15223aafe5aeSCody P Schafer 	for (; ss_pos > 0; ss_pos--)
15233aafe5aeSCody P Schafer 		symsrc__destroy(&ss_[ss_pos - 1]);
15243aafe5aeSCody P Schafer out_free:
152586470930SIngo Molnar 	free(name);
1526aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
15274a936edcSNamhyung Kim 		ret = 0;
15284a936edcSNamhyung Kim out:
15294a936edcSNamhyung Kim 	dso__set_loaded(dso, map->type);
15304a936edcSNamhyung Kim 	pthread_mutex_unlock(&dso->lock);
15314a936edcSNamhyung Kim 
153286470930SIngo Molnar 	return ret;
153386470930SIngo Molnar }
153486470930SIngo Molnar 
1535aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
153679406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1537439d473bSArnaldo Carvalho de Melo {
15381eee78aeSArnaldo Carvalho de Melo 	struct maps *maps = &mg->maps[type];
15394bb7123dSArnaldo Carvalho de Melo 	struct map *map;
1540439d473bSArnaldo Carvalho de Melo 
15416a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_rdlock(&maps->lock);
15426a2ffcddSArnaldo Carvalho de Melo 
15434bb7123dSArnaldo Carvalho de Melo 	for (map = maps__first(maps); map; map = map__next(map)) {
1544b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
15456a2ffcddSArnaldo Carvalho de Melo 			goto out_unlock;
1546439d473bSArnaldo Carvalho de Melo 	}
1547439d473bSArnaldo Carvalho de Melo 
15486a2ffcddSArnaldo Carvalho de Melo 	map = NULL;
15496a2ffcddSArnaldo Carvalho de Melo 
15506a2ffcddSArnaldo Carvalho de Melo out_unlock:
15516a2ffcddSArnaldo Carvalho de Melo 	pthread_rwlock_unlock(&maps->lock);
15526a2ffcddSArnaldo Carvalho de Melo 	return map;
1553439d473bSArnaldo Carvalho de Melo }
1554439d473bSArnaldo Carvalho de Melo 
1555aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
15565230fb7dSArnaldo Carvalho de Melo 		      const char *vmlinux, bool vmlinux_allocated,
15575230fb7dSArnaldo Carvalho de Melo 		      symbol_filter_t filter)
155886470930SIngo Molnar {
1559b68e2f91SCody P Schafer 	int err = -1;
1560b68e2f91SCody P Schafer 	struct symsrc ss;
1561ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
1562005f9294SCody P Schafer 	enum dso_binary_type symtab_type;
156386470930SIngo Molnar 
15645698d2c9SNamhyung Kim 	if (vmlinux[0] == '/')
15655698d2c9SNamhyung Kim 		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
15665698d2c9SNamhyung Kim 	else
1567972f393bSArnaldo Carvalho de Melo 		symbol__join_symfs(symfs_vmlinux, vmlinux);
156886470930SIngo Molnar 
156921ea4539SCody P Schafer 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1570005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
157121ea4539SCody P Schafer 	else
1572005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__VMLINUX;
157321ea4539SCody P Schafer 
1574005f9294SCody P Schafer 	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1575b68e2f91SCody P Schafer 		return -1;
1576b68e2f91SCody P Schafer 
1577261360b6SCody P Schafer 	err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
1578b68e2f91SCody P Schafer 	symsrc__destroy(&ss);
157986470930SIngo Molnar 
1580515850e4SCody P Schafer 	if (err > 0) {
158139b12f78SAdrian Hunter 		if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
15825f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
158339b12f78SAdrian Hunter 		else
15845f70619dSArnaldo Carvalho de Melo 			dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
1585bf4414aeSArnaldo Carvalho de Melo 		dso__set_long_name(dso, vmlinux, vmlinux_allocated);
1586515850e4SCody P Schafer 		dso__set_loaded(dso, map->type);
1587ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
1588515850e4SCody P Schafer 	}
15893846df2eSArnaldo Carvalho de Melo 
159086470930SIngo Molnar 	return err;
159186470930SIngo Molnar }
159286470930SIngo Molnar 
1593aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
15949de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1595a19afe46SArnaldo Carvalho de Melo {
1596a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
159700dc8657SNamhyung Kim 	char *filename = NULL;
1598a19afe46SArnaldo Carvalho de Melo 
1599dc38218eSArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1600dc38218eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
1601dc38218eSArnaldo Carvalho de Melo 
1602dc38218eSArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1603dc38218eSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
1604dc38218eSArnaldo Carvalho de Melo 		if (err > 0)
1605dc38218eSArnaldo Carvalho de Melo 			goto out;
1606dc38218eSArnaldo Carvalho de Melo 	}
1607dc38218eSArnaldo Carvalho de Melo 
160800dc8657SNamhyung Kim 	if (!symbol_conf.ignore_vmlinux_buildid)
1609aeafcbafSArnaldo Carvalho de Melo 		filename = dso__build_id_filename(dso, NULL, 0);
16105ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
16115230fb7dSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, true, filter);
16125230fb7dSArnaldo Carvalho de Melo 		if (err > 0)
16135ad90e4eSArnaldo Carvalho de Melo 			goto out;
16145ad90e4eSArnaldo Carvalho de Melo 		free(filename);
16155ad90e4eSArnaldo Carvalho de Melo 	}
16165ad90e4eSArnaldo Carvalho de Melo out:
1617a19afe46SArnaldo Carvalho de Melo 	return err;
1618a19afe46SArnaldo Carvalho de Melo }
1619a19afe46SArnaldo Carvalho de Melo 
1620c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d)
1621c48903b8SMasami Hiramatsu {
1622c48903b8SMasami Hiramatsu 	if (d->d_type != DT_DIR)
1623c48903b8SMasami Hiramatsu 		return false;
1624c48903b8SMasami Hiramatsu 	return lsdir_no_dot_filter(name, d);
1625c48903b8SMasami Hiramatsu }
1626c48903b8SMasami Hiramatsu 
16270544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
16280544d422SAdrian Hunter {
16290544d422SAdrian Hunter 	char kallsyms_filename[PATH_MAX];
16300544d422SAdrian Hunter 	int ret = -1;
1631c48903b8SMasami Hiramatsu 	struct strlist *dirs;
1632c48903b8SMasami Hiramatsu 	struct str_node *nd;
16330544d422SAdrian Hunter 
1634c48903b8SMasami Hiramatsu 	dirs = lsdir(dir, visible_dir_filter);
1635c48903b8SMasami Hiramatsu 	if (!dirs)
16360544d422SAdrian Hunter 		return -1;
16370544d422SAdrian Hunter 
1638602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(nd, dirs) {
16390544d422SAdrian Hunter 		scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1640c48903b8SMasami Hiramatsu 			  "%s/%s/kallsyms", dir, nd->s);
1641a00d28cbSAdrian Hunter 		if (!validate_kcore_addresses(kallsyms_filename, map)) {
16420544d422SAdrian Hunter 			strlcpy(dir, kallsyms_filename, dir_sz);
16430544d422SAdrian Hunter 			ret = 0;
16440544d422SAdrian Hunter 			break;
16450544d422SAdrian Hunter 		}
16460544d422SAdrian Hunter 	}
16470544d422SAdrian Hunter 
1648c48903b8SMasami Hiramatsu 	strlist__delete(dirs);
16490544d422SAdrian Hunter 
16500544d422SAdrian Hunter 	return ret;
16510544d422SAdrian Hunter }
16520544d422SAdrian Hunter 
165311870d71SMasami Hiramatsu /*
165411870d71SMasami Hiramatsu  * Use open(O_RDONLY) to check readability directly instead of access(R_OK)
165511870d71SMasami Hiramatsu  * since access(R_OK) only checks with real UID/GID but open() use effective
165611870d71SMasami Hiramatsu  * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO).
165711870d71SMasami Hiramatsu  */
165811870d71SMasami Hiramatsu static bool filename__readable(const char *file)
165911870d71SMasami Hiramatsu {
166011870d71SMasami Hiramatsu 	int fd = open(file, O_RDONLY);
166111870d71SMasami Hiramatsu 	if (fd < 0)
166211870d71SMasami Hiramatsu 		return false;
166311870d71SMasami Hiramatsu 	close(fd);
166411870d71SMasami Hiramatsu 	return true;
166511870d71SMasami Hiramatsu }
166611870d71SMasami Hiramatsu 
16670544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map)
16680544d422SAdrian Hunter {
16690544d422SAdrian Hunter 	u8 host_build_id[BUILD_ID_SIZE];
1670b5d8bbe8SMasami Hiramatsu 	char sbuild_id[SBUILD_ID_SIZE];
16710544d422SAdrian Hunter 	bool is_host = false;
16720544d422SAdrian Hunter 	char path[PATH_MAX];
16730544d422SAdrian Hunter 
16740544d422SAdrian Hunter 	if (!dso->has_build_id) {
16750544d422SAdrian Hunter 		/*
16760544d422SAdrian Hunter 		 * Last resort, if we don't have a build-id and couldn't find
16770544d422SAdrian Hunter 		 * any vmlinux file, try the running kernel kallsyms table.
16780544d422SAdrian Hunter 		 */
16790544d422SAdrian Hunter 		goto proc_kallsyms;
16800544d422SAdrian Hunter 	}
16810544d422SAdrian Hunter 
16820544d422SAdrian Hunter 	if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
16830544d422SAdrian Hunter 				 sizeof(host_build_id)) == 0)
16840544d422SAdrian Hunter 		is_host = dso__build_id_equal(dso, host_build_id);
16850544d422SAdrian Hunter 
16864e4b6c06SMasami Hiramatsu 	/* Try a fast path for /proc/kallsyms if possible */
16870544d422SAdrian Hunter 	if (is_host) {
16880544d422SAdrian Hunter 		/*
168911870d71SMasami Hiramatsu 		 * Do not check the build-id cache, unless we know we cannot use
169011870d71SMasami Hiramatsu 		 * /proc/kcore or module maps don't match to /proc/kallsyms.
169111870d71SMasami Hiramatsu 		 * To check readability of /proc/kcore, do not use access(R_OK)
169211870d71SMasami Hiramatsu 		 * since /proc/kcore requires CAP_SYS_RAWIO to read and access
169311870d71SMasami Hiramatsu 		 * can't check it.
16940544d422SAdrian Hunter 		 */
169511870d71SMasami Hiramatsu 		if (filename__readable("/proc/kcore") &&
169611870d71SMasami Hiramatsu 		    !validate_kcore_addresses("/proc/kallsyms", map))
16970544d422SAdrian Hunter 			goto proc_kallsyms;
16980544d422SAdrian Hunter 	}
16990544d422SAdrian Hunter 
17004e4b6c06SMasami Hiramatsu 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
17014e4b6c06SMasami Hiramatsu 
1702449867e3SAdrian Hunter 	/* Find kallsyms in build-id cache with kcore */
17034e4b6c06SMasami Hiramatsu 	scnprintf(path, sizeof(path), "%s/%s/%s",
17044e4b6c06SMasami Hiramatsu 		  buildid_dir, DSO__NAME_KCORE, sbuild_id);
17054e4b6c06SMasami Hiramatsu 
1706449867e3SAdrian Hunter 	if (!find_matching_kcore(map, path, sizeof(path)))
1707449867e3SAdrian Hunter 		return strdup(path);
1708449867e3SAdrian Hunter 
17094e4b6c06SMasami Hiramatsu 	/* Use current /proc/kallsyms if possible */
17104e4b6c06SMasami Hiramatsu 	if (is_host) {
17114e4b6c06SMasami Hiramatsu proc_kallsyms:
17124e4b6c06SMasami Hiramatsu 		return strdup("/proc/kallsyms");
17134e4b6c06SMasami Hiramatsu 	}
17144e4b6c06SMasami Hiramatsu 
17154e4b6c06SMasami Hiramatsu 	/* Finally, find a cache of kallsyms */
171601412261SMasami Hiramatsu 	if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) {
17170544d422SAdrian Hunter 		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
17180544d422SAdrian Hunter 		       sbuild_id);
17190544d422SAdrian Hunter 		return NULL;
17200544d422SAdrian Hunter 	}
17210544d422SAdrian Hunter 
17220544d422SAdrian Hunter 	return strdup(path);
17230544d422SAdrian Hunter }
17240544d422SAdrian Hunter 
1725aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
17269de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
172786470930SIngo Molnar {
1728cc612d81SArnaldo Carvalho de Melo 	int err;
17299e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
17309e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1731dc8d6ab2SArnaldo Carvalho de Melo 	/*
1732b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1733b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1734dc8d6ab2SArnaldo Carvalho de Melo 	 *
1735dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1736dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1737dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1738dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1739dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1740dc8d6ab2SArnaldo Carvalho de Melo 	 *
1741dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1742dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1743dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1744dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1745dc8d6ab2SArnaldo Carvalho de Melo 	 */
1746b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1747b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1748b226a5a7SDavid Ahern 		goto do_kallsyms;
1749b226a5a7SDavid Ahern 	}
1750b226a5a7SDavid Ahern 
1751fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
17525230fb7dSArnaldo Carvalho de Melo 		return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
17535230fb7dSArnaldo Carvalho de Melo 					 false, filter);
1754dc8d6ab2SArnaldo Carvalho de Melo 	}
1755439d473bSArnaldo Carvalho de Melo 
1756fc2be696SWilly Tarreau 	if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
1757aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
1758a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
175939b12f78SAdrian Hunter 			return err;
1760cc612d81SArnaldo Carvalho de Melo 	}
1761cc612d81SArnaldo Carvalho de Melo 
1762ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1763ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1764ec5761eaSDavid Ahern 		return -1;
1765ec5761eaSDavid Ahern 
17660544d422SAdrian Hunter 	kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
17670544d422SAdrian Hunter 	if (!kallsyms_allocated_filename)
17688d0591f6SArnaldo Carvalho de Melo 		return -1;
17698d0591f6SArnaldo Carvalho de Melo 
177019fc2dedSArnaldo Carvalho de Melo 	kallsyms_filename = kallsyms_allocated_filename;
177119fc2dedSArnaldo Carvalho de Melo 
1772dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
1773aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
17743846df2eSArnaldo Carvalho de Melo 	if (err > 0)
17753846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1776dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1777dc8d6ab2SArnaldo Carvalho de Melo 
17788e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1779bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
17800a77582fSMasami Hiramatsu 		dso__set_long_name(dso, DSO__NAME_KALLSYMS, false);
17816a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
17826a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1783439d473bSArnaldo Carvalho de Melo 	}
178494cb9e38SArnaldo Carvalho de Melo 
178586470930SIngo Molnar 	return err;
178686470930SIngo Molnar }
178786470930SIngo Molnar 
1788aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1789a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
1790a1645ce1SZhang, Yanmin {
1791a1645ce1SZhang, Yanmin 	int err;
1792a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
179323346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1794a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1795a1645ce1SZhang, Yanmin 
1796a1645ce1SZhang, Yanmin 	if (!map->groups) {
1797a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1798a1645ce1SZhang, Yanmin 		return -1;
1799a1645ce1SZhang, Yanmin 	}
180023346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1801a1645ce1SZhang, Yanmin 
180223346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1803a1645ce1SZhang, Yanmin 		/*
1804a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1805a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1806a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1807a1645ce1SZhang, Yanmin 		 */
1808a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1809aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
18105230fb7dSArnaldo Carvalho de Melo 						symbol_conf.default_guest_vmlinux_name,
18115230fb7dSArnaldo Carvalho de Melo 						false, filter);
181239b12f78SAdrian Hunter 			return err;
1813a1645ce1SZhang, Yanmin 		}
1814a1645ce1SZhang, Yanmin 
1815a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1816a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1817a1645ce1SZhang, Yanmin 			return -1;
1818a1645ce1SZhang, Yanmin 	} else {
181923346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1820a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1821a1645ce1SZhang, Yanmin 	}
1822a1645ce1SZhang, Yanmin 
1823aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
18248e0cf965SAdrian Hunter 	if (err > 0)
182539b12f78SAdrian Hunter 		pr_debug("Using %s for symbols\n", kallsyms_filename);
18268e0cf965SAdrian Hunter 	if (err > 0 && !dso__is_kcore(dso)) {
1827bdac0bcfSAdrian Hunter 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
182848ea8f54SArnaldo Carvalho de Melo 		machine__mmap_name(machine, path, sizeof(path));
18297e155d4dSArnaldo Carvalho de Melo 		dso__set_long_name(dso, strdup(path), true);
1830a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1831a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1832a1645ce1SZhang, Yanmin 	}
1833a1645ce1SZhang, Yanmin 
1834a1645ce1SZhang, Yanmin 	return err;
1835a1645ce1SZhang, Yanmin }
1836cd84c2acSFrederic Weisbecker 
1837cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
18382446042cSArnaldo Carvalho de Melo {
183904662523SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0)
184004662523SArnaldo Carvalho de Melo 		zfree(&vmlinux_path[vmlinux_path__nr_entries]);
1841c4f03547SWang Nan 	vmlinux_path__nr_entries = 0;
1842cc612d81SArnaldo Carvalho de Melo 
184304662523SArnaldo Carvalho de Melo 	zfree(&vmlinux_path);
1844cc612d81SArnaldo Carvalho de Melo }
1845cc612d81SArnaldo Carvalho de Melo 
1846aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = {
1847aac48647SEkaterina Tumanova 	"vmlinux",
1848aac48647SEkaterina Tumanova 	"/boot/vmlinux"
1849aac48647SEkaterina Tumanova };
1850aac48647SEkaterina Tumanova 
1851aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = {
1852aac48647SEkaterina Tumanova 	"/boot/vmlinux-%s",
1853aac48647SEkaterina Tumanova 	"/usr/lib/debug/boot/vmlinux-%s",
1854aac48647SEkaterina Tumanova 	"/lib/modules/%s/build/vmlinux",
1855f55ae954SEkaterina Tumanova 	"/usr/lib/debug/lib/modules/%s/vmlinux",
1856f55ae954SEkaterina Tumanova 	"/usr/lib/debug/boot/vmlinux-%s.debug"
1857aac48647SEkaterina Tumanova };
1858aac48647SEkaterina Tumanova 
1859aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry)
1860aac48647SEkaterina Tumanova {
1861aac48647SEkaterina Tumanova 	vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
1862aac48647SEkaterina Tumanova 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1863aac48647SEkaterina Tumanova 		return -1;
1864aac48647SEkaterina Tumanova 	++vmlinux_path__nr_entries;
1865aac48647SEkaterina Tumanova 
1866aac48647SEkaterina Tumanova 	return 0;
1867aac48647SEkaterina Tumanova }
1868aac48647SEkaterina Tumanova 
1869ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env)
1870cc612d81SArnaldo Carvalho de Melo {
1871cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1872cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
18730a7e6d1bSNamhyung Kim 	char *kernel_version;
1874aac48647SEkaterina Tumanova 	unsigned int i;
1875cc612d81SArnaldo Carvalho de Melo 
1876aac48647SEkaterina Tumanova 	vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
1877aac48647SEkaterina Tumanova 			      ARRAY_SIZE(vmlinux_paths_upd)));
1878cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1879cc612d81SArnaldo Carvalho de Melo 		return -1;
1880cc612d81SArnaldo Carvalho de Melo 
1881aac48647SEkaterina Tumanova 	for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
1882aac48647SEkaterina Tumanova 		if (vmlinux_path__add(vmlinux_paths[i]) < 0)
1883cc612d81SArnaldo Carvalho de Melo 			goto out_fail;
1884ec5761eaSDavid Ahern 
18850a7e6d1bSNamhyung Kim 	/* only try kernel version if no symfs was given */
1886ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1887ec5761eaSDavid Ahern 		return 0;
1888ec5761eaSDavid Ahern 
18890a7e6d1bSNamhyung Kim 	if (env) {
18900a7e6d1bSNamhyung Kim 		kernel_version = env->os_release;
18910a7e6d1bSNamhyung Kim 	} else {
1892ec5761eaSDavid Ahern 		if (uname(&uts) < 0)
1893e96c674fSNamhyung Kim 			goto out_fail;
1894ec5761eaSDavid Ahern 
18950a7e6d1bSNamhyung Kim 		kernel_version = uts.release;
18960a7e6d1bSNamhyung Kim 	}
18970a7e6d1bSNamhyung Kim 
1898aac48647SEkaterina Tumanova 	for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
1899aac48647SEkaterina Tumanova 		snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
1900aac48647SEkaterina Tumanova 		if (vmlinux_path__add(bf) < 0)
1901cc612d81SArnaldo Carvalho de Melo 			goto out_fail;
1902aac48647SEkaterina Tumanova 	}
1903cc612d81SArnaldo Carvalho de Melo 
1904cc612d81SArnaldo Carvalho de Melo 	return 0;
1905cc612d81SArnaldo Carvalho de Melo 
1906cc612d81SArnaldo Carvalho de Melo out_fail:
1907cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1908cc612d81SArnaldo Carvalho de Melo 	return -1;
1909cc612d81SArnaldo Carvalho de Melo }
1910cc612d81SArnaldo Carvalho de Melo 
19113bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str,
1912655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
1913655000e7SArnaldo Carvalho de Melo {
1914655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
1915655000e7SArnaldo Carvalho de Melo 		return 0;
1916655000e7SArnaldo Carvalho de Melo 
19174a77e218SArnaldo Carvalho de Melo 	*list = strlist__new(list_str, NULL);
1918655000e7SArnaldo Carvalho de Melo 	if (!*list) {
1919655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
1920655000e7SArnaldo Carvalho de Melo 		return -1;
1921655000e7SArnaldo Carvalho de Melo 	}
19220bc2f2f7SArnaldo Carvalho de Melo 
19230bc2f2f7SArnaldo Carvalho de Melo 	symbol_conf.has_filter = true;
1924655000e7SArnaldo Carvalho de Melo 	return 0;
1925655000e7SArnaldo Carvalho de Melo }
1926655000e7SArnaldo Carvalho de Melo 
1927e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str,
1928e03eaa40SDavid Ahern 		  const char *list_name)
1929e03eaa40SDavid Ahern {
1930e03eaa40SDavid Ahern 	if (list_str == NULL)
1931e03eaa40SDavid Ahern 		return 0;
1932e03eaa40SDavid Ahern 
1933e03eaa40SDavid Ahern 	*list = intlist__new(list_str);
1934e03eaa40SDavid Ahern 	if (!*list) {
1935e03eaa40SDavid Ahern 		pr_err("problems parsing %s list\n", list_name);
1936e03eaa40SDavid Ahern 		return -1;
1937e03eaa40SDavid Ahern 	}
1938e03eaa40SDavid Ahern 	return 0;
1939e03eaa40SDavid Ahern }
1940e03eaa40SDavid Ahern 
1941ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
1942ec80fde7SArnaldo Carvalho de Melo {
1943ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
1944ec80fde7SArnaldo Carvalho de Melo 	FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
194538272dc4SWang Nan 
1946ec80fde7SArnaldo Carvalho de Melo 	if (fp != NULL) {
1947ec80fde7SArnaldo Carvalho de Melo 		char line[8];
1948ec80fde7SArnaldo Carvalho de Melo 
1949ec80fde7SArnaldo Carvalho de Melo 		if (fgets(line, sizeof(line), fp) != NULL)
195038272dc4SWang Nan 			value = (geteuid() != 0) ?
195138272dc4SWang Nan 					(atoi(line) != 0) :
195238272dc4SWang Nan 					(atoi(line) == 2);
1953ec80fde7SArnaldo Carvalho de Melo 
1954ec80fde7SArnaldo Carvalho de Melo 		fclose(fp);
1955ec80fde7SArnaldo Carvalho de Melo 	}
1956ec80fde7SArnaldo Carvalho de Melo 
1957ec80fde7SArnaldo Carvalho de Melo 	return value;
1958ec80fde7SArnaldo Carvalho de Melo }
1959ec80fde7SArnaldo Carvalho de Melo 
1960b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void)
1961b01141f4SArnaldo Carvalho de Melo {
1962b01141f4SArnaldo Carvalho de Melo 	if (symbol_conf.initialized) {
1963b01141f4SArnaldo Carvalho de Melo 		pr_err("Annotation needs to be init before symbol__init()\n");
1964b01141f4SArnaldo Carvalho de Melo 		return -1;
1965b01141f4SArnaldo Carvalho de Melo 	}
1966b01141f4SArnaldo Carvalho de Melo 
1967b01141f4SArnaldo Carvalho de Melo 	if (symbol_conf.init_annotation) {
1968b01141f4SArnaldo Carvalho de Melo 		pr_warning("Annotation being initialized multiple times\n");
1969b01141f4SArnaldo Carvalho de Melo 		return 0;
1970b01141f4SArnaldo Carvalho de Melo 	}
1971b01141f4SArnaldo Carvalho de Melo 
1972b01141f4SArnaldo Carvalho de Melo 	symbol_conf.priv_size += sizeof(struct annotation);
1973b01141f4SArnaldo Carvalho de Melo 	symbol_conf.init_annotation = true;
1974b01141f4SArnaldo Carvalho de Melo 	return 0;
1975b01141f4SArnaldo Carvalho de Melo }
1976b01141f4SArnaldo Carvalho de Melo 
1977ce80d3beSKan Liang int symbol__init(struct perf_env *env)
1978cc612d81SArnaldo Carvalho de Melo {
1979ec5761eaSDavid Ahern 	const char *symfs;
1980ec5761eaSDavid Ahern 
198185e00b55SJovi Zhang 	if (symbol_conf.initialized)
198285e00b55SJovi Zhang 		return 0;
198385e00b55SJovi Zhang 
19849ac3e487SIrina Tirdea 	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
19854d439517SDavid S. Miller 
1986166ccc9cSNamhyung Kim 	symbol__elf_init();
1987166ccc9cSNamhyung Kim 
198875be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
198975be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
199079406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
1991b32d133aSArnaldo Carvalho de Melo 
19920a7e6d1bSNamhyung Kim 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
1993cc612d81SArnaldo Carvalho de Melo 		return -1;
1994cc612d81SArnaldo Carvalho de Melo 
1995c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1996c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
1997c410a338SArnaldo Carvalho de Melo 		return -1;
1998c410a338SArnaldo Carvalho de Melo 	}
1999c410a338SArnaldo Carvalho de Melo 
2000655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2001655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2002655000e7SArnaldo Carvalho de Melo 		return -1;
2003655000e7SArnaldo Carvalho de Melo 
2004655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2005655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2006655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2007655000e7SArnaldo Carvalho de Melo 
2008e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.pid_list,
2009e03eaa40SDavid Ahern 		       symbol_conf.pid_list_str, "pid") < 0)
2010e03eaa40SDavid Ahern 		goto out_free_comm_list;
2011e03eaa40SDavid Ahern 
2012e03eaa40SDavid Ahern 	if (setup_intlist(&symbol_conf.tid_list,
2013e03eaa40SDavid Ahern 		       symbol_conf.tid_list_str, "tid") < 0)
2014e03eaa40SDavid Ahern 		goto out_free_pid_list;
2015e03eaa40SDavid Ahern 
2016655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2017655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2018e03eaa40SDavid Ahern 		goto out_free_tid_list;
2019655000e7SArnaldo Carvalho de Melo 
2020ec5761eaSDavid Ahern 	/*
2021ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2022ec5761eaSDavid Ahern 	 * reset here for simplicity.
2023ec5761eaSDavid Ahern 	 */
2024ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2025ec5761eaSDavid Ahern 	if (symfs == NULL)
2026ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2027ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2028ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2029ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2030ec5761eaSDavid Ahern 		free((void *)symfs);
2031ec5761eaSDavid Ahern 
2032ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2033ec80fde7SArnaldo Carvalho de Melo 
203485e00b55SJovi Zhang 	symbol_conf.initialized = true;
20354aa65636SArnaldo Carvalho de Melo 	return 0;
2036655000e7SArnaldo Carvalho de Melo 
2037e03eaa40SDavid Ahern out_free_tid_list:
2038e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2039e03eaa40SDavid Ahern out_free_pid_list:
2040e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2041655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2042655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2043d74c896bSNamhyung Kim out_free_dso_list:
2044d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2045655000e7SArnaldo Carvalho de Melo 	return -1;
2046cc612d81SArnaldo Carvalho de Melo }
2047cc612d81SArnaldo Carvalho de Melo 
2048d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2049d65a458bSArnaldo Carvalho de Melo {
205085e00b55SJovi Zhang 	if (!symbol_conf.initialized)
205185e00b55SJovi Zhang 		return;
2052d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2053d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2054d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2055e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.tid_list);
2056e03eaa40SDavid Ahern 	intlist__delete(symbol_conf.pid_list);
2057d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2058d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
205985e00b55SJovi Zhang 	symbol_conf.initialized = false;
2060d65a458bSArnaldo Carvalho de Melo }
2061a7066709SHe Kuang 
2062a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused,
2063a7066709SHe Kuang 			 const char *dir, int unset __maybe_unused)
2064a7066709SHe Kuang {
2065a7066709SHe Kuang 	char *bf = NULL;
2066a7066709SHe Kuang 	int ret;
2067a7066709SHe Kuang 
2068a7066709SHe Kuang 	symbol_conf.symfs = strdup(dir);
2069a7066709SHe Kuang 	if (symbol_conf.symfs == NULL)
2070a7066709SHe Kuang 		return -ENOMEM;
2071a7066709SHe Kuang 
2072a7066709SHe Kuang 	/* skip the locally configured cache if a symfs is given, and
2073a7066709SHe Kuang 	 * config buildid dir to symfs/.debug
2074a7066709SHe Kuang 	 */
2075a7066709SHe Kuang 	ret = asprintf(&bf, "%s/%s", dir, ".debug");
2076a7066709SHe Kuang 	if (ret < 0)
2077a7066709SHe Kuang 		return -ENOMEM;
2078a7066709SHe Kuang 
2079a7066709SHe Kuang 	set_buildid_dir(bf);
2080a7066709SHe Kuang 
2081a7066709SHe Kuang 	free(bf);
2082a7066709SHe Kuang 	return 0;
2083a7066709SHe Kuang }
2084