xref: /linux/tools/perf/util/symbol.c (revision e9b52ef2228cd0bed7a4465c693a39489e2c338d)
15aab621bSArnaldo Carvalho de Melo #define _GNU_SOURCE
25aab621bSArnaldo Carvalho de Melo #include <ctype.h>
35aab621bSArnaldo Carvalho de Melo #include <dirent.h>
45aab621bSArnaldo Carvalho de Melo #include <errno.h>
55aab621bSArnaldo Carvalho de Melo #include <libgen.h>
65aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
75aab621bSArnaldo Carvalho de Melo #include <stdio.h>
85aab621bSArnaldo Carvalho de Melo #include <string.h>
95aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
105aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
115aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
125aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
135aab621bSArnaldo Carvalho de Melo #include <unistd.h>
149486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
15b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
168a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1786470930SIngo Molnar #include "symbol.h"
185aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1986470930SIngo Molnar 
2086470930SIngo Molnar #include <libelf.h>
2186470930SIngo Molnar #include <gelf.h>
2286470930SIngo Molnar #include <elf.h>
23f1617b40SArnaldo Carvalho de Melo #include <limits.h>
24439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
252cdbc46dSPeter Zijlstra 
263b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN
273b01a413SArnaldo Carvalho de Melo #define KSYM_NAME_LEN 128
283b01a413SArnaldo Carvalho de Melo #endif
293b01a413SArnaldo Carvalho de Melo 
30c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
31c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
32c12e15e7SArnaldo Carvalho de Melo #endif
33c12e15e7SArnaldo Carvalho de Melo 
34aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
3521916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size);
36b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
373610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
38aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
399de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
40aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
41a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
42cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
43cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
44439d473bSArnaldo Carvalho de Melo 
4575be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
46d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
47b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
48b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
49ec5761eaSDavid Ahern 	.symfs            = "",
50b32d133aSArnaldo Carvalho de Melo };
51b32d133aSArnaldo Carvalho de Melo 
52aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso)
538a6c5b26SArnaldo Carvalho de Melo {
548a6c5b26SArnaldo Carvalho de Melo 	if (verbose)
55aeafcbafSArnaldo Carvalho de Melo 		return dso->long_name_len;
568a6c5b26SArnaldo Carvalho de Melo 
57aeafcbafSArnaldo Carvalho de Melo 	return dso->short_name_len;
588a6c5b26SArnaldo Carvalho de Melo }
598a6c5b26SArnaldo Carvalho de Melo 
60aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type)
613610583cSArnaldo Carvalho de Melo {
62aeafcbafSArnaldo Carvalho de Melo 	return dso->loaded & (1 << type);
633610583cSArnaldo Carvalho de Melo }
643610583cSArnaldo Carvalho de Melo 
65aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
6679406cd7SArnaldo Carvalho de Melo {
67aeafcbafSArnaldo Carvalho de Melo 	return dso->sorted_by_name & (1 << type);
6879406cd7SArnaldo Carvalho de Melo }
6979406cd7SArnaldo Carvalho de Melo 
70aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
7179406cd7SArnaldo Carvalho de Melo {
72aeafcbafSArnaldo Carvalho de Melo 	dso->sorted_by_name |= (1 << type);
7379406cd7SArnaldo Carvalho de Melo }
7479406cd7SArnaldo Carvalho de Melo 
7536a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
766893d4eeSArnaldo Carvalho de Melo {
776893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
786893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
796893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
80f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
81f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
826893d4eeSArnaldo Carvalho de Melo 	default:
836893d4eeSArnaldo Carvalho de Melo 		return false;
846893d4eeSArnaldo Carvalho de Melo 	}
856893d4eeSArnaldo Carvalho de Melo }
866893d4eeSArnaldo Carvalho de Melo 
87aeafcbafSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *symbols)
88af427bf5SArnaldo Carvalho de Melo {
89aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(symbols);
902e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
91af427bf5SArnaldo Carvalho de Melo 
92af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
93af427bf5SArnaldo Carvalho de Melo 		return;
94af427bf5SArnaldo Carvalho de Melo 
952e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
962e538c4aSArnaldo Carvalho de Melo 
97af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
982e538c4aSArnaldo Carvalho de Melo 		prev = curr;
992e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
100af427bf5SArnaldo Carvalho de Melo 
1013b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
102af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
103af427bf5SArnaldo Carvalho de Melo 	}
104af427bf5SArnaldo Carvalho de Melo 
1052e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
1062e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
1072e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
1082e538c4aSArnaldo Carvalho de Melo }
1092e538c4aSArnaldo Carvalho de Melo 
110aeafcbafSArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
111af427bf5SArnaldo Carvalho de Melo {
112af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
113aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
114af427bf5SArnaldo Carvalho de Melo 
115af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
116af427bf5SArnaldo Carvalho de Melo 		return;
117af427bf5SArnaldo Carvalho de Melo 
118af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
119af427bf5SArnaldo Carvalho de Melo 
120af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
121af427bf5SArnaldo Carvalho de Melo 		prev = curr;
122af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
123af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1242e538c4aSArnaldo Carvalho de Melo 	}
12590c83218SArnaldo Carvalho de Melo 
12690c83218SArnaldo Carvalho de Melo 	/*
12790c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
12890c83218SArnaldo Carvalho de Melo 	 * last map final address.
12990c83218SArnaldo Carvalho de Melo 	 */
1309d1faba5SIan Munsie 	curr->end = ~0ULL;
131af427bf5SArnaldo Carvalho de Melo }
132af427bf5SArnaldo Carvalho de Melo 
133aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg)
13423ea4a3fSArnaldo Carvalho de Melo {
13523ea4a3fSArnaldo Carvalho de Melo 	int i;
13623ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
137aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(mg, i);
13823ea4a3fSArnaldo Carvalho de Melo }
13923ea4a3fSArnaldo Carvalho de Melo 
140c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
141c408fedfSArnaldo Carvalho de Melo 				  const char *name)
14286470930SIngo Molnar {
14386470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
144aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
145aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
146aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
14786470930SIngo Molnar 		return NULL;
14886470930SIngo Molnar 
14975be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
150aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
15136479484SArnaldo Carvalho de Melo 
152aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
153aeafcbafSArnaldo Carvalho de Melo 	sym->end     = len ? start + len - 1 : start;
154aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
155aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
156e4204992SArnaldo Carvalho de Melo 
157aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
158aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
159aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
160e4204992SArnaldo Carvalho de Melo 
161aeafcbafSArnaldo Carvalho de Melo 	return sym;
16286470930SIngo Molnar }
16386470930SIngo Molnar 
164aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
16586470930SIngo Molnar {
166aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
16786470930SIngo Molnar }
16886470930SIngo Molnar 
169aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
17086470930SIngo Molnar {
1719486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
172aeafcbafSArnaldo Carvalho de Melo 		       sym->start, sym->end,
173aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_GLOBAL ? 'g' :
174aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_LOCAL  ? 'l' : 'w',
175aeafcbafSArnaldo Carvalho de Melo 		       sym->name);
17686470930SIngo Molnar }
17786470930SIngo Molnar 
178aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name)
179cfc10d3bSArnaldo Carvalho de Melo {
180ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
181ef6ae724SArnaldo Carvalho de Melo 		return;
182aeafcbafSArnaldo Carvalho de Melo 	dso->long_name = name;
183aeafcbafSArnaldo Carvalho de Melo 	dso->long_name_len = strlen(name);
184cfc10d3bSArnaldo Carvalho de Melo }
185cfc10d3bSArnaldo Carvalho de Melo 
186aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name)
187b63be8d7SArnaldo Carvalho de Melo {
188b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
189b63be8d7SArnaldo Carvalho de Melo 		return;
190aeafcbafSArnaldo Carvalho de Melo 	dso->short_name = name;
191aeafcbafSArnaldo Carvalho de Melo 	dso->short_name_len = strlen(name);
192b63be8d7SArnaldo Carvalho de Melo }
193b63be8d7SArnaldo Carvalho de Melo 
194aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso)
195cfc10d3bSArnaldo Carvalho de Melo {
196aeafcbafSArnaldo Carvalho de Melo 	dso__set_short_name(dso, basename(dso->long_name));
197cfc10d3bSArnaldo Carvalho de Melo }
198cfc10d3bSArnaldo Carvalho de Melo 
19900a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
20086470930SIngo Molnar {
201aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
20286470930SIngo Molnar 
203aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
2046a4694a4SArnaldo Carvalho de Melo 		int i;
205aeafcbafSArnaldo Carvalho de Melo 		strcpy(dso->name, name);
206aeafcbafSArnaldo Carvalho de Melo 		dso__set_long_name(dso, dso->name);
207aeafcbafSArnaldo Carvalho de Melo 		dso__set_short_name(dso, dso->name);
2086a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
209aeafcbafSArnaldo Carvalho de Melo 			dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
210aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__NOT_FOUND;
211aeafcbafSArnaldo Carvalho de Melo 		dso->loaded = 0;
212aeafcbafSArnaldo Carvalho de Melo 		dso->sorted_by_name = 0;
213aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = 0;
214aeafcbafSArnaldo Carvalho de Melo 		dso->kernel = DSO_TYPE_USER;
215aeafcbafSArnaldo Carvalho de Melo 		INIT_LIST_HEAD(&dso->node);
21686470930SIngo Molnar 	}
21786470930SIngo Molnar 
218aeafcbafSArnaldo Carvalho de Melo 	return dso;
21986470930SIngo Molnar }
22086470930SIngo Molnar 
221aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols)
22286470930SIngo Molnar {
22386470930SIngo Molnar 	struct symbol *pos;
224aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
22586470930SIngo Molnar 
22686470930SIngo Molnar 	while (next) {
22786470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
22886470930SIngo Molnar 		next = rb_next(&pos->rb_node);
229aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
23000a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
23186470930SIngo Molnar 	}
23286470930SIngo Molnar }
23386470930SIngo Molnar 
234aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso)
23586470930SIngo Molnar {
2366a4694a4SArnaldo Carvalho de Melo 	int i;
2376a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
238aeafcbafSArnaldo Carvalho de Melo 		symbols__delete(&dso->symbols[i]);
239aeafcbafSArnaldo Carvalho de Melo 	if (dso->sname_alloc)
240aeafcbafSArnaldo Carvalho de Melo 		free((char *)dso->short_name);
241aeafcbafSArnaldo Carvalho de Melo 	if (dso->lname_alloc)
242aeafcbafSArnaldo Carvalho de Melo 		free(dso->long_name);
243aeafcbafSArnaldo Carvalho de Melo 	free(dso);
24486470930SIngo Molnar }
24586470930SIngo Molnar 
246aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id)
2478d06367fSArnaldo Carvalho de Melo {
248aeafcbafSArnaldo Carvalho de Melo 	memcpy(dso->build_id, build_id, sizeof(dso->build_id));
249aeafcbafSArnaldo Carvalho de Melo 	dso->has_build_id = 1;
2508d06367fSArnaldo Carvalho de Melo }
2518d06367fSArnaldo Carvalho de Melo 
252aeafcbafSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
25386470930SIngo Molnar {
254aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
25586470930SIngo Molnar 	struct rb_node *parent = NULL;
2569cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
25786470930SIngo Molnar 	struct symbol *s;
25886470930SIngo Molnar 
25986470930SIngo Molnar 	while (*p != NULL) {
26086470930SIngo Molnar 		parent = *p;
26186470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
26286470930SIngo Molnar 		if (ip < s->start)
26386470930SIngo Molnar 			p = &(*p)->rb_left;
26486470930SIngo Molnar 		else
26586470930SIngo Molnar 			p = &(*p)->rb_right;
26686470930SIngo Molnar 	}
26786470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
268aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
26986470930SIngo Molnar }
27086470930SIngo Molnar 
271aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
27286470930SIngo Molnar {
27386470930SIngo Molnar 	struct rb_node *n;
27486470930SIngo Molnar 
275aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
27686470930SIngo Molnar 		return NULL;
27786470930SIngo Molnar 
278aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
27986470930SIngo Molnar 
28086470930SIngo Molnar 	while (n) {
28186470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
28286470930SIngo Molnar 
28386470930SIngo Molnar 		if (ip < s->start)
28486470930SIngo Molnar 			n = n->rb_left;
28586470930SIngo Molnar 		else if (ip > s->end)
28686470930SIngo Molnar 			n = n->rb_right;
28786470930SIngo Molnar 		else
28886470930SIngo Molnar 			return s;
28986470930SIngo Molnar 	}
29086470930SIngo Molnar 
29186470930SIngo Molnar 	return NULL;
29286470930SIngo Molnar }
29386470930SIngo Molnar 
29479406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
29579406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
29679406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
29779406cd7SArnaldo Carvalho de Melo };
29879406cd7SArnaldo Carvalho de Melo 
299aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
30079406cd7SArnaldo Carvalho de Melo {
301aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
30279406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
30302a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
30402a9d037SRabin Vincent 
30502a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
30679406cd7SArnaldo Carvalho de Melo 
30779406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
30879406cd7SArnaldo Carvalho de Melo 		parent = *p;
30979406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
31079406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
31179406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
31279406cd7SArnaldo Carvalho de Melo 		else
31379406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
31479406cd7SArnaldo Carvalho de Melo 	}
31579406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
316aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
31779406cd7SArnaldo Carvalho de Melo }
31879406cd7SArnaldo Carvalho de Melo 
319aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
320aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
32179406cd7SArnaldo Carvalho de Melo {
32279406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
32379406cd7SArnaldo Carvalho de Melo 
32479406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
32579406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
326aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
32779406cd7SArnaldo Carvalho de Melo 	}
32879406cd7SArnaldo Carvalho de Melo }
32979406cd7SArnaldo Carvalho de Melo 
330aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
331aeafcbafSArnaldo Carvalho de Melo 					    const char *name)
33279406cd7SArnaldo Carvalho de Melo {
33379406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
33479406cd7SArnaldo Carvalho de Melo 
335aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
33679406cd7SArnaldo Carvalho de Melo 		return NULL;
33779406cd7SArnaldo Carvalho de Melo 
338aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
33979406cd7SArnaldo Carvalho de Melo 
34079406cd7SArnaldo Carvalho de Melo 	while (n) {
34179406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
34279406cd7SArnaldo Carvalho de Melo 		int cmp;
34379406cd7SArnaldo Carvalho de Melo 
34479406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
34579406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
34679406cd7SArnaldo Carvalho de Melo 
34779406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
34879406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
34979406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
35079406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
35179406cd7SArnaldo Carvalho de Melo 		else
35279406cd7SArnaldo Carvalho de Melo 			return &s->sym;
35379406cd7SArnaldo Carvalho de Melo 	}
35479406cd7SArnaldo Carvalho de Melo 
35579406cd7SArnaldo Carvalho de Melo 	return NULL;
35679406cd7SArnaldo Carvalho de Melo }
35779406cd7SArnaldo Carvalho de Melo 
358aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
35979406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
360fcf1203aSArnaldo Carvalho de Melo {
361aeafcbafSArnaldo Carvalho de Melo 	return symbols__find(&dso->symbols[type], addr);
362fcf1203aSArnaldo Carvalho de Melo }
363fcf1203aSArnaldo Carvalho de Melo 
364aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
36579406cd7SArnaldo Carvalho de Melo 					const char *name)
36679406cd7SArnaldo Carvalho de Melo {
367aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
36879406cd7SArnaldo Carvalho de Melo }
36979406cd7SArnaldo Carvalho de Melo 
370aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
37179406cd7SArnaldo Carvalho de Melo {
372aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
373aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
374aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
37579406cd7SArnaldo Carvalho de Melo }
37679406cd7SArnaldo Carvalho de Melo 
377aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf)
3788d06367fSArnaldo Carvalho de Melo {
3798d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
380aeafcbafSArnaldo Carvalho de Melo 	const u8 *raw = build_id;
3818d06367fSArnaldo Carvalho de Melo 	int i;
3828d06367fSArnaldo Carvalho de Melo 
3838d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
3848d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
3858d06367fSArnaldo Carvalho de Melo 		++raw;
3868d06367fSArnaldo Carvalho de Melo 		bid += 2;
3878d06367fSArnaldo Carvalho de Melo 	}
3888d06367fSArnaldo Carvalho de Melo 
389aeafcbafSArnaldo Carvalho de Melo 	return raw - build_id;
3908d06367fSArnaldo Carvalho de Melo }
3918d06367fSArnaldo Carvalho de Melo 
392aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
39386470930SIngo Molnar {
3948d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
3958d06367fSArnaldo Carvalho de Melo 
396aeafcbafSArnaldo Carvalho de Melo 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
3979e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
3989e03eb2dSArnaldo Carvalho de Melo }
3999e03eb2dSArnaldo Carvalho de Melo 
400aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso,
401aeafcbafSArnaldo Carvalho de Melo 				    enum map_type type, FILE *fp)
40290f18e63SSrikar Dronamraju {
40390f18e63SSrikar Dronamraju 	size_t ret = 0;
40490f18e63SSrikar Dronamraju 	struct rb_node *nd;
40590f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
40690f18e63SSrikar Dronamraju 
407aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
40890f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
40990f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
41090f18e63SSrikar Dronamraju 	}
41190f18e63SSrikar Dronamraju 
41290f18e63SSrikar Dronamraju 	return ret;
41390f18e63SSrikar Dronamraju }
41490f18e63SSrikar Dronamraju 
415aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
4169e03eb2dSArnaldo Carvalho de Melo {
4179e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
418aeafcbafSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
4199e03eb2dSArnaldo Carvalho de Melo 
420aeafcbafSArnaldo Carvalho de Melo 	if (dso->short_name != dso->long_name)
421aeafcbafSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", dso->long_name);
4223846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
423aeafcbafSArnaldo Carvalho de Melo 		       dso->loaded ? "" : "NOT ");
424aeafcbafSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(dso, fp);
4256a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
426aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
42786470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
42886470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
42986470930SIngo Molnar 	}
43086470930SIngo Molnar 
43186470930SIngo Molnar 	return ret;
43286470930SIngo Molnar }
43386470930SIngo Molnar 
4349e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
4359e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
4363b01a413SArnaldo Carvalho de Melo 					  char type, u64 start, u64 end))
43786470930SIngo Molnar {
43886470930SIngo Molnar 	char *line = NULL;
43986470930SIngo Molnar 	size_t n;
4403b01a413SArnaldo Carvalho de Melo 	int err = -1;
4413b01a413SArnaldo Carvalho de Melo 	u64 prev_start = 0;
4423b01a413SArnaldo Carvalho de Melo 	char prev_symbol_type = 0;
4433b01a413SArnaldo Carvalho de Melo 	char *prev_symbol_name;
4449e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
44586470930SIngo Molnar 
44686470930SIngo Molnar 	if (file == NULL)
44786470930SIngo Molnar 		goto out_failure;
44886470930SIngo Molnar 
4493b01a413SArnaldo Carvalho de Melo 	prev_symbol_name = malloc(KSYM_NAME_LEN);
4503b01a413SArnaldo Carvalho de Melo 	if (prev_symbol_name == NULL)
4513b01a413SArnaldo Carvalho de Melo 		goto out_close;
4523b01a413SArnaldo Carvalho de Melo 
4533b01a413SArnaldo Carvalho de Melo 	err = 0;
4543b01a413SArnaldo Carvalho de Melo 
45586470930SIngo Molnar 	while (!feof(file)) {
4569cffa8d5SPaul Mackerras 		u64 start;
45786470930SIngo Molnar 		int line_len, len;
45886470930SIngo Molnar 		char symbol_type;
4592e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
46086470930SIngo Molnar 
46186470930SIngo Molnar 		line_len = getline(&line, &n, file);
462a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
46386470930SIngo Molnar 			break;
46486470930SIngo Molnar 
46586470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
46686470930SIngo Molnar 
46786470930SIngo Molnar 		len = hex2u64(line, &start);
46886470930SIngo Molnar 
46986470930SIngo Molnar 		len++;
47086470930SIngo Molnar 		if (len + 2 >= line_len)
47186470930SIngo Molnar 			continue;
47286470930SIngo Molnar 
47386470930SIngo Molnar 		symbol_type = toupper(line[len]);
4743b01a413SArnaldo Carvalho de Melo 		len += 2;
4753b01a413SArnaldo Carvalho de Melo 		symbol_name = line + len;
4763b01a413SArnaldo Carvalho de Melo 		len = line_len - len;
477682b335aSArnaldo Carvalho de Melo 
4783b01a413SArnaldo Carvalho de Melo 		if (len >= KSYM_NAME_LEN) {
4793b01a413SArnaldo Carvalho de Melo 			err = -1;
4803b01a413SArnaldo Carvalho de Melo 			break;
4813b01a413SArnaldo Carvalho de Melo 		}
4823b01a413SArnaldo Carvalho de Melo 
4833b01a413SArnaldo Carvalho de Melo 		if (prev_symbol_type) {
4843b01a413SArnaldo Carvalho de Melo 			u64 end = start;
4853b01a413SArnaldo Carvalho de Melo 			if (end != prev_start)
4863b01a413SArnaldo Carvalho de Melo 				--end;
4873b01a413SArnaldo Carvalho de Melo 			err = process_symbol(arg, prev_symbol_name,
4883b01a413SArnaldo Carvalho de Melo 					     prev_symbol_type, prev_start, end);
489682b335aSArnaldo Carvalho de Melo 			if (err)
490682b335aSArnaldo Carvalho de Melo 				break;
491682b335aSArnaldo Carvalho de Melo 		}
492682b335aSArnaldo Carvalho de Melo 
4933b01a413SArnaldo Carvalho de Melo 		memcpy(prev_symbol_name, symbol_name, len + 1);
4943b01a413SArnaldo Carvalho de Melo 		prev_symbol_type = symbol_type;
4953b01a413SArnaldo Carvalho de Melo 		prev_start = start;
4963b01a413SArnaldo Carvalho de Melo 	}
4973b01a413SArnaldo Carvalho de Melo 
4983b01a413SArnaldo Carvalho de Melo 	free(prev_symbol_name);
499682b335aSArnaldo Carvalho de Melo 	free(line);
5003b01a413SArnaldo Carvalho de Melo out_close:
501682b335aSArnaldo Carvalho de Melo 	fclose(file);
502682b335aSArnaldo Carvalho de Melo 	return err;
503682b335aSArnaldo Carvalho de Melo 
504682b335aSArnaldo Carvalho de Melo out_failure:
505682b335aSArnaldo Carvalho de Melo 	return -1;
506682b335aSArnaldo Carvalho de Melo }
507682b335aSArnaldo Carvalho de Melo 
508682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
509682b335aSArnaldo Carvalho de Melo 	struct map *map;
510682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
511682b335aSArnaldo Carvalho de Melo };
512682b335aSArnaldo Carvalho de Melo 
513c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
514c408fedfSArnaldo Carvalho de Melo {
515c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
516c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
517c408fedfSArnaldo Carvalho de Melo 
518c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
519c408fedfSArnaldo Carvalho de Melo }
520c408fedfSArnaldo Carvalho de Melo 
521682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
5223b01a413SArnaldo Carvalho de Melo 				       char type, u64 start, u64 end)
523682b335aSArnaldo Carvalho de Melo {
524682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
525682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
526682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
527682b335aSArnaldo Carvalho de Melo 
528682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
529682b335aSArnaldo Carvalho de Melo 		return 0;
530682b335aSArnaldo Carvalho de Melo 
5313b01a413SArnaldo Carvalho de Melo 	sym = symbol__new(start, end - start + 1,
5323b01a413SArnaldo Carvalho de Melo 			  kallsyms2elf_type(type), name);
5332e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
534682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
53582164161SArnaldo Carvalho de Melo 	/*
53682164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
5374e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
53882164161SArnaldo Carvalho de Melo 	 */
5394e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
540a1645ce1SZhang, Yanmin 
541682b335aSArnaldo Carvalho de Melo 	return 0;
5422e538c4aSArnaldo Carvalho de Melo }
5432e538c4aSArnaldo Carvalho de Melo 
544682b335aSArnaldo Carvalho de Melo /*
545682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
546682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
547682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
548682b335aSArnaldo Carvalho de Melo  */
549aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
5509e201442SArnaldo Carvalho de Melo 				  struct map *map)
551682b335aSArnaldo Carvalho de Melo {
552aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
5539e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
5542e538c4aSArnaldo Carvalho de Melo }
5552e538c4aSArnaldo Carvalho de Melo 
5562e538c4aSArnaldo Carvalho de Melo /*
5572e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
5582e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
5592e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
5602e538c4aSArnaldo Carvalho de Melo  */
561aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map,
5629de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
5632e538c4aSArnaldo Carvalho de Melo {
5649de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
56523346f21SArnaldo Carvalho de Melo 	struct machine *machine = kmaps->machine;
5664e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
5672e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
5688a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
569aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
5704e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
5712e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
5722e538c4aSArnaldo Carvalho de Melo 
5732e538c4aSArnaldo Carvalho de Melo 	while (next) {
5742e538c4aSArnaldo Carvalho de Melo 		char *module;
5752e538c4aSArnaldo Carvalho de Melo 
5762e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
5772e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
5782e538c4aSArnaldo Carvalho de Melo 
5792e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
5802e538c4aSArnaldo Carvalho de Melo 		if (module) {
58175be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
5821de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
5831de8e245SArnaldo Carvalho de Melo 
5842e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
5852e538c4aSArnaldo Carvalho de Melo 
586b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
587a1645ce1SZhang, Yanmin 				if (curr_map != map &&
588aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
58923346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
590a1645ce1SZhang, Yanmin 					/*
591a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
592a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
593a1645ce1SZhang, Yanmin 					 * points to a module and all its
594a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
595a1645ce1SZhang, Yanmin 					 * loaded.
596a1645ce1SZhang, Yanmin 					 */
597a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
598a1645ce1SZhang, Yanmin 							curr_map->type);
599af427bf5SArnaldo Carvalho de Melo 				}
600b7cece76SArnaldo Carvalho de Melo 
601a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
602a1645ce1SZhang, Yanmin 							map->type, module);
603a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
6042f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
605a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
606a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
60723346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
608a1645ce1SZhang, Yanmin 					curr_map = map;
609a1645ce1SZhang, Yanmin 					goto discard_symbol;
610a1645ce1SZhang, Yanmin 				}
611a1645ce1SZhang, Yanmin 
612a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
61323346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
614b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
615af427bf5SArnaldo Carvalho de Melo 			}
61686470930SIngo Molnar 			/*
6172e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
6182e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
61986470930SIngo Molnar 			 */
6204e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
6214e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
6224e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
6232e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
624aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
62586470930SIngo Molnar 
6268a953312SArnaldo Carvalho de Melo 			if (count == 0) {
6278a953312SArnaldo Carvalho de Melo 				curr_map = map;
6288a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
6298a953312SArnaldo Carvalho de Melo 			}
6308a953312SArnaldo Carvalho de Melo 
631aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
632a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
633a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
634a1645ce1SZhang, Yanmin 					kernel_range++);
635a1645ce1SZhang, Yanmin 			else
636a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
637a1645ce1SZhang, Yanmin 					"[kernel].%d",
6382e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
63986470930SIngo Molnar 
640aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
641aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
6422e538c4aSArnaldo Carvalho de Melo 				return -1;
6432e538c4aSArnaldo Carvalho de Melo 
644aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
645a1645ce1SZhang, Yanmin 
646aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
64737fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
648aeafcbafSArnaldo Carvalho de Melo 				dso__delete(ndso);
6492e538c4aSArnaldo Carvalho de Melo 				return -1;
6502e538c4aSArnaldo Carvalho de Melo 			}
6512e538c4aSArnaldo Carvalho de Melo 
6524e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
6539de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
6542e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
6552e538c4aSArnaldo Carvalho de Melo 		}
6568a953312SArnaldo Carvalho de Melo filter_symbol:
6574e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
6581de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
65900a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
6602e538c4aSArnaldo Carvalho de Melo 		} else {
6614e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
6624e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
6634e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
6648a953312SArnaldo Carvalho de Melo 				++moved;
6658a953312SArnaldo Carvalho de Melo 			} else
6668a953312SArnaldo Carvalho de Melo 				++count;
6679974f496SMike Galbraith 		}
66886470930SIngo Molnar 	}
66986470930SIngo Molnar 
670a1645ce1SZhang, Yanmin 	if (curr_map != map &&
671aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
67223346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
673a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
674a1645ce1SZhang, Yanmin 	}
675a1645ce1SZhang, Yanmin 
6768a953312SArnaldo Carvalho de Melo 	return count + moved;
67786470930SIngo Molnar }
67886470930SIngo Molnar 
679ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename,
680ec80fde7SArnaldo Carvalho de Melo 					const char *restricted_filename)
681ec80fde7SArnaldo Carvalho de Melo {
682ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
683ec80fde7SArnaldo Carvalho de Melo 
684ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
685ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
686ec80fde7SArnaldo Carvalho de Melo 
687ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
688ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
689ec80fde7SArnaldo Carvalho de Melo 			free(r);
690ec80fde7SArnaldo Carvalho de Melo 			return restricted;
691ec80fde7SArnaldo Carvalho de Melo 		}
692ec80fde7SArnaldo Carvalho de Melo 	}
693ec80fde7SArnaldo Carvalho de Melo 
694ec80fde7SArnaldo Carvalho de Melo 	return restricted;
695ec80fde7SArnaldo Carvalho de Melo }
696ec80fde7SArnaldo Carvalho de Melo 
697aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
6989de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
6992e538c4aSArnaldo Carvalho de Melo {
700ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
701ec80fde7SArnaldo Carvalho de Melo 		return -1;
702ec80fde7SArnaldo Carvalho de Melo 
703aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
7042e538c4aSArnaldo Carvalho de Melo 		return -1;
7052e538c4aSArnaldo Carvalho de Melo 
706aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
707aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
708a1645ce1SZhang, Yanmin 	else
709aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__KALLSYMS;
7102e538c4aSArnaldo Carvalho de Melo 
711aeafcbafSArnaldo Carvalho de Melo 	return dso__split_kallsyms(dso, map, filter);
712af427bf5SArnaldo Carvalho de Melo }
713af427bf5SArnaldo Carvalho de Melo 
714aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
7156beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
71680d496beSPekka Enberg {
71780d496beSPekka Enberg 	char *line = NULL;
71880d496beSPekka Enberg 	size_t n;
71980d496beSPekka Enberg 	FILE *file;
72080d496beSPekka Enberg 	int nr_syms = 0;
72180d496beSPekka Enberg 
722aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
72380d496beSPekka Enberg 	if (file == NULL)
72480d496beSPekka Enberg 		goto out_failure;
72580d496beSPekka Enberg 
72680d496beSPekka Enberg 	while (!feof(file)) {
7279cffa8d5SPaul Mackerras 		u64 start, size;
72880d496beSPekka Enberg 		struct symbol *sym;
72980d496beSPekka Enberg 		int line_len, len;
73080d496beSPekka Enberg 
73180d496beSPekka Enberg 		line_len = getline(&line, &n, file);
73280d496beSPekka Enberg 		if (line_len < 0)
73380d496beSPekka Enberg 			break;
73480d496beSPekka Enberg 
73580d496beSPekka Enberg 		if (!line)
73680d496beSPekka Enberg 			goto out_failure;
73780d496beSPekka Enberg 
73880d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
73980d496beSPekka Enberg 
74080d496beSPekka Enberg 		len = hex2u64(line, &start);
74180d496beSPekka Enberg 
74280d496beSPekka Enberg 		len++;
74380d496beSPekka Enberg 		if (len + 2 >= line_len)
74480d496beSPekka Enberg 			continue;
74580d496beSPekka Enberg 
74680d496beSPekka Enberg 		len += hex2u64(line + len, &size);
74780d496beSPekka Enberg 
74880d496beSPekka Enberg 		len++;
74980d496beSPekka Enberg 		if (len + 2 >= line_len)
75080d496beSPekka Enberg 			continue;
75180d496beSPekka Enberg 
752c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
75380d496beSPekka Enberg 
75480d496beSPekka Enberg 		if (sym == NULL)
75580d496beSPekka Enberg 			goto out_delete_line;
75680d496beSPekka Enberg 
757439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
75800a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
75980d496beSPekka Enberg 		else {
760aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
76180d496beSPekka Enberg 			nr_syms++;
76280d496beSPekka Enberg 		}
76380d496beSPekka Enberg 	}
76480d496beSPekka Enberg 
76580d496beSPekka Enberg 	free(line);
76680d496beSPekka Enberg 	fclose(file);
76780d496beSPekka Enberg 
76880d496beSPekka Enberg 	return nr_syms;
76980d496beSPekka Enberg 
77080d496beSPekka Enberg out_delete_line:
77180d496beSPekka Enberg 	free(line);
77280d496beSPekka Enberg out_failure:
77380d496beSPekka Enberg 	return -1;
77480d496beSPekka Enberg }
77580d496beSPekka Enberg 
77686470930SIngo Molnar /**
77786470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
77886470930SIngo Molnar  *
779aeafcbafSArnaldo Carvalho de Melo  * @syms: struct elf_symtab instance to iterate
78083a0944fSIngo Molnar  * @idx: uint32_t idx
78186470930SIngo Molnar  * @sym: GElf_Sym iterator
78286470930SIngo Molnar  */
78383a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
78483a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
78583a0944fSIngo Molnar 	     idx < nr_syms; \
78683a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
78786470930SIngo Molnar 
78886470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
78986470930SIngo Molnar {
79086470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
79186470930SIngo Molnar }
79286470930SIngo Molnar 
79386470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
79486470930SIngo Molnar {
79586470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
79686470930SIngo Molnar 	       sym->st_name != 0 &&
79781833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
79886470930SIngo Molnar }
79986470930SIngo Molnar 
800f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
801f1dfa0b1SArnaldo Carvalho de Melo {
802f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
803f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
804f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
805f1dfa0b1SArnaldo Carvalho de Melo }
806f1dfa0b1SArnaldo Carvalho de Melo 
8076cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
8086cfcc53eSMike Galbraith {
8096cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
8106cfcc53eSMike Galbraith 		sym->st_name != 0 &&
8116cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
8126cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
8136cfcc53eSMike Galbraith }
8146cfcc53eSMike Galbraith 
8156cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
8166cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
8176cfcc53eSMike Galbraith {
8186cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
8196cfcc53eSMike Galbraith }
8206cfcc53eSMike Galbraith 
8216cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
8226cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
8236cfcc53eSMike Galbraith {
8246cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
8256cfcc53eSMike Galbraith }
8266cfcc53eSMike Galbraith 
827f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
828f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
829f1dfa0b1SArnaldo Carvalho de Melo {
830f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
831f1dfa0b1SArnaldo Carvalho de Melo }
832f1dfa0b1SArnaldo Carvalho de Melo 
83386470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
83486470930SIngo Molnar 					const Elf_Data *symstrs)
83586470930SIngo Molnar {
83686470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
83786470930SIngo Molnar }
83886470930SIngo Molnar 
83986470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
84086470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
84183a0944fSIngo Molnar 				    size_t *idx)
84286470930SIngo Molnar {
84386470930SIngo Molnar 	Elf_Scn *sec = NULL;
84486470930SIngo Molnar 	size_t cnt = 1;
84586470930SIngo Molnar 
84686470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
84786470930SIngo Molnar 		char *str;
84886470930SIngo Molnar 
84986470930SIngo Molnar 		gelf_getshdr(sec, shp);
85086470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
85186470930SIngo Molnar 		if (!strcmp(name, str)) {
85283a0944fSIngo Molnar 			if (idx)
85383a0944fSIngo Molnar 				*idx = cnt;
85486470930SIngo Molnar 			break;
85586470930SIngo Molnar 		}
85686470930SIngo Molnar 		++cnt;
85786470930SIngo Molnar 	}
85886470930SIngo Molnar 
85986470930SIngo Molnar 	return sec;
86086470930SIngo Molnar }
86186470930SIngo Molnar 
86286470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
86386470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
86486470930SIngo Molnar 	     idx < nr_entries; \
86586470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
86686470930SIngo Molnar 
86786470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
86886470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
86986470930SIngo Molnar 	     idx < nr_entries; \
87086470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
87186470930SIngo Molnar 
872a25e46c4SArnaldo Carvalho de Melo /*
873a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
874a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
875a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
876a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
877a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
878a25e46c4SArnaldo Carvalho de Melo  */
879aeafcbafSArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *dso, struct map *map,
88082164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
88186470930SIngo Molnar {
88286470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
88386470930SIngo Molnar 	GElf_Sym sym;
8849cffa8d5SPaul Mackerras 	u64 plt_offset;
88586470930SIngo Molnar 	GElf_Shdr shdr_plt;
88686470930SIngo Molnar 	struct symbol *f;
887a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
88886470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
889a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
890a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
891a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
89286470930SIngo Molnar 	char sympltname[1024];
893a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
894a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
895ec5761eaSDavid Ahern 	char name[PATH_MAX];
89686470930SIngo Molnar 
897ec5761eaSDavid Ahern 	snprintf(name, sizeof(name), "%s%s",
898aeafcbafSArnaldo Carvalho de Melo 		 symbol_conf.symfs, dso->long_name);
899ec5761eaSDavid Ahern 	fd = open(name, O_RDONLY);
900a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
901a25e46c4SArnaldo Carvalho de Melo 		goto out;
902a25e46c4SArnaldo Carvalho de Melo 
90384087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
904a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
905a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
906a25e46c4SArnaldo Carvalho de Melo 
907a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
908a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
909a25e46c4SArnaldo Carvalho de Melo 
910a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
911a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
912a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
913a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
914a25e46c4SArnaldo Carvalho de Melo 
915a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
91686470930SIngo Molnar 					  ".rela.plt", NULL);
91786470930SIngo Molnar 	if (scn_plt_rel == NULL) {
918a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
91986470930SIngo Molnar 						  ".rel.plt", NULL);
92086470930SIngo Molnar 		if (scn_plt_rel == NULL)
921a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
92286470930SIngo Molnar 	}
92386470930SIngo Molnar 
924a25e46c4SArnaldo Carvalho de Melo 	err = -1;
92586470930SIngo Molnar 
926a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
927a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
928a25e46c4SArnaldo Carvalho de Melo 
929a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
930a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
93186470930SIngo Molnar 
93286470930SIngo Molnar 	/*
93383a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
93486470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
93586470930SIngo Molnar 	 */
93686470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
93786470930SIngo Molnar 	if (reldata == NULL)
938a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
93986470930SIngo Molnar 
94086470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
94186470930SIngo Molnar 	if (syms == NULL)
942a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
94386470930SIngo Molnar 
944a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
94586470930SIngo Molnar 	if (scn_symstrs == NULL)
946a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
94786470930SIngo Molnar 
94886470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
94986470930SIngo Molnar 	if (symstrs == NULL)
950a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
95186470930SIngo Molnar 
95286470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
95386470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
95486470930SIngo Molnar 
95586470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
95686470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
95786470930SIngo Molnar 
95886470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
95986470930SIngo Molnar 					   nr_rel_entries) {
96086470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
96186470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
96286470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
96386470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
96486470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
96586470930SIngo Molnar 
96686470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
967c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
96886470930SIngo Molnar 			if (!f)
969a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
97086470930SIngo Molnar 
97182164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
97282164161SArnaldo Carvalho de Melo 				symbol__delete(f);
97382164161SArnaldo Carvalho de Melo 			else {
974aeafcbafSArnaldo Carvalho de Melo 				symbols__insert(&dso->symbols[map->type], f);
97586470930SIngo Molnar 				++nr;
97686470930SIngo Molnar 			}
97782164161SArnaldo Carvalho de Melo 		}
97886470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
97986470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
98086470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
98186470930SIngo Molnar 					  nr_rel_entries) {
98286470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
98386470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
98486470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
98586470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
98686470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
98786470930SIngo Molnar 
98886470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
989c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
99086470930SIngo Molnar 			if (!f)
991a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
99286470930SIngo Molnar 
99382164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
99482164161SArnaldo Carvalho de Melo 				symbol__delete(f);
99582164161SArnaldo Carvalho de Melo 			else {
996aeafcbafSArnaldo Carvalho de Melo 				symbols__insert(&dso->symbols[map->type], f);
99786470930SIngo Molnar 				++nr;
99886470930SIngo Molnar 			}
99986470930SIngo Molnar 		}
100082164161SArnaldo Carvalho de Melo 	}
100186470930SIngo Molnar 
1002a25e46c4SArnaldo Carvalho de Melo 	err = 0;
1003a25e46c4SArnaldo Carvalho de Melo out_elf_end:
1004a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
1005a25e46c4SArnaldo Carvalho de Melo out_close:
1006a25e46c4SArnaldo Carvalho de Melo 	close(fd);
1007a25e46c4SArnaldo Carvalho de Melo 
1008a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
100986470930SIngo Molnar 		return nr;
1010a25e46c4SArnaldo Carvalho de Melo out:
1011fe2197b8SArnaldo Carvalho de Melo 	pr_debug("%s: problems reading %s PLT info.\n",
1012aeafcbafSArnaldo Carvalho de Melo 		 __func__, dso->long_name);
1013a25e46c4SArnaldo Carvalho de Melo 	return 0;
101486470930SIngo Molnar }
101586470930SIngo Molnar 
1016aeafcbafSArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
1017d45868d3SArnaldo Carvalho de Melo {
1018d45868d3SArnaldo Carvalho de Melo 	switch (type) {
1019d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1020aeafcbafSArnaldo Carvalho de Melo 		return elf_sym__is_function(sym);
1021f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
1022aeafcbafSArnaldo Carvalho de Melo 		return elf_sym__is_object(sym);
1023d45868d3SArnaldo Carvalho de Melo 	default:
1024d45868d3SArnaldo Carvalho de Melo 		return false;
1025d45868d3SArnaldo Carvalho de Melo 	}
1026d45868d3SArnaldo Carvalho de Melo }
1027d45868d3SArnaldo Carvalho de Melo 
1028aeafcbafSArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
1029aeafcbafSArnaldo Carvalho de Melo 			  enum map_type type)
1030d45868d3SArnaldo Carvalho de Melo {
1031d45868d3SArnaldo Carvalho de Melo 	switch (type) {
1032d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1033aeafcbafSArnaldo Carvalho de Melo 		return elf_sec__is_text(shdr, secstrs);
1034f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
1035aeafcbafSArnaldo Carvalho de Melo 		return elf_sec__is_data(shdr, secstrs);
1036d45868d3SArnaldo Carvalho de Melo 	default:
1037d45868d3SArnaldo Carvalho de Melo 		return false;
1038d45868d3SArnaldo Carvalho de Melo 	}
1039d45868d3SArnaldo Carvalho de Melo }
1040d45868d3SArnaldo Carvalho de Melo 
104170c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
104270c3856bSEric B Munson {
104370c3856bSEric B Munson 	Elf_Scn *sec = NULL;
104470c3856bSEric B Munson 	GElf_Shdr shdr;
104570c3856bSEric B Munson 	size_t cnt = 1;
104670c3856bSEric B Munson 
104770c3856bSEric B Munson 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
104870c3856bSEric B Munson 		gelf_getshdr(sec, &shdr);
104970c3856bSEric B Munson 
105070c3856bSEric B Munson 		if ((addr >= shdr.sh_addr) &&
105170c3856bSEric B Munson 		    (addr < (shdr.sh_addr + shdr.sh_size)))
105270c3856bSEric B Munson 			return cnt;
105370c3856bSEric B Munson 
105470c3856bSEric B Munson 		++cnt;
105570c3856bSEric B Munson 	}
105670c3856bSEric B Munson 
105770c3856bSEric B Munson 	return -1;
105870c3856bSEric B Munson }
105970c3856bSEric B Munson 
1060aeafcbafSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
10616da80ce8SDave Martin 			 int fd, symbol_filter_t filter, int kmodule,
10626da80ce8SDave Martin 			 int want_symtab)
106386470930SIngo Molnar {
1064aeafcbafSArnaldo Carvalho de Melo 	struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
10652e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
1066aeafcbafSArnaldo Carvalho de Melo 	struct dso *curr_dso = dso;
10676cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
106886470930SIngo Molnar 	uint32_t nr_syms;
106986470930SIngo Molnar 	int err = -1;
107083a0944fSIngo Molnar 	uint32_t idx;
107186470930SIngo Molnar 	GElf_Ehdr ehdr;
107270c3856bSEric B Munson 	GElf_Shdr shdr, opdshdr;
107370c3856bSEric B Munson 	Elf_Data *syms, *opddata = NULL;
107486470930SIngo Molnar 	GElf_Sym sym;
107570c3856bSEric B Munson 	Elf_Scn *sec, *sec_strndx, *opdsec;
107686470930SIngo Molnar 	Elf *elf;
1077439d473bSArnaldo Carvalho de Melo 	int nr = 0;
107870c3856bSEric B Munson 	size_t opdidx = 0;
107986470930SIngo Molnar 
108084087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
108186470930SIngo Molnar 	if (elf == NULL) {
10828b1389efSDave Martin 		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
108386470930SIngo Molnar 		goto out_close;
108486470930SIngo Molnar 	}
108586470930SIngo Molnar 
108686470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
10878b1389efSDave Martin 		pr_debug("%s: cannot get elf header.\n", __func__);
108886470930SIngo Molnar 		goto out_elf_end;
108986470930SIngo Molnar 	}
109086470930SIngo Molnar 
10916da80ce8SDave Martin 	/* Always reject images with a mismatched build-id: */
1092aeafcbafSArnaldo Carvalho de Melo 	if (dso->has_build_id) {
109321916c38SDave Martin 		u8 build_id[BUILD_ID_SIZE];
109421916c38SDave Martin 
109521916c38SDave Martin 		if (elf_read_build_id(elf, build_id,
109621916c38SDave Martin 				      BUILD_ID_SIZE) != BUILD_ID_SIZE)
109721916c38SDave Martin 			goto out_elf_end;
109821916c38SDave Martin 
1099aeafcbafSArnaldo Carvalho de Melo 		if (!dso__build_id_equal(dso, build_id))
110021916c38SDave Martin 			goto out_elf_end;
110121916c38SDave Martin 	}
110221916c38SDave Martin 
110386470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
110486470930SIngo Molnar 	if (sec == NULL) {
11056da80ce8SDave Martin 		if (want_symtab)
11066da80ce8SDave Martin 			goto out_elf_end;
11076da80ce8SDave Martin 
1108a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1109a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
111086470930SIngo Molnar 			goto out_elf_end;
111186470930SIngo Molnar 	}
111286470930SIngo Molnar 
111370c3856bSEric B Munson 	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
111470c3856bSEric B Munson 	if (opdsec)
111570c3856bSEric B Munson 		opddata = elf_rawdata(opdsec, NULL);
111670c3856bSEric B Munson 
111786470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
111886470930SIngo Molnar 	if (syms == NULL)
111986470930SIngo Molnar 		goto out_elf_end;
112086470930SIngo Molnar 
112186470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
112286470930SIngo Molnar 	if (sec == NULL)
112386470930SIngo Molnar 		goto out_elf_end;
112486470930SIngo Molnar 
112586470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
112686470930SIngo Molnar 	if (symstrs == NULL)
112786470930SIngo Molnar 		goto out_elf_end;
112886470930SIngo Molnar 
11296cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
11306cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
11316cfcc53eSMike Galbraith 		goto out_elf_end;
11326cfcc53eSMike Galbraith 
11336cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
11349b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
11356cfcc53eSMike Galbraith 		goto out_elf_end;
11366cfcc53eSMike Galbraith 
113786470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
113886470930SIngo Molnar 
1139e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
1140aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_USER) {
1141aeafcbafSArnaldo Carvalho de Melo 		dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
114230d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
1143f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
114430d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
1145aeafcbafSArnaldo Carvalho de Melo 	} else {
1146aeafcbafSArnaldo Carvalho de Melo 		dso->adjust_symbols = 0;
1147aeafcbafSArnaldo Carvalho de Melo 	}
114883a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
114986470930SIngo Molnar 		struct symbol *f;
115056b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
11512e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
11526cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
11536cfcc53eSMike Galbraith 		const char *section_name;
115486470930SIngo Molnar 
11559de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
11569de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
11579de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
115856b03f3cSArnaldo Carvalho de Melo 
1159d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
116086470930SIngo Molnar 			continue;
116186470930SIngo Molnar 
1162696b97a5SDave Martin 		/* Reject ARM ELF "mapping symbols": these aren't unique and
1163696b97a5SDave Martin 		 * don't identify functions, so will confuse the profile
1164696b97a5SDave Martin 		 * output: */
1165696b97a5SDave Martin 		if (ehdr.e_machine == EM_ARM) {
1166696b97a5SDave Martin 			if (!strcmp(elf_name, "$a") ||
1167696b97a5SDave Martin 			    !strcmp(elf_name, "$d") ||
1168696b97a5SDave Martin 			    !strcmp(elf_name, "$t"))
1169696b97a5SDave Martin 				continue;
1170696b97a5SDave Martin 		}
1171696b97a5SDave Martin 
117270c3856bSEric B Munson 		if (opdsec && sym.st_shndx == opdidx) {
117370c3856bSEric B Munson 			u32 offset = sym.st_value - opdshdr.sh_addr;
117470c3856bSEric B Munson 			u64 *opd = opddata->d_buf + offset;
117570c3856bSEric B Munson 			sym.st_value = *opd;
117670c3856bSEric B Munson 			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
117770c3856bSEric B Munson 		}
117870c3856bSEric B Munson 
117986470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
118086470930SIngo Molnar 		if (!sec)
118186470930SIngo Molnar 			goto out_elf_end;
118286470930SIngo Molnar 
118386470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
11846cfcc53eSMike Galbraith 
1185d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
11866cfcc53eSMike Galbraith 			continue;
11876cfcc53eSMike Galbraith 
11886cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
118986470930SIngo Molnar 
1190b2f8fb23SDr. David Alan Gilbert 		/* On ARM, symbols for thumb functions have 1 added to
1191b2f8fb23SDr. David Alan Gilbert 		 * the symbol address as a flag - remove it */
1192b2f8fb23SDr. David Alan Gilbert 		if ((ehdr.e_machine == EM_ARM) &&
1193b2f8fb23SDr. David Alan Gilbert 		    (map->type == MAP__FUNCTION) &&
1194b2f8fb23SDr. David Alan Gilbert 		    (sym.st_value & 1))
1195b2f8fb23SDr. David Alan Gilbert 			--sym.st_value;
1196b2f8fb23SDr. David Alan Gilbert 
1197aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel != DSO_TYPE_USER || kmodule) {
11982e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
11992e538c4aSArnaldo Carvalho de Melo 
12002e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1201b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1202aeafcbafSArnaldo Carvalho de Melo 				    dso->short_name_len)) == 0)
12032e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
12042e538c4aSArnaldo Carvalho de Melo 
12052e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
12062e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
1207aeafcbafSArnaldo Carvalho de Melo 				curr_dso = dso;
12082e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1209af427bf5SArnaldo Carvalho de Melo 			}
1210af427bf5SArnaldo Carvalho de Melo 
12112e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
1212aeafcbafSArnaldo Carvalho de Melo 				 "%s%s", dso->short_name, section_name);
12132e538c4aSArnaldo Carvalho de Melo 
12149de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
12152e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
12162e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
12172e538c4aSArnaldo Carvalho de Melo 
12182e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
12192e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
12202e538c4aSArnaldo Carvalho de Melo 
122100a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
12222e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
12232e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1224aeafcbafSArnaldo Carvalho de Melo 				curr_dso->kernel = dso->kernel;
1225aeafcbafSArnaldo Carvalho de Melo 				curr_dso->long_name = dso->long_name;
1226aeafcbafSArnaldo Carvalho de Melo 				curr_dso->long_name_len = dso->long_name_len;
12273610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
12286275ce2dSArnaldo Carvalho de Melo 						     map->type);
12292e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
12302e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
12312e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
12322e538c4aSArnaldo Carvalho de Melo 				}
1233ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1234ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1235aeafcbafSArnaldo Carvalho de Melo 				curr_dso->symtab_type = dso->symtab_type;
12369de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1237aeafcbafSArnaldo Carvalho de Melo 				dsos__add(&dso->node, curr_dso);
12386275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
12392e538c4aSArnaldo Carvalho de Melo 			} else
12402e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
12412e538c4aSArnaldo Carvalho de Melo 
12422e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
12432e538c4aSArnaldo Carvalho de Melo 		}
12442e538c4aSArnaldo Carvalho de Melo 
12452e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
12469486aa38SArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
12479486aa38SArnaldo Carvalho de Melo 				  "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
124829a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
124929a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
125086470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1251af427bf5SArnaldo Carvalho de Melo 		}
125228ac909bSArnaldo Carvalho de Melo 		/*
125328ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
125428ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
125528ac909bSArnaldo Carvalho de Melo 		 * to it...
125628ac909bSArnaldo Carvalho de Melo 		 */
125783a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
125828ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
125983a0944fSIngo Molnar 			elf_name = demangled;
12602e538c4aSArnaldo Carvalho de Melo new_symbol:
1261c408fedfSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size,
1262c408fedfSArnaldo Carvalho de Melo 				GELF_ST_BIND(sym.st_info), elf_name);
126328ac909bSArnaldo Carvalho de Melo 		free(demangled);
126486470930SIngo Molnar 		if (!f)
126586470930SIngo Molnar 			goto out_elf_end;
126686470930SIngo Molnar 
12672e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
126800a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
126986470930SIngo Molnar 		else {
12706a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
127186470930SIngo Molnar 			nr++;
127286470930SIngo Molnar 		}
127386470930SIngo Molnar 	}
127486470930SIngo Molnar 
12752e538c4aSArnaldo Carvalho de Melo 	/*
12762e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
12772e538c4aSArnaldo Carvalho de Melo 	 */
12786275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
1279aeafcbafSArnaldo Carvalho de Melo 		symbols__fixup_end(&dso->symbols[map->type]);
12806275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
12816275ce2dSArnaldo Carvalho de Melo 			/*
12826275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
12836275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
12846275ce2dSArnaldo Carvalho de Melo 			 */
12856275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
12866275ce2dSArnaldo Carvalho de Melo 		}
12876275ce2dSArnaldo Carvalho de Melo 	}
128886470930SIngo Molnar 	err = nr;
128986470930SIngo Molnar out_elf_end:
129086470930SIngo Molnar 	elf_end(elf);
129186470930SIngo Molnar out_close:
129286470930SIngo Molnar 	return err;
129386470930SIngo Molnar }
129486470930SIngo Molnar 
1295aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
129678075caaSArnaldo Carvalho de Melo {
1297aeafcbafSArnaldo Carvalho de Melo 	return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
129878075caaSArnaldo Carvalho de Melo }
129978075caaSArnaldo Carvalho de Melo 
1300a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
130157f395a7SFrederic Weisbecker {
1302e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
130357f395a7SFrederic Weisbecker 	struct dso *pos;
130457f395a7SFrederic Weisbecker 
13056122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
13066122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
13076122e4e4SArnaldo Carvalho de Melo 			continue;
1308f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
1309f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
1310f6e1467dSArnaldo Carvalho de Melo 			continue;
1311f6e1467dSArnaldo Carvalho de Melo 		}
1312e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1313e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1314e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1315e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
131657f395a7SFrederic Weisbecker 		}
13176122e4e4SArnaldo Carvalho de Melo 	}
131857f395a7SFrederic Weisbecker 
1319e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
132057f395a7SFrederic Weisbecker }
132157f395a7SFrederic Weisbecker 
1322fd7a346eSArnaldo Carvalho de Melo /*
1323fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1324fd7a346eSArnaldo Carvalho de Melo  */
1325fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1326fd7a346eSArnaldo Carvalho de Melo 
132721916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size)
13284d1e00a8SArnaldo Carvalho de Melo {
132921916c38SDave Martin 	int err = -1;
13304d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
13314d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1332fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
13334d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1334e57cfcdaSPekka Enberg 	Elf_Kind ek;
1335fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
13364d1e00a8SArnaldo Carvalho de Melo 
13372643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
13382643ce11SArnaldo Carvalho de Melo 		goto out;
13392643ce11SArnaldo Carvalho de Melo 
1340e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1341e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
134221916c38SDave Martin 		goto out;
1343e57cfcdaSPekka Enberg 
13444d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
13456beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
134621916c38SDave Martin 		goto out;
13474d1e00a8SArnaldo Carvalho de Melo 	}
13484d1e00a8SArnaldo Carvalho de Melo 
13492643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
13502643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1351fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1352fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1353fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
13544d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
135521916c38SDave Martin 			goto out;
1356fd7a346eSArnaldo Carvalho de Melo 	}
13574d1e00a8SArnaldo Carvalho de Melo 
1358fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1359fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
136021916c38SDave Martin 		goto out;
1361fd7a346eSArnaldo Carvalho de Melo 
1362fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1363fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1364fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1365fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1366fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1367fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1368fd7a346eSArnaldo Carvalho de Melo 
1369fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1370fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1371fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1372fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1373fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1374fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1375fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
13762643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1377fd7a346eSArnaldo Carvalho de Melo 				break;
1378fd7a346eSArnaldo Carvalho de Melo 			}
1379fd7a346eSArnaldo Carvalho de Melo 		}
1380fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1381fd7a346eSArnaldo Carvalho de Melo 	}
138221916c38SDave Martin 
138321916c38SDave Martin out:
138421916c38SDave Martin 	return err;
138521916c38SDave Martin }
138621916c38SDave Martin 
138721916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size)
138821916c38SDave Martin {
138921916c38SDave Martin 	int fd, err = -1;
139021916c38SDave Martin 	Elf *elf;
139121916c38SDave Martin 
139221916c38SDave Martin 	if (size < BUILD_ID_SIZE)
139321916c38SDave Martin 		goto out;
139421916c38SDave Martin 
139521916c38SDave Martin 	fd = open(filename, O_RDONLY);
139621916c38SDave Martin 	if (fd < 0)
139721916c38SDave Martin 		goto out;
139821916c38SDave Martin 
139921916c38SDave Martin 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
140021916c38SDave Martin 	if (elf == NULL) {
140121916c38SDave Martin 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
140221916c38SDave Martin 		goto out_close;
140321916c38SDave Martin 	}
140421916c38SDave Martin 
140521916c38SDave Martin 	err = elf_read_build_id(elf, bf, size);
140621916c38SDave Martin 
14072643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
14082643ce11SArnaldo Carvalho de Melo out_close:
14092643ce11SArnaldo Carvalho de Melo 	close(fd);
14102643ce11SArnaldo Carvalho de Melo out:
14112643ce11SArnaldo Carvalho de Melo 	return err;
14122643ce11SArnaldo Carvalho de Melo }
14132643ce11SArnaldo Carvalho de Melo 
1414f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1415f1617b40SArnaldo Carvalho de Melo {
1416f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1417f1617b40SArnaldo Carvalho de Melo 
1418f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1419f1617b40SArnaldo Carvalho de Melo 		goto out;
1420f1617b40SArnaldo Carvalho de Melo 
1421f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1422f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1423f1617b40SArnaldo Carvalho de Melo 		goto out;
1424f1617b40SArnaldo Carvalho de Melo 
1425f1617b40SArnaldo Carvalho de Melo 	while (1) {
1426f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1427f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1428f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1429f1617b40SArnaldo Carvalho de Melo 
1430f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1431f1617b40SArnaldo Carvalho de Melo 			break;
1432f1617b40SArnaldo Carvalho de Melo 
1433fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1434fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1435f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1436f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1437f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1438f1617b40SArnaldo Carvalho de Melo 				break;
1439f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1440f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1441f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1442f1617b40SArnaldo Carvalho de Melo 					err = 0;
1443f1617b40SArnaldo Carvalho de Melo 					break;
1444f1617b40SArnaldo Carvalho de Melo 				}
1445f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1446f1617b40SArnaldo Carvalho de Melo 				break;
1447f1617b40SArnaldo Carvalho de Melo 		} else {
1448f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1449f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1450f1617b40SArnaldo Carvalho de Melo 				break;
1451f1617b40SArnaldo Carvalho de Melo 		}
1452f1617b40SArnaldo Carvalho de Melo 	}
1453f1617b40SArnaldo Carvalho de Melo 	close(fd);
1454f1617b40SArnaldo Carvalho de Melo out:
1455f1617b40SArnaldo Carvalho de Melo 	return err;
1456f1617b40SArnaldo Carvalho de Melo }
1457f1617b40SArnaldo Carvalho de Melo 
1458aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso)
145994cb9e38SArnaldo Carvalho de Melo {
146094cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
1461878b439dSArnaldo Carvalho de Melo 		[SYMTAB__KALLSYMS]	      = 'k',
1462878b439dSArnaldo Carvalho de Melo 		[SYMTAB__JAVA_JIT]	      = 'j',
1463878b439dSArnaldo Carvalho de Melo 		[SYMTAB__BUILD_ID_CACHE]      = 'B',
1464878b439dSArnaldo Carvalho de Melo 		[SYMTAB__FEDORA_DEBUGINFO]    = 'f',
1465878b439dSArnaldo Carvalho de Melo 		[SYMTAB__UBUNTU_DEBUGINFO]    = 'u',
1466878b439dSArnaldo Carvalho de Melo 		[SYMTAB__BUILDID_DEBUGINFO]   = 'b',
1467878b439dSArnaldo Carvalho de Melo 		[SYMTAB__SYSTEM_PATH_DSO]     = 'd',
1468878b439dSArnaldo Carvalho de Melo 		[SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1469878b439dSArnaldo Carvalho de Melo 		[SYMTAB__GUEST_KALLSYMS]      =  'g',
1470878b439dSArnaldo Carvalho de Melo 		[SYMTAB__GUEST_KMODULE]	      =  'G',
147194cb9e38SArnaldo Carvalho de Melo 	};
147294cb9e38SArnaldo Carvalho de Melo 
1473aeafcbafSArnaldo Carvalho de Melo 	if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND)
147494cb9e38SArnaldo Carvalho de Melo 		return '!';
1475aeafcbafSArnaldo Carvalho de Melo 	return origin[dso->symtab_type];
147694cb9e38SArnaldo Carvalho de Melo }
147794cb9e38SArnaldo Carvalho de Melo 
1478aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
147986470930SIngo Molnar {
14804d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1481c338aee8SArnaldo Carvalho de Melo 	char *name;
148286470930SIngo Molnar 	int ret = -1;
148386470930SIngo Molnar 	int fd;
148423346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1485a1645ce1SZhang, Yanmin 	const char *root_dir;
14866da80ce8SDave Martin 	int want_symtab;
148786470930SIngo Molnar 
1488aeafcbafSArnaldo Carvalho de Melo 	dso__set_loaded(dso, map->type);
148966bd8424SArnaldo Carvalho de Melo 
1490aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_KERNEL)
1491aeafcbafSArnaldo Carvalho de Melo 		return dso__load_kernel_sym(dso, map, filter);
1492aeafcbafSArnaldo Carvalho de Melo 	else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1493aeafcbafSArnaldo Carvalho de Melo 		return dso__load_guest_kernel_sym(dso, map, filter);
1494a1645ce1SZhang, Yanmin 
149523346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
149623346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1497a1645ce1SZhang, Yanmin 	else
149823346f21SArnaldo Carvalho de Melo 		machine = NULL;
1499c338aee8SArnaldo Carvalho de Melo 
1500c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
150186470930SIngo Molnar 	if (!name)
150286470930SIngo Molnar 		return -1;
150386470930SIngo Molnar 
1504aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1505f5812a7aSArnaldo Carvalho de Melo 
1506aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1507981c1252SPekka Enberg 		struct stat st;
1508981c1252SPekka Enberg 
1509*e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
1510981c1252SPekka Enberg 			return -1;
1511981c1252SPekka Enberg 
1512981c1252SPekka Enberg 		if (st.st_uid && (st.st_uid != geteuid())) {
1513981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1514981c1252SPekka Enberg 				"ignoring it.\n", dso->name);
1515981c1252SPekka Enberg 			return -1;
1516981c1252SPekka Enberg 		}
1517981c1252SPekka Enberg 
1518aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
1519aeafcbafSArnaldo Carvalho de Melo 		dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1520878b439dSArnaldo Carvalho de Melo 					      SYMTAB__NOT_FOUND;
152194cb9e38SArnaldo Carvalho de Melo 		return ret;
152294cb9e38SArnaldo Carvalho de Melo 	}
152394cb9e38SArnaldo Carvalho de Melo 
15246da80ce8SDave Martin 	/* Iterate over candidate debug images.
15256da80ce8SDave Martin 	 * On the first pass, only load images if they have a full symtab.
15266da80ce8SDave Martin 	 * Failing that, do a second pass where we accept .dynsym also
15276da80ce8SDave Martin 	 */
152860e4b10cSArnaldo Carvalho de Melo 	want_symtab = 1;
152960e4b10cSArnaldo Carvalho de Melo restart:
1530aeafcbafSArnaldo Carvalho de Melo 	for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE;
1531aeafcbafSArnaldo Carvalho de Melo 	     dso->symtab_type != SYMTAB__NOT_FOUND;
1532aeafcbafSArnaldo Carvalho de Melo 	     dso->symtab_type++) {
1533aeafcbafSArnaldo Carvalho de Melo 		switch (dso->symtab_type) {
1534878b439dSArnaldo Carvalho de Melo 		case SYMTAB__BUILD_ID_CACHE:
1535ec5761eaSDavid Ahern 			/* skip the locally configured cache if a symfs is given */
1536ec5761eaSDavid Ahern 			if (symbol_conf.symfs[0] ||
1537aeafcbafSArnaldo Carvalho de Melo 			    (dso__build_id_filename(dso, name, size) == NULL)) {
15386da80ce8SDave Martin 				continue;
1539ec5761eaSDavid Ahern 			}
15406da80ce8SDave Martin 			break;
1541878b439dSArnaldo Carvalho de Melo 		case SYMTAB__FEDORA_DEBUGINFO:
1542ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s.debug",
1543aeafcbafSArnaldo Carvalho de Melo 				 symbol_conf.symfs, dso->long_name);
154486470930SIngo Molnar 			break;
1545878b439dSArnaldo Carvalho de Melo 		case SYMTAB__UBUNTU_DEBUGINFO:
1546ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s",
1547aeafcbafSArnaldo Carvalho de Melo 				 symbol_conf.symfs, dso->long_name);
154886470930SIngo Molnar 			break;
1549878b439dSArnaldo Carvalho de Melo 		case SYMTAB__BUILDID_DEBUGINFO: {
1550b36f19d5SArnaldo Carvalho de Melo 			char build_id_hex[BUILD_ID_SIZE * 2 + 1];
15516da80ce8SDave Martin 
1552aeafcbafSArnaldo Carvalho de Melo 			if (!dso->has_build_id)
15536da80ce8SDave Martin 				continue;
15546da80ce8SDave Martin 
1555aeafcbafSArnaldo Carvalho de Melo 			build_id__sprintf(dso->build_id,
1556aeafcbafSArnaldo Carvalho de Melo 					  sizeof(dso->build_id),
1557d3379ab9SArnaldo Carvalho de Melo 					  build_id_hex);
15584d1e00a8SArnaldo Carvalho de Melo 			snprintf(name, size,
1559ec5761eaSDavid Ahern 				 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1560ec5761eaSDavid Ahern 				 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
15614d1e00a8SArnaldo Carvalho de Melo 			}
15626da80ce8SDave Martin 			break;
1563878b439dSArnaldo Carvalho de Melo 		case SYMTAB__SYSTEM_PATH_DSO:
1564ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s",
1565aeafcbafSArnaldo Carvalho de Melo 			     symbol_conf.symfs, dso->long_name);
156686470930SIngo Molnar 			break;
1567878b439dSArnaldo Carvalho de Melo 		case SYMTAB__GUEST_KMODULE:
1568fb7d0b3cSKyle McMartin 			if (map->groups && machine)
1569fb7d0b3cSKyle McMartin 				root_dir = machine->root_dir;
1570a1645ce1SZhang, Yanmin 			else
1571a1645ce1SZhang, Yanmin 				root_dir = "";
1572ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1573aeafcbafSArnaldo Carvalho de Melo 				 root_dir, dso->long_name);
1574ec5761eaSDavid Ahern 			break;
1575ec5761eaSDavid Ahern 
1576878b439dSArnaldo Carvalho de Melo 		case SYMTAB__SYSTEM_PATH_KMODULE:
1577ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s", symbol_conf.symfs,
1578aeafcbafSArnaldo Carvalho de Melo 				 dso->long_name);
1579a1645ce1SZhang, Yanmin 			break;
158060e4b10cSArnaldo Carvalho de Melo 		default:;
158186470930SIngo Molnar 		}
158286470930SIngo Molnar 
15836da80ce8SDave Martin 		/* Name is now the name of the next image to try */
15846da80ce8SDave Martin 		fd = open(name, O_RDONLY);
15856da80ce8SDave Martin 		if (fd < 0)
15866da80ce8SDave Martin 			continue;
15876da80ce8SDave Martin 
1588aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_sym(dso, map, name, fd, filter, 0,
15896da80ce8SDave Martin 				    want_symtab);
159086470930SIngo Molnar 		close(fd);
159186470930SIngo Molnar 
159286470930SIngo Molnar 		/*
15936da80ce8SDave Martin 		 * Some people seem to have debuginfo files _WITHOUT_ debug
15946da80ce8SDave Martin 		 * info!?!?
159586470930SIngo Molnar 		 */
159686470930SIngo Molnar 		if (!ret)
15976da80ce8SDave Martin 			continue;
159886470930SIngo Molnar 
1599a25e46c4SArnaldo Carvalho de Melo 		if (ret > 0) {
1600aeafcbafSArnaldo Carvalho de Melo 			int nr_plt = dso__synthesize_plt_symbols(dso, map,
1601aeafcbafSArnaldo Carvalho de Melo 								 filter);
1602a25e46c4SArnaldo Carvalho de Melo 			if (nr_plt > 0)
1603a25e46c4SArnaldo Carvalho de Melo 				ret += nr_plt;
16046da80ce8SDave Martin 			break;
1605a25e46c4SArnaldo Carvalho de Melo 		}
16066da80ce8SDave Martin 	}
16076da80ce8SDave Martin 
160860e4b10cSArnaldo Carvalho de Melo 	/*
160960e4b10cSArnaldo Carvalho de Melo 	 * If we wanted a full symtab but no image had one,
161060e4b10cSArnaldo Carvalho de Melo 	 * relax our requirements and repeat the search.
161160e4b10cSArnaldo Carvalho de Melo 	 */
161260e4b10cSArnaldo Carvalho de Melo 	if (ret <= 0 && want_symtab) {
161360e4b10cSArnaldo Carvalho de Melo 		want_symtab = 0;
161460e4b10cSArnaldo Carvalho de Melo 		goto restart;
161560e4b10cSArnaldo Carvalho de Melo 	}
161660e4b10cSArnaldo Carvalho de Melo 
161786470930SIngo Molnar 	free(name);
1618aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
16191340e6bbSArnaldo Carvalho de Melo 		return 0;
162086470930SIngo Molnar 	return ret;
162186470930SIngo Molnar }
162286470930SIngo Molnar 
1623aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
162479406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1625439d473bSArnaldo Carvalho de Melo {
1626439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1627439d473bSArnaldo Carvalho de Melo 
1628aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
1629439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1630439d473bSArnaldo Carvalho de Melo 
1631b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1632439d473bSArnaldo Carvalho de Melo 			return map;
1633439d473bSArnaldo Carvalho de Melo 	}
1634439d473bSArnaldo Carvalho de Melo 
1635439d473bSArnaldo Carvalho de Melo 	return NULL;
1636439d473bSArnaldo Carvalho de Melo }
1637439d473bSArnaldo Carvalho de Melo 
1638aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso,
1639a1645ce1SZhang, Yanmin 					   const char *root_dir)
1640b7cece76SArnaldo Carvalho de Melo {
1641b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1642b7cece76SArnaldo Carvalho de Melo 	/*
1643b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1644b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1645b7cece76SArnaldo Carvalho de Melo 	 */
1646aeafcbafSArnaldo Carvalho de Melo 	const char *name = dso->short_name + 1;
1647b7cece76SArnaldo Carvalho de Melo 
1648b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1649a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1650a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1651b7cece76SArnaldo Carvalho de Melo 
1652aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, dso->build_id,
1653aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
1654aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
1655b7cece76SArnaldo Carvalho de Melo 
1656b7cece76SArnaldo Carvalho de Melo 	return 0;
1657b7cece76SArnaldo Carvalho de Melo }
1658b7cece76SArnaldo Carvalho de Melo 
1659aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg,
1660a1645ce1SZhang, Yanmin 				const char *dir_name)
16616cfcc53eSMike Galbraith {
1662439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
16635aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
166474534341SGui Jianfeng 	int ret = 0;
16656cfcc53eSMike Galbraith 
1666439d473bSArnaldo Carvalho de Melo 	if (!dir) {
16675aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1668439d473bSArnaldo Carvalho de Melo 		return -1;
1669439d473bSArnaldo Carvalho de Melo 	}
16706cfcc53eSMike Galbraith 
1671439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1672439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1673a1645ce1SZhang, Yanmin 		struct stat st;
1674439d473bSArnaldo Carvalho de Melo 
1675a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
1676a1645ce1SZhang, Yanmin 		sprintf(path, "%s/%s", dir_name, dent->d_name);
1677a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1678a1645ce1SZhang, Yanmin 			continue;
1679a1645ce1SZhang, Yanmin 
1680a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1681439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1682439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1683439d473bSArnaldo Carvalho de Melo 				continue;
1684439d473bSArnaldo Carvalho de Melo 
1685439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
16865aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
1687aeafcbafSArnaldo Carvalho de Melo 			ret = map_groups__set_modules_path_dir(mg, path);
168874534341SGui Jianfeng 			if (ret < 0)
168974534341SGui Jianfeng 				goto out;
1690439d473bSArnaldo Carvalho de Melo 		} else {
1691439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1692439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1693439d473bSArnaldo Carvalho de Melo 			struct map *map;
1694cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1695439d473bSArnaldo Carvalho de Melo 
1696439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1697439d473bSArnaldo Carvalho de Melo 				continue;
1698439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1699439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1700439d473bSArnaldo Carvalho de Melo 
1701a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
1702aeafcbafSArnaldo Carvalho de Melo 			map = map_groups__find_by_name(mg, MAP__FUNCTION,
1703aeafcbafSArnaldo Carvalho de Melo 						       dso_name);
1704439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1705439d473bSArnaldo Carvalho de Melo 				continue;
1706439d473bSArnaldo Carvalho de Melo 
1707439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
17085aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
1709439d473bSArnaldo Carvalho de Melo 
1710cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
171174534341SGui Jianfeng 			if (long_name == NULL) {
171274534341SGui Jianfeng 				ret = -1;
171374534341SGui Jianfeng 				goto out;
171474534341SGui Jianfeng 			}
1715cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
17166e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1717a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1718439d473bSArnaldo Carvalho de Melo 		}
1719439d473bSArnaldo Carvalho de Melo 	}
1720439d473bSArnaldo Carvalho de Melo 
172174534341SGui Jianfeng out:
1722439d473bSArnaldo Carvalho de Melo 	closedir(dir);
172374534341SGui Jianfeng 	return ret;
1724439d473bSArnaldo Carvalho de Melo }
1725439d473bSArnaldo Carvalho de Melo 
1726a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1727439d473bSArnaldo Carvalho de Melo {
1728a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1729a1645ce1SZhang, Yanmin 	FILE *file;
1730a1645ce1SZhang, Yanmin 	char *name, *tmp;
1731a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1732a1645ce1SZhang, Yanmin 
1733a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1734a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1735a1645ce1SZhang, Yanmin 	if (!file)
1736a1645ce1SZhang, Yanmin 		return NULL;
1737a1645ce1SZhang, Yanmin 
1738a1645ce1SZhang, Yanmin 	version[0] = '\0';
1739a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1740a1645ce1SZhang, Yanmin 	fclose(file);
1741a1645ce1SZhang, Yanmin 
1742a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1743a1645ce1SZhang, Yanmin 	if (!name)
1744a1645ce1SZhang, Yanmin 		return NULL;
1745a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1746a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1747a1645ce1SZhang, Yanmin 	if (tmp)
1748a1645ce1SZhang, Yanmin 		*tmp = '\0';
1749a1645ce1SZhang, Yanmin 
1750a1645ce1SZhang, Yanmin 	return strdup(name);
1751a1645ce1SZhang, Yanmin }
1752a1645ce1SZhang, Yanmin 
1753aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine)
1754a1645ce1SZhang, Yanmin {
1755a1645ce1SZhang, Yanmin 	char *version;
1756439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1757439d473bSArnaldo Carvalho de Melo 
1758aeafcbafSArnaldo Carvalho de Melo 	version = get_kernel_version(machine->root_dir);
1759a1645ce1SZhang, Yanmin 	if (!version)
1760439d473bSArnaldo Carvalho de Melo 		return -1;
1761439d473bSArnaldo Carvalho de Melo 
1762a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1763aeafcbafSArnaldo Carvalho de Melo 		 machine->root_dir, version);
1764a1645ce1SZhang, Yanmin 	free(version);
1765439d473bSArnaldo Carvalho de Melo 
1766aeafcbafSArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
1767439d473bSArnaldo Carvalho de Melo }
17686cfcc53eSMike Galbraith 
17696cfcc53eSMike Galbraith /*
1770439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1771439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1772439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
17736cfcc53eSMike Galbraith  */
17743610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1775439d473bSArnaldo Carvalho de Melo {
1776aeafcbafSArnaldo Carvalho de Melo 	struct map *map = calloc(1, (sizeof(*map) +
17775aab621bSArnaldo Carvalho de Melo 				     (dso->kernel ? sizeof(struct kmap) : 0)));
1778aeafcbafSArnaldo Carvalho de Melo 	if (map != NULL) {
1779439d473bSArnaldo Carvalho de Melo 		/*
1780afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1781439d473bSArnaldo Carvalho de Melo 		 */
1782aeafcbafSArnaldo Carvalho de Melo 		map__init(map, type, start, 0, 0, dso);
1783439d473bSArnaldo Carvalho de Melo 	}
1784afb7b4f0SArnaldo Carvalho de Melo 
1785aeafcbafSArnaldo Carvalho de Melo 	return map;
1786439d473bSArnaldo Carvalho de Melo }
1787439d473bSArnaldo Carvalho de Melo 
1788aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start,
1789d28c6223SArnaldo Carvalho de Melo 				const char *filename)
1790b7cece76SArnaldo Carvalho de Melo {
1791b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1792aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1793b7cece76SArnaldo Carvalho de Melo 
1794b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1795b7cece76SArnaldo Carvalho de Melo 		return NULL;
1796b7cece76SArnaldo Carvalho de Melo 
1797b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1798b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1799b7cece76SArnaldo Carvalho de Melo 		return NULL;
1800b7cece76SArnaldo Carvalho de Melo 
1801aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine))
1802878b439dSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
1803a1645ce1SZhang, Yanmin 	else
1804878b439dSArnaldo Carvalho de Melo 		dso->symtab_type = SYMTAB__GUEST_KMODULE;
1805aeafcbafSArnaldo Carvalho de Melo 	map_groups__insert(&machine->kmaps, map);
1806b7cece76SArnaldo Carvalho de Melo 	return map;
1807b7cece76SArnaldo Carvalho de Melo }
1808b7cece76SArnaldo Carvalho de Melo 
1809aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine)
1810439d473bSArnaldo Carvalho de Melo {
1811439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1812439d473bSArnaldo Carvalho de Melo 	size_t n;
1813a1645ce1SZhang, Yanmin 	FILE *file;
1814439d473bSArnaldo Carvalho de Melo 	struct map *map;
1815a1645ce1SZhang, Yanmin 	const char *modules;
1816a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1817439d473bSArnaldo Carvalho de Melo 
1818aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
1819a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
1820a1645ce1SZhang, Yanmin 	else {
1821aeafcbafSArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", machine->root_dir);
1822a1645ce1SZhang, Yanmin 		modules = path;
1823a1645ce1SZhang, Yanmin 	}
1824a1645ce1SZhang, Yanmin 
1825ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(path, "/proc/modules"))
1826ec80fde7SArnaldo Carvalho de Melo 		return -1;
1827ec80fde7SArnaldo Carvalho de Melo 
1828a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
1829439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1830439d473bSArnaldo Carvalho de Melo 		return -1;
1831439d473bSArnaldo Carvalho de Melo 
1832439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1833439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1834439d473bSArnaldo Carvalho de Melo 		u64 start;
1835439d473bSArnaldo Carvalho de Melo 		char *sep;
1836439d473bSArnaldo Carvalho de Melo 		int line_len;
1837439d473bSArnaldo Carvalho de Melo 
1838439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1839439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
18406cfcc53eSMike Galbraith 			break;
18416cfcc53eSMike Galbraith 
1842439d473bSArnaldo Carvalho de Melo 		if (!line)
1843439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1844439d473bSArnaldo Carvalho de Melo 
1845439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1846439d473bSArnaldo Carvalho de Melo 
1847439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1848439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1849439d473bSArnaldo Carvalho de Melo 			continue;
1850439d473bSArnaldo Carvalho de Melo 
1851439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1852439d473bSArnaldo Carvalho de Melo 
1853439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1854439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1855439d473bSArnaldo Carvalho de Melo 			continue;
1856439d473bSArnaldo Carvalho de Melo 
1857439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1858439d473bSArnaldo Carvalho de Melo 
1859439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
1860aeafcbafSArnaldo Carvalho de Melo 		map = machine__new_module(machine, start, name);
1861b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1862439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1863aeafcbafSArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, machine->root_dir);
18646cfcc53eSMike Galbraith 	}
18656cfcc53eSMike Galbraith 
1866439d473bSArnaldo Carvalho de Melo 	free(line);
1867439d473bSArnaldo Carvalho de Melo 	fclose(file);
1868439d473bSArnaldo Carvalho de Melo 
1869aeafcbafSArnaldo Carvalho de Melo 	return machine__set_modules_path(machine);
1870439d473bSArnaldo Carvalho de Melo 
1871439d473bSArnaldo Carvalho de Melo out_delete_line:
1872439d473bSArnaldo Carvalho de Melo 	free(line);
1873439d473bSArnaldo Carvalho de Melo out_failure:
1874439d473bSArnaldo Carvalho de Melo 	return -1;
18756cfcc53eSMike Galbraith }
18766cfcc53eSMike Galbraith 
1877aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
18786beba7adSArnaldo Carvalho de Melo 		      const char *vmlinux, symbol_filter_t filter)
187986470930SIngo Molnar {
1880fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
1881ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
188286470930SIngo Molnar 
1883a639dc64SArnaldo Carvalho de Melo 	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1884ec5761eaSDavid Ahern 		 symbol_conf.symfs, vmlinux);
1885ec5761eaSDavid Ahern 	fd = open(symfs_vmlinux, O_RDONLY);
188686470930SIngo Molnar 	if (fd < 0)
188786470930SIngo Molnar 		return -1;
188886470930SIngo Molnar 
1889aeafcbafSArnaldo Carvalho de Melo 	dso__set_long_name(dso, (char *)vmlinux);
1890aeafcbafSArnaldo Carvalho de Melo 	dso__set_loaded(dso, map->type);
1891aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
189286470930SIngo Molnar 	close(fd);
189386470930SIngo Molnar 
18943846df2eSArnaldo Carvalho de Melo 	if (err > 0)
1895ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
18963846df2eSArnaldo Carvalho de Melo 
189786470930SIngo Molnar 	return err;
189886470930SIngo Molnar }
189986470930SIngo Molnar 
1900aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
19019de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1902a19afe46SArnaldo Carvalho de Melo {
1903a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
19045ad90e4eSArnaldo Carvalho de Melo 	char *filename;
1905a19afe46SArnaldo Carvalho de Melo 
1906a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
19075ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
19085ad90e4eSArnaldo Carvalho de Melo 
1909aeafcbafSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(dso, NULL, 0);
19105ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
1911aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, filter);
19125ad90e4eSArnaldo Carvalho de Melo 		if (err > 0) {
1913aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, filename);
19145ad90e4eSArnaldo Carvalho de Melo 			goto out;
19155ad90e4eSArnaldo Carvalho de Melo 		}
19165ad90e4eSArnaldo Carvalho de Melo 		free(filename);
19175ad90e4eSArnaldo Carvalho de Melo 	}
1918a19afe46SArnaldo Carvalho de Melo 
1919a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1920aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1921a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1922aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(vmlinux_path[i]));
1923a19afe46SArnaldo Carvalho de Melo 			break;
1924a19afe46SArnaldo Carvalho de Melo 		}
1925a19afe46SArnaldo Carvalho de Melo 	}
19265ad90e4eSArnaldo Carvalho de Melo out:
1927a19afe46SArnaldo Carvalho de Melo 	return err;
1928a19afe46SArnaldo Carvalho de Melo }
1929a19afe46SArnaldo Carvalho de Melo 
1930aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
19319de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
193286470930SIngo Molnar {
1933cc612d81SArnaldo Carvalho de Melo 	int err;
19349e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
19359e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1936dc8d6ab2SArnaldo Carvalho de Melo 	/*
1937b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1938b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1939dc8d6ab2SArnaldo Carvalho de Melo 	 *
1940dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1941dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1942dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1943dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1944dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1945dc8d6ab2SArnaldo Carvalho de Melo 	 *
1946dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1947dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1948dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1949dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1950dc8d6ab2SArnaldo Carvalho de Melo 	 */
1951b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1952b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1953b226a5a7SDavid Ahern 		goto do_kallsyms;
1954b226a5a7SDavid Ahern 	}
1955b226a5a7SDavid Ahern 
1956dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
1957aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map,
1958dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1959e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
1960aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso,
1961e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
1962e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
1963e7dadc00SArnaldo Carvalho de Melo 		}
1964e7dadc00SArnaldo Carvalho de Melo 		return err;
1965dc8d6ab2SArnaldo Carvalho de Melo 	}
1966439d473bSArnaldo Carvalho de Melo 
1967cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
1968aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
1969a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1970cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1971cc612d81SArnaldo Carvalho de Melo 	}
1972cc612d81SArnaldo Carvalho de Melo 
1973ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1974ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1975ec5761eaSDavid Ahern 		return -1;
1976ec5761eaSDavid Ahern 
1977b7cece76SArnaldo Carvalho de Melo 	/*
1978b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1979b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1980b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1981b7cece76SArnaldo Carvalho de Melo 	 */
1982aeafcbafSArnaldo Carvalho de Melo 	if (dso->has_build_id) {
1983b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
19849e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1985b7cece76SArnaldo Carvalho de Melo 
1986b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
19878d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
1988aeafcbafSArnaldo Carvalho de Melo 			if (dso__build_id_equal(dso, kallsyms_build_id)) {
19899e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1990b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
19918d0591f6SArnaldo Carvalho de Melo 			}
19929e201442SArnaldo Carvalho de Melo 		}
1993dc8d6ab2SArnaldo Carvalho de Melo 		/*
1994dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1995dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1996dc8d6ab2SArnaldo Carvalho de Melo 		 */
1997aeafcbafSArnaldo Carvalho de Melo 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
19989e201442SArnaldo Carvalho de Melo 				  sbuild_id);
19999e201442SArnaldo Carvalho de Melo 
20009e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
20019e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
20023846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
20033846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
20048d0591f6SArnaldo Carvalho de Melo 			return -1;
20053846df2eSArnaldo Carvalho de Melo 		}
20068d0591f6SArnaldo Carvalho de Melo 
200719fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
200819fc2dedSArnaldo Carvalho de Melo 
2009dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
20103846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
20113846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
20129e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
2013dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
2014ef6ae724SArnaldo Carvalho de Melo 		}
2015dc8d6ab2SArnaldo Carvalho de Melo 	} else {
2016dc8d6ab2SArnaldo Carvalho de Melo 		/*
2017dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
2018dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
2019dc8d6ab2SArnaldo Carvalho de Melo 		 */
2020dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
2021dc8d6ab2SArnaldo Carvalho de Melo 	}
2022dc8d6ab2SArnaldo Carvalho de Melo 
2023dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
2024aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
20253846df2eSArnaldo Carvalho de Melo 	if (err > 0)
20263846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
2027dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
2028dc8d6ab2SArnaldo Carvalho de Melo 
2029439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
2030cc612d81SArnaldo Carvalho de Melo out_fixup:
2031e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
2032aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
20336a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
20346a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
2035439d473bSArnaldo Carvalho de Melo 	}
203694cb9e38SArnaldo Carvalho de Melo 
203786470930SIngo Molnar 	return err;
203886470930SIngo Molnar }
203986470930SIngo Molnar 
2040aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
2041a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
2042a1645ce1SZhang, Yanmin {
2043a1645ce1SZhang, Yanmin 	int err;
2044a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
204523346f21SArnaldo Carvalho de Melo 	struct machine *machine;
2046a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2047a1645ce1SZhang, Yanmin 
2048a1645ce1SZhang, Yanmin 	if (!map->groups) {
2049a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
2050a1645ce1SZhang, Yanmin 		return -1;
2051a1645ce1SZhang, Yanmin 	}
205223346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
2053a1645ce1SZhang, Yanmin 
205423346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
2055a1645ce1SZhang, Yanmin 		/*
2056a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
2057a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
2058a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
2059a1645ce1SZhang, Yanmin 		 */
2060a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
2061aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
2062a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
2063a1645ce1SZhang, Yanmin 			goto out_try_fixup;
2064a1645ce1SZhang, Yanmin 		}
2065a1645ce1SZhang, Yanmin 
2066a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
2067a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
2068a1645ce1SZhang, Yanmin 			return -1;
2069a1645ce1SZhang, Yanmin 	} else {
207023346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2071a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
2072a1645ce1SZhang, Yanmin 	}
2073a1645ce1SZhang, Yanmin 
2074aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
2075a1645ce1SZhang, Yanmin 	if (err > 0)
2076a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
2077a1645ce1SZhang, Yanmin 
2078a1645ce1SZhang, Yanmin out_try_fixup:
2079a1645ce1SZhang, Yanmin 	if (err > 0) {
2080a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
208148ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
2082aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(path));
2083a1645ce1SZhang, Yanmin 		}
2084a1645ce1SZhang, Yanmin 		map__fixup_start(map);
2085a1645ce1SZhang, Yanmin 		map__fixup_end(map);
2086a1645ce1SZhang, Yanmin 	}
2087a1645ce1SZhang, Yanmin 
2088a1645ce1SZhang, Yanmin 	return err;
2089a1645ce1SZhang, Yanmin }
2090cd84c2acSFrederic Weisbecker 
2091b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
2092cd84c2acSFrederic Weisbecker {
2093b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
2094cd84c2acSFrederic Weisbecker }
2095cd84c2acSFrederic Weisbecker 
2096b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
2097cd84c2acSFrederic Weisbecker {
2098cd84c2acSFrederic Weisbecker 	struct dso *pos;
2099cd84c2acSFrederic Weisbecker 
2100b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
2101cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
2102cd84c2acSFrederic Weisbecker 			return pos;
2103cd84c2acSFrederic Weisbecker 	return NULL;
2104cd84c2acSFrederic Weisbecker }
2105cd84c2acSFrederic Weisbecker 
2106a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
2107cd84c2acSFrederic Weisbecker {
2108a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
2109cd84c2acSFrederic Weisbecker 
2110e4204992SArnaldo Carvalho de Melo 	if (!dso) {
211100a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
2112cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
2113a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
2114cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
2115cfc10d3bSArnaldo Carvalho de Melo 		}
2116e4204992SArnaldo Carvalho de Melo 	}
2117cd84c2acSFrederic Weisbecker 
2118cd84c2acSFrederic Weisbecker 	return dso;
2119cd84c2acSFrederic Weisbecker }
2120cd84c2acSFrederic Weisbecker 
21211f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2122cd84c2acSFrederic Weisbecker {
2123cd84c2acSFrederic Weisbecker 	struct dso *pos;
2124cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2125cd84c2acSFrederic Weisbecker 
212695011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
212795011c60SArnaldo Carvalho de Melo 		int i;
212895011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
2129cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
2130cd84c2acSFrederic Weisbecker 	}
2131cd84c2acSFrederic Weisbecker 
2132cbf69680SArnaldo Carvalho de Melo 	return ret;
2133cbf69680SArnaldo Carvalho de Melo }
2134cbf69680SArnaldo Carvalho de Melo 
2135aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
2136b0da954aSArnaldo Carvalho de Melo {
2137a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2138cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2139a1645ce1SZhang, Yanmin 
2140aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
214123346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2142cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2143cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
2144a1645ce1SZhang, Yanmin 	}
2145cbf69680SArnaldo Carvalho de Melo 
2146cbf69680SArnaldo Carvalho de Melo 	return ret;
2147b0da954aSArnaldo Carvalho de Melo }
2148b0da954aSArnaldo Carvalho de Melo 
214988d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
215088d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
21519e03eb2dSArnaldo Carvalho de Melo {
21529e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
21539e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
21549e03eb2dSArnaldo Carvalho de Melo 
2155b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
215688d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
215788d3d9b7SArnaldo Carvalho de Melo 			continue;
21589e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
21599e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
21609e03eb2dSArnaldo Carvalho de Melo 	}
21619e03eb2dSArnaldo Carvalho de Melo 	return ret;
21629e03eb2dSArnaldo Carvalho de Melo }
21639e03eb2dSArnaldo Carvalho de Melo 
2164aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
2165aeafcbafSArnaldo Carvalho de Melo 				     bool with_hits)
2166f869097eSArnaldo Carvalho de Melo {
2167aeafcbafSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
2168aeafcbafSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
2169f869097eSArnaldo Carvalho de Melo }
2170f869097eSArnaldo Carvalho de Melo 
2171aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2172aeafcbafSArnaldo Carvalho de Melo 				      FILE *fp, bool with_hits)
2173b0da954aSArnaldo Carvalho de Melo {
2174a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2175a1645ce1SZhang, Yanmin 	size_t ret = 0;
2176a1645ce1SZhang, Yanmin 
2177aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
217823346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2179f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2180a1645ce1SZhang, Yanmin 	}
2181a1645ce1SZhang, Yanmin 	return ret;
2182b0da954aSArnaldo Carvalho de Melo }
2183b0da954aSArnaldo Carvalho de Melo 
2184f57b05edSJiri Olsa static struct dso*
2185f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name,
2186f57b05edSJiri Olsa 		    const char *short_name, int dso_type)
2187fd1d908cSArnaldo Carvalho de Melo {
2188f57b05edSJiri Olsa 	/*
2189f57b05edSJiri Olsa 	 * The kernel dso could be created by build_id processing.
2190f57b05edSJiri Olsa 	 */
2191f57b05edSJiri Olsa 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
2192fd1d908cSArnaldo Carvalho de Melo 
2193f57b05edSJiri Olsa 	/*
2194f57b05edSJiri Olsa 	 * We need to run this in all cases, since during the build_id
2195f57b05edSJiri Olsa 	 * processing we had no idea this was the kernel dso.
2196f57b05edSJiri Olsa 	 */
2197aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
2198f57b05edSJiri Olsa 		dso__set_short_name(dso, short_name);
2199f57b05edSJiri Olsa 		dso->kernel = dso_type;
2200a1645ce1SZhang, Yanmin 	}
2201a1645ce1SZhang, Yanmin 
2202aeafcbafSArnaldo Carvalho de Melo 	return dso;
2203a1645ce1SZhang, Yanmin }
2204a1645ce1SZhang, Yanmin 
2205aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2206a1645ce1SZhang, Yanmin {
2207a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2208a1645ce1SZhang, Yanmin 
220923346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2210a1645ce1SZhang, Yanmin 		return;
221123346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2212aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(path, dso->build_id,
2213aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
2214aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
2215fd1d908cSArnaldo Carvalho de Melo }
2216fd1d908cSArnaldo Carvalho de Melo 
2217f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine)
2218cd84c2acSFrederic Weisbecker {
2219a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
2220a1645ce1SZhang, Yanmin 	struct dso *kernel;
2221cd84c2acSFrederic Weisbecker 
2222aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine)) {
2223a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2224f57b05edSJiri Olsa 		if (!vmlinux_name)
2225f57b05edSJiri Olsa 			vmlinux_name = "[kernel.kallsyms]";
2226f57b05edSJiri Olsa 
2227f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
2228f57b05edSJiri Olsa 					     "[kernel]",
2229f57b05edSJiri Olsa 					     DSO_TYPE_KERNEL);
2230a1645ce1SZhang, Yanmin 	} else {
2231f57b05edSJiri Olsa 		char bf[PATH_MAX];
2232f57b05edSJiri Olsa 
2233aeafcbafSArnaldo Carvalho de Melo 		if (machine__is_default_guest(machine))
2234a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2235f57b05edSJiri Olsa 		if (!vmlinux_name)
2236f57b05edSJiri Olsa 			vmlinux_name = machine__mmap_name(machine, bf,
2237f57b05edSJiri Olsa 							  sizeof(bf));
2238f57b05edSJiri Olsa 
2239f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
2240f57b05edSJiri Olsa 					     "[guest.kernel]",
2241f57b05edSJiri Olsa 					     DSO_TYPE_GUEST_KERNEL);
22428d92c02aSArnaldo Carvalho de Melo 	}
2243cd84c2acSFrederic Weisbecker 
2244f57b05edSJiri Olsa 	if (kernel != NULL && (!kernel->has_build_id))
2245aeafcbafSArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, machine);
2246f57b05edSJiri Olsa 
2247f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2248f1dfa0b1SArnaldo Carvalho de Melo }
2249f1dfa0b1SArnaldo Carvalho de Melo 
2250d214afbdSMing Lei struct process_args {
2251d214afbdSMing Lei 	u64 start;
2252d214afbdSMing Lei };
2253d214afbdSMing Lei 
2254d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name,
22553b01a413SArnaldo Carvalho de Melo 			     char type __used, u64 start, u64 end __used)
2256d214afbdSMing Lei {
2257d214afbdSMing Lei 	struct process_args *args = arg;
2258d214afbdSMing Lei 
2259d214afbdSMing Lei 	if (strchr(name, '['))
2260d214afbdSMing Lei 		return 0;
2261d214afbdSMing Lei 
2262d214afbdSMing Lei 	args->start = start;
2263d214afbdSMing Lei 	return 1;
2264d214afbdSMing Lei }
2265d214afbdSMing Lei 
2266d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */
2267d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine)
2268d214afbdSMing Lei {
2269d214afbdSMing Lei 	const char *filename;
2270d214afbdSMing Lei 	char path[PATH_MAX];
2271d214afbdSMing Lei 	struct process_args args;
2272d214afbdSMing Lei 
2273d214afbdSMing Lei 	if (machine__is_host(machine)) {
2274d214afbdSMing Lei 		filename = "/proc/kallsyms";
2275d214afbdSMing Lei 	} else {
2276d214afbdSMing Lei 		if (machine__is_default_guest(machine))
2277d214afbdSMing Lei 			filename = (char *)symbol_conf.default_guest_kallsyms;
2278d214afbdSMing Lei 		else {
2279d214afbdSMing Lei 			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2280d214afbdSMing Lei 			filename = path;
2281d214afbdSMing Lei 		}
2282d214afbdSMing Lei 	}
2283d214afbdSMing Lei 
2284ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
2285ec80fde7SArnaldo Carvalho de Melo 		return 0;
2286ec80fde7SArnaldo Carvalho de Melo 
2287d214afbdSMing Lei 	if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2288d214afbdSMing Lei 		return 0;
2289d214afbdSMing Lei 
2290d214afbdSMing Lei 	return args.start;
2291d214afbdSMing Lei }
2292d214afbdSMing Lei 
2293aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
2294f1dfa0b1SArnaldo Carvalho de Melo {
2295de176489SArnaldo Carvalho de Melo 	enum map_type type;
2296aeafcbafSArnaldo Carvalho de Melo 	u64 start = machine__get_kernel_start_addr(machine);
2297f1dfa0b1SArnaldo Carvalho de Melo 
2298de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
22999de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
23009de89fe7SArnaldo Carvalho de Melo 
2301aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = map__new2(start, kernel, type);
2302aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
2303f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2304f1dfa0b1SArnaldo Carvalho de Melo 
2305aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type]->map_ip =
2306aeafcbafSArnaldo Carvalho de Melo 			machine->vmlinux_maps[type]->unmap_ip =
2307aeafcbafSArnaldo Carvalho de Melo 				identity__map_ip;
2308aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
2309aeafcbafSArnaldo Carvalho de Melo 		kmap->kmaps = &machine->kmaps;
2310aeafcbafSArnaldo Carvalho de Melo 		map_groups__insert(&machine->kmaps,
2311aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
2312f1dfa0b1SArnaldo Carvalho de Melo 	}
2313f1dfa0b1SArnaldo Carvalho de Melo 
2314f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
23152446042cSArnaldo Carvalho de Melo }
23162446042cSArnaldo Carvalho de Melo 
2317aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine)
2318076c6e45SArnaldo Carvalho de Melo {
2319076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
2320076c6e45SArnaldo Carvalho de Melo 
2321076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
2322076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
2323076c6e45SArnaldo Carvalho de Melo 
2324aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
2325076c6e45SArnaldo Carvalho de Melo 			continue;
2326076c6e45SArnaldo Carvalho de Melo 
2327aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
2328aeafcbafSArnaldo Carvalho de Melo 		map_groups__remove(&machine->kmaps,
2329aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
2330076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
2331076c6e45SArnaldo Carvalho de Melo 			/*
2332076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
2333076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
2334076c6e45SArnaldo Carvalho de Melo 			 */
2335076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
2336076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
2337076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
2338076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
2339076c6e45SArnaldo Carvalho de Melo 			}
2340076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
2341076c6e45SArnaldo Carvalho de Melo 		}
2342076c6e45SArnaldo Carvalho de Melo 
2343aeafcbafSArnaldo Carvalho de Melo 		map__delete(machine->vmlinux_maps[type]);
2344aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = NULL;
2345076c6e45SArnaldo Carvalho de Melo 	}
2346076c6e45SArnaldo Carvalho de Melo }
2347076c6e45SArnaldo Carvalho de Melo 
2348aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine)
23495c0541d5SArnaldo Carvalho de Melo {
2350f57b05edSJiri Olsa 	struct dso *kernel = machine__get_kernel(machine);
23515c0541d5SArnaldo Carvalho de Melo 
23525c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
2353aeafcbafSArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(machine, kernel) < 0)
23545c0541d5SArnaldo Carvalho de Melo 		return -1;
23555c0541d5SArnaldo Carvalho de Melo 
2356aeafcbafSArnaldo Carvalho de Melo 	if (symbol_conf.use_modules && machine__create_modules(machine) < 0)
23575c0541d5SArnaldo Carvalho de Melo 		pr_debug("Problems creating module maps, continuing anyway...\n");
23585c0541d5SArnaldo Carvalho de Melo 	/*
23595c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
23605c0541d5SArnaldo Carvalho de Melo 	 */
2361aeafcbafSArnaldo Carvalho de Melo 	map_groups__fixup_end(&machine->kmaps);
23625c0541d5SArnaldo Carvalho de Melo 	return 0;
23635c0541d5SArnaldo Carvalho de Melo }
23645c0541d5SArnaldo Carvalho de Melo 
2365cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
23662446042cSArnaldo Carvalho de Melo {
2367cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2368cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2369cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2370cc612d81SArnaldo Carvalho de Melo 	}
2371cc612d81SArnaldo Carvalho de Melo 
2372cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2373cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2374cc612d81SArnaldo Carvalho de Melo }
2375cc612d81SArnaldo Carvalho de Melo 
2376cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2377cc612d81SArnaldo Carvalho de Melo {
2378cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2379cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2380cc612d81SArnaldo Carvalho de Melo 
2381cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2382cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2383cc612d81SArnaldo Carvalho de Melo 		return -1;
2384cc612d81SArnaldo Carvalho de Melo 
2385cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2386cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2387cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2388cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2389cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2390cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2391cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2392cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2393ec5761eaSDavid Ahern 
2394ec5761eaSDavid Ahern 	/* only try running kernel version if no symfs was given */
2395ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2396ec5761eaSDavid Ahern 		return 0;
2397ec5761eaSDavid Ahern 
2398ec5761eaSDavid Ahern 	if (uname(&uts) < 0)
2399ec5761eaSDavid Ahern 		return -1;
2400ec5761eaSDavid Ahern 
2401cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2402cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2403cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2404cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2405cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2406cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2407cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2408cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2409cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2410cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2411cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2412cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2413cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2414cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2415cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2416cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2417cc612d81SArnaldo Carvalho de Melo 
2418cc612d81SArnaldo Carvalho de Melo 	return 0;
2419cc612d81SArnaldo Carvalho de Melo 
2420cc612d81SArnaldo Carvalho de Melo out_fail:
2421cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2422cc612d81SArnaldo Carvalho de Melo 	return -1;
2423cc612d81SArnaldo Carvalho de Melo }
2424cc612d81SArnaldo Carvalho de Melo 
2425aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
2426b0a9ab62SArnaldo Carvalho de Melo {
2427b0a9ab62SArnaldo Carvalho de Melo 	int i;
2428b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
2429aeafcbafSArnaldo Carvalho de Melo 	struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
24305ad90e4eSArnaldo Carvalho de Melo 
24315ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
24325ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
24335ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
24345ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
24355ad90e4eSArnaldo Carvalho de Melo 	}
2436b0a9ab62SArnaldo Carvalho de Melo 
2437b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
24385ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
24395ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
2440b0a9ab62SArnaldo Carvalho de Melo 
2441b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2442b0a9ab62SArnaldo Carvalho de Melo }
2443b0a9ab62SArnaldo Carvalho de Melo 
2444655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2445655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2446655000e7SArnaldo Carvalho de Melo {
2447655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2448655000e7SArnaldo Carvalho de Melo 		return 0;
2449655000e7SArnaldo Carvalho de Melo 
2450655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2451655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2452655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2453655000e7SArnaldo Carvalho de Melo 		return -1;
2454655000e7SArnaldo Carvalho de Melo 	}
2455655000e7SArnaldo Carvalho de Melo 	return 0;
2456655000e7SArnaldo Carvalho de Melo }
2457655000e7SArnaldo Carvalho de Melo 
2458ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
2459ec80fde7SArnaldo Carvalho de Melo {
2460ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
2461ec80fde7SArnaldo Carvalho de Melo 
2462ec80fde7SArnaldo Carvalho de Melo 	if (geteuid() != 0) {
2463ec80fde7SArnaldo Carvalho de Melo 		FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
2464ec80fde7SArnaldo Carvalho de Melo 		if (fp != NULL) {
2465ec80fde7SArnaldo Carvalho de Melo 			char line[8];
2466ec80fde7SArnaldo Carvalho de Melo 
2467ec80fde7SArnaldo Carvalho de Melo 			if (fgets(line, sizeof(line), fp) != NULL)
2468ec80fde7SArnaldo Carvalho de Melo 				value = atoi(line) != 0;
2469ec80fde7SArnaldo Carvalho de Melo 
2470ec80fde7SArnaldo Carvalho de Melo 			fclose(fp);
2471ec80fde7SArnaldo Carvalho de Melo 		}
2472ec80fde7SArnaldo Carvalho de Melo 	}
2473ec80fde7SArnaldo Carvalho de Melo 
2474ec80fde7SArnaldo Carvalho de Melo 	return value;
2475ec80fde7SArnaldo Carvalho de Melo }
2476ec80fde7SArnaldo Carvalho de Melo 
247775be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2478cc612d81SArnaldo Carvalho de Melo {
2479ec5761eaSDavid Ahern 	const char *symfs;
2480ec5761eaSDavid Ahern 
248185e00b55SJovi Zhang 	if (symbol_conf.initialized)
248285e00b55SJovi Zhang 		return 0;
248385e00b55SJovi Zhang 
24844d439517SDavid S. Miller 	symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
24854d439517SDavid S. Miller 
248695011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
248775be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
248875be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
248979406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2490b32d133aSArnaldo Carvalho de Melo 
249175be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2492cc612d81SArnaldo Carvalho de Melo 		return -1;
2493cc612d81SArnaldo Carvalho de Melo 
2494c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2495c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2496c410a338SArnaldo Carvalho de Melo 		return -1;
2497c410a338SArnaldo Carvalho de Melo 	}
2498c410a338SArnaldo Carvalho de Melo 
2499655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2500655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2501655000e7SArnaldo Carvalho de Melo 		return -1;
2502655000e7SArnaldo Carvalho de Melo 
2503655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2504655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2505655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2506655000e7SArnaldo Carvalho de Melo 
2507655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2508655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2509655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2510655000e7SArnaldo Carvalho de Melo 
2511ec5761eaSDavid Ahern 	/*
2512ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2513ec5761eaSDavid Ahern 	 * reset here for simplicity.
2514ec5761eaSDavid Ahern 	 */
2515ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2516ec5761eaSDavid Ahern 	if (symfs == NULL)
2517ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2518ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2519ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2520ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2521ec5761eaSDavid Ahern 		free((void *)symfs);
2522ec5761eaSDavid Ahern 
2523ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2524ec80fde7SArnaldo Carvalho de Melo 
252585e00b55SJovi Zhang 	symbol_conf.initialized = true;
25264aa65636SArnaldo Carvalho de Melo 	return 0;
2527655000e7SArnaldo Carvalho de Melo 
2528655000e7SArnaldo Carvalho de Melo out_free_dso_list:
2529655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2530655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2531655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2532655000e7SArnaldo Carvalho de Melo 	return -1;
2533cc612d81SArnaldo Carvalho de Melo }
2534cc612d81SArnaldo Carvalho de Melo 
2535d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2536d65a458bSArnaldo Carvalho de Melo {
253785e00b55SJovi Zhang 	if (!symbol_conf.initialized)
253885e00b55SJovi Zhang 		return;
2539d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2540d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2541d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2542d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2543d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
254485e00b55SJovi Zhang 	symbol_conf.initialized = false;
2545d65a458bSArnaldo Carvalho de Melo }
2546d65a458bSArnaldo Carvalho de Melo 
2547aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
25484aa65636SArnaldo Carvalho de Melo {
2549aeafcbafSArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(machines, pid);
25509de89fe7SArnaldo Carvalho de Melo 
255123346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2552a1645ce1SZhang, Yanmin 		return -1;
25534aa65636SArnaldo Carvalho de Melo 
25545c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2555cd84c2acSFrederic Weisbecker }
25565aab621bSArnaldo Carvalho de Melo 
25575aab621bSArnaldo Carvalho de Melo static int hex(char ch)
25585aab621bSArnaldo Carvalho de Melo {
25595aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
25605aab621bSArnaldo Carvalho de Melo 		return ch - '0';
25615aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
25625aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
25635aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
25645aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
25655aab621bSArnaldo Carvalho de Melo 	return -1;
25665aab621bSArnaldo Carvalho de Melo }
25675aab621bSArnaldo Carvalho de Melo 
25685aab621bSArnaldo Carvalho de Melo /*
25695aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
25705aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
25715aab621bSArnaldo Carvalho de Melo  */
25725aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
25735aab621bSArnaldo Carvalho de Melo {
25745aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
25755aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
25765aab621bSArnaldo Carvalho de Melo 
25775aab621bSArnaldo Carvalho de Melo 	while (*p) {
25785aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
25795aab621bSArnaldo Carvalho de Melo 
25805aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
25815aab621bSArnaldo Carvalho de Melo 			break;
25825aab621bSArnaldo Carvalho de Melo 
25835aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
25845aab621bSArnaldo Carvalho de Melo 		p++;
25855aab621bSArnaldo Carvalho de Melo 	}
25865aab621bSArnaldo Carvalho de Melo 
25875aab621bSArnaldo Carvalho de Melo 	return p - ptr;
25885aab621bSArnaldo Carvalho de Melo }
25895aab621bSArnaldo Carvalho de Melo 
25905aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
25915aab621bSArnaldo Carvalho de Melo {
25925aab621bSArnaldo Carvalho de Melo 	char *p = s;
25935aab621bSArnaldo Carvalho de Melo 
25945aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
25955aab621bSArnaldo Carvalho de Melo 		*p++ = to;
25965aab621bSArnaldo Carvalho de Melo 
25975aab621bSArnaldo Carvalho de Melo 	return s;
25985aab621bSArnaldo Carvalho de Melo }
2599a1645ce1SZhang, Yanmin 
2600aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines)
2601a1645ce1SZhang, Yanmin {
2602a1645ce1SZhang, Yanmin 	int ret = 0;
2603a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2604a1645ce1SZhang, Yanmin 	int i, items = 0;
2605a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2606a1645ce1SZhang, Yanmin 	pid_t pid;
2607a1645ce1SZhang, Yanmin 
2608a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2609a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2610a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2611aeafcbafSArnaldo Carvalho de Melo 		machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
2612a1645ce1SZhang, Yanmin 	}
2613a1645ce1SZhang, Yanmin 
2614a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2615a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2616a1645ce1SZhang, Yanmin 		if (items <= 0)
2617a1645ce1SZhang, Yanmin 			return -ENOENT;
2618a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2619a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2620a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2621a1645ce1SZhang, Yanmin 				continue;
2622a1645ce1SZhang, Yanmin 			}
2623a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2624a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2625a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2626a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2627a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2628a1645ce1SZhang, Yanmin 			if (ret) {
2629a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2630a1645ce1SZhang, Yanmin 				goto failure;
2631a1645ce1SZhang, Yanmin 			}
2632aeafcbafSArnaldo Carvalho de Melo 			machines__create_kernel_maps(machines, pid);
2633a1645ce1SZhang, Yanmin 		}
2634a1645ce1SZhang, Yanmin failure:
2635a1645ce1SZhang, Yanmin 		free(namelist);
2636a1645ce1SZhang, Yanmin 	}
2637a1645ce1SZhang, Yanmin 
2638a1645ce1SZhang, Yanmin 	return ret;
2639a1645ce1SZhang, Yanmin }
26405c0541d5SArnaldo Carvalho de Melo 
2641aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines)
2642076c6e45SArnaldo Carvalho de Melo {
2643aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(machines);
2644076c6e45SArnaldo Carvalho de Melo 
2645076c6e45SArnaldo Carvalho de Melo 	while (next) {
2646076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2647076c6e45SArnaldo Carvalho de Melo 
2648076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2649aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, machines);
2650076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2651076c6e45SArnaldo Carvalho de Melo 	}
2652076c6e45SArnaldo Carvalho de Melo }
2653076c6e45SArnaldo Carvalho de Melo 
2654aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename,
26555c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
26565c0541d5SArnaldo Carvalho de Melo {
2657aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
26585c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
26595c0541d5SArnaldo Carvalho de Melo 
26605c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
26615c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
26625c0541d5SArnaldo Carvalho de Melo 		/*
26635c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
26645c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
26655c0541d5SArnaldo Carvalho de Melo 		 * sections.
26665c0541d5SArnaldo Carvalho de Melo 		 */
2667aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(&machine->kmaps, type);
26685c0541d5SArnaldo Carvalho de Melo 	}
26695c0541d5SArnaldo Carvalho de Melo 
26705c0541d5SArnaldo Carvalho de Melo 	return ret;
26715c0541d5SArnaldo Carvalho de Melo }
26725c0541d5SArnaldo Carvalho de Melo 
2673aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
26745c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
26755c0541d5SArnaldo Carvalho de Melo {
2676aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
26775c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
26785c0541d5SArnaldo Carvalho de Melo 
26795c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
26805c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
26815c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
26825c0541d5SArnaldo Carvalho de Melo 	}
26835c0541d5SArnaldo Carvalho de Melo 
26845c0541d5SArnaldo Carvalho de Melo 	return ret;
26855c0541d5SArnaldo Carvalho de Melo }
2686