xref: /linux/tools/perf/util/symbol.c (revision f51304d3fe4fee475991ee424a4b7f85eec65a7b)
15aab621bSArnaldo Carvalho de Melo #include <dirent.h>
25aab621bSArnaldo Carvalho de Melo #include <errno.h>
35aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
45aab621bSArnaldo Carvalho de Melo #include <stdio.h>
55aab621bSArnaldo Carvalho de Melo #include <string.h>
65aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
85aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
95aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
105aab621bSArnaldo Carvalho de Melo #include <unistd.h>
119486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
12b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
13e334c726SNamhyung Kim #include "util.h"
148a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1586470930SIngo Molnar #include "symbol.h"
165aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1786470930SIngo Molnar 
1886470930SIngo Molnar #include <libelf.h>
1986470930SIngo Molnar #include <gelf.h>
2086470930SIngo Molnar #include <elf.h>
21f1617b40SArnaldo Carvalho de Melo #include <limits.h>
22439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
232cdbc46dSPeter Zijlstra 
243b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN
25c752d040SRicardo Ribalda Delgado #define KSYM_NAME_LEN 256
263b01a413SArnaldo Carvalho de Melo #endif
273b01a413SArnaldo Carvalho de Melo 
28c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
29c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
30c12e15e7SArnaldo Carvalho de Melo #endif
31c12e15e7SArnaldo Carvalho de Melo 
32aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
3321916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size);
34b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
353610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
36aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
379de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
38aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
39a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
40cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
41cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
42439d473bSArnaldo Carvalho de Melo 
4375be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
44d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
45b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
46b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
473e6a2a7fSStephane Eranian 	.annotate_src	  = true,
48ec5761eaSDavid Ahern 	.symfs            = "",
49b32d133aSArnaldo Carvalho de Melo };
50b32d133aSArnaldo Carvalho de Melo 
51aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso)
528a6c5b26SArnaldo Carvalho de Melo {
531e2dd2f7SDavid Miller 	if (!dso)
541e2dd2f7SDavid Miller 		return strlen("[unknown]");
558a6c5b26SArnaldo Carvalho de Melo 	if (verbose)
56aeafcbafSArnaldo Carvalho de Melo 		return dso->long_name_len;
578a6c5b26SArnaldo Carvalho de Melo 
58aeafcbafSArnaldo Carvalho de Melo 	return dso->short_name_len;
598a6c5b26SArnaldo Carvalho de Melo }
608a6c5b26SArnaldo Carvalho de Melo 
61aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type)
623610583cSArnaldo Carvalho de Melo {
63aeafcbafSArnaldo Carvalho de Melo 	return dso->loaded & (1 << type);
643610583cSArnaldo Carvalho de Melo }
653610583cSArnaldo Carvalho de Melo 
66aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
6779406cd7SArnaldo Carvalho de Melo {
68aeafcbafSArnaldo Carvalho de Melo 	return dso->sorted_by_name & (1 << type);
6979406cd7SArnaldo Carvalho de Melo }
7079406cd7SArnaldo Carvalho de Melo 
71aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
7279406cd7SArnaldo Carvalho de Melo {
73aeafcbafSArnaldo Carvalho de Melo 	dso->sorted_by_name |= (1 << type);
7479406cd7SArnaldo Carvalho de Melo }
7579406cd7SArnaldo Carvalho de Melo 
7636a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
776893d4eeSArnaldo Carvalho de Melo {
7831877908SAnton Blanchard 	symbol_type = toupper(symbol_type);
7931877908SAnton Blanchard 
806893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
816893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
826893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
83f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
8431877908SAnton Blanchard 		return symbol_type == 'D';
856893d4eeSArnaldo Carvalho de Melo 	default:
866893d4eeSArnaldo Carvalho de Melo 		return false;
876893d4eeSArnaldo Carvalho de Melo 	}
886893d4eeSArnaldo Carvalho de Melo }
896893d4eeSArnaldo Carvalho de Melo 
90694bf407SAnton Blanchard static int prefix_underscores_count(const char *str)
91694bf407SAnton Blanchard {
92694bf407SAnton Blanchard 	const char *tail = str;
93694bf407SAnton Blanchard 
94694bf407SAnton Blanchard 	while (*tail == '_')
95694bf407SAnton Blanchard 		tail++;
96694bf407SAnton Blanchard 
97694bf407SAnton Blanchard 	return tail - str;
98694bf407SAnton Blanchard }
99694bf407SAnton Blanchard 
100694bf407SAnton Blanchard #define SYMBOL_A 0
101694bf407SAnton Blanchard #define SYMBOL_B 1
102694bf407SAnton Blanchard 
103694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
104694bf407SAnton Blanchard {
105694bf407SAnton Blanchard 	s64 a;
106694bf407SAnton Blanchard 	s64 b;
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 
140694bf407SAnton Blanchard 	/* If all else fails, choose the symbol with the longest name */
141694bf407SAnton Blanchard 	if (strlen(syma->name) >= strlen(symb->name))
142694bf407SAnton Blanchard 		return SYMBOL_A;
143694bf407SAnton Blanchard 	else
144694bf407SAnton Blanchard 		return SYMBOL_B;
145694bf407SAnton Blanchard }
146694bf407SAnton Blanchard 
147694bf407SAnton Blanchard static void symbols__fixup_duplicate(struct rb_root *symbols)
148694bf407SAnton Blanchard {
149694bf407SAnton Blanchard 	struct rb_node *nd;
150694bf407SAnton Blanchard 	struct symbol *curr, *next;
151694bf407SAnton Blanchard 
152694bf407SAnton Blanchard 	nd = rb_first(symbols);
153694bf407SAnton Blanchard 
154694bf407SAnton Blanchard 	while (nd) {
155694bf407SAnton Blanchard 		curr = rb_entry(nd, struct symbol, rb_node);
156694bf407SAnton Blanchard again:
157694bf407SAnton Blanchard 		nd = rb_next(&curr->rb_node);
158694bf407SAnton Blanchard 		next = rb_entry(nd, struct symbol, rb_node);
159694bf407SAnton Blanchard 
160694bf407SAnton Blanchard 		if (!nd)
161694bf407SAnton Blanchard 			break;
162694bf407SAnton Blanchard 
163694bf407SAnton Blanchard 		if (curr->start != next->start)
164694bf407SAnton Blanchard 			continue;
165694bf407SAnton Blanchard 
166694bf407SAnton Blanchard 		if (choose_best_symbol(curr, next) == SYMBOL_A) {
167694bf407SAnton Blanchard 			rb_erase(&next->rb_node, symbols);
168694bf407SAnton Blanchard 			goto again;
169694bf407SAnton Blanchard 		} else {
170694bf407SAnton Blanchard 			nd = rb_next(&curr->rb_node);
171694bf407SAnton Blanchard 			rb_erase(&curr->rb_node, symbols);
172694bf407SAnton Blanchard 		}
173694bf407SAnton Blanchard 	}
174694bf407SAnton Blanchard }
175694bf407SAnton Blanchard 
176aeafcbafSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *symbols)
177af427bf5SArnaldo Carvalho de Melo {
178aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(symbols);
1792e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
180af427bf5SArnaldo Carvalho de Melo 
181af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
182af427bf5SArnaldo Carvalho de Melo 		return;
183af427bf5SArnaldo Carvalho de Melo 
1842e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
1852e538c4aSArnaldo Carvalho de Melo 
186af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
1872e538c4aSArnaldo Carvalho de Melo 		prev = curr;
1882e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
189af427bf5SArnaldo Carvalho de Melo 
1903b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
191af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
192af427bf5SArnaldo Carvalho de Melo 	}
193af427bf5SArnaldo Carvalho de Melo 
1942e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
1952e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
1962e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
1972e538c4aSArnaldo Carvalho de Melo }
1982e538c4aSArnaldo Carvalho de Melo 
199aeafcbafSArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
200af427bf5SArnaldo Carvalho de Melo {
201af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
202aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
203af427bf5SArnaldo Carvalho de Melo 
204af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
205af427bf5SArnaldo Carvalho de Melo 		return;
206af427bf5SArnaldo Carvalho de Melo 
207af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
208af427bf5SArnaldo Carvalho de Melo 
209af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
210af427bf5SArnaldo Carvalho de Melo 		prev = curr;
211af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
212af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
2132e538c4aSArnaldo Carvalho de Melo 	}
21490c83218SArnaldo Carvalho de Melo 
21590c83218SArnaldo Carvalho de Melo 	/*
21690c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
21790c83218SArnaldo Carvalho de Melo 	 * last map final address.
21890c83218SArnaldo Carvalho de Melo 	 */
2199d1faba5SIan Munsie 	curr->end = ~0ULL;
220af427bf5SArnaldo Carvalho de Melo }
221af427bf5SArnaldo Carvalho de Melo 
222aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg)
22323ea4a3fSArnaldo Carvalho de Melo {
22423ea4a3fSArnaldo Carvalho de Melo 	int i;
22523ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
226aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(mg, i);
22723ea4a3fSArnaldo Carvalho de Melo }
22823ea4a3fSArnaldo Carvalho de Melo 
229c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
230c408fedfSArnaldo Carvalho de Melo 				  const char *name)
23186470930SIngo Molnar {
23286470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
233aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
234aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
235aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
23686470930SIngo Molnar 		return NULL;
23786470930SIngo Molnar 
23875be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
239aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
24036479484SArnaldo Carvalho de Melo 
241aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
242aeafcbafSArnaldo Carvalho de Melo 	sym->end     = len ? start + len - 1 : start;
243aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
244aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
245e4204992SArnaldo Carvalho de Melo 
246aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
247aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
248aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
249e4204992SArnaldo Carvalho de Melo 
250aeafcbafSArnaldo Carvalho de Melo 	return sym;
25186470930SIngo Molnar }
25286470930SIngo Molnar 
253aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
25486470930SIngo Molnar {
255aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
25686470930SIngo Molnar }
25786470930SIngo Molnar 
258aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
25986470930SIngo Molnar {
2609486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
261aeafcbafSArnaldo Carvalho de Melo 		       sym->start, sym->end,
262aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_GLOBAL ? 'g' :
263aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_LOCAL  ? 'l' : 'w',
264aeafcbafSArnaldo Carvalho de Melo 		       sym->name);
26586470930SIngo Molnar }
26686470930SIngo Molnar 
267a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym,
268a978f2abSAkihiro Nagai 				    const struct addr_location *al, FILE *fp)
269a978f2abSAkihiro Nagai {
270a978f2abSAkihiro Nagai 	unsigned long offset;
271a978f2abSAkihiro Nagai 	size_t length;
272a978f2abSAkihiro Nagai 
273a978f2abSAkihiro Nagai 	if (sym && sym->name) {
274a978f2abSAkihiro Nagai 		length = fprintf(fp, "%s", sym->name);
275a978f2abSAkihiro Nagai 		if (al) {
276a978f2abSAkihiro Nagai 			offset = al->addr - sym->start;
277a978f2abSAkihiro Nagai 			length += fprintf(fp, "+0x%lx", offset);
278a978f2abSAkihiro Nagai 		}
279a978f2abSAkihiro Nagai 		return length;
280a978f2abSAkihiro Nagai 	} else
281a978f2abSAkihiro Nagai 		return fprintf(fp, "[unknown]");
282a978f2abSAkihiro Nagai }
283a978f2abSAkihiro Nagai 
284547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
285547a92e0SAkihiro Nagai {
286a978f2abSAkihiro Nagai 	return symbol__fprintf_symname_offs(sym, NULL, fp);
287547a92e0SAkihiro Nagai }
288547a92e0SAkihiro Nagai 
289aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name)
290cfc10d3bSArnaldo Carvalho de Melo {
291ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
292ef6ae724SArnaldo Carvalho de Melo 		return;
293aeafcbafSArnaldo Carvalho de Melo 	dso->long_name = name;
294aeafcbafSArnaldo Carvalho de Melo 	dso->long_name_len = strlen(name);
295cfc10d3bSArnaldo Carvalho de Melo }
296cfc10d3bSArnaldo Carvalho de Melo 
297aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name)
298b63be8d7SArnaldo Carvalho de Melo {
299b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
300b63be8d7SArnaldo Carvalho de Melo 		return;
301aeafcbafSArnaldo Carvalho de Melo 	dso->short_name = name;
302aeafcbafSArnaldo Carvalho de Melo 	dso->short_name_len = strlen(name);
303b63be8d7SArnaldo Carvalho de Melo }
304b63be8d7SArnaldo Carvalho de Melo 
305aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso)
306cfc10d3bSArnaldo Carvalho de Melo {
307aeafcbafSArnaldo Carvalho de Melo 	dso__set_short_name(dso, basename(dso->long_name));
308cfc10d3bSArnaldo Carvalho de Melo }
309cfc10d3bSArnaldo Carvalho de Melo 
31000a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
31186470930SIngo Molnar {
312aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
31386470930SIngo Molnar 
314aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
3156a4694a4SArnaldo Carvalho de Melo 		int i;
316aeafcbafSArnaldo Carvalho de Melo 		strcpy(dso->name, name);
317aeafcbafSArnaldo Carvalho de Melo 		dso__set_long_name(dso, dso->name);
318aeafcbafSArnaldo Carvalho de Melo 		dso__set_short_name(dso, dso->name);
3196a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
320aeafcbafSArnaldo Carvalho de Melo 			dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
321aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__NOT_FOUND;
322aeafcbafSArnaldo Carvalho de Melo 		dso->loaded = 0;
323aeafcbafSArnaldo Carvalho de Melo 		dso->sorted_by_name = 0;
324aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = 0;
325aeafcbafSArnaldo Carvalho de Melo 		dso->kernel = DSO_TYPE_USER;
3268db4841fSJiri Olsa 		dso->needs_swap = DSO_SWAP__UNSET;
327aeafcbafSArnaldo Carvalho de Melo 		INIT_LIST_HEAD(&dso->node);
32886470930SIngo Molnar 	}
32986470930SIngo Molnar 
330aeafcbafSArnaldo Carvalho de Melo 	return dso;
33186470930SIngo Molnar }
33286470930SIngo Molnar 
333aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols)
33486470930SIngo Molnar {
33586470930SIngo Molnar 	struct symbol *pos;
336aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
33786470930SIngo Molnar 
33886470930SIngo Molnar 	while (next) {
33986470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
34086470930SIngo Molnar 		next = rb_next(&pos->rb_node);
341aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
34200a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
34386470930SIngo Molnar 	}
34486470930SIngo Molnar }
34586470930SIngo Molnar 
346aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso)
34786470930SIngo Molnar {
3486a4694a4SArnaldo Carvalho de Melo 	int i;
3496a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
350aeafcbafSArnaldo Carvalho de Melo 		symbols__delete(&dso->symbols[i]);
351aeafcbafSArnaldo Carvalho de Melo 	if (dso->sname_alloc)
352aeafcbafSArnaldo Carvalho de Melo 		free((char *)dso->short_name);
353aeafcbafSArnaldo Carvalho de Melo 	if (dso->lname_alloc)
354aeafcbafSArnaldo Carvalho de Melo 		free(dso->long_name);
355aeafcbafSArnaldo Carvalho de Melo 	free(dso);
35686470930SIngo Molnar }
35786470930SIngo Molnar 
358aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id)
3598d06367fSArnaldo Carvalho de Melo {
360aeafcbafSArnaldo Carvalho de Melo 	memcpy(dso->build_id, build_id, sizeof(dso->build_id));
361aeafcbafSArnaldo Carvalho de Melo 	dso->has_build_id = 1;
3628d06367fSArnaldo Carvalho de Melo }
3638d06367fSArnaldo Carvalho de Melo 
364aeafcbafSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
36586470930SIngo Molnar {
366aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
36786470930SIngo Molnar 	struct rb_node *parent = NULL;
3689cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
36986470930SIngo Molnar 	struct symbol *s;
37086470930SIngo Molnar 
37186470930SIngo Molnar 	while (*p != NULL) {
37286470930SIngo Molnar 		parent = *p;
37386470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
37486470930SIngo Molnar 		if (ip < s->start)
37586470930SIngo Molnar 			p = &(*p)->rb_left;
37686470930SIngo Molnar 		else
37786470930SIngo Molnar 			p = &(*p)->rb_right;
37886470930SIngo Molnar 	}
37986470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
380aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
38186470930SIngo Molnar }
38286470930SIngo Molnar 
383aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
38486470930SIngo Molnar {
38586470930SIngo Molnar 	struct rb_node *n;
38686470930SIngo Molnar 
387aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
38886470930SIngo Molnar 		return NULL;
38986470930SIngo Molnar 
390aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
39186470930SIngo Molnar 
39286470930SIngo Molnar 	while (n) {
39386470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
39486470930SIngo Molnar 
39586470930SIngo Molnar 		if (ip < s->start)
39686470930SIngo Molnar 			n = n->rb_left;
39786470930SIngo Molnar 		else if (ip > s->end)
39886470930SIngo Molnar 			n = n->rb_right;
39986470930SIngo Molnar 		else
40086470930SIngo Molnar 			return s;
40186470930SIngo Molnar 	}
40286470930SIngo Molnar 
40386470930SIngo Molnar 	return NULL;
40486470930SIngo Molnar }
40586470930SIngo Molnar 
40679406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
40779406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
40879406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
40979406cd7SArnaldo Carvalho de Melo };
41079406cd7SArnaldo Carvalho de Melo 
411aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
41279406cd7SArnaldo Carvalho de Melo {
413aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
41479406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
41502a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
41602a9d037SRabin Vincent 
41702a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
41879406cd7SArnaldo Carvalho de Melo 
41979406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
42079406cd7SArnaldo Carvalho de Melo 		parent = *p;
42179406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
42279406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
42379406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
42479406cd7SArnaldo Carvalho de Melo 		else
42579406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
42679406cd7SArnaldo Carvalho de Melo 	}
42779406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
428aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
42979406cd7SArnaldo Carvalho de Melo }
43079406cd7SArnaldo Carvalho de Melo 
431aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
432aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
43379406cd7SArnaldo Carvalho de Melo {
43479406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
43579406cd7SArnaldo Carvalho de Melo 
43679406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
43779406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
438aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
43979406cd7SArnaldo Carvalho de Melo 	}
44079406cd7SArnaldo Carvalho de Melo }
44179406cd7SArnaldo Carvalho de Melo 
442aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
443aeafcbafSArnaldo Carvalho de Melo 					    const char *name)
44479406cd7SArnaldo Carvalho de Melo {
44579406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
44679406cd7SArnaldo Carvalho de Melo 
447aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
44879406cd7SArnaldo Carvalho de Melo 		return NULL;
44979406cd7SArnaldo Carvalho de Melo 
450aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
45179406cd7SArnaldo Carvalho de Melo 
45279406cd7SArnaldo Carvalho de Melo 	while (n) {
45379406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
45479406cd7SArnaldo Carvalho de Melo 		int cmp;
45579406cd7SArnaldo Carvalho de Melo 
45679406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
45779406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
45879406cd7SArnaldo Carvalho de Melo 
45979406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
46079406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
46179406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
46279406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
46379406cd7SArnaldo Carvalho de Melo 		else
46479406cd7SArnaldo Carvalho de Melo 			return &s->sym;
46579406cd7SArnaldo Carvalho de Melo 	}
46679406cd7SArnaldo Carvalho de Melo 
46779406cd7SArnaldo Carvalho de Melo 	return NULL;
46879406cd7SArnaldo Carvalho de Melo }
46979406cd7SArnaldo Carvalho de Melo 
470aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
47179406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
472fcf1203aSArnaldo Carvalho de Melo {
473aeafcbafSArnaldo Carvalho de Melo 	return symbols__find(&dso->symbols[type], addr);
474fcf1203aSArnaldo Carvalho de Melo }
475fcf1203aSArnaldo Carvalho de Melo 
476aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
47779406cd7SArnaldo Carvalho de Melo 					const char *name)
47879406cd7SArnaldo Carvalho de Melo {
479aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
48079406cd7SArnaldo Carvalho de Melo }
48179406cd7SArnaldo Carvalho de Melo 
482aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
48379406cd7SArnaldo Carvalho de Melo {
484aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
485aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
486aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
48779406cd7SArnaldo Carvalho de Melo }
48879406cd7SArnaldo Carvalho de Melo 
489aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf)
4908d06367fSArnaldo Carvalho de Melo {
4918d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
492aeafcbafSArnaldo Carvalho de Melo 	const u8 *raw = build_id;
4938d06367fSArnaldo Carvalho de Melo 	int i;
4948d06367fSArnaldo Carvalho de Melo 
4958d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
4968d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
4978d06367fSArnaldo Carvalho de Melo 		++raw;
4988d06367fSArnaldo Carvalho de Melo 		bid += 2;
4998d06367fSArnaldo Carvalho de Melo 	}
5008d06367fSArnaldo Carvalho de Melo 
501aeafcbafSArnaldo Carvalho de Melo 	return raw - build_id;
5028d06367fSArnaldo Carvalho de Melo }
5038d06367fSArnaldo Carvalho de Melo 
504aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
50586470930SIngo Molnar {
5068d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
5078d06367fSArnaldo Carvalho de Melo 
508aeafcbafSArnaldo Carvalho de Melo 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
5099e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
5109e03eb2dSArnaldo Carvalho de Melo }
5119e03eb2dSArnaldo Carvalho de Melo 
512aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso,
513aeafcbafSArnaldo Carvalho de Melo 				    enum map_type type, FILE *fp)
51490f18e63SSrikar Dronamraju {
51590f18e63SSrikar Dronamraju 	size_t ret = 0;
51690f18e63SSrikar Dronamraju 	struct rb_node *nd;
51790f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
51890f18e63SSrikar Dronamraju 
519aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
52090f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
52190f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
52290f18e63SSrikar Dronamraju 	}
52390f18e63SSrikar Dronamraju 
52490f18e63SSrikar Dronamraju 	return ret;
52590f18e63SSrikar Dronamraju }
52690f18e63SSrikar Dronamraju 
527aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
5289e03eb2dSArnaldo Carvalho de Melo {
5299e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
530aeafcbafSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
5319e03eb2dSArnaldo Carvalho de Melo 
532aeafcbafSArnaldo Carvalho de Melo 	if (dso->short_name != dso->long_name)
533aeafcbafSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", dso->long_name);
5343846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
535aeafcbafSArnaldo Carvalho de Melo 		       dso->loaded ? "" : "NOT ");
536aeafcbafSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(dso, fp);
5376a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
538aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
53986470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
54086470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
54186470930SIngo Molnar 	}
54286470930SIngo Molnar 
54386470930SIngo Molnar 	return ret;
54486470930SIngo Molnar }
54586470930SIngo Molnar 
5469e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
5479e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
5483b01a413SArnaldo Carvalho de Melo 					  char type, u64 start, u64 end))
54986470930SIngo Molnar {
55086470930SIngo Molnar 	char *line = NULL;
55186470930SIngo Molnar 	size_t n;
5523b01a413SArnaldo Carvalho de Melo 	int err = -1;
5539e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
55486470930SIngo Molnar 
55586470930SIngo Molnar 	if (file == NULL)
55686470930SIngo Molnar 		goto out_failure;
55786470930SIngo Molnar 
5583b01a413SArnaldo Carvalho de Melo 	err = 0;
5593b01a413SArnaldo Carvalho de Melo 
56086470930SIngo Molnar 	while (!feof(file)) {
5619cffa8d5SPaul Mackerras 		u64 start;
56286470930SIngo Molnar 		int line_len, len;
56386470930SIngo Molnar 		char symbol_type;
5642e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
56586470930SIngo Molnar 
56686470930SIngo Molnar 		line_len = getline(&line, &n, file);
567a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
56886470930SIngo Molnar 			break;
56986470930SIngo Molnar 
57086470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
57186470930SIngo Molnar 
57286470930SIngo Molnar 		len = hex2u64(line, &start);
57386470930SIngo Molnar 
57486470930SIngo Molnar 		len++;
57586470930SIngo Molnar 		if (len + 2 >= line_len)
57686470930SIngo Molnar 			continue;
57786470930SIngo Molnar 
57831877908SAnton Blanchard 		symbol_type = line[len];
5793b01a413SArnaldo Carvalho de Melo 		len += 2;
5803b01a413SArnaldo Carvalho de Melo 		symbol_name = line + len;
5813b01a413SArnaldo Carvalho de Melo 		len = line_len - len;
582682b335aSArnaldo Carvalho de Melo 
5833b01a413SArnaldo Carvalho de Melo 		if (len >= KSYM_NAME_LEN) {
5843b01a413SArnaldo Carvalho de Melo 			err = -1;
5853b01a413SArnaldo Carvalho de Melo 			break;
5863b01a413SArnaldo Carvalho de Melo 		}
5873b01a413SArnaldo Carvalho de Melo 
5883f5a4272SAnton Blanchard 		/*
5893f5a4272SAnton Blanchard 		 * module symbols are not sorted so we add all
5903f5a4272SAnton Blanchard 		 * symbols with zero length and rely on
5913f5a4272SAnton Blanchard 		 * symbols__fixup_end() to fix it up.
5923f5a4272SAnton Blanchard 		 */
5933f5a4272SAnton Blanchard 		err = process_symbol(arg, symbol_name,
5943f5a4272SAnton Blanchard 				     symbol_type, start, start);
595682b335aSArnaldo Carvalho de Melo 		if (err)
596682b335aSArnaldo Carvalho de Melo 			break;
597682b335aSArnaldo Carvalho de Melo 	}
598682b335aSArnaldo Carvalho de Melo 
599682b335aSArnaldo Carvalho de Melo 	free(line);
600682b335aSArnaldo Carvalho de Melo 	fclose(file);
601682b335aSArnaldo Carvalho de Melo 	return err;
602682b335aSArnaldo Carvalho de Melo 
603682b335aSArnaldo Carvalho de Melo out_failure:
604682b335aSArnaldo Carvalho de Melo 	return -1;
605682b335aSArnaldo Carvalho de Melo }
606682b335aSArnaldo Carvalho de Melo 
607682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
608682b335aSArnaldo Carvalho de Melo 	struct map *map;
609682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
610682b335aSArnaldo Carvalho de Melo };
611682b335aSArnaldo Carvalho de Melo 
612c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
613c408fedfSArnaldo Carvalho de Melo {
614c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
615c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
616c408fedfSArnaldo Carvalho de Melo 
617c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
618c408fedfSArnaldo Carvalho de Melo }
619c408fedfSArnaldo Carvalho de Melo 
620682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
6213b01a413SArnaldo Carvalho de Melo 				       char type, u64 start, u64 end)
622682b335aSArnaldo Carvalho de Melo {
623682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
624682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
625682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
626682b335aSArnaldo Carvalho de Melo 
627682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
628682b335aSArnaldo Carvalho de Melo 		return 0;
629682b335aSArnaldo Carvalho de Melo 
6303b01a413SArnaldo Carvalho de Melo 	sym = symbol__new(start, end - start + 1,
6313b01a413SArnaldo Carvalho de Melo 			  kallsyms2elf_type(type), name);
6322e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
633682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
63482164161SArnaldo Carvalho de Melo 	/*
63582164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6364e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
63782164161SArnaldo Carvalho de Melo 	 */
6384e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
639a1645ce1SZhang, Yanmin 
640682b335aSArnaldo Carvalho de Melo 	return 0;
6412e538c4aSArnaldo Carvalho de Melo }
6422e538c4aSArnaldo Carvalho de Melo 
643682b335aSArnaldo Carvalho de Melo /*
644682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
645682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
646682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
647682b335aSArnaldo Carvalho de Melo  */
648aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6499e201442SArnaldo Carvalho de Melo 				  struct map *map)
650682b335aSArnaldo Carvalho de Melo {
651aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6529e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6532e538c4aSArnaldo Carvalho de Melo }
6542e538c4aSArnaldo Carvalho de Melo 
6552e538c4aSArnaldo Carvalho de Melo /*
6562e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
6572e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
6582e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
6592e538c4aSArnaldo Carvalho de Melo  */
660aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map,
6619de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
6622e538c4aSArnaldo Carvalho de Melo {
6639de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
66423346f21SArnaldo Carvalho de Melo 	struct machine *machine = kmaps->machine;
6654e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
6662e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
6678a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
668aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
6694e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
6702e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
6712e538c4aSArnaldo Carvalho de Melo 
6722e538c4aSArnaldo Carvalho de Melo 	while (next) {
6732e538c4aSArnaldo Carvalho de Melo 		char *module;
6742e538c4aSArnaldo Carvalho de Melo 
6752e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
6762e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
6772e538c4aSArnaldo Carvalho de Melo 
6782e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
6792e538c4aSArnaldo Carvalho de Melo 		if (module) {
68075be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
6811de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
6821de8e245SArnaldo Carvalho de Melo 
6832e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
6842e538c4aSArnaldo Carvalho de Melo 
685b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
686a1645ce1SZhang, Yanmin 				if (curr_map != map &&
687aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
68823346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
689a1645ce1SZhang, Yanmin 					/*
690a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
691a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
692a1645ce1SZhang, Yanmin 					 * points to a module and all its
693a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
694a1645ce1SZhang, Yanmin 					 * loaded.
695a1645ce1SZhang, Yanmin 					 */
696a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
697a1645ce1SZhang, Yanmin 							curr_map->type);
698af427bf5SArnaldo Carvalho de Melo 				}
699b7cece76SArnaldo Carvalho de Melo 
700a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
701a1645ce1SZhang, Yanmin 							map->type, module);
702a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7032f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
704a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
705a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
70623346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
707a1645ce1SZhang, Yanmin 					curr_map = map;
708a1645ce1SZhang, Yanmin 					goto discard_symbol;
709a1645ce1SZhang, Yanmin 				}
710a1645ce1SZhang, Yanmin 
711a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
71223346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
713b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
714af427bf5SArnaldo Carvalho de Melo 			}
71586470930SIngo Molnar 			/*
7162e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
7172e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
71886470930SIngo Molnar 			 */
7194e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
7204e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
7214e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
7222e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
723aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
72486470930SIngo Molnar 
7258a953312SArnaldo Carvalho de Melo 			if (count == 0) {
7268a953312SArnaldo Carvalho de Melo 				curr_map = map;
7278a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
7288a953312SArnaldo Carvalho de Melo 			}
7298a953312SArnaldo Carvalho de Melo 
730aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
731a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
732a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
733a1645ce1SZhang, Yanmin 					kernel_range++);
734a1645ce1SZhang, Yanmin 			else
735a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
736a1645ce1SZhang, Yanmin 					"[kernel].%d",
7372e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
73886470930SIngo Molnar 
739aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
740aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
7412e538c4aSArnaldo Carvalho de Melo 				return -1;
7422e538c4aSArnaldo Carvalho de Melo 
743aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
744a1645ce1SZhang, Yanmin 
745aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
74637fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
747aeafcbafSArnaldo Carvalho de Melo 				dso__delete(ndso);
7482e538c4aSArnaldo Carvalho de Melo 				return -1;
7492e538c4aSArnaldo Carvalho de Melo 			}
7502e538c4aSArnaldo Carvalho de Melo 
7514e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
7529de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
7532e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
7542e538c4aSArnaldo Carvalho de Melo 		}
7558a953312SArnaldo Carvalho de Melo filter_symbol:
7564e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
7571de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
75800a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
7592e538c4aSArnaldo Carvalho de Melo 		} else {
7604e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
7614e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
7624e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
7638a953312SArnaldo Carvalho de Melo 				++moved;
7648a953312SArnaldo Carvalho de Melo 			} else
7658a953312SArnaldo Carvalho de Melo 				++count;
7669974f496SMike Galbraith 		}
76786470930SIngo Molnar 	}
76886470930SIngo Molnar 
769a1645ce1SZhang, Yanmin 	if (curr_map != map &&
770aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
77123346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
772a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
773a1645ce1SZhang, Yanmin 	}
774a1645ce1SZhang, Yanmin 
7758a953312SArnaldo Carvalho de Melo 	return count + moved;
77686470930SIngo Molnar }
77786470930SIngo Molnar 
778ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename,
779ec80fde7SArnaldo Carvalho de Melo 					const char *restricted_filename)
780ec80fde7SArnaldo Carvalho de Melo {
781ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
782ec80fde7SArnaldo Carvalho de Melo 
783ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
784ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
785ec80fde7SArnaldo Carvalho de Melo 
786ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
787ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
788ec80fde7SArnaldo Carvalho de Melo 			free(r);
789ec80fde7SArnaldo Carvalho de Melo 			return restricted;
790ec80fde7SArnaldo Carvalho de Melo 		}
791ec80fde7SArnaldo Carvalho de Melo 	}
792ec80fde7SArnaldo Carvalho de Melo 
793ec80fde7SArnaldo Carvalho de Melo 	return restricted;
794ec80fde7SArnaldo Carvalho de Melo }
795ec80fde7SArnaldo Carvalho de Melo 
796aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
7979de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
7982e538c4aSArnaldo Carvalho de Melo {
799ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
800ec80fde7SArnaldo Carvalho de Melo 		return -1;
801ec80fde7SArnaldo Carvalho de Melo 
802aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
8032e538c4aSArnaldo Carvalho de Melo 		return -1;
8042e538c4aSArnaldo Carvalho de Melo 
805694bf407SAnton Blanchard 	symbols__fixup_duplicate(&dso->symbols[map->type]);
8063f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
8073f5a4272SAnton Blanchard 
808aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
809aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
810a1645ce1SZhang, Yanmin 	else
811aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__KALLSYMS;
8122e538c4aSArnaldo Carvalho de Melo 
813aeafcbafSArnaldo Carvalho de Melo 	return dso__split_kallsyms(dso, map, filter);
814af427bf5SArnaldo Carvalho de Melo }
815af427bf5SArnaldo Carvalho de Melo 
816aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
8176beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
81880d496beSPekka Enberg {
81980d496beSPekka Enberg 	char *line = NULL;
82080d496beSPekka Enberg 	size_t n;
82180d496beSPekka Enberg 	FILE *file;
82280d496beSPekka Enberg 	int nr_syms = 0;
82380d496beSPekka Enberg 
824aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
82580d496beSPekka Enberg 	if (file == NULL)
82680d496beSPekka Enberg 		goto out_failure;
82780d496beSPekka Enberg 
82880d496beSPekka Enberg 	while (!feof(file)) {
8299cffa8d5SPaul Mackerras 		u64 start, size;
83080d496beSPekka Enberg 		struct symbol *sym;
83180d496beSPekka Enberg 		int line_len, len;
83280d496beSPekka Enberg 
83380d496beSPekka Enberg 		line_len = getline(&line, &n, file);
83480d496beSPekka Enberg 		if (line_len < 0)
83580d496beSPekka Enberg 			break;
83680d496beSPekka Enberg 
83780d496beSPekka Enberg 		if (!line)
83880d496beSPekka Enberg 			goto out_failure;
83980d496beSPekka Enberg 
84080d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
84180d496beSPekka Enberg 
84280d496beSPekka Enberg 		len = hex2u64(line, &start);
84380d496beSPekka Enberg 
84480d496beSPekka Enberg 		len++;
84580d496beSPekka Enberg 		if (len + 2 >= line_len)
84680d496beSPekka Enberg 			continue;
84780d496beSPekka Enberg 
84880d496beSPekka Enberg 		len += hex2u64(line + len, &size);
84980d496beSPekka Enberg 
85080d496beSPekka Enberg 		len++;
85180d496beSPekka Enberg 		if (len + 2 >= line_len)
85280d496beSPekka Enberg 			continue;
85380d496beSPekka Enberg 
854c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
85580d496beSPekka Enberg 
85680d496beSPekka Enberg 		if (sym == NULL)
85780d496beSPekka Enberg 			goto out_delete_line;
85880d496beSPekka Enberg 
859439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
86000a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
86180d496beSPekka Enberg 		else {
862aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
86380d496beSPekka Enberg 			nr_syms++;
86480d496beSPekka Enberg 		}
86580d496beSPekka Enberg 	}
86680d496beSPekka Enberg 
86780d496beSPekka Enberg 	free(line);
86880d496beSPekka Enberg 	fclose(file);
86980d496beSPekka Enberg 
87080d496beSPekka Enberg 	return nr_syms;
87180d496beSPekka Enberg 
87280d496beSPekka Enberg out_delete_line:
87380d496beSPekka Enberg 	free(line);
87480d496beSPekka Enberg out_failure:
87580d496beSPekka Enberg 	return -1;
87680d496beSPekka Enberg }
87780d496beSPekka Enberg 
87886470930SIngo Molnar /**
87986470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
88086470930SIngo Molnar  *
881aeafcbafSArnaldo Carvalho de Melo  * @syms: struct elf_symtab instance to iterate
88283a0944fSIngo Molnar  * @idx: uint32_t idx
88386470930SIngo Molnar  * @sym: GElf_Sym iterator
88486470930SIngo Molnar  */
88583a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
88683a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
88783a0944fSIngo Molnar 	     idx < nr_syms; \
88883a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
88986470930SIngo Molnar 
89086470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
89186470930SIngo Molnar {
89286470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
89386470930SIngo Molnar }
89486470930SIngo Molnar 
89586470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
89686470930SIngo Molnar {
89786470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
89886470930SIngo Molnar 	       sym->st_name != 0 &&
89981833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
90086470930SIngo Molnar }
90186470930SIngo Molnar 
902f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
903f1dfa0b1SArnaldo Carvalho de Melo {
904f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
905f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
906f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
907f1dfa0b1SArnaldo Carvalho de Melo }
908f1dfa0b1SArnaldo Carvalho de Melo 
9096cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
9106cfcc53eSMike Galbraith {
9116cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
9126cfcc53eSMike Galbraith 		sym->st_name != 0 &&
9136cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
9146cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
9156cfcc53eSMike Galbraith }
9166cfcc53eSMike Galbraith 
9176cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
9186cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
9196cfcc53eSMike Galbraith {
9206cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
9216cfcc53eSMike Galbraith }
9226cfcc53eSMike Galbraith 
9236cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
9246cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
9256cfcc53eSMike Galbraith {
9266cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
9276cfcc53eSMike Galbraith }
9286cfcc53eSMike Galbraith 
929f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
930f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
931f1dfa0b1SArnaldo Carvalho de Melo {
932f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
933f1dfa0b1SArnaldo Carvalho de Melo }
934f1dfa0b1SArnaldo Carvalho de Melo 
93586470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
93686470930SIngo Molnar 					const Elf_Data *symstrs)
93786470930SIngo Molnar {
93886470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
93986470930SIngo Molnar }
94086470930SIngo Molnar 
94186470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
94286470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
94383a0944fSIngo Molnar 				    size_t *idx)
94486470930SIngo Molnar {
94586470930SIngo Molnar 	Elf_Scn *sec = NULL;
94686470930SIngo Molnar 	size_t cnt = 1;
94786470930SIngo Molnar 
94886470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
94986470930SIngo Molnar 		char *str;
95086470930SIngo Molnar 
95186470930SIngo Molnar 		gelf_getshdr(sec, shp);
95286470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
95386470930SIngo Molnar 		if (!strcmp(name, str)) {
95483a0944fSIngo Molnar 			if (idx)
95583a0944fSIngo Molnar 				*idx = cnt;
95686470930SIngo Molnar 			break;
95786470930SIngo Molnar 		}
95886470930SIngo Molnar 		++cnt;
95986470930SIngo Molnar 	}
96086470930SIngo Molnar 
96186470930SIngo Molnar 	return sec;
96286470930SIngo Molnar }
96386470930SIngo Molnar 
96486470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
96586470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
96686470930SIngo Molnar 	     idx < nr_entries; \
96786470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
96886470930SIngo Molnar 
96986470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
97086470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
97186470930SIngo Molnar 	     idx < nr_entries; \
97286470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
97386470930SIngo Molnar 
974a25e46c4SArnaldo Carvalho de Melo /*
975a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
976a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
977a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
978a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
979a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
980a25e46c4SArnaldo Carvalho de Melo  */
98133ff581eSJiri Olsa static int
98233ff581eSJiri Olsa dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
98382164161SArnaldo Carvalho de Melo 			    symbol_filter_t filter)
98486470930SIngo Molnar {
98586470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
98686470930SIngo Molnar 	GElf_Sym sym;
9879cffa8d5SPaul Mackerras 	u64 plt_offset;
98886470930SIngo Molnar 	GElf_Shdr shdr_plt;
98986470930SIngo Molnar 	struct symbol *f;
990a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
99186470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
992a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
993a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
994a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
99586470930SIngo Molnar 	char sympltname[1024];
996a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
997a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
99886470930SIngo Molnar 
999ec5761eaSDavid Ahern 	fd = open(name, O_RDONLY);
1000a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
1001a25e46c4SArnaldo Carvalho de Melo 		goto out;
1002a25e46c4SArnaldo Carvalho de Melo 
100384087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1004a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
1005a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
1006a25e46c4SArnaldo Carvalho de Melo 
1007a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
1008a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
1009a25e46c4SArnaldo Carvalho de Melo 
1010a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
1011a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
1012a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
1013a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
1014a25e46c4SArnaldo Carvalho de Melo 
1015a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
101686470930SIngo Molnar 					  ".rela.plt", NULL);
101786470930SIngo Molnar 	if (scn_plt_rel == NULL) {
1018a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
101986470930SIngo Molnar 						  ".rel.plt", NULL);
102086470930SIngo Molnar 		if (scn_plt_rel == NULL)
1021a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
102286470930SIngo Molnar 	}
102386470930SIngo Molnar 
1024a25e46c4SArnaldo Carvalho de Melo 	err = -1;
102586470930SIngo Molnar 
1026a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
1027a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
1028a25e46c4SArnaldo Carvalho de Melo 
1029a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
1030a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
103186470930SIngo Molnar 
103286470930SIngo Molnar 	/*
103383a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
103486470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
103586470930SIngo Molnar 	 */
103686470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
103786470930SIngo Molnar 	if (reldata == NULL)
1038a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
103986470930SIngo Molnar 
104086470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
104186470930SIngo Molnar 	if (syms == NULL)
1042a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
104386470930SIngo Molnar 
1044a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
104586470930SIngo Molnar 	if (scn_symstrs == NULL)
1046a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
104786470930SIngo Molnar 
104886470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
104986470930SIngo Molnar 	if (symstrs == NULL)
1050a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
105186470930SIngo Molnar 
105286470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
105386470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
105486470930SIngo Molnar 
105586470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
105686470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
105786470930SIngo Molnar 
105886470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
105986470930SIngo Molnar 					   nr_rel_entries) {
106086470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
106186470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
106286470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
106386470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
106486470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
106586470930SIngo Molnar 
106686470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
1067c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
106886470930SIngo Molnar 			if (!f)
1069a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
107086470930SIngo Molnar 
107182164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
107282164161SArnaldo Carvalho de Melo 				symbol__delete(f);
107382164161SArnaldo Carvalho de Melo 			else {
1074aeafcbafSArnaldo Carvalho de Melo 				symbols__insert(&dso->symbols[map->type], f);
107586470930SIngo Molnar 				++nr;
107686470930SIngo Molnar 			}
107782164161SArnaldo Carvalho de Melo 		}
107886470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
107986470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
108086470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
108186470930SIngo Molnar 					  nr_rel_entries) {
108286470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
108386470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
108486470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
108586470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
108686470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
108786470930SIngo Molnar 
108886470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
1089c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
109086470930SIngo Molnar 			if (!f)
1091a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
109286470930SIngo Molnar 
109382164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
109482164161SArnaldo Carvalho de Melo 				symbol__delete(f);
109582164161SArnaldo Carvalho de Melo 			else {
1096aeafcbafSArnaldo Carvalho de Melo 				symbols__insert(&dso->symbols[map->type], f);
109786470930SIngo Molnar 				++nr;
109886470930SIngo Molnar 			}
109986470930SIngo Molnar 		}
110082164161SArnaldo Carvalho de Melo 	}
110186470930SIngo Molnar 
1102a25e46c4SArnaldo Carvalho de Melo 	err = 0;
1103a25e46c4SArnaldo Carvalho de Melo out_elf_end:
1104a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
1105a25e46c4SArnaldo Carvalho de Melo out_close:
1106a25e46c4SArnaldo Carvalho de Melo 	close(fd);
1107a25e46c4SArnaldo Carvalho de Melo 
1108a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
110986470930SIngo Molnar 		return nr;
1110a25e46c4SArnaldo Carvalho de Melo out:
1111fe2197b8SArnaldo Carvalho de Melo 	pr_debug("%s: problems reading %s PLT info.\n",
1112aeafcbafSArnaldo Carvalho de Melo 		 __func__, dso->long_name);
1113a25e46c4SArnaldo Carvalho de Melo 	return 0;
111486470930SIngo Molnar }
111586470930SIngo Molnar 
1116aeafcbafSArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
1117d45868d3SArnaldo Carvalho de Melo {
1118d45868d3SArnaldo Carvalho de Melo 	switch (type) {
1119d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1120aeafcbafSArnaldo Carvalho de Melo 		return elf_sym__is_function(sym);
1121f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
1122aeafcbafSArnaldo Carvalho de Melo 		return elf_sym__is_object(sym);
1123d45868d3SArnaldo Carvalho de Melo 	default:
1124d45868d3SArnaldo Carvalho de Melo 		return false;
1125d45868d3SArnaldo Carvalho de Melo 	}
1126d45868d3SArnaldo Carvalho de Melo }
1127d45868d3SArnaldo Carvalho de Melo 
1128aeafcbafSArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
1129aeafcbafSArnaldo Carvalho de Melo 			  enum map_type type)
1130d45868d3SArnaldo Carvalho de Melo {
1131d45868d3SArnaldo Carvalho de Melo 	switch (type) {
1132d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1133aeafcbafSArnaldo Carvalho de Melo 		return elf_sec__is_text(shdr, secstrs);
1134f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
1135aeafcbafSArnaldo Carvalho de Melo 		return elf_sec__is_data(shdr, secstrs);
1136d45868d3SArnaldo Carvalho de Melo 	default:
1137d45868d3SArnaldo Carvalho de Melo 		return false;
1138d45868d3SArnaldo Carvalho de Melo 	}
1139d45868d3SArnaldo Carvalho de Melo }
1140d45868d3SArnaldo Carvalho de Melo 
114170c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
114270c3856bSEric B Munson {
114370c3856bSEric B Munson 	Elf_Scn *sec = NULL;
114470c3856bSEric B Munson 	GElf_Shdr shdr;
114570c3856bSEric B Munson 	size_t cnt = 1;
114670c3856bSEric B Munson 
114770c3856bSEric B Munson 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
114870c3856bSEric B Munson 		gelf_getshdr(sec, &shdr);
114970c3856bSEric B Munson 
115070c3856bSEric B Munson 		if ((addr >= shdr.sh_addr) &&
115170c3856bSEric B Munson 		    (addr < (shdr.sh_addr + shdr.sh_size)))
115270c3856bSEric B Munson 			return cnt;
115370c3856bSEric B Munson 
115470c3856bSEric B Munson 		++cnt;
115570c3856bSEric B Munson 	}
115670c3856bSEric B Munson 
115770c3856bSEric B Munson 	return -1;
115870c3856bSEric B Munson }
115970c3856bSEric B Munson 
11608db4841fSJiri Olsa static int dso__swap_init(struct dso *dso, unsigned char eidata)
11618db4841fSJiri Olsa {
11628db4841fSJiri Olsa 	static unsigned int const endian = 1;
11638db4841fSJiri Olsa 
11648db4841fSJiri Olsa 	dso->needs_swap = DSO_SWAP__NO;
11658db4841fSJiri Olsa 
11668db4841fSJiri Olsa 	switch (eidata) {
11678db4841fSJiri Olsa 	case ELFDATA2LSB:
11688db4841fSJiri Olsa 		/* We are big endian, DSO is little endian. */
11698db4841fSJiri Olsa 		if (*(unsigned char const *)&endian != 1)
11708db4841fSJiri Olsa 			dso->needs_swap = DSO_SWAP__YES;
11718db4841fSJiri Olsa 		break;
11728db4841fSJiri Olsa 
11738db4841fSJiri Olsa 	case ELFDATA2MSB:
11748db4841fSJiri Olsa 		/* We are little endian, DSO is big endian. */
11758db4841fSJiri Olsa 		if (*(unsigned char const *)&endian != 0)
11768db4841fSJiri Olsa 			dso->needs_swap = DSO_SWAP__YES;
11778db4841fSJiri Olsa 		break;
11788db4841fSJiri Olsa 
11798db4841fSJiri Olsa 	default:
11808db4841fSJiri Olsa 		pr_err("unrecognized DSO data encoding %d\n", eidata);
11818db4841fSJiri Olsa 		return -EINVAL;
11828db4841fSJiri Olsa 	}
11838db4841fSJiri Olsa 
11848db4841fSJiri Olsa 	return 0;
11858db4841fSJiri Olsa }
11868db4841fSJiri Olsa 
1187aeafcbafSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
11886da80ce8SDave Martin 			 int fd, symbol_filter_t filter, int kmodule,
11896da80ce8SDave Martin 			 int want_symtab)
119086470930SIngo Molnar {
1191aeafcbafSArnaldo Carvalho de Melo 	struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
11922e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
1193aeafcbafSArnaldo Carvalho de Melo 	struct dso *curr_dso = dso;
11946cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
119586470930SIngo Molnar 	uint32_t nr_syms;
119686470930SIngo Molnar 	int err = -1;
119783a0944fSIngo Molnar 	uint32_t idx;
119886470930SIngo Molnar 	GElf_Ehdr ehdr;
119970c3856bSEric B Munson 	GElf_Shdr shdr, opdshdr;
120070c3856bSEric B Munson 	Elf_Data *syms, *opddata = NULL;
120186470930SIngo Molnar 	GElf_Sym sym;
120270c3856bSEric B Munson 	Elf_Scn *sec, *sec_strndx, *opdsec;
120386470930SIngo Molnar 	Elf *elf;
1204439d473bSArnaldo Carvalho de Melo 	int nr = 0;
120570c3856bSEric B Munson 	size_t opdidx = 0;
120686470930SIngo Molnar 
120784087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
120886470930SIngo Molnar 	if (elf == NULL) {
12098b1389efSDave Martin 		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
121086470930SIngo Molnar 		goto out_close;
121186470930SIngo Molnar 	}
121286470930SIngo Molnar 
121386470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
12148b1389efSDave Martin 		pr_debug("%s: cannot get elf header.\n", __func__);
121586470930SIngo Molnar 		goto out_elf_end;
121686470930SIngo Molnar 	}
121786470930SIngo Molnar 
12188db4841fSJiri Olsa 	if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
12198db4841fSJiri Olsa 		goto out_elf_end;
12208db4841fSJiri Olsa 
12216da80ce8SDave Martin 	/* Always reject images with a mismatched build-id: */
1222aeafcbafSArnaldo Carvalho de Melo 	if (dso->has_build_id) {
122321916c38SDave Martin 		u8 build_id[BUILD_ID_SIZE];
122421916c38SDave Martin 
1225be96ea8fSStephane Eranian 		if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
122621916c38SDave Martin 			goto out_elf_end;
122721916c38SDave Martin 
1228aeafcbafSArnaldo Carvalho de Melo 		if (!dso__build_id_equal(dso, build_id))
122921916c38SDave Martin 			goto out_elf_end;
123021916c38SDave Martin 	}
123121916c38SDave Martin 
123286470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
123386470930SIngo Molnar 	if (sec == NULL) {
12346da80ce8SDave Martin 		if (want_symtab)
12356da80ce8SDave Martin 			goto out_elf_end;
12366da80ce8SDave Martin 
1237a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1238a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
123986470930SIngo Molnar 			goto out_elf_end;
124086470930SIngo Molnar 	}
124186470930SIngo Molnar 
124270c3856bSEric B Munson 	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1243adb09184SAnton Blanchard 	if (opdshdr.sh_type != SHT_PROGBITS)
1244adb09184SAnton Blanchard 		opdsec = NULL;
124570c3856bSEric B Munson 	if (opdsec)
124670c3856bSEric B Munson 		opddata = elf_rawdata(opdsec, NULL);
124770c3856bSEric B Munson 
124886470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
124986470930SIngo Molnar 	if (syms == NULL)
125086470930SIngo Molnar 		goto out_elf_end;
125186470930SIngo Molnar 
125286470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
125386470930SIngo Molnar 	if (sec == NULL)
125486470930SIngo Molnar 		goto out_elf_end;
125586470930SIngo Molnar 
125686470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
125786470930SIngo Molnar 	if (symstrs == NULL)
125886470930SIngo Molnar 		goto out_elf_end;
125986470930SIngo Molnar 
12606cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
12616cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
12626cfcc53eSMike Galbraith 		goto out_elf_end;
12636cfcc53eSMike Galbraith 
12646cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
12659b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
12666cfcc53eSMike Galbraith 		goto out_elf_end;
12676cfcc53eSMike Galbraith 
126886470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
126986470930SIngo Molnar 
1270e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
1271aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_USER) {
1272aeafcbafSArnaldo Carvalho de Melo 		dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
127330d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
1274f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
127530d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
1276aeafcbafSArnaldo Carvalho de Melo 	} else {
1277aeafcbafSArnaldo Carvalho de Melo 		dso->adjust_symbols = 0;
1278aeafcbafSArnaldo Carvalho de Melo 	}
127983a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
128086470930SIngo Molnar 		struct symbol *f;
128156b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
12822e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
12836cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
12846cfcc53eSMike Galbraith 		const char *section_name;
128586470930SIngo Molnar 
12869de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
12879de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
12889de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
128956b03f3cSArnaldo Carvalho de Melo 
1290d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
129186470930SIngo Molnar 			continue;
129286470930SIngo Molnar 
1293696b97a5SDave Martin 		/* Reject ARM ELF "mapping symbols": these aren't unique and
1294696b97a5SDave Martin 		 * don't identify functions, so will confuse the profile
1295696b97a5SDave Martin 		 * output: */
1296696b97a5SDave Martin 		if (ehdr.e_machine == EM_ARM) {
1297696b97a5SDave Martin 			if (!strcmp(elf_name, "$a") ||
1298696b97a5SDave Martin 			    !strcmp(elf_name, "$d") ||
1299696b97a5SDave Martin 			    !strcmp(elf_name, "$t"))
1300696b97a5SDave Martin 				continue;
1301696b97a5SDave Martin 		}
1302696b97a5SDave Martin 
130370c3856bSEric B Munson 		if (opdsec && sym.st_shndx == opdidx) {
130470c3856bSEric B Munson 			u32 offset = sym.st_value - opdshdr.sh_addr;
130570c3856bSEric B Munson 			u64 *opd = opddata->d_buf + offset;
13068db4841fSJiri Olsa 			sym.st_value = DSO__SWAP(dso, u64, *opd);
130770c3856bSEric B Munson 			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
130870c3856bSEric B Munson 		}
130970c3856bSEric B Munson 
131086470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
131186470930SIngo Molnar 		if (!sec)
131286470930SIngo Molnar 			goto out_elf_end;
131386470930SIngo Molnar 
131486470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
13156cfcc53eSMike Galbraith 
1316d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
13176cfcc53eSMike Galbraith 			continue;
13186cfcc53eSMike Galbraith 
13196cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
132086470930SIngo Molnar 
1321b2f8fb23SDr. David Alan Gilbert 		/* On ARM, symbols for thumb functions have 1 added to
1322b2f8fb23SDr. David Alan Gilbert 		 * the symbol address as a flag - remove it */
1323b2f8fb23SDr. David Alan Gilbert 		if ((ehdr.e_machine == EM_ARM) &&
1324b2f8fb23SDr. David Alan Gilbert 		    (map->type == MAP__FUNCTION) &&
1325b2f8fb23SDr. David Alan Gilbert 		    (sym.st_value & 1))
1326b2f8fb23SDr. David Alan Gilbert 			--sym.st_value;
1327b2f8fb23SDr. David Alan Gilbert 
1328aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel != DSO_TYPE_USER || kmodule) {
13292e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
13302e538c4aSArnaldo Carvalho de Melo 
13312e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1332b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1333aeafcbafSArnaldo Carvalho de Melo 				    dso->short_name_len)) == 0)
13342e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
13352e538c4aSArnaldo Carvalho de Melo 
13362e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
13372e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
1338aeafcbafSArnaldo Carvalho de Melo 				curr_dso = dso;
13392e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1340af427bf5SArnaldo Carvalho de Melo 			}
1341af427bf5SArnaldo Carvalho de Melo 
13422e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
1343aeafcbafSArnaldo Carvalho de Melo 				 "%s%s", dso->short_name, section_name);
13442e538c4aSArnaldo Carvalho de Melo 
13459de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
13462e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
13472e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
13482e538c4aSArnaldo Carvalho de Melo 
13492e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
13502e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
13512e538c4aSArnaldo Carvalho de Melo 
135200a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
13532e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
13542e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1355aeafcbafSArnaldo Carvalho de Melo 				curr_dso->kernel = dso->kernel;
1356aeafcbafSArnaldo Carvalho de Melo 				curr_dso->long_name = dso->long_name;
1357aeafcbafSArnaldo Carvalho de Melo 				curr_dso->long_name_len = dso->long_name_len;
13583610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
13596275ce2dSArnaldo Carvalho de Melo 						     map->type);
13602e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
13612e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
13622e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
13632e538c4aSArnaldo Carvalho de Melo 				}
1364ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1365ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1366aeafcbafSArnaldo Carvalho de Melo 				curr_dso->symtab_type = dso->symtab_type;
13679de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1368aeafcbafSArnaldo Carvalho de Melo 				dsos__add(&dso->node, curr_dso);
13696275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
13702e538c4aSArnaldo Carvalho de Melo 			} else
13712e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
13722e538c4aSArnaldo Carvalho de Melo 
13732e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
13742e538c4aSArnaldo Carvalho de Melo 		}
13752e538c4aSArnaldo Carvalho de Melo 
13762e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
13779486aa38SArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
13789486aa38SArnaldo Carvalho de Melo 				  "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
137929a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
138029a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
138186470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1382af427bf5SArnaldo Carvalho de Melo 		}
138328ac909bSArnaldo Carvalho de Melo 		/*
138428ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
138528ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
138628ac909bSArnaldo Carvalho de Melo 		 * to it...
138728ac909bSArnaldo Carvalho de Melo 		 */
138883a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
138928ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
139083a0944fSIngo Molnar 			elf_name = demangled;
13912e538c4aSArnaldo Carvalho de Melo new_symbol:
1392c408fedfSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size,
1393c408fedfSArnaldo Carvalho de Melo 				GELF_ST_BIND(sym.st_info), elf_name);
139428ac909bSArnaldo Carvalho de Melo 		free(demangled);
139586470930SIngo Molnar 		if (!f)
139686470930SIngo Molnar 			goto out_elf_end;
139786470930SIngo Molnar 
13982e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
139900a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
140086470930SIngo Molnar 		else {
14016a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
140286470930SIngo Molnar 			nr++;
140386470930SIngo Molnar 		}
140486470930SIngo Molnar 	}
140586470930SIngo Molnar 
14062e538c4aSArnaldo Carvalho de Melo 	/*
14072e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
14082e538c4aSArnaldo Carvalho de Melo 	 */
14096275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
1410694bf407SAnton Blanchard 		symbols__fixup_duplicate(&dso->symbols[map->type]);
1411aeafcbafSArnaldo Carvalho de Melo 		symbols__fixup_end(&dso->symbols[map->type]);
14126275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
14136275ce2dSArnaldo Carvalho de Melo 			/*
14146275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
14156275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
14166275ce2dSArnaldo Carvalho de Melo 			 */
14176275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
14186275ce2dSArnaldo Carvalho de Melo 		}
14196275ce2dSArnaldo Carvalho de Melo 	}
142086470930SIngo Molnar 	err = nr;
142186470930SIngo Molnar out_elf_end:
142286470930SIngo Molnar 	elf_end(elf);
142386470930SIngo Molnar out_close:
142486470930SIngo Molnar 	return err;
142586470930SIngo Molnar }
142686470930SIngo Molnar 
1427aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
142878075caaSArnaldo Carvalho de Melo {
1429aeafcbafSArnaldo Carvalho de Melo 	return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
143078075caaSArnaldo Carvalho de Melo }
143178075caaSArnaldo Carvalho de Melo 
1432a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
143357f395a7SFrederic Weisbecker {
1434e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
143557f395a7SFrederic Weisbecker 	struct dso *pos;
143657f395a7SFrederic Weisbecker 
14376122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
14386122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
14396122e4e4SArnaldo Carvalho de Melo 			continue;
1440f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
1441f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
1442f6e1467dSArnaldo Carvalho de Melo 			continue;
1443f6e1467dSArnaldo Carvalho de Melo 		}
1444e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1445e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1446e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1447e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
144857f395a7SFrederic Weisbecker 		}
14496122e4e4SArnaldo Carvalho de Melo 	}
145057f395a7SFrederic Weisbecker 
1451e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
145257f395a7SFrederic Weisbecker }
145357f395a7SFrederic Weisbecker 
1454fd7a346eSArnaldo Carvalho de Melo /*
1455fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1456fd7a346eSArnaldo Carvalho de Melo  */
1457fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1458fd7a346eSArnaldo Carvalho de Melo 
145921916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size)
14604d1e00a8SArnaldo Carvalho de Melo {
146121916c38SDave Martin 	int err = -1;
14624d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
14634d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1464fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
14654d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1466e57cfcdaSPekka Enberg 	Elf_Kind ek;
1467fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
14684d1e00a8SArnaldo Carvalho de Melo 
14692643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
14702643ce11SArnaldo Carvalho de Melo 		goto out;
14712643ce11SArnaldo Carvalho de Melo 
1472e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1473e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
147421916c38SDave Martin 		goto out;
1475e57cfcdaSPekka Enberg 
14764d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
14776beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
147821916c38SDave Martin 		goto out;
14794d1e00a8SArnaldo Carvalho de Melo 	}
14804d1e00a8SArnaldo Carvalho de Melo 
14811388d715SJiri Olsa 	/*
14821388d715SJiri Olsa 	 * Check following sections for notes:
14831388d715SJiri Olsa 	 *   '.note.gnu.build-id'
14841388d715SJiri Olsa 	 *   '.notes'
14851388d715SJiri Olsa 	 *   '.note' (VDSO specific)
14861388d715SJiri Olsa 	 */
14871388d715SJiri Olsa 	do {
14882643ce11SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
14892643ce11SArnaldo Carvalho de Melo 					  ".note.gnu.build-id", NULL);
14901388d715SJiri Olsa 		if (sec)
14911388d715SJiri Olsa 			break;
14921388d715SJiri Olsa 
1493fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1494fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
14951388d715SJiri Olsa 		if (sec)
14961388d715SJiri Olsa 			break;
14971388d715SJiri Olsa 
14981388d715SJiri Olsa 		sec = elf_section_by_name(elf, &ehdr, &shdr,
14991388d715SJiri Olsa 					  ".note", NULL);
15001388d715SJiri Olsa 		if (sec)
15011388d715SJiri Olsa 			break;
15021388d715SJiri Olsa 
15031388d715SJiri Olsa 		return err;
15041388d715SJiri Olsa 
15051388d715SJiri Olsa 	} while (0);
15064d1e00a8SArnaldo Carvalho de Melo 
1507fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1508fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
150921916c38SDave Martin 		goto out;
1510fd7a346eSArnaldo Carvalho de Melo 
1511fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1512fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1513fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1514be96ea8fSStephane Eranian 		size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
1515fd7a346eSArnaldo Carvalho de Melo 		       descsz = NOTE_ALIGN(nhdr->n_descsz);
1516fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1517fd7a346eSArnaldo Carvalho de Melo 
1518fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1519fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1520fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1521fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1522fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1523fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1524be96ea8fSStephane Eranian 				size_t sz = min(size, descsz);
1525be96ea8fSStephane Eranian 				memcpy(bf, ptr, sz);
1526be96ea8fSStephane Eranian 				memset(bf + sz, 0, size - sz);
1527be96ea8fSStephane Eranian 				err = descsz;
1528fd7a346eSArnaldo Carvalho de Melo 				break;
1529fd7a346eSArnaldo Carvalho de Melo 			}
1530fd7a346eSArnaldo Carvalho de Melo 		}
1531fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1532fd7a346eSArnaldo Carvalho de Melo 	}
153321916c38SDave Martin 
153421916c38SDave Martin out:
153521916c38SDave Martin 	return err;
153621916c38SDave Martin }
153721916c38SDave Martin 
153821916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size)
153921916c38SDave Martin {
154021916c38SDave Martin 	int fd, err = -1;
154121916c38SDave Martin 	Elf *elf;
154221916c38SDave Martin 
154321916c38SDave Martin 	if (size < BUILD_ID_SIZE)
154421916c38SDave Martin 		goto out;
154521916c38SDave Martin 
154621916c38SDave Martin 	fd = open(filename, O_RDONLY);
154721916c38SDave Martin 	if (fd < 0)
154821916c38SDave Martin 		goto out;
154921916c38SDave Martin 
155021916c38SDave Martin 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
155121916c38SDave Martin 	if (elf == NULL) {
155221916c38SDave Martin 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
155321916c38SDave Martin 		goto out_close;
155421916c38SDave Martin 	}
155521916c38SDave Martin 
155621916c38SDave Martin 	err = elf_read_build_id(elf, bf, size);
155721916c38SDave Martin 
15582643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
15592643ce11SArnaldo Carvalho de Melo out_close:
15602643ce11SArnaldo Carvalho de Melo 	close(fd);
15612643ce11SArnaldo Carvalho de Melo out:
15622643ce11SArnaldo Carvalho de Melo 	return err;
15632643ce11SArnaldo Carvalho de Melo }
15642643ce11SArnaldo Carvalho de Melo 
1565f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1566f1617b40SArnaldo Carvalho de Melo {
1567f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1568f1617b40SArnaldo Carvalho de Melo 
1569f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1570f1617b40SArnaldo Carvalho de Melo 		goto out;
1571f1617b40SArnaldo Carvalho de Melo 
1572f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1573f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1574f1617b40SArnaldo Carvalho de Melo 		goto out;
1575f1617b40SArnaldo Carvalho de Melo 
1576f1617b40SArnaldo Carvalho de Melo 	while (1) {
1577f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1578f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1579be96ea8fSStephane Eranian 		size_t namesz, descsz;
1580f1617b40SArnaldo Carvalho de Melo 
1581f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1582f1617b40SArnaldo Carvalho de Melo 			break;
1583f1617b40SArnaldo Carvalho de Melo 
1584fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1585fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1586f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1587f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1588be96ea8fSStephane Eranian 			if (read(fd, bf, namesz) != (ssize_t)namesz)
1589f1617b40SArnaldo Carvalho de Melo 				break;
1590f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1591be96ea8fSStephane Eranian 				size_t sz = min(descsz, size);
1592be96ea8fSStephane Eranian 				if (read(fd, build_id, sz) == (ssize_t)sz) {
1593be96ea8fSStephane Eranian 					memset(build_id + sz, 0, size - sz);
1594f1617b40SArnaldo Carvalho de Melo 					err = 0;
1595f1617b40SArnaldo Carvalho de Melo 					break;
1596f1617b40SArnaldo Carvalho de Melo 				}
1597be96ea8fSStephane Eranian 			} else if (read(fd, bf, descsz) != (ssize_t)descsz)
1598f1617b40SArnaldo Carvalho de Melo 				break;
1599f1617b40SArnaldo Carvalho de Melo 		} else {
1600f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1601f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1602f1617b40SArnaldo Carvalho de Melo 				break;
1603f1617b40SArnaldo Carvalho de Melo 		}
1604f1617b40SArnaldo Carvalho de Melo 	}
1605f1617b40SArnaldo Carvalho de Melo 	close(fd);
1606f1617b40SArnaldo Carvalho de Melo out:
1607f1617b40SArnaldo Carvalho de Melo 	return err;
1608f1617b40SArnaldo Carvalho de Melo }
1609f1617b40SArnaldo Carvalho de Melo 
1610209bd9e3SPierre-Loup A. Griffais static int filename__read_debuglink(const char *filename,
1611209bd9e3SPierre-Loup A. Griffais 				    char *debuglink, size_t size)
1612209bd9e3SPierre-Loup A. Griffais {
1613209bd9e3SPierre-Loup A. Griffais 	int fd, err = -1;
1614209bd9e3SPierre-Loup A. Griffais 	Elf *elf;
1615209bd9e3SPierre-Loup A. Griffais 	GElf_Ehdr ehdr;
1616209bd9e3SPierre-Loup A. Griffais 	GElf_Shdr shdr;
1617209bd9e3SPierre-Loup A. Griffais 	Elf_Data *data;
1618209bd9e3SPierre-Loup A. Griffais 	Elf_Scn *sec;
1619209bd9e3SPierre-Loup A. Griffais 	Elf_Kind ek;
1620209bd9e3SPierre-Loup A. Griffais 
1621209bd9e3SPierre-Loup A. Griffais 	fd = open(filename, O_RDONLY);
1622209bd9e3SPierre-Loup A. Griffais 	if (fd < 0)
1623209bd9e3SPierre-Loup A. Griffais 		goto out;
1624209bd9e3SPierre-Loup A. Griffais 
1625209bd9e3SPierre-Loup A. Griffais 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1626209bd9e3SPierre-Loup A. Griffais 	if (elf == NULL) {
1627209bd9e3SPierre-Loup A. Griffais 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1628209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1629209bd9e3SPierre-Loup A. Griffais 	}
1630209bd9e3SPierre-Loup A. Griffais 
1631209bd9e3SPierre-Loup A. Griffais 	ek = elf_kind(elf);
1632209bd9e3SPierre-Loup A. Griffais 	if (ek != ELF_K_ELF)
1633209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1634209bd9e3SPierre-Loup A. Griffais 
1635209bd9e3SPierre-Loup A. Griffais 	if (gelf_getehdr(elf, &ehdr) == NULL) {
1636209bd9e3SPierre-Loup A. Griffais 		pr_err("%s: cannot get elf header.\n", __func__);
1637209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1638209bd9e3SPierre-Loup A. Griffais 	}
1639209bd9e3SPierre-Loup A. Griffais 
1640209bd9e3SPierre-Loup A. Griffais 	sec = elf_section_by_name(elf, &ehdr, &shdr,
1641209bd9e3SPierre-Loup A. Griffais 				  ".gnu_debuglink", NULL);
1642209bd9e3SPierre-Loup A. Griffais 	if (sec == NULL)
1643209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1644209bd9e3SPierre-Loup A. Griffais 
1645209bd9e3SPierre-Loup A. Griffais 	data = elf_getdata(sec, NULL);
1646209bd9e3SPierre-Loup A. Griffais 	if (data == NULL)
1647209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1648209bd9e3SPierre-Loup A. Griffais 
1649209bd9e3SPierre-Loup A. Griffais 	/* the start of this section is a zero-terminated string */
1650209bd9e3SPierre-Loup A. Griffais 	strncpy(debuglink, data->d_buf, size);
1651209bd9e3SPierre-Loup A. Griffais 
1652209bd9e3SPierre-Loup A. Griffais 	elf_end(elf);
1653209bd9e3SPierre-Loup A. Griffais 
1654209bd9e3SPierre-Loup A. Griffais out_close:
1655209bd9e3SPierre-Loup A. Griffais 	close(fd);
1656209bd9e3SPierre-Loup A. Griffais out:
1657209bd9e3SPierre-Loup A. Griffais 	return err;
1658209bd9e3SPierre-Loup A. Griffais }
1659209bd9e3SPierre-Loup A. Griffais 
1660aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso)
166194cb9e38SArnaldo Carvalho de Melo {
166294cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
1663878b439dSArnaldo Carvalho de Melo 		[SYMTAB__KALLSYMS]	      = 'k',
1664878b439dSArnaldo Carvalho de Melo 		[SYMTAB__JAVA_JIT]	      = 'j',
1665209bd9e3SPierre-Loup A. Griffais 		[SYMTAB__DEBUGLINK]           = 'l',
1666878b439dSArnaldo Carvalho de Melo 		[SYMTAB__BUILD_ID_CACHE]      = 'B',
1667878b439dSArnaldo Carvalho de Melo 		[SYMTAB__FEDORA_DEBUGINFO]    = 'f',
1668878b439dSArnaldo Carvalho de Melo 		[SYMTAB__UBUNTU_DEBUGINFO]    = 'u',
1669878b439dSArnaldo Carvalho de Melo 		[SYMTAB__BUILDID_DEBUGINFO]   = 'b',
1670878b439dSArnaldo Carvalho de Melo 		[SYMTAB__SYSTEM_PATH_DSO]     = 'd',
1671878b439dSArnaldo Carvalho de Melo 		[SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1672878b439dSArnaldo Carvalho de Melo 		[SYMTAB__GUEST_KALLSYMS]      =  'g',
1673878b439dSArnaldo Carvalho de Melo 		[SYMTAB__GUEST_KMODULE]	      =  'G',
167494cb9e38SArnaldo Carvalho de Melo 	};
167594cb9e38SArnaldo Carvalho de Melo 
1676aeafcbafSArnaldo Carvalho de Melo 	if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND)
167794cb9e38SArnaldo Carvalho de Melo 		return '!';
1678aeafcbafSArnaldo Carvalho de Melo 	return origin[dso->symtab_type];
167994cb9e38SArnaldo Carvalho de Melo }
168094cb9e38SArnaldo Carvalho de Melo 
1681aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
168286470930SIngo Molnar {
16834d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1684c338aee8SArnaldo Carvalho de Melo 	char *name;
168586470930SIngo Molnar 	int ret = -1;
168686470930SIngo Molnar 	int fd;
168723346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1688a1645ce1SZhang, Yanmin 	const char *root_dir;
16896da80ce8SDave Martin 	int want_symtab;
169086470930SIngo Molnar 
1691aeafcbafSArnaldo Carvalho de Melo 	dso__set_loaded(dso, map->type);
169266bd8424SArnaldo Carvalho de Melo 
1693aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_KERNEL)
1694aeafcbafSArnaldo Carvalho de Melo 		return dso__load_kernel_sym(dso, map, filter);
1695aeafcbafSArnaldo Carvalho de Melo 	else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1696aeafcbafSArnaldo Carvalho de Melo 		return dso__load_guest_kernel_sym(dso, map, filter);
1697a1645ce1SZhang, Yanmin 
169823346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
169923346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1700a1645ce1SZhang, Yanmin 	else
170123346f21SArnaldo Carvalho de Melo 		machine = NULL;
1702c338aee8SArnaldo Carvalho de Melo 
1703c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
170486470930SIngo Molnar 	if (!name)
170586470930SIngo Molnar 		return -1;
170686470930SIngo Molnar 
1707aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1708f5812a7aSArnaldo Carvalho de Melo 
1709aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1710981c1252SPekka Enberg 		struct stat st;
1711981c1252SPekka Enberg 
1712e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
1713981c1252SPekka Enberg 			return -1;
1714981c1252SPekka Enberg 
1715981c1252SPekka Enberg 		if (st.st_uid && (st.st_uid != geteuid())) {
1716981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1717981c1252SPekka Enberg 				"ignoring it.\n", dso->name);
1718981c1252SPekka Enberg 			return -1;
1719981c1252SPekka Enberg 		}
1720981c1252SPekka Enberg 
1721aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
1722aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1723878b439dSArnaldo Carvalho de Melo 					      SYMTAB__NOT_FOUND;
172494cb9e38SArnaldo Carvalho de Melo 		return ret;
172594cb9e38SArnaldo Carvalho de Melo 	}
172694cb9e38SArnaldo Carvalho de Melo 
17276da80ce8SDave Martin 	/* Iterate over candidate debug images.
17286da80ce8SDave Martin 	 * On the first pass, only load images if they have a full symtab.
17296da80ce8SDave Martin 	 * Failing that, do a second pass where we accept .dynsym also
17306da80ce8SDave Martin 	 */
173160e4b10cSArnaldo Carvalho de Melo 	want_symtab = 1;
173260e4b10cSArnaldo Carvalho de Melo restart:
1733209bd9e3SPierre-Loup A. Griffais 	for (dso->symtab_type = SYMTAB__DEBUGLINK;
1734aeafcbafSArnaldo Carvalho de Melo 	     dso->symtab_type != SYMTAB__NOT_FOUND;
1735aeafcbafSArnaldo Carvalho de Melo 	     dso->symtab_type++) {
1736aeafcbafSArnaldo Carvalho de Melo 		switch (dso->symtab_type) {
1737209bd9e3SPierre-Loup A. Griffais 		case SYMTAB__DEBUGLINK: {
1738209bd9e3SPierre-Loup A. Griffais 			char *debuglink;
1739209bd9e3SPierre-Loup A. Griffais 			strncpy(name, dso->long_name, size);
1740209bd9e3SPierre-Loup A. Griffais 			debuglink = name + dso->long_name_len;
1741209bd9e3SPierre-Loup A. Griffais 			while (debuglink != name && *debuglink != '/')
1742209bd9e3SPierre-Loup A. Griffais 				debuglink--;
1743209bd9e3SPierre-Loup A. Griffais 			if (*debuglink == '/')
1744209bd9e3SPierre-Loup A. Griffais 				debuglink++;
1745209bd9e3SPierre-Loup A. Griffais 			filename__read_debuglink(dso->long_name, debuglink,
1746209bd9e3SPierre-Loup A. Griffais 						 size - (debuglink - name));
1747209bd9e3SPierre-Loup A. Griffais 			}
1748209bd9e3SPierre-Loup A. Griffais 			break;
1749878b439dSArnaldo Carvalho de Melo 		case SYMTAB__BUILD_ID_CACHE:
1750ec5761eaSDavid Ahern 			/* skip the locally configured cache if a symfs is given */
1751ec5761eaSDavid Ahern 			if (symbol_conf.symfs[0] ||
1752aeafcbafSArnaldo Carvalho de Melo 			    (dso__build_id_filename(dso, name, size) == NULL)) {
17536da80ce8SDave Martin 				continue;
1754ec5761eaSDavid Ahern 			}
17556da80ce8SDave Martin 			break;
1756878b439dSArnaldo Carvalho de Melo 		case SYMTAB__FEDORA_DEBUGINFO:
1757ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s.debug",
1758aeafcbafSArnaldo Carvalho de Melo 				 symbol_conf.symfs, dso->long_name);
175986470930SIngo Molnar 			break;
1760878b439dSArnaldo Carvalho de Melo 		case SYMTAB__UBUNTU_DEBUGINFO:
1761ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s",
1762aeafcbafSArnaldo Carvalho de Melo 				 symbol_conf.symfs, dso->long_name);
176386470930SIngo Molnar 			break;
1764878b439dSArnaldo Carvalho de Melo 		case SYMTAB__BUILDID_DEBUGINFO: {
1765b36f19d5SArnaldo Carvalho de Melo 			char build_id_hex[BUILD_ID_SIZE * 2 + 1];
17666da80ce8SDave Martin 
1767aeafcbafSArnaldo Carvalho de Melo 			if (!dso->has_build_id)
17686da80ce8SDave Martin 				continue;
17696da80ce8SDave Martin 
1770aeafcbafSArnaldo Carvalho de Melo 			build_id__sprintf(dso->build_id,
1771aeafcbafSArnaldo Carvalho de Melo 					  sizeof(dso->build_id),
1772d3379ab9SArnaldo Carvalho de Melo 					  build_id_hex);
17734d1e00a8SArnaldo Carvalho de Melo 			snprintf(name, size,
1774ec5761eaSDavid Ahern 				 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1775ec5761eaSDavid Ahern 				 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
17764d1e00a8SArnaldo Carvalho de Melo 			}
17776da80ce8SDave Martin 			break;
1778878b439dSArnaldo Carvalho de Melo 		case SYMTAB__SYSTEM_PATH_DSO:
1779ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s",
1780aeafcbafSArnaldo Carvalho de Melo 			     symbol_conf.symfs, dso->long_name);
178186470930SIngo Molnar 			break;
1782878b439dSArnaldo Carvalho de Melo 		case SYMTAB__GUEST_KMODULE:
1783fb7d0b3cSKyle McMartin 			if (map->groups && machine)
1784fb7d0b3cSKyle McMartin 				root_dir = machine->root_dir;
1785a1645ce1SZhang, Yanmin 			else
1786a1645ce1SZhang, Yanmin 				root_dir = "";
1787ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1788aeafcbafSArnaldo Carvalho de Melo 				 root_dir, dso->long_name);
1789ec5761eaSDavid Ahern 			break;
1790ec5761eaSDavid Ahern 
1791878b439dSArnaldo Carvalho de Melo 		case SYMTAB__SYSTEM_PATH_KMODULE:
1792ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s", symbol_conf.symfs,
1793aeafcbafSArnaldo Carvalho de Melo 				 dso->long_name);
1794a1645ce1SZhang, Yanmin 			break;
179560e4b10cSArnaldo Carvalho de Melo 		default:;
179686470930SIngo Molnar 		}
179786470930SIngo Molnar 
17986da80ce8SDave Martin 		/* Name is now the name of the next image to try */
17996da80ce8SDave Martin 		fd = open(name, O_RDONLY);
18006da80ce8SDave Martin 		if (fd < 0)
18016da80ce8SDave Martin 			continue;
18026da80ce8SDave Martin 
1803aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_sym(dso, map, name, fd, filter, 0,
18046da80ce8SDave Martin 				    want_symtab);
180586470930SIngo Molnar 		close(fd);
180686470930SIngo Molnar 
180786470930SIngo Molnar 		/*
18086da80ce8SDave Martin 		 * Some people seem to have debuginfo files _WITHOUT_ debug
18096da80ce8SDave Martin 		 * info!?!?
181086470930SIngo Molnar 		 */
181186470930SIngo Molnar 		if (!ret)
18126da80ce8SDave Martin 			continue;
181386470930SIngo Molnar 
1814a25e46c4SArnaldo Carvalho de Melo 		if (ret > 0) {
181533ff581eSJiri Olsa 			int nr_plt;
181633ff581eSJiri Olsa 
181733ff581eSJiri Olsa 			nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter);
1818a25e46c4SArnaldo Carvalho de Melo 			if (nr_plt > 0)
1819a25e46c4SArnaldo Carvalho de Melo 				ret += nr_plt;
18206da80ce8SDave Martin 			break;
1821a25e46c4SArnaldo Carvalho de Melo 		}
18226da80ce8SDave Martin 	}
18236da80ce8SDave Martin 
182460e4b10cSArnaldo Carvalho de Melo 	/*
182560e4b10cSArnaldo Carvalho de Melo 	 * If we wanted a full symtab but no image had one,
182660e4b10cSArnaldo Carvalho de Melo 	 * relax our requirements and repeat the search.
182760e4b10cSArnaldo Carvalho de Melo 	 */
182860e4b10cSArnaldo Carvalho de Melo 	if (ret <= 0 && want_symtab) {
182960e4b10cSArnaldo Carvalho de Melo 		want_symtab = 0;
183060e4b10cSArnaldo Carvalho de Melo 		goto restart;
183160e4b10cSArnaldo Carvalho de Melo 	}
183260e4b10cSArnaldo Carvalho de Melo 
183386470930SIngo Molnar 	free(name);
1834aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
18351340e6bbSArnaldo Carvalho de Melo 		return 0;
183686470930SIngo Molnar 	return ret;
183786470930SIngo Molnar }
183886470930SIngo Molnar 
1839aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
184079406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1841439d473bSArnaldo Carvalho de Melo {
1842439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1843439d473bSArnaldo Carvalho de Melo 
1844aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
1845439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1846439d473bSArnaldo Carvalho de Melo 
1847b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1848439d473bSArnaldo Carvalho de Melo 			return map;
1849439d473bSArnaldo Carvalho de Melo 	}
1850439d473bSArnaldo Carvalho de Melo 
1851439d473bSArnaldo Carvalho de Melo 	return NULL;
1852439d473bSArnaldo Carvalho de Melo }
1853439d473bSArnaldo Carvalho de Melo 
1854aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso,
1855a1645ce1SZhang, Yanmin 					   const char *root_dir)
1856b7cece76SArnaldo Carvalho de Melo {
1857b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1858b7cece76SArnaldo Carvalho de Melo 	/*
1859b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1860b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1861b7cece76SArnaldo Carvalho de Melo 	 */
1862aeafcbafSArnaldo Carvalho de Melo 	const char *name = dso->short_name + 1;
1863b7cece76SArnaldo Carvalho de Melo 
1864b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1865a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1866a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1867b7cece76SArnaldo Carvalho de Melo 
1868aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, dso->build_id,
1869aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
1870aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
1871b7cece76SArnaldo Carvalho de Melo 
1872b7cece76SArnaldo Carvalho de Melo 	return 0;
1873b7cece76SArnaldo Carvalho de Melo }
1874b7cece76SArnaldo Carvalho de Melo 
1875aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg,
1876a1645ce1SZhang, Yanmin 				const char *dir_name)
18776cfcc53eSMike Galbraith {
1878439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
18795aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
188074534341SGui Jianfeng 	int ret = 0;
18816cfcc53eSMike Galbraith 
1882439d473bSArnaldo Carvalho de Melo 	if (!dir) {
18835aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1884439d473bSArnaldo Carvalho de Melo 		return -1;
1885439d473bSArnaldo Carvalho de Melo 	}
18866cfcc53eSMike Galbraith 
1887439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1888439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1889a1645ce1SZhang, Yanmin 		struct stat st;
1890439d473bSArnaldo Carvalho de Melo 
1891a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
18922b600f95SNamhyung Kim 		snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
1893a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1894a1645ce1SZhang, Yanmin 			continue;
1895a1645ce1SZhang, Yanmin 
1896a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1897439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1898439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1899439d473bSArnaldo Carvalho de Melo 				continue;
1900439d473bSArnaldo Carvalho de Melo 
1901aeafcbafSArnaldo Carvalho de Melo 			ret = map_groups__set_modules_path_dir(mg, path);
190274534341SGui Jianfeng 			if (ret < 0)
190374534341SGui Jianfeng 				goto out;
1904439d473bSArnaldo Carvalho de Melo 		} else {
1905439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1906439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1907439d473bSArnaldo Carvalho de Melo 			struct map *map;
1908cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1909439d473bSArnaldo Carvalho de Melo 
1910439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1911439d473bSArnaldo Carvalho de Melo 				continue;
1912439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1913439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1914439d473bSArnaldo Carvalho de Melo 
1915a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
1916aeafcbafSArnaldo Carvalho de Melo 			map = map_groups__find_by_name(mg, MAP__FUNCTION,
1917aeafcbafSArnaldo Carvalho de Melo 						       dso_name);
1918439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1919439d473bSArnaldo Carvalho de Melo 				continue;
1920439d473bSArnaldo Carvalho de Melo 
1921cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
192274534341SGui Jianfeng 			if (long_name == NULL) {
192374534341SGui Jianfeng 				ret = -1;
192474534341SGui Jianfeng 				goto out;
192574534341SGui Jianfeng 			}
1926cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
19276e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1928a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1929439d473bSArnaldo Carvalho de Melo 		}
1930439d473bSArnaldo Carvalho de Melo 	}
1931439d473bSArnaldo Carvalho de Melo 
193274534341SGui Jianfeng out:
1933439d473bSArnaldo Carvalho de Melo 	closedir(dir);
193474534341SGui Jianfeng 	return ret;
1935439d473bSArnaldo Carvalho de Melo }
1936439d473bSArnaldo Carvalho de Melo 
1937a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1938439d473bSArnaldo Carvalho de Melo {
1939a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1940a1645ce1SZhang, Yanmin 	FILE *file;
1941a1645ce1SZhang, Yanmin 	char *name, *tmp;
1942a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1943a1645ce1SZhang, Yanmin 
1944a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1945a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1946a1645ce1SZhang, Yanmin 	if (!file)
1947a1645ce1SZhang, Yanmin 		return NULL;
1948a1645ce1SZhang, Yanmin 
1949a1645ce1SZhang, Yanmin 	version[0] = '\0';
1950a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1951a1645ce1SZhang, Yanmin 	fclose(file);
1952a1645ce1SZhang, Yanmin 
1953a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1954a1645ce1SZhang, Yanmin 	if (!name)
1955a1645ce1SZhang, Yanmin 		return NULL;
1956a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1957a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1958a1645ce1SZhang, Yanmin 	if (tmp)
1959a1645ce1SZhang, Yanmin 		*tmp = '\0';
1960a1645ce1SZhang, Yanmin 
1961a1645ce1SZhang, Yanmin 	return strdup(name);
1962a1645ce1SZhang, Yanmin }
1963a1645ce1SZhang, Yanmin 
1964aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine)
1965a1645ce1SZhang, Yanmin {
1966a1645ce1SZhang, Yanmin 	char *version;
1967439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1968439d473bSArnaldo Carvalho de Melo 
1969aeafcbafSArnaldo Carvalho de Melo 	version = get_kernel_version(machine->root_dir);
1970a1645ce1SZhang, Yanmin 	if (!version)
1971439d473bSArnaldo Carvalho de Melo 		return -1;
1972439d473bSArnaldo Carvalho de Melo 
1973a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1974aeafcbafSArnaldo Carvalho de Melo 		 machine->root_dir, version);
1975a1645ce1SZhang, Yanmin 	free(version);
1976439d473bSArnaldo Carvalho de Melo 
1977aeafcbafSArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
1978439d473bSArnaldo Carvalho de Melo }
19796cfcc53eSMike Galbraith 
19806cfcc53eSMike Galbraith /*
1981439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1982439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1983439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
19846cfcc53eSMike Galbraith  */
19853610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1986439d473bSArnaldo Carvalho de Melo {
1987aeafcbafSArnaldo Carvalho de Melo 	struct map *map = calloc(1, (sizeof(*map) +
19885aab621bSArnaldo Carvalho de Melo 				     (dso->kernel ? sizeof(struct kmap) : 0)));
1989aeafcbafSArnaldo Carvalho de Melo 	if (map != NULL) {
1990439d473bSArnaldo Carvalho de Melo 		/*
1991afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1992439d473bSArnaldo Carvalho de Melo 		 */
1993aeafcbafSArnaldo Carvalho de Melo 		map__init(map, type, start, 0, 0, dso);
1994439d473bSArnaldo Carvalho de Melo 	}
1995afb7b4f0SArnaldo Carvalho de Melo 
1996aeafcbafSArnaldo Carvalho de Melo 	return map;
1997439d473bSArnaldo Carvalho de Melo }
1998439d473bSArnaldo Carvalho de Melo 
1999aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start,
2000d28c6223SArnaldo Carvalho de Melo 				const char *filename)
2001b7cece76SArnaldo Carvalho de Melo {
2002b7cece76SArnaldo Carvalho de Melo 	struct map *map;
2003aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
2004b7cece76SArnaldo Carvalho de Melo 
2005b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
2006b7cece76SArnaldo Carvalho de Melo 		return NULL;
2007b7cece76SArnaldo Carvalho de Melo 
2008b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
2009b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
2010b7cece76SArnaldo Carvalho de Melo 		return NULL;
2011b7cece76SArnaldo Carvalho de Melo 
2012aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine))
2013878b439dSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
2014a1645ce1SZhang, Yanmin 	else
2015878b439dSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__GUEST_KMODULE;
2016aeafcbafSArnaldo Carvalho de Melo 	map_groups__insert(&machine->kmaps, map);
2017b7cece76SArnaldo Carvalho de Melo 	return map;
2018b7cece76SArnaldo Carvalho de Melo }
2019b7cece76SArnaldo Carvalho de Melo 
2020aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine)
2021439d473bSArnaldo Carvalho de Melo {
2022439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
2023439d473bSArnaldo Carvalho de Melo 	size_t n;
2024a1645ce1SZhang, Yanmin 	FILE *file;
2025439d473bSArnaldo Carvalho de Melo 	struct map *map;
2026a1645ce1SZhang, Yanmin 	const char *modules;
2027a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2028439d473bSArnaldo Carvalho de Melo 
2029aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2030a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
2031a1645ce1SZhang, Yanmin 	else {
2032aeafcbafSArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", machine->root_dir);
2033a1645ce1SZhang, Yanmin 		modules = path;
2034a1645ce1SZhang, Yanmin 	}
2035a1645ce1SZhang, Yanmin 
2036ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(path, "/proc/modules"))
2037ec80fde7SArnaldo Carvalho de Melo 		return -1;
2038ec80fde7SArnaldo Carvalho de Melo 
2039a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
2040439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
2041439d473bSArnaldo Carvalho de Melo 		return -1;
2042439d473bSArnaldo Carvalho de Melo 
2043439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
2044439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
2045439d473bSArnaldo Carvalho de Melo 		u64 start;
2046439d473bSArnaldo Carvalho de Melo 		char *sep;
2047439d473bSArnaldo Carvalho de Melo 		int line_len;
2048439d473bSArnaldo Carvalho de Melo 
2049439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
2050439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
20516cfcc53eSMike Galbraith 			break;
20526cfcc53eSMike Galbraith 
2053439d473bSArnaldo Carvalho de Melo 		if (!line)
2054439d473bSArnaldo Carvalho de Melo 			goto out_failure;
2055439d473bSArnaldo Carvalho de Melo 
2056439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
2057439d473bSArnaldo Carvalho de Melo 
2058439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
2059439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
2060439d473bSArnaldo Carvalho de Melo 			continue;
2061439d473bSArnaldo Carvalho de Melo 
2062439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
2063439d473bSArnaldo Carvalho de Melo 
2064439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
2065439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
2066439d473bSArnaldo Carvalho de Melo 			continue;
2067439d473bSArnaldo Carvalho de Melo 
2068439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
2069439d473bSArnaldo Carvalho de Melo 
2070439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
2071aeafcbafSArnaldo Carvalho de Melo 		map = machine__new_module(machine, start, name);
2072b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
2073439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
2074aeafcbafSArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, machine->root_dir);
20756cfcc53eSMike Galbraith 	}
20766cfcc53eSMike Galbraith 
2077439d473bSArnaldo Carvalho de Melo 	free(line);
2078439d473bSArnaldo Carvalho de Melo 	fclose(file);
2079439d473bSArnaldo Carvalho de Melo 
2080aeafcbafSArnaldo Carvalho de Melo 	return machine__set_modules_path(machine);
2081439d473bSArnaldo Carvalho de Melo 
2082439d473bSArnaldo Carvalho de Melo out_delete_line:
2083439d473bSArnaldo Carvalho de Melo 	free(line);
2084439d473bSArnaldo Carvalho de Melo out_failure:
2085439d473bSArnaldo Carvalho de Melo 	return -1;
20866cfcc53eSMike Galbraith }
20876cfcc53eSMike Galbraith 
2088aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
20896beba7adSArnaldo Carvalho de Melo 		      const char *vmlinux, symbol_filter_t filter)
209086470930SIngo Molnar {
2091fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
2092ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
209386470930SIngo Molnar 
2094a639dc64SArnaldo Carvalho de Melo 	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
2095ec5761eaSDavid Ahern 		 symbol_conf.symfs, vmlinux);
2096ec5761eaSDavid Ahern 	fd = open(symfs_vmlinux, O_RDONLY);
209786470930SIngo Molnar 	if (fd < 0)
209886470930SIngo Molnar 		return -1;
209986470930SIngo Molnar 
2100aeafcbafSArnaldo Carvalho de Melo 	dso__set_long_name(dso, (char *)vmlinux);
2101aeafcbafSArnaldo Carvalho de Melo 	dso__set_loaded(dso, map->type);
2102aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
210386470930SIngo Molnar 	close(fd);
210486470930SIngo Molnar 
21053846df2eSArnaldo Carvalho de Melo 	if (err > 0)
2106ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
21073846df2eSArnaldo Carvalho de Melo 
210886470930SIngo Molnar 	return err;
210986470930SIngo Molnar }
211086470930SIngo Molnar 
2111aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
21129de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
2113a19afe46SArnaldo Carvalho de Melo {
2114a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
21155ad90e4eSArnaldo Carvalho de Melo 	char *filename;
2116a19afe46SArnaldo Carvalho de Melo 
2117a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
21185ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
21195ad90e4eSArnaldo Carvalho de Melo 
2120aeafcbafSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(dso, NULL, 0);
21215ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
2122aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, filter);
21235ad90e4eSArnaldo Carvalho de Melo 		if (err > 0) {
2124aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, filename);
21255ad90e4eSArnaldo Carvalho de Melo 			goto out;
21265ad90e4eSArnaldo Carvalho de Melo 		}
21275ad90e4eSArnaldo Carvalho de Melo 		free(filename);
21285ad90e4eSArnaldo Carvalho de Melo 	}
2129a19afe46SArnaldo Carvalho de Melo 
2130a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
2131aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
2132a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
2133aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(vmlinux_path[i]));
2134a19afe46SArnaldo Carvalho de Melo 			break;
2135a19afe46SArnaldo Carvalho de Melo 		}
2136a19afe46SArnaldo Carvalho de Melo 	}
21375ad90e4eSArnaldo Carvalho de Melo out:
2138a19afe46SArnaldo Carvalho de Melo 	return err;
2139a19afe46SArnaldo Carvalho de Melo }
2140a19afe46SArnaldo Carvalho de Melo 
2141aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
21429de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
214386470930SIngo Molnar {
2144cc612d81SArnaldo Carvalho de Melo 	int err;
21459e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
21469e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
2147dc8d6ab2SArnaldo Carvalho de Melo 	/*
2148b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
2149b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
2150dc8d6ab2SArnaldo Carvalho de Melo 	 *
2151dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
2152dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
2153dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
2154dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
2155dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
2156dc8d6ab2SArnaldo Carvalho de Melo 	 *
2157dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
2158dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
2159dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
2160dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
2161dc8d6ab2SArnaldo Carvalho de Melo 	 */
2162b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
2163b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
2164b226a5a7SDavid Ahern 		goto do_kallsyms;
2165b226a5a7SDavid Ahern 	}
2166b226a5a7SDavid Ahern 
2167dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
2168aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map,
2169dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
2170e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
2171aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso,
2172e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
2173e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
2174e7dadc00SArnaldo Carvalho de Melo 		}
2175e7dadc00SArnaldo Carvalho de Melo 		return err;
2176dc8d6ab2SArnaldo Carvalho de Melo 	}
2177439d473bSArnaldo Carvalho de Melo 
2178cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
2179aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
2180a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
2181cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
2182cc612d81SArnaldo Carvalho de Melo 	}
2183cc612d81SArnaldo Carvalho de Melo 
2184ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
2185ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2186ec5761eaSDavid Ahern 		return -1;
2187ec5761eaSDavid Ahern 
2188b7cece76SArnaldo Carvalho de Melo 	/*
2189b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
2190b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
2191b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
2192b7cece76SArnaldo Carvalho de Melo 	 */
2193aeafcbafSArnaldo Carvalho de Melo 	if (dso->has_build_id) {
2194b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
21959e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2196b7cece76SArnaldo Carvalho de Melo 
2197b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
21988d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
2199aeafcbafSArnaldo Carvalho de Melo 			if (dso__build_id_equal(dso, kallsyms_build_id)) {
22009e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
2201b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
22028d0591f6SArnaldo Carvalho de Melo 			}
22039e201442SArnaldo Carvalho de Melo 		}
2204dc8d6ab2SArnaldo Carvalho de Melo 		/*
2205dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
2206dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
2207dc8d6ab2SArnaldo Carvalho de Melo 		 */
2208aeafcbafSArnaldo Carvalho de Melo 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
22099e201442SArnaldo Carvalho de Melo 				  sbuild_id);
22109e201442SArnaldo Carvalho de Melo 
22119e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
22129e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
22133846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
22143846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
22158d0591f6SArnaldo Carvalho de Melo 			return -1;
22163846df2eSArnaldo Carvalho de Melo 		}
22178d0591f6SArnaldo Carvalho de Melo 
221819fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
221919fc2dedSArnaldo Carvalho de Melo 
2220dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
22213846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
22223846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
22239e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
2224dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
2225ef6ae724SArnaldo Carvalho de Melo 		}
2226dc8d6ab2SArnaldo Carvalho de Melo 	} else {
2227dc8d6ab2SArnaldo Carvalho de Melo 		/*
2228dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
2229dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
2230dc8d6ab2SArnaldo Carvalho de Melo 		 */
2231dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
2232dc8d6ab2SArnaldo Carvalho de Melo 	}
2233dc8d6ab2SArnaldo Carvalho de Melo 
2234dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
2235aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
22363846df2eSArnaldo Carvalho de Melo 	if (err > 0)
22373846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
2238dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
2239dc8d6ab2SArnaldo Carvalho de Melo 
2240439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
2241cc612d81SArnaldo Carvalho de Melo out_fixup:
2242e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
2243aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
22446a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
22456a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
2246439d473bSArnaldo Carvalho de Melo 	}
224794cb9e38SArnaldo Carvalho de Melo 
224886470930SIngo Molnar 	return err;
224986470930SIngo Molnar }
225086470930SIngo Molnar 
2251aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
2252a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
2253a1645ce1SZhang, Yanmin {
2254a1645ce1SZhang, Yanmin 	int err;
2255a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
225623346f21SArnaldo Carvalho de Melo 	struct machine *machine;
2257a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2258a1645ce1SZhang, Yanmin 
2259a1645ce1SZhang, Yanmin 	if (!map->groups) {
2260a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
2261a1645ce1SZhang, Yanmin 		return -1;
2262a1645ce1SZhang, Yanmin 	}
226323346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
2264a1645ce1SZhang, Yanmin 
226523346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
2266a1645ce1SZhang, Yanmin 		/*
2267a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
2268a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
2269a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
2270a1645ce1SZhang, Yanmin 		 */
2271a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
2272aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
2273a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
2274a1645ce1SZhang, Yanmin 			goto out_try_fixup;
2275a1645ce1SZhang, Yanmin 		}
2276a1645ce1SZhang, Yanmin 
2277a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
2278a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
2279a1645ce1SZhang, Yanmin 			return -1;
2280a1645ce1SZhang, Yanmin 	} else {
228123346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2282a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
2283a1645ce1SZhang, Yanmin 	}
2284a1645ce1SZhang, Yanmin 
2285aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
2286a1645ce1SZhang, Yanmin 	if (err > 0)
2287a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
2288a1645ce1SZhang, Yanmin 
2289a1645ce1SZhang, Yanmin out_try_fixup:
2290a1645ce1SZhang, Yanmin 	if (err > 0) {
2291a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
229248ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
2293aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(path));
2294a1645ce1SZhang, Yanmin 		}
2295a1645ce1SZhang, Yanmin 		map__fixup_start(map);
2296a1645ce1SZhang, Yanmin 		map__fixup_end(map);
2297a1645ce1SZhang, Yanmin 	}
2298a1645ce1SZhang, Yanmin 
2299a1645ce1SZhang, Yanmin 	return err;
2300a1645ce1SZhang, Yanmin }
2301cd84c2acSFrederic Weisbecker 
2302b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
2303cd84c2acSFrederic Weisbecker {
2304b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
2305cd84c2acSFrederic Weisbecker }
2306cd84c2acSFrederic Weisbecker 
2307b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
2308cd84c2acSFrederic Weisbecker {
2309cd84c2acSFrederic Weisbecker 	struct dso *pos;
2310cd84c2acSFrederic Weisbecker 
2311b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
2312cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
2313cd84c2acSFrederic Weisbecker 			return pos;
2314cd84c2acSFrederic Weisbecker 	return NULL;
2315cd84c2acSFrederic Weisbecker }
2316cd84c2acSFrederic Weisbecker 
2317a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
2318cd84c2acSFrederic Weisbecker {
2319a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
2320cd84c2acSFrederic Weisbecker 
2321e4204992SArnaldo Carvalho de Melo 	if (!dso) {
232200a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
2323cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
2324a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
2325cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
2326cfc10d3bSArnaldo Carvalho de Melo 		}
2327e4204992SArnaldo Carvalho de Melo 	}
2328cd84c2acSFrederic Weisbecker 
2329cd84c2acSFrederic Weisbecker 	return dso;
2330cd84c2acSFrederic Weisbecker }
2331cd84c2acSFrederic Weisbecker 
23321f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2333cd84c2acSFrederic Weisbecker {
2334cd84c2acSFrederic Weisbecker 	struct dso *pos;
2335cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2336cd84c2acSFrederic Weisbecker 
233795011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
233895011c60SArnaldo Carvalho de Melo 		int i;
233995011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
2340cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
2341cd84c2acSFrederic Weisbecker 	}
2342cd84c2acSFrederic Weisbecker 
2343cbf69680SArnaldo Carvalho de Melo 	return ret;
2344cbf69680SArnaldo Carvalho de Melo }
2345cbf69680SArnaldo Carvalho de Melo 
2346aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
2347b0da954aSArnaldo Carvalho de Melo {
2348a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2349cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2350a1645ce1SZhang, Yanmin 
2351aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
235223346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2353cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2354cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
2355a1645ce1SZhang, Yanmin 	}
2356cbf69680SArnaldo Carvalho de Melo 
2357cbf69680SArnaldo Carvalho de Melo 	return ret;
2358b0da954aSArnaldo Carvalho de Melo }
2359b0da954aSArnaldo Carvalho de Melo 
236088d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
236188d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
23629e03eb2dSArnaldo Carvalho de Melo {
23639e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
23649e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
23659e03eb2dSArnaldo Carvalho de Melo 
2366b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
236788d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
236888d3d9b7SArnaldo Carvalho de Melo 			continue;
23699e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
23709e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
23719e03eb2dSArnaldo Carvalho de Melo 	}
23729e03eb2dSArnaldo Carvalho de Melo 	return ret;
23739e03eb2dSArnaldo Carvalho de Melo }
23749e03eb2dSArnaldo Carvalho de Melo 
2375aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
2376aeafcbafSArnaldo Carvalho de Melo 				     bool with_hits)
2377f869097eSArnaldo Carvalho de Melo {
2378aeafcbafSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
2379aeafcbafSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
2380f869097eSArnaldo Carvalho de Melo }
2381f869097eSArnaldo Carvalho de Melo 
2382aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2383aeafcbafSArnaldo Carvalho de Melo 				      FILE *fp, bool with_hits)
2384b0da954aSArnaldo Carvalho de Melo {
2385a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2386a1645ce1SZhang, Yanmin 	size_t ret = 0;
2387a1645ce1SZhang, Yanmin 
2388aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
238923346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2390f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2391a1645ce1SZhang, Yanmin 	}
2392a1645ce1SZhang, Yanmin 	return ret;
2393b0da954aSArnaldo Carvalho de Melo }
2394b0da954aSArnaldo Carvalho de Melo 
2395f57b05edSJiri Olsa static struct dso*
2396f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name,
2397f57b05edSJiri Olsa 		    const char *short_name, int dso_type)
2398fd1d908cSArnaldo Carvalho de Melo {
2399f57b05edSJiri Olsa 	/*
2400f57b05edSJiri Olsa 	 * The kernel dso could be created by build_id processing.
2401f57b05edSJiri Olsa 	 */
2402f57b05edSJiri Olsa 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
2403fd1d908cSArnaldo Carvalho de Melo 
2404f57b05edSJiri Olsa 	/*
2405f57b05edSJiri Olsa 	 * We need to run this in all cases, since during the build_id
2406f57b05edSJiri Olsa 	 * processing we had no idea this was the kernel dso.
2407f57b05edSJiri Olsa 	 */
2408aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
2409f57b05edSJiri Olsa 		dso__set_short_name(dso, short_name);
2410f57b05edSJiri Olsa 		dso->kernel = dso_type;
2411a1645ce1SZhang, Yanmin 	}
2412a1645ce1SZhang, Yanmin 
2413aeafcbafSArnaldo Carvalho de Melo 	return dso;
2414a1645ce1SZhang, Yanmin }
2415a1645ce1SZhang, Yanmin 
2416aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2417a1645ce1SZhang, Yanmin {
2418a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2419a1645ce1SZhang, Yanmin 
242023346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2421a1645ce1SZhang, Yanmin 		return;
242223346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2423aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(path, dso->build_id,
2424aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
2425aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
2426fd1d908cSArnaldo Carvalho de Melo }
2427fd1d908cSArnaldo Carvalho de Melo 
2428f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine)
2429cd84c2acSFrederic Weisbecker {
2430a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
2431a1645ce1SZhang, Yanmin 	struct dso *kernel;
2432cd84c2acSFrederic Weisbecker 
2433aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine)) {
2434a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2435f57b05edSJiri Olsa 		if (!vmlinux_name)
2436f57b05edSJiri Olsa 			vmlinux_name = "[kernel.kallsyms]";
2437f57b05edSJiri Olsa 
2438f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
2439f57b05edSJiri Olsa 					     "[kernel]",
2440f57b05edSJiri Olsa 					     DSO_TYPE_KERNEL);
2441a1645ce1SZhang, Yanmin 	} else {
2442f57b05edSJiri Olsa 		char bf[PATH_MAX];
2443f57b05edSJiri Olsa 
2444aeafcbafSArnaldo Carvalho de Melo 		if (machine__is_default_guest(machine))
2445a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2446f57b05edSJiri Olsa 		if (!vmlinux_name)
2447f57b05edSJiri Olsa 			vmlinux_name = machine__mmap_name(machine, bf,
2448f57b05edSJiri Olsa 							  sizeof(bf));
2449f57b05edSJiri Olsa 
2450f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
2451f57b05edSJiri Olsa 					     "[guest.kernel]",
2452f57b05edSJiri Olsa 					     DSO_TYPE_GUEST_KERNEL);
24538d92c02aSArnaldo Carvalho de Melo 	}
2454cd84c2acSFrederic Weisbecker 
2455f57b05edSJiri Olsa 	if (kernel != NULL && (!kernel->has_build_id))
2456aeafcbafSArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, machine);
2457f57b05edSJiri Olsa 
2458f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2459f1dfa0b1SArnaldo Carvalho de Melo }
2460f1dfa0b1SArnaldo Carvalho de Melo 
2461d214afbdSMing Lei struct process_args {
2462d214afbdSMing Lei 	u64 start;
2463d214afbdSMing Lei };
2464d214afbdSMing Lei 
2465d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name,
24663b01a413SArnaldo Carvalho de Melo 			     char type __used, u64 start, u64 end __used)
2467d214afbdSMing Lei {
2468d214afbdSMing Lei 	struct process_args *args = arg;
2469d214afbdSMing Lei 
2470d214afbdSMing Lei 	if (strchr(name, '['))
2471d214afbdSMing Lei 		return 0;
2472d214afbdSMing Lei 
2473d214afbdSMing Lei 	args->start = start;
2474d214afbdSMing Lei 	return 1;
2475d214afbdSMing Lei }
2476d214afbdSMing Lei 
2477d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */
2478d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine)
2479d214afbdSMing Lei {
2480d214afbdSMing Lei 	const char *filename;
2481d214afbdSMing Lei 	char path[PATH_MAX];
2482d214afbdSMing Lei 	struct process_args args;
2483d214afbdSMing Lei 
2484d214afbdSMing Lei 	if (machine__is_host(machine)) {
2485d214afbdSMing Lei 		filename = "/proc/kallsyms";
2486d214afbdSMing Lei 	} else {
2487d214afbdSMing Lei 		if (machine__is_default_guest(machine))
2488d214afbdSMing Lei 			filename = (char *)symbol_conf.default_guest_kallsyms;
2489d214afbdSMing Lei 		else {
2490d214afbdSMing Lei 			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2491d214afbdSMing Lei 			filename = path;
2492d214afbdSMing Lei 		}
2493d214afbdSMing Lei 	}
2494d214afbdSMing Lei 
2495ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
2496ec80fde7SArnaldo Carvalho de Melo 		return 0;
2497ec80fde7SArnaldo Carvalho de Melo 
2498d214afbdSMing Lei 	if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2499d214afbdSMing Lei 		return 0;
2500d214afbdSMing Lei 
2501d214afbdSMing Lei 	return args.start;
2502d214afbdSMing Lei }
2503d214afbdSMing Lei 
2504aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
2505f1dfa0b1SArnaldo Carvalho de Melo {
2506de176489SArnaldo Carvalho de Melo 	enum map_type type;
2507aeafcbafSArnaldo Carvalho de Melo 	u64 start = machine__get_kernel_start_addr(machine);
2508f1dfa0b1SArnaldo Carvalho de Melo 
2509de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
25109de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
25119de89fe7SArnaldo Carvalho de Melo 
2512aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = map__new2(start, kernel, type);
2513aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
2514f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2515f1dfa0b1SArnaldo Carvalho de Melo 
2516aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type]->map_ip =
2517aeafcbafSArnaldo Carvalho de Melo 			machine->vmlinux_maps[type]->unmap_ip =
2518aeafcbafSArnaldo Carvalho de Melo 				identity__map_ip;
2519aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
2520aeafcbafSArnaldo Carvalho de Melo 		kmap->kmaps = &machine->kmaps;
2521aeafcbafSArnaldo Carvalho de Melo 		map_groups__insert(&machine->kmaps,
2522aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
2523f1dfa0b1SArnaldo Carvalho de Melo 	}
2524f1dfa0b1SArnaldo Carvalho de Melo 
2525f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
25262446042cSArnaldo Carvalho de Melo }
25272446042cSArnaldo Carvalho de Melo 
2528aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine)
2529076c6e45SArnaldo Carvalho de Melo {
2530076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
2531076c6e45SArnaldo Carvalho de Melo 
2532076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
2533076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
2534076c6e45SArnaldo Carvalho de Melo 
2535aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
2536076c6e45SArnaldo Carvalho de Melo 			continue;
2537076c6e45SArnaldo Carvalho de Melo 
2538aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
2539aeafcbafSArnaldo Carvalho de Melo 		map_groups__remove(&machine->kmaps,
2540aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
2541076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
2542076c6e45SArnaldo Carvalho de Melo 			/*
2543076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
2544076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
2545076c6e45SArnaldo Carvalho de Melo 			 */
2546076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
2547076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
2548076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
2549076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
2550076c6e45SArnaldo Carvalho de Melo 			}
2551076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
2552076c6e45SArnaldo Carvalho de Melo 		}
2553076c6e45SArnaldo Carvalho de Melo 
2554aeafcbafSArnaldo Carvalho de Melo 		map__delete(machine->vmlinux_maps[type]);
2555aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = NULL;
2556076c6e45SArnaldo Carvalho de Melo 	}
2557076c6e45SArnaldo Carvalho de Melo }
2558076c6e45SArnaldo Carvalho de Melo 
2559aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine)
25605c0541d5SArnaldo Carvalho de Melo {
2561f57b05edSJiri Olsa 	struct dso *kernel = machine__get_kernel(machine);
25625c0541d5SArnaldo Carvalho de Melo 
25635c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
2564aeafcbafSArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(machine, kernel) < 0)
25655c0541d5SArnaldo Carvalho de Melo 		return -1;
25665c0541d5SArnaldo Carvalho de Melo 
2567*f51304d3SDavid Ahern 	if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
2568*f51304d3SDavid Ahern 		if (machine__is_host(machine))
2569*f51304d3SDavid Ahern 			pr_debug("Problems creating module maps, "
2570*f51304d3SDavid Ahern 				 "continuing anyway...\n");
2571*f51304d3SDavid Ahern 		else
2572*f51304d3SDavid Ahern 			pr_debug("Problems creating module maps for guest %d, "
2573*f51304d3SDavid Ahern 				 "continuing anyway...\n", machine->pid);
2574*f51304d3SDavid Ahern 	}
2575*f51304d3SDavid Ahern 
25765c0541d5SArnaldo Carvalho de Melo 	/*
25775c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
25785c0541d5SArnaldo Carvalho de Melo 	 */
2579aeafcbafSArnaldo Carvalho de Melo 	map_groups__fixup_end(&machine->kmaps);
25805c0541d5SArnaldo Carvalho de Melo 	return 0;
25815c0541d5SArnaldo Carvalho de Melo }
25825c0541d5SArnaldo Carvalho de Melo 
2583cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
25842446042cSArnaldo Carvalho de Melo {
2585cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2586cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2587cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2588cc612d81SArnaldo Carvalho de Melo 	}
2589cc612d81SArnaldo Carvalho de Melo 
2590cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2591cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2592cc612d81SArnaldo Carvalho de Melo }
2593cc612d81SArnaldo Carvalho de Melo 
2594cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2595cc612d81SArnaldo Carvalho de Melo {
2596cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2597cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2598cc612d81SArnaldo Carvalho de Melo 
2599cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2600cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2601cc612d81SArnaldo Carvalho de Melo 		return -1;
2602cc612d81SArnaldo Carvalho de Melo 
2603cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2604cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2605cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2606cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2607cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2608cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2609cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2610cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2611ec5761eaSDavid Ahern 
2612ec5761eaSDavid Ahern 	/* only try running kernel version if no symfs was given */
2613ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2614ec5761eaSDavid Ahern 		return 0;
2615ec5761eaSDavid Ahern 
2616ec5761eaSDavid Ahern 	if (uname(&uts) < 0)
2617ec5761eaSDavid Ahern 		return -1;
2618ec5761eaSDavid Ahern 
2619cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2620cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2621cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2622cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2623cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2624cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2625cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2626cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2627cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2628cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2629cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2630cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2631cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2632cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2633cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2634cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2635cc612d81SArnaldo Carvalho de Melo 
2636cc612d81SArnaldo Carvalho de Melo 	return 0;
2637cc612d81SArnaldo Carvalho de Melo 
2638cc612d81SArnaldo Carvalho de Melo out_fail:
2639cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2640cc612d81SArnaldo Carvalho de Melo 	return -1;
2641cc612d81SArnaldo Carvalho de Melo }
2642cc612d81SArnaldo Carvalho de Melo 
2643aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
2644b0a9ab62SArnaldo Carvalho de Melo {
2645b0a9ab62SArnaldo Carvalho de Melo 	int i;
2646b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
2647aeafcbafSArnaldo Carvalho de Melo 	struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
26485ad90e4eSArnaldo Carvalho de Melo 
26495ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
26505ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
26515ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
26525ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
26535ad90e4eSArnaldo Carvalho de Melo 	}
2654b0a9ab62SArnaldo Carvalho de Melo 
2655b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
26565ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
26575ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
2658b0a9ab62SArnaldo Carvalho de Melo 
2659b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2660b0a9ab62SArnaldo Carvalho de Melo }
2661b0a9ab62SArnaldo Carvalho de Melo 
2662655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2663655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2664655000e7SArnaldo Carvalho de Melo {
2665655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2666655000e7SArnaldo Carvalho de Melo 		return 0;
2667655000e7SArnaldo Carvalho de Melo 
2668655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2669655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2670655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2671655000e7SArnaldo Carvalho de Melo 		return -1;
2672655000e7SArnaldo Carvalho de Melo 	}
2673655000e7SArnaldo Carvalho de Melo 	return 0;
2674655000e7SArnaldo Carvalho de Melo }
2675655000e7SArnaldo Carvalho de Melo 
2676ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
2677ec80fde7SArnaldo Carvalho de Melo {
2678ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
2679ec80fde7SArnaldo Carvalho de Melo 
2680ec80fde7SArnaldo Carvalho de Melo 	if (geteuid() != 0) {
2681ec80fde7SArnaldo Carvalho de Melo 		FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
2682ec80fde7SArnaldo Carvalho de Melo 		if (fp != NULL) {
2683ec80fde7SArnaldo Carvalho de Melo 			char line[8];
2684ec80fde7SArnaldo Carvalho de Melo 
2685ec80fde7SArnaldo Carvalho de Melo 			if (fgets(line, sizeof(line), fp) != NULL)
2686ec80fde7SArnaldo Carvalho de Melo 				value = atoi(line) != 0;
2687ec80fde7SArnaldo Carvalho de Melo 
2688ec80fde7SArnaldo Carvalho de Melo 			fclose(fp);
2689ec80fde7SArnaldo Carvalho de Melo 		}
2690ec80fde7SArnaldo Carvalho de Melo 	}
2691ec80fde7SArnaldo Carvalho de Melo 
2692ec80fde7SArnaldo Carvalho de Melo 	return value;
2693ec80fde7SArnaldo Carvalho de Melo }
2694ec80fde7SArnaldo Carvalho de Melo 
269575be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2696cc612d81SArnaldo Carvalho de Melo {
2697ec5761eaSDavid Ahern 	const char *symfs;
2698ec5761eaSDavid Ahern 
269985e00b55SJovi Zhang 	if (symbol_conf.initialized)
270085e00b55SJovi Zhang 		return 0;
270185e00b55SJovi Zhang 
27024d439517SDavid S. Miller 	symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
27034d439517SDavid S. Miller 
270495011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
270575be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
270675be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
270779406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2708b32d133aSArnaldo Carvalho de Melo 
270975be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2710cc612d81SArnaldo Carvalho de Melo 		return -1;
2711cc612d81SArnaldo Carvalho de Melo 
2712c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2713c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2714c410a338SArnaldo Carvalho de Melo 		return -1;
2715c410a338SArnaldo Carvalho de Melo 	}
2716c410a338SArnaldo Carvalho de Melo 
2717655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2718655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2719655000e7SArnaldo Carvalho de Melo 		return -1;
2720655000e7SArnaldo Carvalho de Melo 
2721655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2722655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2723655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2724655000e7SArnaldo Carvalho de Melo 
2725655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2726655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2727655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2728655000e7SArnaldo Carvalho de Melo 
2729ec5761eaSDavid Ahern 	/*
2730ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2731ec5761eaSDavid Ahern 	 * reset here for simplicity.
2732ec5761eaSDavid Ahern 	 */
2733ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2734ec5761eaSDavid Ahern 	if (symfs == NULL)
2735ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2736ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2737ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2738ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2739ec5761eaSDavid Ahern 		free((void *)symfs);
2740ec5761eaSDavid Ahern 
2741ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2742ec80fde7SArnaldo Carvalho de Melo 
274385e00b55SJovi Zhang 	symbol_conf.initialized = true;
27444aa65636SArnaldo Carvalho de Melo 	return 0;
2745655000e7SArnaldo Carvalho de Melo 
2746655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2747655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2748d74c896bSNamhyung Kim out_free_dso_list:
2749d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2750655000e7SArnaldo Carvalho de Melo 	return -1;
2751cc612d81SArnaldo Carvalho de Melo }
2752cc612d81SArnaldo Carvalho de Melo 
2753d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2754d65a458bSArnaldo Carvalho de Melo {
275585e00b55SJovi Zhang 	if (!symbol_conf.initialized)
275685e00b55SJovi Zhang 		return;
2757d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2758d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2759d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2760d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2761d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
276285e00b55SJovi Zhang 	symbol_conf.initialized = false;
2763d65a458bSArnaldo Carvalho de Melo }
2764d65a458bSArnaldo Carvalho de Melo 
2765aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
27664aa65636SArnaldo Carvalho de Melo {
2767aeafcbafSArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(machines, pid);
27689de89fe7SArnaldo Carvalho de Melo 
276923346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2770a1645ce1SZhang, Yanmin 		return -1;
27714aa65636SArnaldo Carvalho de Melo 
27725c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2773cd84c2acSFrederic Weisbecker }
27745aab621bSArnaldo Carvalho de Melo 
27755aab621bSArnaldo Carvalho de Melo static int hex(char ch)
27765aab621bSArnaldo Carvalho de Melo {
27775aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
27785aab621bSArnaldo Carvalho de Melo 		return ch - '0';
27795aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
27805aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
27815aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
27825aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
27835aab621bSArnaldo Carvalho de Melo 	return -1;
27845aab621bSArnaldo Carvalho de Melo }
27855aab621bSArnaldo Carvalho de Melo 
27865aab621bSArnaldo Carvalho de Melo /*
27875aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
27885aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
27895aab621bSArnaldo Carvalho de Melo  */
27905aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
27915aab621bSArnaldo Carvalho de Melo {
27925aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
27935aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
27945aab621bSArnaldo Carvalho de Melo 
27955aab621bSArnaldo Carvalho de Melo 	while (*p) {
27965aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
27975aab621bSArnaldo Carvalho de Melo 
27985aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
27995aab621bSArnaldo Carvalho de Melo 			break;
28005aab621bSArnaldo Carvalho de Melo 
28015aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
28025aab621bSArnaldo Carvalho de Melo 		p++;
28035aab621bSArnaldo Carvalho de Melo 	}
28045aab621bSArnaldo Carvalho de Melo 
28055aab621bSArnaldo Carvalho de Melo 	return p - ptr;
28065aab621bSArnaldo Carvalho de Melo }
28075aab621bSArnaldo Carvalho de Melo 
28085aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
28095aab621bSArnaldo Carvalho de Melo {
28105aab621bSArnaldo Carvalho de Melo 	char *p = s;
28115aab621bSArnaldo Carvalho de Melo 
28125aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
28135aab621bSArnaldo Carvalho de Melo 		*p++ = to;
28145aab621bSArnaldo Carvalho de Melo 
28155aab621bSArnaldo Carvalho de Melo 	return s;
28165aab621bSArnaldo Carvalho de Melo }
2817a1645ce1SZhang, Yanmin 
2818aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines)
2819a1645ce1SZhang, Yanmin {
2820a1645ce1SZhang, Yanmin 	int ret = 0;
2821a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2822a1645ce1SZhang, Yanmin 	int i, items = 0;
2823a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2824a1645ce1SZhang, Yanmin 	pid_t pid;
2825a1645ce1SZhang, Yanmin 
2826a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2827a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2828a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2829aeafcbafSArnaldo Carvalho de Melo 		machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
2830a1645ce1SZhang, Yanmin 	}
2831a1645ce1SZhang, Yanmin 
2832a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2833a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2834a1645ce1SZhang, Yanmin 		if (items <= 0)
2835a1645ce1SZhang, Yanmin 			return -ENOENT;
2836a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2837a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2838a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2839a1645ce1SZhang, Yanmin 				continue;
2840a1645ce1SZhang, Yanmin 			}
2841a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2842a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2843a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2844a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2845a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2846a1645ce1SZhang, Yanmin 			if (ret) {
2847a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2848a1645ce1SZhang, Yanmin 				goto failure;
2849a1645ce1SZhang, Yanmin 			}
2850aeafcbafSArnaldo Carvalho de Melo 			machines__create_kernel_maps(machines, pid);
2851a1645ce1SZhang, Yanmin 		}
2852a1645ce1SZhang, Yanmin failure:
2853a1645ce1SZhang, Yanmin 		free(namelist);
2854a1645ce1SZhang, Yanmin 	}
2855a1645ce1SZhang, Yanmin 
2856a1645ce1SZhang, Yanmin 	return ret;
2857a1645ce1SZhang, Yanmin }
28585c0541d5SArnaldo Carvalho de Melo 
2859aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines)
2860076c6e45SArnaldo Carvalho de Melo {
2861aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(machines);
2862076c6e45SArnaldo Carvalho de Melo 
2863076c6e45SArnaldo Carvalho de Melo 	while (next) {
2864076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2865076c6e45SArnaldo Carvalho de Melo 
2866076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2867aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, machines);
2868076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2869076c6e45SArnaldo Carvalho de Melo 	}
2870076c6e45SArnaldo Carvalho de Melo }
2871076c6e45SArnaldo Carvalho de Melo 
2872aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename,
28735c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
28745c0541d5SArnaldo Carvalho de Melo {
2875aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
28765c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
28775c0541d5SArnaldo Carvalho de Melo 
28785c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
28795c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
28805c0541d5SArnaldo Carvalho de Melo 		/*
28815c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
28825c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
28835c0541d5SArnaldo Carvalho de Melo 		 * sections.
28845c0541d5SArnaldo Carvalho de Melo 		 */
2885aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(&machine->kmaps, type);
28865c0541d5SArnaldo Carvalho de Melo 	}
28875c0541d5SArnaldo Carvalho de Melo 
28885c0541d5SArnaldo Carvalho de Melo 	return ret;
28895c0541d5SArnaldo Carvalho de Melo }
28905c0541d5SArnaldo Carvalho de Melo 
2891aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
28925c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
28935c0541d5SArnaldo Carvalho de Melo {
2894aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
28955c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
28965c0541d5SArnaldo Carvalho de Melo 
28975c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
28985c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
28995c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
29005c0541d5SArnaldo Carvalho de Melo 	}
29015c0541d5SArnaldo Carvalho de Melo 
29025c0541d5SArnaldo Carvalho de Melo 	return ret;
29035c0541d5SArnaldo Carvalho de Melo }
2904225466f1SSrikar Dronamraju 
2905225466f1SSrikar Dronamraju struct map *dso__new_map(const char *name)
2906225466f1SSrikar Dronamraju {
2907378474e4SSrikar Dronamraju 	struct map *map = NULL;
2908225466f1SSrikar Dronamraju 	struct dso *dso = dso__new(name);
2909378474e4SSrikar Dronamraju 
2910378474e4SSrikar Dronamraju 	if (dso)
2911378474e4SSrikar Dronamraju 		map = map__new2(0, dso, MAP__FUNCTION);
2912225466f1SSrikar Dronamraju 
2913225466f1SSrikar Dronamraju 	return map;
2914225466f1SSrikar Dronamraju }
2915