xref: /linux/tools/perf/util/symbol.c (revision 1d037ca1648b775277fc96401ec2aa233724906c)
15aab621bSArnaldo Carvalho de Melo #include <dirent.h>
25aab621bSArnaldo Carvalho de Melo #include <errno.h>
35aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
45aab621bSArnaldo Carvalho de Melo #include <stdio.h>
55aab621bSArnaldo Carvalho de Melo #include <string.h>
65aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
85aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
95aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
105aab621bSArnaldo Carvalho de Melo #include <unistd.h>
119486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
12b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
13e334c726SNamhyung Kim #include "util.h"
148a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1586470930SIngo Molnar #include "symbol.h"
165aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1786470930SIngo Molnar 
1886470930SIngo Molnar #include <elf.h>
19f1617b40SArnaldo Carvalho de Melo #include <limits.h>
20439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
212cdbc46dSPeter Zijlstra 
223b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN
23c752d040SRicardo Ribalda Delgado #define KSYM_NAME_LEN 256
243b01a413SArnaldo Carvalho de Melo #endif
253b01a413SArnaldo Carvalho de Melo 
264dff624aSJiri Olsa static void dso_cache__free(struct rb_root *root);
27aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
289de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
29aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
30a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
31cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
32cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
33439d473bSArnaldo Carvalho de Melo 
3475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
35d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
36b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
37b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
383e6a2a7fSStephane Eranian 	.annotate_src	  = true,
39ec5761eaSDavid Ahern 	.symfs            = "",
40b32d133aSArnaldo Carvalho de Melo };
41b32d133aSArnaldo Carvalho de Melo 
4244f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = {
4344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__KALLSYMS,
4444f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KALLSYMS,
4544f24cb3SJiri Olsa 	DSO_BINARY_TYPE__JAVA_JIT,
4644f24cb3SJiri Olsa 	DSO_BINARY_TYPE__DEBUGLINK,
4744f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
4844f24cb3SJiri Olsa 	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
4944f24cb3SJiri Olsa 	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
5044f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
5144f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
5244f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KMODULE,
5344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
5444f24cb3SJiri Olsa 	DSO_BINARY_TYPE__NOT_FOUND,
5544f24cb3SJiri Olsa };
5644f24cb3SJiri Olsa 
57028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
5844f24cb3SJiri Olsa 
59949d160bSJiri Olsa static enum dso_binary_type binary_type_data[] = {
60949d160bSJiri Olsa 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
61949d160bSJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
62949d160bSJiri Olsa 	DSO_BINARY_TYPE__NOT_FOUND,
63949d160bSJiri Olsa };
64949d160bSJiri Olsa 
65028df767SJiri Olsa #define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
66949d160bSJiri Olsa 
67aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso)
688a6c5b26SArnaldo Carvalho de Melo {
691e2dd2f7SDavid Miller 	if (!dso)
701e2dd2f7SDavid Miller 		return strlen("[unknown]");
718a6c5b26SArnaldo Carvalho de Melo 	if (verbose)
72aeafcbafSArnaldo Carvalho de Melo 		return dso->long_name_len;
738a6c5b26SArnaldo Carvalho de Melo 
74aeafcbafSArnaldo Carvalho de Melo 	return dso->short_name_len;
758a6c5b26SArnaldo Carvalho de Melo }
768a6c5b26SArnaldo Carvalho de Melo 
77aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type)
783610583cSArnaldo Carvalho de Melo {
79aeafcbafSArnaldo Carvalho de Melo 	return dso->loaded & (1 << type);
803610583cSArnaldo Carvalho de Melo }
813610583cSArnaldo Carvalho de Melo 
82aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
8379406cd7SArnaldo Carvalho de Melo {
84aeafcbafSArnaldo Carvalho de Melo 	return dso->sorted_by_name & (1 << type);
8579406cd7SArnaldo Carvalho de Melo }
8679406cd7SArnaldo Carvalho de Melo 
87aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
8879406cd7SArnaldo Carvalho de Melo {
89aeafcbafSArnaldo Carvalho de Melo 	dso->sorted_by_name |= (1 << type);
9079406cd7SArnaldo Carvalho de Melo }
9179406cd7SArnaldo Carvalho de Melo 
9236a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
936893d4eeSArnaldo Carvalho de Melo {
9431877908SAnton Blanchard 	symbol_type = toupper(symbol_type);
9531877908SAnton Blanchard 
966893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
976893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
986893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
99f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
10031877908SAnton Blanchard 		return symbol_type == 'D';
1016893d4eeSArnaldo Carvalho de Melo 	default:
1026893d4eeSArnaldo Carvalho de Melo 		return false;
1036893d4eeSArnaldo Carvalho de Melo 	}
1046893d4eeSArnaldo Carvalho de Melo }
1056893d4eeSArnaldo Carvalho de Melo 
106694bf407SAnton Blanchard static int prefix_underscores_count(const char *str)
107694bf407SAnton Blanchard {
108694bf407SAnton Blanchard 	const char *tail = str;
109694bf407SAnton Blanchard 
110694bf407SAnton Blanchard 	while (*tail == '_')
111694bf407SAnton Blanchard 		tail++;
112694bf407SAnton Blanchard 
113694bf407SAnton Blanchard 	return tail - str;
114694bf407SAnton Blanchard }
115694bf407SAnton Blanchard 
116694bf407SAnton Blanchard #define SYMBOL_A 0
117694bf407SAnton Blanchard #define SYMBOL_B 1
118694bf407SAnton Blanchard 
119694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
120694bf407SAnton Blanchard {
121694bf407SAnton Blanchard 	s64 a;
122694bf407SAnton Blanchard 	s64 b;
123694bf407SAnton Blanchard 
124694bf407SAnton Blanchard 	/* Prefer a symbol with non zero length */
125694bf407SAnton Blanchard 	a = syma->end - syma->start;
126694bf407SAnton Blanchard 	b = symb->end - symb->start;
127694bf407SAnton Blanchard 	if ((b == 0) && (a > 0))
128694bf407SAnton Blanchard 		return SYMBOL_A;
129694bf407SAnton Blanchard 	else if ((a == 0) && (b > 0))
130694bf407SAnton Blanchard 		return SYMBOL_B;
131694bf407SAnton Blanchard 
132694bf407SAnton Blanchard 	/* Prefer a non weak symbol over a weak one */
133694bf407SAnton Blanchard 	a = syma->binding == STB_WEAK;
134694bf407SAnton Blanchard 	b = symb->binding == STB_WEAK;
135694bf407SAnton Blanchard 	if (b && !a)
136694bf407SAnton Blanchard 		return SYMBOL_A;
137694bf407SAnton Blanchard 	if (a && !b)
138694bf407SAnton Blanchard 		return SYMBOL_B;
139694bf407SAnton Blanchard 
140694bf407SAnton Blanchard 	/* Prefer a global symbol over a non global one */
141694bf407SAnton Blanchard 	a = syma->binding == STB_GLOBAL;
142694bf407SAnton Blanchard 	b = symb->binding == STB_GLOBAL;
143694bf407SAnton Blanchard 	if (a && !b)
144694bf407SAnton Blanchard 		return SYMBOL_A;
145694bf407SAnton Blanchard 	if (b && !a)
146694bf407SAnton Blanchard 		return SYMBOL_B;
147694bf407SAnton Blanchard 
148694bf407SAnton Blanchard 	/* Prefer a symbol with less underscores */
149694bf407SAnton Blanchard 	a = prefix_underscores_count(syma->name);
150694bf407SAnton Blanchard 	b = prefix_underscores_count(symb->name);
151694bf407SAnton Blanchard 	if (b > a)
152694bf407SAnton Blanchard 		return SYMBOL_A;
153694bf407SAnton Blanchard 	else if (a > b)
154694bf407SAnton Blanchard 		return SYMBOL_B;
155694bf407SAnton Blanchard 
156694bf407SAnton Blanchard 	/* If all else fails, choose the symbol with the longest name */
157694bf407SAnton Blanchard 	if (strlen(syma->name) >= strlen(symb->name))
158694bf407SAnton Blanchard 		return SYMBOL_A;
159694bf407SAnton Blanchard 	else
160694bf407SAnton Blanchard 		return SYMBOL_B;
161694bf407SAnton Blanchard }
162694bf407SAnton Blanchard 
163e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols)
164694bf407SAnton Blanchard {
165694bf407SAnton Blanchard 	struct rb_node *nd;
166694bf407SAnton Blanchard 	struct symbol *curr, *next;
167694bf407SAnton Blanchard 
168694bf407SAnton Blanchard 	nd = rb_first(symbols);
169694bf407SAnton Blanchard 
170694bf407SAnton Blanchard 	while (nd) {
171694bf407SAnton Blanchard 		curr = rb_entry(nd, struct symbol, rb_node);
172694bf407SAnton Blanchard again:
173694bf407SAnton Blanchard 		nd = rb_next(&curr->rb_node);
174694bf407SAnton Blanchard 		next = rb_entry(nd, struct symbol, rb_node);
175694bf407SAnton Blanchard 
176694bf407SAnton Blanchard 		if (!nd)
177694bf407SAnton Blanchard 			break;
178694bf407SAnton Blanchard 
179694bf407SAnton Blanchard 		if (curr->start != next->start)
180694bf407SAnton Blanchard 			continue;
181694bf407SAnton Blanchard 
182694bf407SAnton Blanchard 		if (choose_best_symbol(curr, next) == SYMBOL_A) {
183694bf407SAnton Blanchard 			rb_erase(&next->rb_node, symbols);
184694bf407SAnton Blanchard 			goto again;
185694bf407SAnton Blanchard 		} else {
186694bf407SAnton Blanchard 			nd = rb_next(&curr->rb_node);
187694bf407SAnton Blanchard 			rb_erase(&curr->rb_node, symbols);
188694bf407SAnton Blanchard 		}
189694bf407SAnton Blanchard 	}
190694bf407SAnton Blanchard }
191694bf407SAnton Blanchard 
192e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols)
193af427bf5SArnaldo Carvalho de Melo {
194aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(symbols);
1952e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
196af427bf5SArnaldo Carvalho de Melo 
197af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
198af427bf5SArnaldo Carvalho de Melo 		return;
199af427bf5SArnaldo Carvalho de Melo 
2002e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
2012e538c4aSArnaldo Carvalho de Melo 
202af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
2032e538c4aSArnaldo Carvalho de Melo 		prev = curr;
2042e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
205af427bf5SArnaldo Carvalho de Melo 
2063b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
207af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
208af427bf5SArnaldo Carvalho de Melo 	}
209af427bf5SArnaldo Carvalho de Melo 
2102e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
2112e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
2122e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
2132e538c4aSArnaldo Carvalho de Melo }
2142e538c4aSArnaldo Carvalho de Melo 
215e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
216af427bf5SArnaldo Carvalho de Melo {
217af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
218aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
219af427bf5SArnaldo Carvalho de Melo 
220af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
221af427bf5SArnaldo Carvalho de Melo 		return;
222af427bf5SArnaldo Carvalho de Melo 
223af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
224af427bf5SArnaldo Carvalho de Melo 
225af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
226af427bf5SArnaldo Carvalho de Melo 		prev = curr;
227af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
228af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
2292e538c4aSArnaldo Carvalho de Melo 	}
23090c83218SArnaldo Carvalho de Melo 
23190c83218SArnaldo Carvalho de Melo 	/*
23290c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
23390c83218SArnaldo Carvalho de Melo 	 * last map final address.
23490c83218SArnaldo Carvalho de Melo 	 */
2359d1faba5SIan Munsie 	curr->end = ~0ULL;
236af427bf5SArnaldo Carvalho de Melo }
237af427bf5SArnaldo Carvalho de Melo 
238aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg)
23923ea4a3fSArnaldo Carvalho de Melo {
24023ea4a3fSArnaldo Carvalho de Melo 	int i;
24123ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
242aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(mg, i);
24323ea4a3fSArnaldo Carvalho de Melo }
24423ea4a3fSArnaldo Carvalho de Melo 
245e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
24686470930SIngo Molnar {
24786470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
248aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
249aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
250aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
25186470930SIngo Molnar 		return NULL;
25286470930SIngo Molnar 
25375be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
254aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
25536479484SArnaldo Carvalho de Melo 
256aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
257aeafcbafSArnaldo Carvalho de Melo 	sym->end     = len ? start + len - 1 : start;
258aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
259aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
260e4204992SArnaldo Carvalho de Melo 
261aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
262aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
263aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
264e4204992SArnaldo Carvalho de Melo 
265aeafcbafSArnaldo Carvalho de Melo 	return sym;
26686470930SIngo Molnar }
26786470930SIngo Molnar 
268aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
26986470930SIngo Molnar {
270aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
27186470930SIngo Molnar }
27286470930SIngo Molnar 
273aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
27486470930SIngo Molnar {
2759486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
276aeafcbafSArnaldo Carvalho de Melo 		       sym->start, sym->end,
277aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_GLOBAL ? 'g' :
278aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_LOCAL  ? 'l' : 'w',
279aeafcbafSArnaldo Carvalho de Melo 		       sym->name);
28086470930SIngo Molnar }
28186470930SIngo Molnar 
282a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym,
283a978f2abSAkihiro Nagai 				    const struct addr_location *al, FILE *fp)
284a978f2abSAkihiro Nagai {
285a978f2abSAkihiro Nagai 	unsigned long offset;
286a978f2abSAkihiro Nagai 	size_t length;
287a978f2abSAkihiro Nagai 
288a978f2abSAkihiro Nagai 	if (sym && sym->name) {
289a978f2abSAkihiro Nagai 		length = fprintf(fp, "%s", sym->name);
290a978f2abSAkihiro Nagai 		if (al) {
291a978f2abSAkihiro Nagai 			offset = al->addr - sym->start;
292a978f2abSAkihiro Nagai 			length += fprintf(fp, "+0x%lx", offset);
293a978f2abSAkihiro Nagai 		}
294a978f2abSAkihiro Nagai 		return length;
295a978f2abSAkihiro Nagai 	} else
296a978f2abSAkihiro Nagai 		return fprintf(fp, "[unknown]");
297a978f2abSAkihiro Nagai }
298a978f2abSAkihiro Nagai 
299547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
300547a92e0SAkihiro Nagai {
301a978f2abSAkihiro Nagai 	return symbol__fprintf_symname_offs(sym, NULL, fp);
302547a92e0SAkihiro Nagai }
303547a92e0SAkihiro Nagai 
304aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name)
305cfc10d3bSArnaldo Carvalho de Melo {
306ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
307ef6ae724SArnaldo Carvalho de Melo 		return;
308aeafcbafSArnaldo Carvalho de Melo 	dso->long_name = name;
309aeafcbafSArnaldo Carvalho de Melo 	dso->long_name_len = strlen(name);
310cfc10d3bSArnaldo Carvalho de Melo }
311cfc10d3bSArnaldo Carvalho de Melo 
312aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name)
313b63be8d7SArnaldo Carvalho de Melo {
314b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
315b63be8d7SArnaldo Carvalho de Melo 		return;
316aeafcbafSArnaldo Carvalho de Melo 	dso->short_name = name;
317aeafcbafSArnaldo Carvalho de Melo 	dso->short_name_len = strlen(name);
318b63be8d7SArnaldo Carvalho de Melo }
319b63be8d7SArnaldo Carvalho de Melo 
320aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso)
321cfc10d3bSArnaldo Carvalho de Melo {
322aeafcbafSArnaldo Carvalho de Melo 	dso__set_short_name(dso, basename(dso->long_name));
323cfc10d3bSArnaldo Carvalho de Melo }
324cfc10d3bSArnaldo Carvalho de Melo 
32500a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
32686470930SIngo Molnar {
327aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
32886470930SIngo Molnar 
329aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
3306a4694a4SArnaldo Carvalho de Melo 		int i;
331aeafcbafSArnaldo Carvalho de Melo 		strcpy(dso->name, name);
332aeafcbafSArnaldo Carvalho de Melo 		dso__set_long_name(dso, dso->name);
333aeafcbafSArnaldo Carvalho de Melo 		dso__set_short_name(dso, dso->name);
3346a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
335aeafcbafSArnaldo Carvalho de Melo 			dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
3364dff624aSJiri Olsa 		dso->cache = RB_ROOT;
33744f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
338949d160bSJiri Olsa 		dso->data_type   = DSO_BINARY_TYPE__NOT_FOUND;
339aeafcbafSArnaldo Carvalho de Melo 		dso->loaded = 0;
340aeafcbafSArnaldo Carvalho de Melo 		dso->sorted_by_name = 0;
341aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = 0;
342aeafcbafSArnaldo Carvalho de Melo 		dso->kernel = DSO_TYPE_USER;
3438db4841fSJiri Olsa 		dso->needs_swap = DSO_SWAP__UNSET;
344aeafcbafSArnaldo Carvalho de Melo 		INIT_LIST_HEAD(&dso->node);
34586470930SIngo Molnar 	}
34686470930SIngo Molnar 
347aeafcbafSArnaldo Carvalho de Melo 	return dso;
34886470930SIngo Molnar }
34986470930SIngo Molnar 
350aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols)
35186470930SIngo Molnar {
35286470930SIngo Molnar 	struct symbol *pos;
353aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
35486470930SIngo Molnar 
35586470930SIngo Molnar 	while (next) {
35686470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
35786470930SIngo Molnar 		next = rb_next(&pos->rb_node);
358aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
35900a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
36086470930SIngo Molnar 	}
36186470930SIngo Molnar }
36286470930SIngo Molnar 
363aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso)
36486470930SIngo Molnar {
3656a4694a4SArnaldo Carvalho de Melo 	int i;
3666a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
367aeafcbafSArnaldo Carvalho de Melo 		symbols__delete(&dso->symbols[i]);
368aeafcbafSArnaldo Carvalho de Melo 	if (dso->sname_alloc)
369aeafcbafSArnaldo Carvalho de Melo 		free((char *)dso->short_name);
370aeafcbafSArnaldo Carvalho de Melo 	if (dso->lname_alloc)
371aeafcbafSArnaldo Carvalho de Melo 		free(dso->long_name);
3724dff624aSJiri Olsa 	dso_cache__free(&dso->cache);
373aeafcbafSArnaldo Carvalho de Melo 	free(dso);
37486470930SIngo Molnar }
37586470930SIngo Molnar 
376aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id)
3778d06367fSArnaldo Carvalho de Melo {
378aeafcbafSArnaldo Carvalho de Melo 	memcpy(dso->build_id, build_id, sizeof(dso->build_id));
379aeafcbafSArnaldo Carvalho de Melo 	dso->has_build_id = 1;
3808d06367fSArnaldo Carvalho de Melo }
3818d06367fSArnaldo Carvalho de Melo 
382e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym)
38386470930SIngo Molnar {
384aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
38586470930SIngo Molnar 	struct rb_node *parent = NULL;
3869cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
38786470930SIngo Molnar 	struct symbol *s;
38886470930SIngo Molnar 
38986470930SIngo Molnar 	while (*p != NULL) {
39086470930SIngo Molnar 		parent = *p;
39186470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
39286470930SIngo Molnar 		if (ip < s->start)
39386470930SIngo Molnar 			p = &(*p)->rb_left;
39486470930SIngo Molnar 		else
39586470930SIngo Molnar 			p = &(*p)->rb_right;
39686470930SIngo Molnar 	}
39786470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
398aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
39986470930SIngo Molnar }
40086470930SIngo Molnar 
401aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
40286470930SIngo Molnar {
40386470930SIngo Molnar 	struct rb_node *n;
40486470930SIngo Molnar 
405aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
40686470930SIngo Molnar 		return NULL;
40786470930SIngo Molnar 
408aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
40986470930SIngo Molnar 
41086470930SIngo Molnar 	while (n) {
41186470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
41286470930SIngo Molnar 
41386470930SIngo Molnar 		if (ip < s->start)
41486470930SIngo Molnar 			n = n->rb_left;
41586470930SIngo Molnar 		else if (ip > s->end)
41686470930SIngo Molnar 			n = n->rb_right;
41786470930SIngo Molnar 		else
41886470930SIngo Molnar 			return s;
41986470930SIngo Molnar 	}
42086470930SIngo Molnar 
42186470930SIngo Molnar 	return NULL;
42286470930SIngo Molnar }
42386470930SIngo Molnar 
42479406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
42579406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
42679406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
42779406cd7SArnaldo Carvalho de Melo };
42879406cd7SArnaldo Carvalho de Melo 
429aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
43079406cd7SArnaldo Carvalho de Melo {
431aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
43279406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
43302a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
43402a9d037SRabin Vincent 
43502a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
43679406cd7SArnaldo Carvalho de Melo 
43779406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
43879406cd7SArnaldo Carvalho de Melo 		parent = *p;
43979406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
44079406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
44179406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
44279406cd7SArnaldo Carvalho de Melo 		else
44379406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
44479406cd7SArnaldo Carvalho de Melo 	}
44579406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
446aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
44779406cd7SArnaldo Carvalho de Melo }
44879406cd7SArnaldo Carvalho de Melo 
449aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
450aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
45179406cd7SArnaldo Carvalho de Melo {
45279406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
45379406cd7SArnaldo Carvalho de Melo 
45479406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
45579406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
456aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
45779406cd7SArnaldo Carvalho de Melo 	}
45879406cd7SArnaldo Carvalho de Melo }
45979406cd7SArnaldo Carvalho de Melo 
460aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
461aeafcbafSArnaldo Carvalho de Melo 					    const char *name)
46279406cd7SArnaldo Carvalho de Melo {
46379406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
46479406cd7SArnaldo Carvalho de Melo 
465aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
46679406cd7SArnaldo Carvalho de Melo 		return NULL;
46779406cd7SArnaldo Carvalho de Melo 
468aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
46979406cd7SArnaldo Carvalho de Melo 
47079406cd7SArnaldo Carvalho de Melo 	while (n) {
47179406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
47279406cd7SArnaldo Carvalho de Melo 		int cmp;
47379406cd7SArnaldo Carvalho de Melo 
47479406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
47579406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
47679406cd7SArnaldo Carvalho de Melo 
47779406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
47879406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
47979406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
48079406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
48179406cd7SArnaldo Carvalho de Melo 		else
48279406cd7SArnaldo Carvalho de Melo 			return &s->sym;
48379406cd7SArnaldo Carvalho de Melo 	}
48479406cd7SArnaldo Carvalho de Melo 
48579406cd7SArnaldo Carvalho de Melo 	return NULL;
48679406cd7SArnaldo Carvalho de Melo }
48779406cd7SArnaldo Carvalho de Melo 
488aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
48979406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
490fcf1203aSArnaldo Carvalho de Melo {
491aeafcbafSArnaldo Carvalho de Melo 	return symbols__find(&dso->symbols[type], addr);
492fcf1203aSArnaldo Carvalho de Melo }
493fcf1203aSArnaldo Carvalho de Melo 
494aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
49579406cd7SArnaldo Carvalho de Melo 					const char *name)
49679406cd7SArnaldo Carvalho de Melo {
497aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
49879406cd7SArnaldo Carvalho de Melo }
49979406cd7SArnaldo Carvalho de Melo 
500aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
50179406cd7SArnaldo Carvalho de Melo {
502aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
503aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
504aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
50579406cd7SArnaldo Carvalho de Melo }
50679406cd7SArnaldo Carvalho de Melo 
507aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf)
5088d06367fSArnaldo Carvalho de Melo {
5098d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
510aeafcbafSArnaldo Carvalho de Melo 	const u8 *raw = build_id;
5118d06367fSArnaldo Carvalho de Melo 	int i;
5128d06367fSArnaldo Carvalho de Melo 
5138d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
5148d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
5158d06367fSArnaldo Carvalho de Melo 		++raw;
5168d06367fSArnaldo Carvalho de Melo 		bid += 2;
5178d06367fSArnaldo Carvalho de Melo 	}
5188d06367fSArnaldo Carvalho de Melo 
519aeafcbafSArnaldo Carvalho de Melo 	return raw - build_id;
5208d06367fSArnaldo Carvalho de Melo }
5218d06367fSArnaldo Carvalho de Melo 
522aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
52386470930SIngo Molnar {
5248d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
5258d06367fSArnaldo Carvalho de Melo 
526aeafcbafSArnaldo Carvalho de Melo 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
5279e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
5289e03eb2dSArnaldo Carvalho de Melo }
5299e03eb2dSArnaldo Carvalho de Melo 
530aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso,
531aeafcbafSArnaldo Carvalho de Melo 				    enum map_type type, FILE *fp)
53290f18e63SSrikar Dronamraju {
53390f18e63SSrikar Dronamraju 	size_t ret = 0;
53490f18e63SSrikar Dronamraju 	struct rb_node *nd;
53590f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
53690f18e63SSrikar Dronamraju 
537aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
53890f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
53990f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
54090f18e63SSrikar Dronamraju 	}
54190f18e63SSrikar Dronamraju 
54290f18e63SSrikar Dronamraju 	return ret;
54390f18e63SSrikar Dronamraju }
54490f18e63SSrikar Dronamraju 
545aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
5469e03eb2dSArnaldo Carvalho de Melo {
5479e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
548aeafcbafSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
5499e03eb2dSArnaldo Carvalho de Melo 
550aeafcbafSArnaldo Carvalho de Melo 	if (dso->short_name != dso->long_name)
551aeafcbafSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", dso->long_name);
5523846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
553aeafcbafSArnaldo Carvalho de Melo 		       dso->loaded ? "" : "NOT ");
554aeafcbafSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(dso, fp);
5556a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
556aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
55786470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
55886470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
55986470930SIngo Molnar 	}
56086470930SIngo Molnar 
56186470930SIngo Molnar 	return ret;
56286470930SIngo Molnar }
56386470930SIngo Molnar 
5649e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
5659e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
56682151520SCody P Schafer 					  char type, u64 start))
56786470930SIngo Molnar {
56886470930SIngo Molnar 	char *line = NULL;
56986470930SIngo Molnar 	size_t n;
5703b01a413SArnaldo Carvalho de Melo 	int err = -1;
5719e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
57286470930SIngo Molnar 
57386470930SIngo Molnar 	if (file == NULL)
57486470930SIngo Molnar 		goto out_failure;
57586470930SIngo Molnar 
5763b01a413SArnaldo Carvalho de Melo 	err = 0;
5773b01a413SArnaldo Carvalho de Melo 
57886470930SIngo Molnar 	while (!feof(file)) {
5799cffa8d5SPaul Mackerras 		u64 start;
58086470930SIngo Molnar 		int line_len, len;
58186470930SIngo Molnar 		char symbol_type;
5822e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
58386470930SIngo Molnar 
58486470930SIngo Molnar 		line_len = getline(&line, &n, file);
585a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
58686470930SIngo Molnar 			break;
58786470930SIngo Molnar 
58886470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
58986470930SIngo Molnar 
59086470930SIngo Molnar 		len = hex2u64(line, &start);
59186470930SIngo Molnar 
59286470930SIngo Molnar 		len++;
59386470930SIngo Molnar 		if (len + 2 >= line_len)
59486470930SIngo Molnar 			continue;
59586470930SIngo Molnar 
59631877908SAnton Blanchard 		symbol_type = line[len];
5973b01a413SArnaldo Carvalho de Melo 		len += 2;
5983b01a413SArnaldo Carvalho de Melo 		symbol_name = line + len;
5993b01a413SArnaldo Carvalho de Melo 		len = line_len - len;
600682b335aSArnaldo Carvalho de Melo 
6013b01a413SArnaldo Carvalho de Melo 		if (len >= KSYM_NAME_LEN) {
6023b01a413SArnaldo Carvalho de Melo 			err = -1;
6033b01a413SArnaldo Carvalho de Melo 			break;
6043b01a413SArnaldo Carvalho de Melo 		}
6053b01a413SArnaldo Carvalho de Melo 
6063f5a4272SAnton Blanchard 		err = process_symbol(arg, symbol_name,
60782151520SCody P Schafer 				     symbol_type, start);
608682b335aSArnaldo Carvalho de Melo 		if (err)
609682b335aSArnaldo Carvalho de Melo 			break;
610682b335aSArnaldo Carvalho de Melo 	}
611682b335aSArnaldo Carvalho de Melo 
612682b335aSArnaldo Carvalho de Melo 	free(line);
613682b335aSArnaldo Carvalho de Melo 	fclose(file);
614682b335aSArnaldo Carvalho de Melo 	return err;
615682b335aSArnaldo Carvalho de Melo 
616682b335aSArnaldo Carvalho de Melo out_failure:
617682b335aSArnaldo Carvalho de Melo 	return -1;
618682b335aSArnaldo Carvalho de Melo }
619682b335aSArnaldo Carvalho de Melo 
620682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
621682b335aSArnaldo Carvalho de Melo 	struct map *map;
622682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
623682b335aSArnaldo Carvalho de Melo };
624682b335aSArnaldo Carvalho de Melo 
625c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
626c408fedfSArnaldo Carvalho de Melo {
627c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
628c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
629c408fedfSArnaldo Carvalho de Melo 
630c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
631c408fedfSArnaldo Carvalho de Melo }
632c408fedfSArnaldo Carvalho de Melo 
633682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
63482151520SCody P Schafer 				       char type, u64 start)
635682b335aSArnaldo Carvalho de Melo {
636682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
637682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
638682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
639682b335aSArnaldo Carvalho de Melo 
640682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
641682b335aSArnaldo Carvalho de Melo 		return 0;
642682b335aSArnaldo Carvalho de Melo 
64382151520SCody P Schafer 	/*
64482151520SCody P Schafer 	 * module symbols are not sorted so we add all
64582151520SCody P Schafer 	 * symbols, setting length to 0, and rely on
64682151520SCody P Schafer 	 * symbols__fixup_end() to fix it up.
64782151520SCody P Schafer 	 */
64882151520SCody P Schafer 	sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
6492e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
650682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
65182164161SArnaldo Carvalho de Melo 	/*
65282164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6534e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
65482164161SArnaldo Carvalho de Melo 	 */
6554e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
656a1645ce1SZhang, Yanmin 
657682b335aSArnaldo Carvalho de Melo 	return 0;
6582e538c4aSArnaldo Carvalho de Melo }
6592e538c4aSArnaldo Carvalho de Melo 
660682b335aSArnaldo Carvalho de Melo /*
661682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
662682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
663682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
664682b335aSArnaldo Carvalho de Melo  */
665aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6669e201442SArnaldo Carvalho de Melo 				  struct map *map)
667682b335aSArnaldo Carvalho de Melo {
668aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6699e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6702e538c4aSArnaldo Carvalho de Melo }
6712e538c4aSArnaldo Carvalho de Melo 
6722e538c4aSArnaldo Carvalho de Melo /*
6732e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
6742e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
6752e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
6762e538c4aSArnaldo Carvalho de Melo  */
677aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map,
6789de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
6792e538c4aSArnaldo Carvalho de Melo {
6809de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
68123346f21SArnaldo Carvalho de Melo 	struct machine *machine = kmaps->machine;
6824e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
6832e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
6848a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
685aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
6864e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
6872e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
6882e538c4aSArnaldo Carvalho de Melo 
6892e538c4aSArnaldo Carvalho de Melo 	while (next) {
6902e538c4aSArnaldo Carvalho de Melo 		char *module;
6912e538c4aSArnaldo Carvalho de Melo 
6922e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
6932e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
6942e538c4aSArnaldo Carvalho de Melo 
6952e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
6962e538c4aSArnaldo Carvalho de Melo 		if (module) {
69775be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
6981de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
6991de8e245SArnaldo Carvalho de Melo 
7002e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
7012e538c4aSArnaldo Carvalho de Melo 
702b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
703a1645ce1SZhang, Yanmin 				if (curr_map != map &&
704aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
70523346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
706a1645ce1SZhang, Yanmin 					/*
707a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
708a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
709a1645ce1SZhang, Yanmin 					 * points to a module and all its
710a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
711a1645ce1SZhang, Yanmin 					 * loaded.
712a1645ce1SZhang, Yanmin 					 */
713a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
714a1645ce1SZhang, Yanmin 							curr_map->type);
715af427bf5SArnaldo Carvalho de Melo 				}
716b7cece76SArnaldo Carvalho de Melo 
717a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
718a1645ce1SZhang, Yanmin 							map->type, module);
719a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7202f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
721a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
722a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
72323346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
724a1645ce1SZhang, Yanmin 					curr_map = map;
725a1645ce1SZhang, Yanmin 					goto discard_symbol;
726a1645ce1SZhang, Yanmin 				}
727a1645ce1SZhang, Yanmin 
728a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
72923346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
730b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
731af427bf5SArnaldo Carvalho de Melo 			}
73286470930SIngo Molnar 			/*
7332e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
7342e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
73586470930SIngo Molnar 			 */
7364e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
7374e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
7384e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
7392e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
740aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
74186470930SIngo Molnar 
7428a953312SArnaldo Carvalho de Melo 			if (count == 0) {
7438a953312SArnaldo Carvalho de Melo 				curr_map = map;
7448a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
7458a953312SArnaldo Carvalho de Melo 			}
7468a953312SArnaldo Carvalho de Melo 
747aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
748a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
749a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
750a1645ce1SZhang, Yanmin 					kernel_range++);
751a1645ce1SZhang, Yanmin 			else
752a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
753a1645ce1SZhang, Yanmin 					"[kernel].%d",
7542e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
75586470930SIngo Molnar 
756aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
757aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
7582e538c4aSArnaldo Carvalho de Melo 				return -1;
7592e538c4aSArnaldo Carvalho de Melo 
760aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
761a1645ce1SZhang, Yanmin 
762aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
76337fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
764aeafcbafSArnaldo Carvalho de Melo 				dso__delete(ndso);
7652e538c4aSArnaldo Carvalho de Melo 				return -1;
7662e538c4aSArnaldo Carvalho de Melo 			}
7672e538c4aSArnaldo Carvalho de Melo 
7684e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
7699de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
7702e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
7712e538c4aSArnaldo Carvalho de Melo 		}
7728a953312SArnaldo Carvalho de Melo filter_symbol:
7734e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
7741de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
77500a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
7762e538c4aSArnaldo Carvalho de Melo 		} else {
7774e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
7784e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
7794e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
7808a953312SArnaldo Carvalho de Melo 				++moved;
7818a953312SArnaldo Carvalho de Melo 			} else
7828a953312SArnaldo Carvalho de Melo 				++count;
7839974f496SMike Galbraith 		}
78486470930SIngo Molnar 	}
78586470930SIngo Molnar 
786a1645ce1SZhang, Yanmin 	if (curr_map != map &&
787aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
78823346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
789a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
790a1645ce1SZhang, Yanmin 	}
791a1645ce1SZhang, Yanmin 
7928a953312SArnaldo Carvalho de Melo 	return count + moved;
79386470930SIngo Molnar }
79486470930SIngo Molnar 
795ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename,
796ec80fde7SArnaldo Carvalho de Melo 					const char *restricted_filename)
797ec80fde7SArnaldo Carvalho de Melo {
798ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
799ec80fde7SArnaldo Carvalho de Melo 
800ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
801ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
802ec80fde7SArnaldo Carvalho de Melo 
803ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
804ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
805ec80fde7SArnaldo Carvalho de Melo 			free(r);
806ec80fde7SArnaldo Carvalho de Melo 			return restricted;
807ec80fde7SArnaldo Carvalho de Melo 		}
808ec80fde7SArnaldo Carvalho de Melo 	}
809ec80fde7SArnaldo Carvalho de Melo 
810ec80fde7SArnaldo Carvalho de Melo 	return restricted;
811ec80fde7SArnaldo Carvalho de Melo }
812ec80fde7SArnaldo Carvalho de Melo 
813aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
8149de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
8152e538c4aSArnaldo Carvalho de Melo {
816ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
817ec80fde7SArnaldo Carvalho de Melo 		return -1;
818ec80fde7SArnaldo Carvalho de Melo 
819aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
8202e538c4aSArnaldo Carvalho de Melo 		return -1;
8212e538c4aSArnaldo Carvalho de Melo 
822694bf407SAnton Blanchard 	symbols__fixup_duplicate(&dso->symbols[map->type]);
8233f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
8243f5a4272SAnton Blanchard 
825aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
82644f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
827a1645ce1SZhang, Yanmin 	else
82844f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
8292e538c4aSArnaldo Carvalho de Melo 
830aeafcbafSArnaldo Carvalho de Melo 	return dso__split_kallsyms(dso, map, filter);
831af427bf5SArnaldo Carvalho de Melo }
832af427bf5SArnaldo Carvalho de Melo 
833aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
8346beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
83580d496beSPekka Enberg {
83680d496beSPekka Enberg 	char *line = NULL;
83780d496beSPekka Enberg 	size_t n;
83880d496beSPekka Enberg 	FILE *file;
83980d496beSPekka Enberg 	int nr_syms = 0;
84080d496beSPekka Enberg 
841aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
84280d496beSPekka Enberg 	if (file == NULL)
84380d496beSPekka Enberg 		goto out_failure;
84480d496beSPekka Enberg 
84580d496beSPekka Enberg 	while (!feof(file)) {
8469cffa8d5SPaul Mackerras 		u64 start, size;
84780d496beSPekka Enberg 		struct symbol *sym;
84880d496beSPekka Enberg 		int line_len, len;
84980d496beSPekka Enberg 
85080d496beSPekka Enberg 		line_len = getline(&line, &n, file);
85180d496beSPekka Enberg 		if (line_len < 0)
85280d496beSPekka Enberg 			break;
85380d496beSPekka Enberg 
85480d496beSPekka Enberg 		if (!line)
85580d496beSPekka Enberg 			goto out_failure;
85680d496beSPekka Enberg 
85780d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
85880d496beSPekka Enberg 
85980d496beSPekka Enberg 		len = hex2u64(line, &start);
86080d496beSPekka Enberg 
86180d496beSPekka Enberg 		len++;
86280d496beSPekka Enberg 		if (len + 2 >= line_len)
86380d496beSPekka Enberg 			continue;
86480d496beSPekka Enberg 
86580d496beSPekka Enberg 		len += hex2u64(line + len, &size);
86680d496beSPekka Enberg 
86780d496beSPekka Enberg 		len++;
86880d496beSPekka Enberg 		if (len + 2 >= line_len)
86980d496beSPekka Enberg 			continue;
87080d496beSPekka Enberg 
871c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
87280d496beSPekka Enberg 
87380d496beSPekka Enberg 		if (sym == NULL)
87480d496beSPekka Enberg 			goto out_delete_line;
87580d496beSPekka Enberg 
876439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
87700a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
87880d496beSPekka Enberg 		else {
879aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
88080d496beSPekka Enberg 			nr_syms++;
88180d496beSPekka Enberg 		}
88280d496beSPekka Enberg 	}
88380d496beSPekka Enberg 
88480d496beSPekka Enberg 	free(line);
88580d496beSPekka Enberg 	fclose(file);
88680d496beSPekka Enberg 
88780d496beSPekka Enberg 	return nr_syms;
88880d496beSPekka Enberg 
88980d496beSPekka Enberg out_delete_line:
89080d496beSPekka Enberg 	free(line);
89180d496beSPekka Enberg out_failure:
89280d496beSPekka Enberg 	return -1;
89380d496beSPekka Enberg }
89480d496beSPekka Enberg 
895e5a1845fSNamhyung Kim bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
89678075caaSArnaldo Carvalho de Melo {
897aeafcbafSArnaldo Carvalho de Melo 	return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
89878075caaSArnaldo Carvalho de Melo }
89978075caaSArnaldo Carvalho de Melo 
900a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
90157f395a7SFrederic Weisbecker {
902e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
90357f395a7SFrederic Weisbecker 	struct dso *pos;
90457f395a7SFrederic Weisbecker 
9056122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
9066122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
9076122e4e4SArnaldo Carvalho de Melo 			continue;
908f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
909f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
910f6e1467dSArnaldo Carvalho de Melo 			continue;
911f6e1467dSArnaldo Carvalho de Melo 		}
912e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
913e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
914e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
915e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
91657f395a7SFrederic Weisbecker 		}
9176122e4e4SArnaldo Carvalho de Melo 	}
91857f395a7SFrederic Weisbecker 
919e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
92057f395a7SFrederic Weisbecker }
92157f395a7SFrederic Weisbecker 
922aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso)
92394cb9e38SArnaldo Carvalho de Melo {
92494cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
92544f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__KALLSYMS]		= 'k',
92621ea4539SCody P Schafer 		[DSO_BINARY_TYPE__VMLINUX]		= 'v',
92744f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__JAVA_JIT]		= 'j',
92844f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__DEBUGLINK]		= 'l',
92944f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__BUILD_ID_CACHE]	= 'B',
93044f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__FEDORA_DEBUGINFO]	= 'f',
93144f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__UBUNTU_DEBUGINFO]	= 'u',
93244f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__BUILDID_DEBUGINFO]	= 'b',
93344f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__SYSTEM_PATH_DSO]	= 'd',
93444f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]	= 'K',
93544f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__GUEST_KALLSYMS]	= 'g',
93644f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__GUEST_KMODULE]	= 'G',
93721ea4539SCody P Schafer 		[DSO_BINARY_TYPE__GUEST_VMLINUX]	= 'V',
93894cb9e38SArnaldo Carvalho de Melo 	};
93994cb9e38SArnaldo Carvalho de Melo 
94044f24cb3SJiri Olsa 	if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
94194cb9e38SArnaldo Carvalho de Melo 		return '!';
942aeafcbafSArnaldo Carvalho de Melo 	return origin[dso->symtab_type];
94394cb9e38SArnaldo Carvalho de Melo }
94494cb9e38SArnaldo Carvalho de Melo 
94544f24cb3SJiri Olsa int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
94644f24cb3SJiri Olsa 			  char *root_dir, char *file, size_t size)
94744f24cb3SJiri Olsa {
94844f24cb3SJiri Olsa 	char build_id_hex[BUILD_ID_SIZE * 2 + 1];
94944f24cb3SJiri Olsa 	int ret = 0;
95044f24cb3SJiri Olsa 
95144f24cb3SJiri Olsa 	switch (type) {
95244f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__DEBUGLINK: {
95344f24cb3SJiri Olsa 		char *debuglink;
95444f24cb3SJiri Olsa 
95544f24cb3SJiri Olsa 		strncpy(file, dso->long_name, size);
95644f24cb3SJiri Olsa 		debuglink = file + dso->long_name_len;
95744f24cb3SJiri Olsa 		while (debuglink != file && *debuglink != '/')
95844f24cb3SJiri Olsa 			debuglink--;
95944f24cb3SJiri Olsa 		if (*debuglink == '/')
96044f24cb3SJiri Olsa 			debuglink++;
96144f24cb3SJiri Olsa 		filename__read_debuglink(dso->long_name, debuglink,
96244f24cb3SJiri Olsa 					 size - (debuglink - file));
96344f24cb3SJiri Olsa 		}
96444f24cb3SJiri Olsa 		break;
96544f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
96644f24cb3SJiri Olsa 		/* skip the locally configured cache if a symfs is given */
96744f24cb3SJiri Olsa 		if (symbol_conf.symfs[0] ||
96844f24cb3SJiri Olsa 		    (dso__build_id_filename(dso, file, size) == NULL))
96944f24cb3SJiri Olsa 			ret = -1;
97044f24cb3SJiri Olsa 		break;
97144f24cb3SJiri Olsa 
97244f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
97344f24cb3SJiri Olsa 		snprintf(file, size, "%s/usr/lib/debug%s.debug",
97444f24cb3SJiri Olsa 			 symbol_conf.symfs, dso->long_name);
97544f24cb3SJiri Olsa 		break;
97644f24cb3SJiri Olsa 
97744f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
97844f24cb3SJiri Olsa 		snprintf(file, size, "%s/usr/lib/debug%s",
97944f24cb3SJiri Olsa 			 symbol_conf.symfs, dso->long_name);
98044f24cb3SJiri Olsa 		break;
98144f24cb3SJiri Olsa 
98244f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
98344f24cb3SJiri Olsa 		if (!dso->has_build_id) {
98444f24cb3SJiri Olsa 			ret = -1;
98544f24cb3SJiri Olsa 			break;
98644f24cb3SJiri Olsa 		}
98744f24cb3SJiri Olsa 
98844f24cb3SJiri Olsa 		build_id__sprintf(dso->build_id,
98944f24cb3SJiri Olsa 				  sizeof(dso->build_id),
99044f24cb3SJiri Olsa 				  build_id_hex);
99144f24cb3SJiri Olsa 		snprintf(file, size,
99244f24cb3SJiri Olsa 			 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
99344f24cb3SJiri Olsa 			 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
99444f24cb3SJiri Olsa 		break;
99544f24cb3SJiri Olsa 
99644f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
99744f24cb3SJiri Olsa 		snprintf(file, size, "%s%s",
99844f24cb3SJiri Olsa 			 symbol_conf.symfs, dso->long_name);
99944f24cb3SJiri Olsa 		break;
100044f24cb3SJiri Olsa 
100144f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__GUEST_KMODULE:
100244f24cb3SJiri Olsa 		snprintf(file, size, "%s%s%s", symbol_conf.symfs,
100344f24cb3SJiri Olsa 			 root_dir, dso->long_name);
100444f24cb3SJiri Olsa 		break;
100544f24cb3SJiri Olsa 
100644f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
100744f24cb3SJiri Olsa 		snprintf(file, size, "%s%s", symbol_conf.symfs,
100844f24cb3SJiri Olsa 			 dso->long_name);
100944f24cb3SJiri Olsa 		break;
101044f24cb3SJiri Olsa 
101144f24cb3SJiri Olsa 	default:
101244f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__KALLSYMS:
101321ea4539SCody P Schafer 	case DSO_BINARY_TYPE__VMLINUX:
101444f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
101521ea4539SCody P Schafer 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
101644f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__JAVA_JIT:
101744f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__NOT_FOUND:
101844f24cb3SJiri Olsa 		ret = -1;
101944f24cb3SJiri Olsa 		break;
102044f24cb3SJiri Olsa 	}
102144f24cb3SJiri Olsa 
102244f24cb3SJiri Olsa 	return ret;
102344f24cb3SJiri Olsa }
102444f24cb3SJiri Olsa 
1025aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
102686470930SIngo Molnar {
1027c338aee8SArnaldo Carvalho de Melo 	char *name;
102886470930SIngo Molnar 	int ret = -1;
102944f24cb3SJiri Olsa 	u_int i;
103023346f21SArnaldo Carvalho de Melo 	struct machine *machine;
103144f24cb3SJiri Olsa 	char *root_dir = (char *) "";
10323aafe5aeSCody P Schafer 	int ss_pos = 0;
10333aafe5aeSCody P Schafer 	struct symsrc ss_[2];
10343aafe5aeSCody P Schafer 	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
103586470930SIngo Molnar 
1036aeafcbafSArnaldo Carvalho de Melo 	dso__set_loaded(dso, map->type);
103766bd8424SArnaldo Carvalho de Melo 
1038aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_KERNEL)
1039aeafcbafSArnaldo Carvalho de Melo 		return dso__load_kernel_sym(dso, map, filter);
1040aeafcbafSArnaldo Carvalho de Melo 	else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1041aeafcbafSArnaldo Carvalho de Melo 		return dso__load_guest_kernel_sym(dso, map, filter);
1042a1645ce1SZhang, Yanmin 
104323346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
104423346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1045a1645ce1SZhang, Yanmin 	else
104623346f21SArnaldo Carvalho de Melo 		machine = NULL;
1047c338aee8SArnaldo Carvalho de Melo 
104844f24cb3SJiri Olsa 	name = malloc(PATH_MAX);
104986470930SIngo Molnar 	if (!name)
105086470930SIngo Molnar 		return -1;
105186470930SIngo Molnar 
1052aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1053f5812a7aSArnaldo Carvalho de Melo 
1054aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1055981c1252SPekka Enberg 		struct stat st;
1056981c1252SPekka Enberg 
1057e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
1058981c1252SPekka Enberg 			return -1;
1059981c1252SPekka Enberg 
1060981c1252SPekka Enberg 		if (st.st_uid && (st.st_uid != geteuid())) {
1061981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1062981c1252SPekka Enberg 				"ignoring it.\n", dso->name);
1063981c1252SPekka Enberg 			return -1;
1064981c1252SPekka Enberg 		}
1065981c1252SPekka Enberg 
1066aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
106744f24cb3SJiri Olsa 		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
106844f24cb3SJiri Olsa 					     DSO_BINARY_TYPE__NOT_FOUND;
106994cb9e38SArnaldo Carvalho de Melo 		return ret;
107094cb9e38SArnaldo Carvalho de Melo 	}
107194cb9e38SArnaldo Carvalho de Melo 
107244f24cb3SJiri Olsa 	if (machine)
107344f24cb3SJiri Olsa 		root_dir = machine->root_dir;
107444f24cb3SJiri Olsa 
10756da80ce8SDave Martin 	/* Iterate over candidate debug images.
10763aafe5aeSCody P Schafer 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
10773aafe5aeSCody P Schafer 	 * and/or opd section) for processing.
10786da80ce8SDave Martin 	 */
107944f24cb3SJiri Olsa 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
10803aafe5aeSCody P Schafer 		struct symsrc *ss = &ss_[ss_pos];
10813aafe5aeSCody P Schafer 		bool next_slot = false;
108244f24cb3SJiri Olsa 
1083005f9294SCody P Schafer 		enum dso_binary_type symtab_type = binary_type_symtab[i];
108444f24cb3SJiri Olsa 
1085005f9294SCody P Schafer 		if (dso__binary_type_file(dso, symtab_type,
108644f24cb3SJiri Olsa 					  root_dir, name, PATH_MAX))
10876da80ce8SDave Martin 			continue;
108886470930SIngo Molnar 
10896da80ce8SDave Martin 		/* Name is now the name of the next image to try */
10903aafe5aeSCody P Schafer 		if (symsrc__init(ss, dso, name, symtab_type) < 0)
10916da80ce8SDave Martin 			continue;
10926da80ce8SDave Martin 
10933aafe5aeSCody P Schafer 		if (!syms_ss && symsrc__has_symtab(ss)) {
10943aafe5aeSCody P Schafer 			syms_ss = ss;
10953aafe5aeSCody P Schafer 			next_slot = true;
1096d26cd12bSCody P Schafer 		}
1097d26cd12bSCody P Schafer 
10983aafe5aeSCody P Schafer 		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
10993aafe5aeSCody P Schafer 			runtime_ss = ss;
11003aafe5aeSCody P Schafer 			next_slot = true;
1101a44f605bSCody P Schafer 		}
110286470930SIngo Molnar 
11033aafe5aeSCody P Schafer 		if (next_slot) {
11043aafe5aeSCody P Schafer 			ss_pos++;
110533ff581eSJiri Olsa 
11063aafe5aeSCody P Schafer 			if (syms_ss && runtime_ss)
11076da80ce8SDave Martin 				break;
1108a25e46c4SArnaldo Carvalho de Melo 		}
11093aafe5aeSCody P Schafer 
11106da80ce8SDave Martin 	}
11116da80ce8SDave Martin 
11123aafe5aeSCody P Schafer 	if (!runtime_ss && !syms_ss)
11133aafe5aeSCody P Schafer 		goto out_free;
11143aafe5aeSCody P Schafer 
11153aafe5aeSCody P Schafer 	if (runtime_ss && !syms_ss) {
11163aafe5aeSCody P Schafer 		syms_ss = runtime_ss;
111760e4b10cSArnaldo Carvalho de Melo 	}
111860e4b10cSArnaldo Carvalho de Melo 
11193aafe5aeSCody P Schafer 	/* We'll have to hope for the best */
11203aafe5aeSCody P Schafer 	if (!runtime_ss && syms_ss)
11213aafe5aeSCody P Schafer 		runtime_ss = syms_ss;
11223aafe5aeSCody P Schafer 
11233aafe5aeSCody P Schafer 	if (syms_ss)
11243aafe5aeSCody P Schafer 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0);
11253aafe5aeSCody P Schafer 	else
11263aafe5aeSCody P Schafer 		ret = -1;
11273aafe5aeSCody P Schafer 
1128f47b58b7SDavid Ahern 	if (ret > 0) {
11293aafe5aeSCody P Schafer 		int nr_plt;
11303aafe5aeSCody P Schafer 
11313aafe5aeSCody P Schafer 		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
11323aafe5aeSCody P Schafer 		if (nr_plt > 0)
11333aafe5aeSCody P Schafer 			ret += nr_plt;
11343aafe5aeSCody P Schafer 	}
11353aafe5aeSCody P Schafer 
11363aafe5aeSCody P Schafer 	for (; ss_pos > 0; ss_pos--)
11373aafe5aeSCody P Schafer 		symsrc__destroy(&ss_[ss_pos - 1]);
11383aafe5aeSCody P Schafer out_free:
113986470930SIngo Molnar 	free(name);
1140aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
11411340e6bbSArnaldo Carvalho de Melo 		return 0;
114286470930SIngo Molnar 	return ret;
114386470930SIngo Molnar }
114486470930SIngo Molnar 
1145aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
114679406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1147439d473bSArnaldo Carvalho de Melo {
1148439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1149439d473bSArnaldo Carvalho de Melo 
1150aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
1151439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1152439d473bSArnaldo Carvalho de Melo 
1153b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1154439d473bSArnaldo Carvalho de Melo 			return map;
1155439d473bSArnaldo Carvalho de Melo 	}
1156439d473bSArnaldo Carvalho de Melo 
1157439d473bSArnaldo Carvalho de Melo 	return NULL;
1158439d473bSArnaldo Carvalho de Melo }
1159439d473bSArnaldo Carvalho de Melo 
1160aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso,
1161a1645ce1SZhang, Yanmin 					   const char *root_dir)
1162b7cece76SArnaldo Carvalho de Melo {
1163b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1164b7cece76SArnaldo Carvalho de Melo 	/*
1165b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1166b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1167b7cece76SArnaldo Carvalho de Melo 	 */
1168aeafcbafSArnaldo Carvalho de Melo 	const char *name = dso->short_name + 1;
1169b7cece76SArnaldo Carvalho de Melo 
1170b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1171a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1172a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1173b7cece76SArnaldo Carvalho de Melo 
1174aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, dso->build_id,
1175aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
1176aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
1177b7cece76SArnaldo Carvalho de Melo 
1178b7cece76SArnaldo Carvalho de Melo 	return 0;
1179b7cece76SArnaldo Carvalho de Melo }
1180b7cece76SArnaldo Carvalho de Melo 
1181aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg,
1182a1645ce1SZhang, Yanmin 				const char *dir_name)
11836cfcc53eSMike Galbraith {
1184439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
11855aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
118674534341SGui Jianfeng 	int ret = 0;
11876cfcc53eSMike Galbraith 
1188439d473bSArnaldo Carvalho de Melo 	if (!dir) {
11895aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1190439d473bSArnaldo Carvalho de Melo 		return -1;
1191439d473bSArnaldo Carvalho de Melo 	}
11926cfcc53eSMike Galbraith 
1193439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1194439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1195a1645ce1SZhang, Yanmin 		struct stat st;
1196439d473bSArnaldo Carvalho de Melo 
1197a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
11982b600f95SNamhyung Kim 		snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
1199a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1200a1645ce1SZhang, Yanmin 			continue;
1201a1645ce1SZhang, Yanmin 
1202a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1203439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1204439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1205439d473bSArnaldo Carvalho de Melo 				continue;
1206439d473bSArnaldo Carvalho de Melo 
1207aeafcbafSArnaldo Carvalho de Melo 			ret = map_groups__set_modules_path_dir(mg, path);
120874534341SGui Jianfeng 			if (ret < 0)
120974534341SGui Jianfeng 				goto out;
1210439d473bSArnaldo Carvalho de Melo 		} else {
1211439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1212439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1213439d473bSArnaldo Carvalho de Melo 			struct map *map;
1214cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1215439d473bSArnaldo Carvalho de Melo 
1216439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1217439d473bSArnaldo Carvalho de Melo 				continue;
1218439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1219439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1220439d473bSArnaldo Carvalho de Melo 
1221a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
1222aeafcbafSArnaldo Carvalho de Melo 			map = map_groups__find_by_name(mg, MAP__FUNCTION,
1223aeafcbafSArnaldo Carvalho de Melo 						       dso_name);
1224439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1225439d473bSArnaldo Carvalho de Melo 				continue;
1226439d473bSArnaldo Carvalho de Melo 
1227cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
122874534341SGui Jianfeng 			if (long_name == NULL) {
122974534341SGui Jianfeng 				ret = -1;
123074534341SGui Jianfeng 				goto out;
123174534341SGui Jianfeng 			}
1232cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
12336e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1234a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1235439d473bSArnaldo Carvalho de Melo 		}
1236439d473bSArnaldo Carvalho de Melo 	}
1237439d473bSArnaldo Carvalho de Melo 
123874534341SGui Jianfeng out:
1239439d473bSArnaldo Carvalho de Melo 	closedir(dir);
124074534341SGui Jianfeng 	return ret;
1241439d473bSArnaldo Carvalho de Melo }
1242439d473bSArnaldo Carvalho de Melo 
1243a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1244439d473bSArnaldo Carvalho de Melo {
1245a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1246a1645ce1SZhang, Yanmin 	FILE *file;
1247a1645ce1SZhang, Yanmin 	char *name, *tmp;
1248a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1249a1645ce1SZhang, Yanmin 
1250a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1251a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1252a1645ce1SZhang, Yanmin 	if (!file)
1253a1645ce1SZhang, Yanmin 		return NULL;
1254a1645ce1SZhang, Yanmin 
1255a1645ce1SZhang, Yanmin 	version[0] = '\0';
1256a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1257a1645ce1SZhang, Yanmin 	fclose(file);
1258a1645ce1SZhang, Yanmin 
1259a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1260a1645ce1SZhang, Yanmin 	if (!name)
1261a1645ce1SZhang, Yanmin 		return NULL;
1262a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1263a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1264a1645ce1SZhang, Yanmin 	if (tmp)
1265a1645ce1SZhang, Yanmin 		*tmp = '\0';
1266a1645ce1SZhang, Yanmin 
1267a1645ce1SZhang, Yanmin 	return strdup(name);
1268a1645ce1SZhang, Yanmin }
1269a1645ce1SZhang, Yanmin 
1270aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine)
1271a1645ce1SZhang, Yanmin {
1272a1645ce1SZhang, Yanmin 	char *version;
1273439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1274439d473bSArnaldo Carvalho de Melo 
1275aeafcbafSArnaldo Carvalho de Melo 	version = get_kernel_version(machine->root_dir);
1276a1645ce1SZhang, Yanmin 	if (!version)
1277439d473bSArnaldo Carvalho de Melo 		return -1;
1278439d473bSArnaldo Carvalho de Melo 
1279a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1280aeafcbafSArnaldo Carvalho de Melo 		 machine->root_dir, version);
1281a1645ce1SZhang, Yanmin 	free(version);
1282439d473bSArnaldo Carvalho de Melo 
1283aeafcbafSArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
1284439d473bSArnaldo Carvalho de Melo }
12856cfcc53eSMike Galbraith 
1286aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start,
1287d28c6223SArnaldo Carvalho de Melo 				const char *filename)
1288b7cece76SArnaldo Carvalho de Melo {
1289b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1290aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1291b7cece76SArnaldo Carvalho de Melo 
1292b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1293b7cece76SArnaldo Carvalho de Melo 		return NULL;
1294b7cece76SArnaldo Carvalho de Melo 
1295b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1296b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1297b7cece76SArnaldo Carvalho de Melo 		return NULL;
1298b7cece76SArnaldo Carvalho de Melo 
1299aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine))
130044f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
1301a1645ce1SZhang, Yanmin 	else
130244f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
1303aeafcbafSArnaldo Carvalho de Melo 	map_groups__insert(&machine->kmaps, map);
1304b7cece76SArnaldo Carvalho de Melo 	return map;
1305b7cece76SArnaldo Carvalho de Melo }
1306b7cece76SArnaldo Carvalho de Melo 
1307aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine)
1308439d473bSArnaldo Carvalho de Melo {
1309439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1310439d473bSArnaldo Carvalho de Melo 	size_t n;
1311a1645ce1SZhang, Yanmin 	FILE *file;
1312439d473bSArnaldo Carvalho de Melo 	struct map *map;
1313a1645ce1SZhang, Yanmin 	const char *modules;
1314a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1315439d473bSArnaldo Carvalho de Melo 
1316aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
1317a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
1318a1645ce1SZhang, Yanmin 	else {
1319aeafcbafSArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", machine->root_dir);
1320a1645ce1SZhang, Yanmin 		modules = path;
1321a1645ce1SZhang, Yanmin 	}
1322a1645ce1SZhang, Yanmin 
1323ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(path, "/proc/modules"))
1324ec80fde7SArnaldo Carvalho de Melo 		return -1;
1325ec80fde7SArnaldo Carvalho de Melo 
1326a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
1327439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1328439d473bSArnaldo Carvalho de Melo 		return -1;
1329439d473bSArnaldo Carvalho de Melo 
1330439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1331439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1332439d473bSArnaldo Carvalho de Melo 		u64 start;
1333439d473bSArnaldo Carvalho de Melo 		char *sep;
1334439d473bSArnaldo Carvalho de Melo 		int line_len;
1335439d473bSArnaldo Carvalho de Melo 
1336439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1337439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
13386cfcc53eSMike Galbraith 			break;
13396cfcc53eSMike Galbraith 
1340439d473bSArnaldo Carvalho de Melo 		if (!line)
1341439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1342439d473bSArnaldo Carvalho de Melo 
1343439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1344439d473bSArnaldo Carvalho de Melo 
1345439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1346439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1347439d473bSArnaldo Carvalho de Melo 			continue;
1348439d473bSArnaldo Carvalho de Melo 
1349439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1350439d473bSArnaldo Carvalho de Melo 
1351439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1352439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1353439d473bSArnaldo Carvalho de Melo 			continue;
1354439d473bSArnaldo Carvalho de Melo 
1355439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1356439d473bSArnaldo Carvalho de Melo 
1357439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
1358aeafcbafSArnaldo Carvalho de Melo 		map = machine__new_module(machine, start, name);
1359b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1360439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1361aeafcbafSArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, machine->root_dir);
13626cfcc53eSMike Galbraith 	}
13636cfcc53eSMike Galbraith 
1364439d473bSArnaldo Carvalho de Melo 	free(line);
1365439d473bSArnaldo Carvalho de Melo 	fclose(file);
1366439d473bSArnaldo Carvalho de Melo 
1367aeafcbafSArnaldo Carvalho de Melo 	return machine__set_modules_path(machine);
1368439d473bSArnaldo Carvalho de Melo 
1369439d473bSArnaldo Carvalho de Melo out_delete_line:
1370439d473bSArnaldo Carvalho de Melo 	free(line);
1371439d473bSArnaldo Carvalho de Melo out_failure:
1372439d473bSArnaldo Carvalho de Melo 	return -1;
13736cfcc53eSMike Galbraith }
13746cfcc53eSMike Galbraith 
1375aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
13766beba7adSArnaldo Carvalho de Melo 		      const char *vmlinux, symbol_filter_t filter)
137786470930SIngo Molnar {
1378b68e2f91SCody P Schafer 	int err = -1;
1379b68e2f91SCody P Schafer 	struct symsrc ss;
1380ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
1381005f9294SCody P Schafer 	enum dso_binary_type symtab_type;
138286470930SIngo Molnar 
1383a639dc64SArnaldo Carvalho de Melo 	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1384ec5761eaSDavid Ahern 		 symbol_conf.symfs, vmlinux);
138586470930SIngo Molnar 
138621ea4539SCody P Schafer 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1387005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
138821ea4539SCody P Schafer 	else
1389005f9294SCody P Schafer 		symtab_type = DSO_BINARY_TYPE__VMLINUX;
139021ea4539SCody P Schafer 
1391005f9294SCody P Schafer 	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1392b68e2f91SCody P Schafer 		return -1;
1393b68e2f91SCody P Schafer 
1394261360b6SCody P Schafer 	err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
1395b68e2f91SCody P Schafer 	symsrc__destroy(&ss);
139686470930SIngo Molnar 
1397515850e4SCody P Schafer 	if (err > 0) {
1398515850e4SCody P Schafer 		dso__set_long_name(dso, (char *)vmlinux);
1399515850e4SCody P Schafer 		dso__set_loaded(dso, map->type);
1400ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
1401515850e4SCody P Schafer 	}
14023846df2eSArnaldo Carvalho de Melo 
140386470930SIngo Molnar 	return err;
140486470930SIngo Molnar }
140586470930SIngo Molnar 
1406aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
14079de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1408a19afe46SArnaldo Carvalho de Melo {
1409a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
14105ad90e4eSArnaldo Carvalho de Melo 	char *filename;
1411a19afe46SArnaldo Carvalho de Melo 
1412a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
14135ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
14145ad90e4eSArnaldo Carvalho de Melo 
1415aeafcbafSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(dso, NULL, 0);
14165ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
1417aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, filter);
1418261ee821SCody P Schafer 		if (err > 0)
14195ad90e4eSArnaldo Carvalho de Melo 			goto out;
14205ad90e4eSArnaldo Carvalho de Melo 		free(filename);
14215ad90e4eSArnaldo Carvalho de Melo 	}
1422a19afe46SArnaldo Carvalho de Melo 
1423a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1424aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1425a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1426aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(vmlinux_path[i]));
1427a19afe46SArnaldo Carvalho de Melo 			break;
1428a19afe46SArnaldo Carvalho de Melo 		}
1429a19afe46SArnaldo Carvalho de Melo 	}
14305ad90e4eSArnaldo Carvalho de Melo out:
1431a19afe46SArnaldo Carvalho de Melo 	return err;
1432a19afe46SArnaldo Carvalho de Melo }
1433a19afe46SArnaldo Carvalho de Melo 
1434aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
14359de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
143686470930SIngo Molnar {
1437cc612d81SArnaldo Carvalho de Melo 	int err;
14389e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
14399e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1440dc8d6ab2SArnaldo Carvalho de Melo 	/*
1441b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1442b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1443dc8d6ab2SArnaldo Carvalho de Melo 	 *
1444dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1445dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1446dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1447dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1448dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1449dc8d6ab2SArnaldo Carvalho de Melo 	 *
1450dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1451dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1452dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1453dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1454dc8d6ab2SArnaldo Carvalho de Melo 	 */
1455b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1456b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1457b226a5a7SDavid Ahern 		goto do_kallsyms;
1458b226a5a7SDavid Ahern 	}
1459b226a5a7SDavid Ahern 
1460dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
1461aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map,
1462dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1463e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
1464aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso,
1465e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
1466e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
1467e7dadc00SArnaldo Carvalho de Melo 		}
1468e7dadc00SArnaldo Carvalho de Melo 		return err;
1469dc8d6ab2SArnaldo Carvalho de Melo 	}
1470439d473bSArnaldo Carvalho de Melo 
1471cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
1472aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
1473a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1474cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1475cc612d81SArnaldo Carvalho de Melo 	}
1476cc612d81SArnaldo Carvalho de Melo 
1477ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1478ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1479ec5761eaSDavid Ahern 		return -1;
1480ec5761eaSDavid Ahern 
1481b7cece76SArnaldo Carvalho de Melo 	/*
1482b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1483b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1484b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1485b7cece76SArnaldo Carvalho de Melo 	 */
1486aeafcbafSArnaldo Carvalho de Melo 	if (dso->has_build_id) {
1487b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
14889e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1489b7cece76SArnaldo Carvalho de Melo 
1490b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
14918d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
1492aeafcbafSArnaldo Carvalho de Melo 			if (dso__build_id_equal(dso, kallsyms_build_id)) {
14939e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1494b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
14958d0591f6SArnaldo Carvalho de Melo 			}
14969e201442SArnaldo Carvalho de Melo 		}
1497dc8d6ab2SArnaldo Carvalho de Melo 		/*
1498dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1499dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1500dc8d6ab2SArnaldo Carvalho de Melo 		 */
1501aeafcbafSArnaldo Carvalho de Melo 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
15029e201442SArnaldo Carvalho de Melo 				  sbuild_id);
15039e201442SArnaldo Carvalho de Melo 
15049e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
15059e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
15063846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
15073846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
15088d0591f6SArnaldo Carvalho de Melo 			return -1;
15093846df2eSArnaldo Carvalho de Melo 		}
15108d0591f6SArnaldo Carvalho de Melo 
151119fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
151219fc2dedSArnaldo Carvalho de Melo 
1513dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
15143846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
15153846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
15169e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
1517dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
1518ef6ae724SArnaldo Carvalho de Melo 		}
1519dc8d6ab2SArnaldo Carvalho de Melo 	} else {
1520dc8d6ab2SArnaldo Carvalho de Melo 		/*
1521dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
1522dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
1523dc8d6ab2SArnaldo Carvalho de Melo 		 */
1524dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
1525dc8d6ab2SArnaldo Carvalho de Melo 	}
1526dc8d6ab2SArnaldo Carvalho de Melo 
1527dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
1528aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
15293846df2eSArnaldo Carvalho de Melo 	if (err > 0)
15303846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1531dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1532dc8d6ab2SArnaldo Carvalho de Melo 
1533439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1534aeafcbafSArnaldo Carvalho de Melo 		dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
15350a0317b4SCody P Schafer out_fixup:
15366a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
15376a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1538439d473bSArnaldo Carvalho de Melo 	}
153994cb9e38SArnaldo Carvalho de Melo 
154086470930SIngo Molnar 	return err;
154186470930SIngo Molnar }
154286470930SIngo Molnar 
1543aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1544a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
1545a1645ce1SZhang, Yanmin {
1546a1645ce1SZhang, Yanmin 	int err;
1547a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
154823346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1549a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1550a1645ce1SZhang, Yanmin 
1551a1645ce1SZhang, Yanmin 	if (!map->groups) {
1552a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1553a1645ce1SZhang, Yanmin 		return -1;
1554a1645ce1SZhang, Yanmin 	}
155523346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1556a1645ce1SZhang, Yanmin 
155723346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1558a1645ce1SZhang, Yanmin 		/*
1559a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1560a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1561a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1562a1645ce1SZhang, Yanmin 		 */
1563a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1564aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
1565a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
1566a1645ce1SZhang, Yanmin 			goto out_try_fixup;
1567a1645ce1SZhang, Yanmin 		}
1568a1645ce1SZhang, Yanmin 
1569a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1570a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1571a1645ce1SZhang, Yanmin 			return -1;
1572a1645ce1SZhang, Yanmin 	} else {
157323346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1574a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1575a1645ce1SZhang, Yanmin 	}
1576a1645ce1SZhang, Yanmin 
1577aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
1578a1645ce1SZhang, Yanmin 	if (err > 0)
1579a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1580a1645ce1SZhang, Yanmin 
1581a1645ce1SZhang, Yanmin out_try_fixup:
1582a1645ce1SZhang, Yanmin 	if (err > 0) {
1583a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
158448ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
1585aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(path));
1586a1645ce1SZhang, Yanmin 		}
1587a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1588a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1589a1645ce1SZhang, Yanmin 	}
1590a1645ce1SZhang, Yanmin 
1591a1645ce1SZhang, Yanmin 	return err;
1592a1645ce1SZhang, Yanmin }
1593cd84c2acSFrederic Weisbecker 
1594e5a1845fSNamhyung Kim void dsos__add(struct list_head *head, struct dso *dso)
1595cd84c2acSFrederic Weisbecker {
1596b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1597cd84c2acSFrederic Weisbecker }
1598cd84c2acSFrederic Weisbecker 
15991c4be9ffSJiri Olsa struct dso *dsos__find(struct list_head *head, const char *name)
1600cd84c2acSFrederic Weisbecker {
1601cd84c2acSFrederic Weisbecker 	struct dso *pos;
1602cd84c2acSFrederic Weisbecker 
1603b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1604cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
1605cd84c2acSFrederic Weisbecker 			return pos;
1606cd84c2acSFrederic Weisbecker 	return NULL;
1607cd84c2acSFrederic Weisbecker }
1608cd84c2acSFrederic Weisbecker 
1609a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
1610cd84c2acSFrederic Weisbecker {
1611a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
1612cd84c2acSFrederic Weisbecker 
1613e4204992SArnaldo Carvalho de Melo 	if (!dso) {
161400a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1615cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1616a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
1617cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1618cfc10d3bSArnaldo Carvalho de Melo 		}
1619e4204992SArnaldo Carvalho de Melo 	}
1620cd84c2acSFrederic Weisbecker 
1621cd84c2acSFrederic Weisbecker 	return dso;
1622cd84c2acSFrederic Weisbecker }
1623cd84c2acSFrederic Weisbecker 
16241f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1625cd84c2acSFrederic Weisbecker {
1626cd84c2acSFrederic Weisbecker 	struct dso *pos;
1627cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
1628cd84c2acSFrederic Weisbecker 
162995011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
163095011c60SArnaldo Carvalho de Melo 		int i;
163195011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
1632cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
1633cd84c2acSFrederic Weisbecker 	}
1634cd84c2acSFrederic Weisbecker 
1635cbf69680SArnaldo Carvalho de Melo 	return ret;
1636cbf69680SArnaldo Carvalho de Melo }
1637cbf69680SArnaldo Carvalho de Melo 
1638aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1639b0da954aSArnaldo Carvalho de Melo {
1640a1645ce1SZhang, Yanmin 	struct rb_node *nd;
1641cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
1642a1645ce1SZhang, Yanmin 
1643aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
164423346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
1645cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
1646cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
1647a1645ce1SZhang, Yanmin 	}
1648cbf69680SArnaldo Carvalho de Melo 
1649cbf69680SArnaldo Carvalho de Melo 	return ret;
1650b0da954aSArnaldo Carvalho de Melo }
1651b0da954aSArnaldo Carvalho de Melo 
165288d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
165388d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
16549e03eb2dSArnaldo Carvalho de Melo {
16559e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
16569e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
16579e03eb2dSArnaldo Carvalho de Melo 
1658b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
165988d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
166088d3d9b7SArnaldo Carvalho de Melo 			continue;
16619e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
16629e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
16639e03eb2dSArnaldo Carvalho de Melo 	}
16649e03eb2dSArnaldo Carvalho de Melo 	return ret;
16659e03eb2dSArnaldo Carvalho de Melo }
16669e03eb2dSArnaldo Carvalho de Melo 
1667aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1668aeafcbafSArnaldo Carvalho de Melo 				     bool with_hits)
1669f869097eSArnaldo Carvalho de Melo {
1670aeafcbafSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
1671aeafcbafSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
1672f869097eSArnaldo Carvalho de Melo }
1673f869097eSArnaldo Carvalho de Melo 
1674aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1675aeafcbafSArnaldo Carvalho de Melo 				      FILE *fp, bool with_hits)
1676b0da954aSArnaldo Carvalho de Melo {
1677a1645ce1SZhang, Yanmin 	struct rb_node *nd;
1678a1645ce1SZhang, Yanmin 	size_t ret = 0;
1679a1645ce1SZhang, Yanmin 
1680aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
168123346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
1682f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
1683a1645ce1SZhang, Yanmin 	}
1684a1645ce1SZhang, Yanmin 	return ret;
1685b0da954aSArnaldo Carvalho de Melo }
1686b0da954aSArnaldo Carvalho de Melo 
1687f57b05edSJiri Olsa static struct dso*
1688f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name,
1689f57b05edSJiri Olsa 		    const char *short_name, int dso_type)
1690fd1d908cSArnaldo Carvalho de Melo {
1691f57b05edSJiri Olsa 	/*
1692f57b05edSJiri Olsa 	 * The kernel dso could be created by build_id processing.
1693f57b05edSJiri Olsa 	 */
1694f57b05edSJiri Olsa 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
1695fd1d908cSArnaldo Carvalho de Melo 
1696f57b05edSJiri Olsa 	/*
1697f57b05edSJiri Olsa 	 * We need to run this in all cases, since during the build_id
1698f57b05edSJiri Olsa 	 * processing we had no idea this was the kernel dso.
1699f57b05edSJiri Olsa 	 */
1700aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
1701f57b05edSJiri Olsa 		dso__set_short_name(dso, short_name);
1702f57b05edSJiri Olsa 		dso->kernel = dso_type;
1703a1645ce1SZhang, Yanmin 	}
1704a1645ce1SZhang, Yanmin 
1705aeafcbafSArnaldo Carvalho de Melo 	return dso;
1706a1645ce1SZhang, Yanmin }
1707a1645ce1SZhang, Yanmin 
1708aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
1709a1645ce1SZhang, Yanmin {
1710a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1711a1645ce1SZhang, Yanmin 
171223346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
1713a1645ce1SZhang, Yanmin 		return;
171423346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
1715aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(path, dso->build_id,
1716aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
1717aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
1718fd1d908cSArnaldo Carvalho de Melo }
1719fd1d908cSArnaldo Carvalho de Melo 
1720f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine)
1721cd84c2acSFrederic Weisbecker {
1722a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
1723a1645ce1SZhang, Yanmin 	struct dso *kernel;
1724cd84c2acSFrederic Weisbecker 
1725aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine)) {
1726a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
1727f57b05edSJiri Olsa 		if (!vmlinux_name)
1728f57b05edSJiri Olsa 			vmlinux_name = "[kernel.kallsyms]";
1729f57b05edSJiri Olsa 
1730f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
1731f57b05edSJiri Olsa 					     "[kernel]",
1732f57b05edSJiri Olsa 					     DSO_TYPE_KERNEL);
1733a1645ce1SZhang, Yanmin 	} else {
1734f57b05edSJiri Olsa 		char bf[PATH_MAX];
1735f57b05edSJiri Olsa 
1736aeafcbafSArnaldo Carvalho de Melo 		if (machine__is_default_guest(machine))
1737a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
1738f57b05edSJiri Olsa 		if (!vmlinux_name)
1739f57b05edSJiri Olsa 			vmlinux_name = machine__mmap_name(machine, bf,
1740f57b05edSJiri Olsa 							  sizeof(bf));
1741f57b05edSJiri Olsa 
1742f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
1743f57b05edSJiri Olsa 					     "[guest.kernel]",
1744f57b05edSJiri Olsa 					     DSO_TYPE_GUEST_KERNEL);
17458d92c02aSArnaldo Carvalho de Melo 	}
1746cd84c2acSFrederic Weisbecker 
1747f57b05edSJiri Olsa 	if (kernel != NULL && (!kernel->has_build_id))
1748aeafcbafSArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, machine);
1749f57b05edSJiri Olsa 
1750f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
1751f1dfa0b1SArnaldo Carvalho de Melo }
1752f1dfa0b1SArnaldo Carvalho de Melo 
1753d214afbdSMing Lei struct process_args {
1754d214afbdSMing Lei 	u64 start;
1755d214afbdSMing Lei };
1756d214afbdSMing Lei 
1757d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name,
1758*1d037ca1SIrina Tirdea 			     char type __maybe_unused, u64 start)
1759d214afbdSMing Lei {
1760d214afbdSMing Lei 	struct process_args *args = arg;
1761d214afbdSMing Lei 
1762d214afbdSMing Lei 	if (strchr(name, '['))
1763d214afbdSMing Lei 		return 0;
1764d214afbdSMing Lei 
1765d214afbdSMing Lei 	args->start = start;
1766d214afbdSMing Lei 	return 1;
1767d214afbdSMing Lei }
1768d214afbdSMing Lei 
1769d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */
1770d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine)
1771d214afbdSMing Lei {
1772d214afbdSMing Lei 	const char *filename;
1773d214afbdSMing Lei 	char path[PATH_MAX];
1774d214afbdSMing Lei 	struct process_args args;
1775d214afbdSMing Lei 
1776d214afbdSMing Lei 	if (machine__is_host(machine)) {
1777d214afbdSMing Lei 		filename = "/proc/kallsyms";
1778d214afbdSMing Lei 	} else {
1779d214afbdSMing Lei 		if (machine__is_default_guest(machine))
1780d214afbdSMing Lei 			filename = (char *)symbol_conf.default_guest_kallsyms;
1781d214afbdSMing Lei 		else {
1782d214afbdSMing Lei 			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1783d214afbdSMing Lei 			filename = path;
1784d214afbdSMing Lei 		}
1785d214afbdSMing Lei 	}
1786d214afbdSMing Lei 
1787ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1788ec80fde7SArnaldo Carvalho de Melo 		return 0;
1789ec80fde7SArnaldo Carvalho de Melo 
1790d214afbdSMing Lei 	if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
1791d214afbdSMing Lei 		return 0;
1792d214afbdSMing Lei 
1793d214afbdSMing Lei 	return args.start;
1794d214afbdSMing Lei }
1795d214afbdSMing Lei 
1796aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
1797f1dfa0b1SArnaldo Carvalho de Melo {
1798de176489SArnaldo Carvalho de Melo 	enum map_type type;
1799aeafcbafSArnaldo Carvalho de Melo 	u64 start = machine__get_kernel_start_addr(machine);
1800f1dfa0b1SArnaldo Carvalho de Melo 
1801de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
18029de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
18039de89fe7SArnaldo Carvalho de Melo 
1804aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = map__new2(start, kernel, type);
1805aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
1806f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
1807f1dfa0b1SArnaldo Carvalho de Melo 
1808aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type]->map_ip =
1809aeafcbafSArnaldo Carvalho de Melo 			machine->vmlinux_maps[type]->unmap_ip =
1810aeafcbafSArnaldo Carvalho de Melo 				identity__map_ip;
1811aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
1812aeafcbafSArnaldo Carvalho de Melo 		kmap->kmaps = &machine->kmaps;
1813aeafcbafSArnaldo Carvalho de Melo 		map_groups__insert(&machine->kmaps,
1814aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
1815f1dfa0b1SArnaldo Carvalho de Melo 	}
1816f1dfa0b1SArnaldo Carvalho de Melo 
1817f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
18182446042cSArnaldo Carvalho de Melo }
18192446042cSArnaldo Carvalho de Melo 
1820aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine)
1821076c6e45SArnaldo Carvalho de Melo {
1822076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
1823076c6e45SArnaldo Carvalho de Melo 
1824076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
1825076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
1826076c6e45SArnaldo Carvalho de Melo 
1827aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
1828076c6e45SArnaldo Carvalho de Melo 			continue;
1829076c6e45SArnaldo Carvalho de Melo 
1830aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
1831aeafcbafSArnaldo Carvalho de Melo 		map_groups__remove(&machine->kmaps,
1832aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
1833076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
1834076c6e45SArnaldo Carvalho de Melo 			/*
1835076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
1836076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
1837076c6e45SArnaldo Carvalho de Melo 			 */
1838076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
1839076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
1840076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
1841076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
1842076c6e45SArnaldo Carvalho de Melo 			}
1843076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
1844076c6e45SArnaldo Carvalho de Melo 		}
1845076c6e45SArnaldo Carvalho de Melo 
1846aeafcbafSArnaldo Carvalho de Melo 		map__delete(machine->vmlinux_maps[type]);
1847aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = NULL;
1848076c6e45SArnaldo Carvalho de Melo 	}
1849076c6e45SArnaldo Carvalho de Melo }
1850076c6e45SArnaldo Carvalho de Melo 
1851aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine)
18525c0541d5SArnaldo Carvalho de Melo {
1853f57b05edSJiri Olsa 	struct dso *kernel = machine__get_kernel(machine);
18545c0541d5SArnaldo Carvalho de Melo 
18555c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
1856aeafcbafSArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(machine, kernel) < 0)
18575c0541d5SArnaldo Carvalho de Melo 		return -1;
18585c0541d5SArnaldo Carvalho de Melo 
1859f51304d3SDavid Ahern 	if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
1860f51304d3SDavid Ahern 		if (machine__is_host(machine))
1861f51304d3SDavid Ahern 			pr_debug("Problems creating module maps, "
1862f51304d3SDavid Ahern 				 "continuing anyway...\n");
1863f51304d3SDavid Ahern 		else
1864f51304d3SDavid Ahern 			pr_debug("Problems creating module maps for guest %d, "
1865f51304d3SDavid Ahern 				 "continuing anyway...\n", machine->pid);
1866f51304d3SDavid Ahern 	}
1867f51304d3SDavid Ahern 
18685c0541d5SArnaldo Carvalho de Melo 	/*
18695c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
18705c0541d5SArnaldo Carvalho de Melo 	 */
1871aeafcbafSArnaldo Carvalho de Melo 	map_groups__fixup_end(&machine->kmaps);
18725c0541d5SArnaldo Carvalho de Melo 	return 0;
18735c0541d5SArnaldo Carvalho de Melo }
18745c0541d5SArnaldo Carvalho de Melo 
1875cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
18762446042cSArnaldo Carvalho de Melo {
1877cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
1878cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
1879cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
1880cc612d81SArnaldo Carvalho de Melo 	}
1881cc612d81SArnaldo Carvalho de Melo 
1882cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
1883cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
1884cc612d81SArnaldo Carvalho de Melo }
1885cc612d81SArnaldo Carvalho de Melo 
1886cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
1887cc612d81SArnaldo Carvalho de Melo {
1888cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1889cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
1890cc612d81SArnaldo Carvalho de Melo 
1891cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
1892cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1893cc612d81SArnaldo Carvalho de Melo 		return -1;
1894cc612d81SArnaldo Carvalho de Melo 
1895cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1896cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1897cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1898cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1899cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1900cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1901cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1902cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1903ec5761eaSDavid Ahern 
1904ec5761eaSDavid Ahern 	/* only try running kernel version if no symfs was given */
1905ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1906ec5761eaSDavid Ahern 		return 0;
1907ec5761eaSDavid Ahern 
1908ec5761eaSDavid Ahern 	if (uname(&uts) < 0)
1909ec5761eaSDavid Ahern 		return -1;
1910ec5761eaSDavid Ahern 
1911cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1912cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1913cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1914cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1915cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1916cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1917cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1918cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1919cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1920cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1921cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1922cc612d81SArnaldo Carvalho de Melo 		 uts.release);
1923cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1924cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1925cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1926cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1927cc612d81SArnaldo Carvalho de Melo 
1928cc612d81SArnaldo Carvalho de Melo 	return 0;
1929cc612d81SArnaldo Carvalho de Melo 
1930cc612d81SArnaldo Carvalho de Melo out_fail:
1931cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1932cc612d81SArnaldo Carvalho de Melo 	return -1;
1933cc612d81SArnaldo Carvalho de Melo }
1934cc612d81SArnaldo Carvalho de Melo 
1935aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
1936b0a9ab62SArnaldo Carvalho de Melo {
1937b0a9ab62SArnaldo Carvalho de Melo 	int i;
1938b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
1939aeafcbafSArnaldo Carvalho de Melo 	struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
19405ad90e4eSArnaldo Carvalho de Melo 
19415ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
19425ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
19435ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
19445ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
19455ad90e4eSArnaldo Carvalho de Melo 	}
1946b0a9ab62SArnaldo Carvalho de Melo 
1947b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
19485ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
19495ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
1950b0a9ab62SArnaldo Carvalho de Melo 
1951b0a9ab62SArnaldo Carvalho de Melo 	return printed;
1952b0a9ab62SArnaldo Carvalho de Melo }
1953b0a9ab62SArnaldo Carvalho de Melo 
1954655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
1955655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
1956655000e7SArnaldo Carvalho de Melo {
1957655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
1958655000e7SArnaldo Carvalho de Melo 		return 0;
1959655000e7SArnaldo Carvalho de Melo 
1960655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
1961655000e7SArnaldo Carvalho de Melo 	if (!*list) {
1962655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
1963655000e7SArnaldo Carvalho de Melo 		return -1;
1964655000e7SArnaldo Carvalho de Melo 	}
1965655000e7SArnaldo Carvalho de Melo 	return 0;
1966655000e7SArnaldo Carvalho de Melo }
1967655000e7SArnaldo Carvalho de Melo 
1968ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
1969ec80fde7SArnaldo Carvalho de Melo {
1970ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
1971ec80fde7SArnaldo Carvalho de Melo 
1972ec80fde7SArnaldo Carvalho de Melo 	if (geteuid() != 0) {
1973ec80fde7SArnaldo Carvalho de Melo 		FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
1974ec80fde7SArnaldo Carvalho de Melo 		if (fp != NULL) {
1975ec80fde7SArnaldo Carvalho de Melo 			char line[8];
1976ec80fde7SArnaldo Carvalho de Melo 
1977ec80fde7SArnaldo Carvalho de Melo 			if (fgets(line, sizeof(line), fp) != NULL)
1978ec80fde7SArnaldo Carvalho de Melo 				value = atoi(line) != 0;
1979ec80fde7SArnaldo Carvalho de Melo 
1980ec80fde7SArnaldo Carvalho de Melo 			fclose(fp);
1981ec80fde7SArnaldo Carvalho de Melo 		}
1982ec80fde7SArnaldo Carvalho de Melo 	}
1983ec80fde7SArnaldo Carvalho de Melo 
1984ec80fde7SArnaldo Carvalho de Melo 	return value;
1985ec80fde7SArnaldo Carvalho de Melo }
1986ec80fde7SArnaldo Carvalho de Melo 
198775be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
1988cc612d81SArnaldo Carvalho de Melo {
1989ec5761eaSDavid Ahern 	const char *symfs;
1990ec5761eaSDavid Ahern 
199185e00b55SJovi Zhang 	if (symbol_conf.initialized)
199285e00b55SJovi Zhang 		return 0;
199385e00b55SJovi Zhang 
19949ac3e487SIrina Tirdea 	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
19954d439517SDavid S. Miller 
1996166ccc9cSNamhyung Kim 	symbol__elf_init();
1997166ccc9cSNamhyung Kim 
199875be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
199975be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
200079406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2001b32d133aSArnaldo Carvalho de Melo 
200275be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2003cc612d81SArnaldo Carvalho de Melo 		return -1;
2004cc612d81SArnaldo Carvalho de Melo 
2005c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2006c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2007c410a338SArnaldo Carvalho de Melo 		return -1;
2008c410a338SArnaldo Carvalho de Melo 	}
2009c410a338SArnaldo Carvalho de Melo 
2010655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2011655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2012655000e7SArnaldo Carvalho de Melo 		return -1;
2013655000e7SArnaldo Carvalho de Melo 
2014655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2015655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2016655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2017655000e7SArnaldo Carvalho de Melo 
2018655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2019655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2020655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2021655000e7SArnaldo Carvalho de Melo 
2022ec5761eaSDavid Ahern 	/*
2023ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2024ec5761eaSDavid Ahern 	 * reset here for simplicity.
2025ec5761eaSDavid Ahern 	 */
2026ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2027ec5761eaSDavid Ahern 	if (symfs == NULL)
2028ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2029ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2030ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2031ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2032ec5761eaSDavid Ahern 		free((void *)symfs);
2033ec5761eaSDavid Ahern 
2034ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2035ec80fde7SArnaldo Carvalho de Melo 
203685e00b55SJovi Zhang 	symbol_conf.initialized = true;
20374aa65636SArnaldo Carvalho de Melo 	return 0;
2038655000e7SArnaldo Carvalho de Melo 
2039655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2040655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2041d74c896bSNamhyung Kim out_free_dso_list:
2042d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2043655000e7SArnaldo Carvalho de Melo 	return -1;
2044cc612d81SArnaldo Carvalho de Melo }
2045cc612d81SArnaldo Carvalho de Melo 
2046d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2047d65a458bSArnaldo Carvalho de Melo {
204885e00b55SJovi Zhang 	if (!symbol_conf.initialized)
204985e00b55SJovi Zhang 		return;
2050d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2051d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2052d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2053d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2054d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
205585e00b55SJovi Zhang 	symbol_conf.initialized = false;
2056d65a458bSArnaldo Carvalho de Melo }
2057d65a458bSArnaldo Carvalho de Melo 
2058aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
20594aa65636SArnaldo Carvalho de Melo {
2060aeafcbafSArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(machines, pid);
20619de89fe7SArnaldo Carvalho de Melo 
206223346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2063a1645ce1SZhang, Yanmin 		return -1;
20644aa65636SArnaldo Carvalho de Melo 
20655c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2066cd84c2acSFrederic Weisbecker }
20675aab621bSArnaldo Carvalho de Melo 
20685aab621bSArnaldo Carvalho de Melo static int hex(char ch)
20695aab621bSArnaldo Carvalho de Melo {
20705aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
20715aab621bSArnaldo Carvalho de Melo 		return ch - '0';
20725aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
20735aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
20745aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
20755aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
20765aab621bSArnaldo Carvalho de Melo 	return -1;
20775aab621bSArnaldo Carvalho de Melo }
20785aab621bSArnaldo Carvalho de Melo 
20795aab621bSArnaldo Carvalho de Melo /*
20805aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
20815aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
20825aab621bSArnaldo Carvalho de Melo  */
20835aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
20845aab621bSArnaldo Carvalho de Melo {
20855aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
20865aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
20875aab621bSArnaldo Carvalho de Melo 
20885aab621bSArnaldo Carvalho de Melo 	while (*p) {
20895aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
20905aab621bSArnaldo Carvalho de Melo 
20915aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
20925aab621bSArnaldo Carvalho de Melo 			break;
20935aab621bSArnaldo Carvalho de Melo 
20945aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
20955aab621bSArnaldo Carvalho de Melo 		p++;
20965aab621bSArnaldo Carvalho de Melo 	}
20975aab621bSArnaldo Carvalho de Melo 
20985aab621bSArnaldo Carvalho de Melo 	return p - ptr;
20995aab621bSArnaldo Carvalho de Melo }
21005aab621bSArnaldo Carvalho de Melo 
21015aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
21025aab621bSArnaldo Carvalho de Melo {
21035aab621bSArnaldo Carvalho de Melo 	char *p = s;
21045aab621bSArnaldo Carvalho de Melo 
21055aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
21065aab621bSArnaldo Carvalho de Melo 		*p++ = to;
21075aab621bSArnaldo Carvalho de Melo 
21085aab621bSArnaldo Carvalho de Melo 	return s;
21095aab621bSArnaldo Carvalho de Melo }
2110a1645ce1SZhang, Yanmin 
2111aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines)
2112a1645ce1SZhang, Yanmin {
2113a1645ce1SZhang, Yanmin 	int ret = 0;
2114a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2115a1645ce1SZhang, Yanmin 	int i, items = 0;
2116a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2117a1645ce1SZhang, Yanmin 	pid_t pid;
2118347ed990SDavid Ahern 	char *endp;
2119a1645ce1SZhang, Yanmin 
2120a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2121a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2122a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2123aeafcbafSArnaldo Carvalho de Melo 		machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
2124a1645ce1SZhang, Yanmin 	}
2125a1645ce1SZhang, Yanmin 
2126a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2127a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2128a1645ce1SZhang, Yanmin 		if (items <= 0)
2129a1645ce1SZhang, Yanmin 			return -ENOENT;
2130a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2131a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2132a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2133a1645ce1SZhang, Yanmin 				continue;
2134a1645ce1SZhang, Yanmin 			}
2135347ed990SDavid Ahern 			pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
2136347ed990SDavid Ahern 			if ((*endp != '\0') ||
2137347ed990SDavid Ahern 			    (endp == namelist[i]->d_name) ||
2138347ed990SDavid Ahern 			    (errno == ERANGE)) {
2139347ed990SDavid Ahern 				pr_debug("invalid directory (%s). Skipping.\n",
2140347ed990SDavid Ahern 					 namelist[i]->d_name);
2141347ed990SDavid Ahern 				continue;
2142347ed990SDavid Ahern 			}
2143a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2144a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2145a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2146a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2147a1645ce1SZhang, Yanmin 			if (ret) {
2148a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2149a1645ce1SZhang, Yanmin 				goto failure;
2150a1645ce1SZhang, Yanmin 			}
2151aeafcbafSArnaldo Carvalho de Melo 			machines__create_kernel_maps(machines, pid);
2152a1645ce1SZhang, Yanmin 		}
2153a1645ce1SZhang, Yanmin failure:
2154a1645ce1SZhang, Yanmin 		free(namelist);
2155a1645ce1SZhang, Yanmin 	}
2156a1645ce1SZhang, Yanmin 
2157a1645ce1SZhang, Yanmin 	return ret;
2158a1645ce1SZhang, Yanmin }
21595c0541d5SArnaldo Carvalho de Melo 
2160aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines)
2161076c6e45SArnaldo Carvalho de Melo {
2162aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(machines);
2163076c6e45SArnaldo Carvalho de Melo 
2164076c6e45SArnaldo Carvalho de Melo 	while (next) {
2165076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2166076c6e45SArnaldo Carvalho de Melo 
2167076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2168aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, machines);
2169076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2170076c6e45SArnaldo Carvalho de Melo 	}
2171076c6e45SArnaldo Carvalho de Melo }
2172076c6e45SArnaldo Carvalho de Melo 
2173aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename,
21745c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
21755c0541d5SArnaldo Carvalho de Melo {
2176aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
21775c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
21785c0541d5SArnaldo Carvalho de Melo 
21795c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
21805c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
21815c0541d5SArnaldo Carvalho de Melo 		/*
21825c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
21835c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
21845c0541d5SArnaldo Carvalho de Melo 		 * sections.
21855c0541d5SArnaldo Carvalho de Melo 		 */
2186aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(&machine->kmaps, type);
21875c0541d5SArnaldo Carvalho de Melo 	}
21885c0541d5SArnaldo Carvalho de Melo 
21895c0541d5SArnaldo Carvalho de Melo 	return ret;
21905c0541d5SArnaldo Carvalho de Melo }
21915c0541d5SArnaldo Carvalho de Melo 
2192aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
21935c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
21945c0541d5SArnaldo Carvalho de Melo {
2195aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
21965c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
21975c0541d5SArnaldo Carvalho de Melo 
21985c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
21995c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
22005c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
22015c0541d5SArnaldo Carvalho de Melo 	}
22025c0541d5SArnaldo Carvalho de Melo 
22035c0541d5SArnaldo Carvalho de Melo 	return ret;
22045c0541d5SArnaldo Carvalho de Melo }
2205225466f1SSrikar Dronamraju 
2206225466f1SSrikar Dronamraju struct map *dso__new_map(const char *name)
2207225466f1SSrikar Dronamraju {
2208378474e4SSrikar Dronamraju 	struct map *map = NULL;
2209225466f1SSrikar Dronamraju 	struct dso *dso = dso__new(name);
2210378474e4SSrikar Dronamraju 
2211378474e4SSrikar Dronamraju 	if (dso)
2212378474e4SSrikar Dronamraju 		map = map__new2(0, dso, MAP__FUNCTION);
2213225466f1SSrikar Dronamraju 
2214225466f1SSrikar Dronamraju 	return map;
2215225466f1SSrikar Dronamraju }
2216949d160bSJiri Olsa 
2217949d160bSJiri Olsa static int open_dso(struct dso *dso, struct machine *machine)
2218949d160bSJiri Olsa {
2219949d160bSJiri Olsa 	char *root_dir = (char *) "";
2220949d160bSJiri Olsa 	char *name;
2221949d160bSJiri Olsa 	int fd;
2222949d160bSJiri Olsa 
2223949d160bSJiri Olsa 	name = malloc(PATH_MAX);
2224949d160bSJiri Olsa 	if (!name)
2225949d160bSJiri Olsa 		return -ENOMEM;
2226949d160bSJiri Olsa 
2227949d160bSJiri Olsa 	if (machine)
2228949d160bSJiri Olsa 		root_dir = machine->root_dir;
2229949d160bSJiri Olsa 
2230949d160bSJiri Olsa 	if (dso__binary_type_file(dso, dso->data_type,
2231949d160bSJiri Olsa 				  root_dir, name, PATH_MAX)) {
2232949d160bSJiri Olsa 		free(name);
2233949d160bSJiri Olsa 		return -EINVAL;
2234949d160bSJiri Olsa 	}
2235949d160bSJiri Olsa 
2236949d160bSJiri Olsa 	fd = open(name, O_RDONLY);
2237949d160bSJiri Olsa 	free(name);
2238949d160bSJiri Olsa 	return fd;
2239949d160bSJiri Olsa }
2240949d160bSJiri Olsa 
2241949d160bSJiri Olsa int dso__data_fd(struct dso *dso, struct machine *machine)
2242949d160bSJiri Olsa {
2243949d160bSJiri Olsa 	int i = 0;
2244949d160bSJiri Olsa 
2245949d160bSJiri Olsa 	if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
2246949d160bSJiri Olsa 		return open_dso(dso, machine);
2247949d160bSJiri Olsa 
2248949d160bSJiri Olsa 	do {
2249949d160bSJiri Olsa 		int fd;
2250949d160bSJiri Olsa 
2251949d160bSJiri Olsa 		dso->data_type = binary_type_data[i++];
2252949d160bSJiri Olsa 
2253949d160bSJiri Olsa 		fd = open_dso(dso, machine);
2254949d160bSJiri Olsa 		if (fd >= 0)
2255949d160bSJiri Olsa 			return fd;
2256949d160bSJiri Olsa 
2257949d160bSJiri Olsa 	} while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
2258949d160bSJiri Olsa 
2259949d160bSJiri Olsa 	return -EINVAL;
2260949d160bSJiri Olsa }
2261949d160bSJiri Olsa 
22624dff624aSJiri Olsa static void
22634dff624aSJiri Olsa dso_cache__free(struct rb_root *root)
2264949d160bSJiri Olsa {
22654dff624aSJiri Olsa 	struct rb_node *next = rb_first(root);
22664dff624aSJiri Olsa 
22674dff624aSJiri Olsa 	while (next) {
22684dff624aSJiri Olsa 		struct dso_cache *cache;
22694dff624aSJiri Olsa 
22704dff624aSJiri Olsa 		cache = rb_entry(next, struct dso_cache, rb_node);
22714dff624aSJiri Olsa 		next = rb_next(&cache->rb_node);
22724dff624aSJiri Olsa 		rb_erase(&cache->rb_node, root);
22734dff624aSJiri Olsa 		free(cache);
22744dff624aSJiri Olsa 	}
2275949d160bSJiri Olsa }
2276949d160bSJiri Olsa 
22774dff624aSJiri Olsa static struct dso_cache*
22784dff624aSJiri Olsa dso_cache__find(struct rb_root *root, u64 offset)
2279949d160bSJiri Olsa {
22804dff624aSJiri Olsa 	struct rb_node **p = &root->rb_node;
22814dff624aSJiri Olsa 	struct rb_node *parent = NULL;
22824dff624aSJiri Olsa 	struct dso_cache *cache;
22834dff624aSJiri Olsa 
22844dff624aSJiri Olsa 	while (*p != NULL) {
22854dff624aSJiri Olsa 		u64 end;
22864dff624aSJiri Olsa 
22874dff624aSJiri Olsa 		parent = *p;
22884dff624aSJiri Olsa 		cache = rb_entry(parent, struct dso_cache, rb_node);
22894dff624aSJiri Olsa 		end = cache->offset + DSO__DATA_CACHE_SIZE;
22904dff624aSJiri Olsa 
22914dff624aSJiri Olsa 		if (offset < cache->offset)
22924dff624aSJiri Olsa 			p = &(*p)->rb_left;
22934dff624aSJiri Olsa 		else if (offset >= end)
22944dff624aSJiri Olsa 			p = &(*p)->rb_right;
22954dff624aSJiri Olsa 		else
22964dff624aSJiri Olsa 			return cache;
22974dff624aSJiri Olsa 	}
22984dff624aSJiri Olsa 	return NULL;
2299949d160bSJiri Olsa }
2300949d160bSJiri Olsa 
23014dff624aSJiri Olsa static void
23024dff624aSJiri Olsa dso_cache__insert(struct rb_root *root, struct dso_cache *new)
23034dff624aSJiri Olsa {
23044dff624aSJiri Olsa 	struct rb_node **p = &root->rb_node;
23054dff624aSJiri Olsa 	struct rb_node *parent = NULL;
23064dff624aSJiri Olsa 	struct dso_cache *cache;
23074dff624aSJiri Olsa 	u64 offset = new->offset;
23084dff624aSJiri Olsa 
23094dff624aSJiri Olsa 	while (*p != NULL) {
23104dff624aSJiri Olsa 		u64 end;
23114dff624aSJiri Olsa 
23124dff624aSJiri Olsa 		parent = *p;
23134dff624aSJiri Olsa 		cache = rb_entry(parent, struct dso_cache, rb_node);
23144dff624aSJiri Olsa 		end = cache->offset + DSO__DATA_CACHE_SIZE;
23154dff624aSJiri Olsa 
23164dff624aSJiri Olsa 		if (offset < cache->offset)
23174dff624aSJiri Olsa 			p = &(*p)->rb_left;
23184dff624aSJiri Olsa 		else if (offset >= end)
23194dff624aSJiri Olsa 			p = &(*p)->rb_right;
23204dff624aSJiri Olsa 	}
23214dff624aSJiri Olsa 
23224dff624aSJiri Olsa 	rb_link_node(&new->rb_node, parent, p);
23234dff624aSJiri Olsa 	rb_insert_color(&new->rb_node, root);
23244dff624aSJiri Olsa }
23254dff624aSJiri Olsa 
23264dff624aSJiri Olsa static ssize_t
23274dff624aSJiri Olsa dso_cache__memcpy(struct dso_cache *cache, u64 offset,
23284dff624aSJiri Olsa 		  u8 *data, u64 size)
23294dff624aSJiri Olsa {
23304dff624aSJiri Olsa 	u64 cache_offset = offset - cache->offset;
23314dff624aSJiri Olsa 	u64 cache_size   = min(cache->size - cache_offset, size);
23324dff624aSJiri Olsa 
23334dff624aSJiri Olsa 	memcpy(data, cache->data + cache_offset, cache_size);
23344dff624aSJiri Olsa 	return cache_size;
23354dff624aSJiri Olsa }
23364dff624aSJiri Olsa 
23374dff624aSJiri Olsa static ssize_t
23384dff624aSJiri Olsa dso_cache__read(struct dso *dso, struct machine *machine,
2339949d160bSJiri Olsa 		 u64 offset, u8 *data, ssize_t size)
2340949d160bSJiri Olsa {
23414dff624aSJiri Olsa 	struct dso_cache *cache;
23424dff624aSJiri Olsa 	ssize_t ret;
2343949d160bSJiri Olsa 	int fd;
2344949d160bSJiri Olsa 
2345949d160bSJiri Olsa 	fd = dso__data_fd(dso, machine);
2346949d160bSJiri Olsa 	if (fd < 0)
2347949d160bSJiri Olsa 		return -1;
2348949d160bSJiri Olsa 
2349949d160bSJiri Olsa 	do {
23504dff624aSJiri Olsa 		u64 cache_offset;
23514dff624aSJiri Olsa 
23524dff624aSJiri Olsa 		ret = -ENOMEM;
23534dff624aSJiri Olsa 
23544dff624aSJiri Olsa 		cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
23554dff624aSJiri Olsa 		if (!cache)
2356949d160bSJiri Olsa 			break;
2357949d160bSJiri Olsa 
23584dff624aSJiri Olsa 		cache_offset = offset & DSO__DATA_CACHE_MASK;
23594dff624aSJiri Olsa 		ret = -EINVAL;
23604dff624aSJiri Olsa 
23614dff624aSJiri Olsa 		if (-1 == lseek(fd, cache_offset, SEEK_SET))
2362949d160bSJiri Olsa 			break;
2363949d160bSJiri Olsa 
23644dff624aSJiri Olsa 		ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
23654dff624aSJiri Olsa 		if (ret <= 0)
23664dff624aSJiri Olsa 			break;
23674dff624aSJiri Olsa 
23684dff624aSJiri Olsa 		cache->offset = cache_offset;
23694dff624aSJiri Olsa 		cache->size   = ret;
23704dff624aSJiri Olsa 		dso_cache__insert(&dso->cache, cache);
23714dff624aSJiri Olsa 
23724dff624aSJiri Olsa 		ret = dso_cache__memcpy(cache, offset, data, size);
2373949d160bSJiri Olsa 
2374949d160bSJiri Olsa 	} while (0);
2375949d160bSJiri Olsa 
23764dff624aSJiri Olsa 	if (ret <= 0)
23774dff624aSJiri Olsa 		free(cache);
23784dff624aSJiri Olsa 
2379949d160bSJiri Olsa 	close(fd);
23804dff624aSJiri Olsa 	return ret;
23814dff624aSJiri Olsa }
23824dff624aSJiri Olsa 
23834dff624aSJiri Olsa static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
23844dff624aSJiri Olsa 			      u64 offset, u8 *data, ssize_t size)
23854dff624aSJiri Olsa {
23864dff624aSJiri Olsa 	struct dso_cache *cache;
23874dff624aSJiri Olsa 
23884dff624aSJiri Olsa 	cache = dso_cache__find(&dso->cache, offset);
23894dff624aSJiri Olsa 	if (cache)
23904dff624aSJiri Olsa 		return dso_cache__memcpy(cache, offset, data, size);
23914dff624aSJiri Olsa 	else
23924dff624aSJiri Olsa 		return dso_cache__read(dso, machine, offset, data, size);
2393949d160bSJiri Olsa }
2394949d160bSJiri Olsa 
2395949d160bSJiri Olsa ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
2396949d160bSJiri Olsa 			      u64 offset, u8 *data, ssize_t size)
2397949d160bSJiri Olsa {
23984dff624aSJiri Olsa 	ssize_t r = 0;
23994dff624aSJiri Olsa 	u8 *p = data;
24004dff624aSJiri Olsa 
24014dff624aSJiri Olsa 	do {
24024dff624aSJiri Olsa 		ssize_t ret;
24034dff624aSJiri Olsa 
24044dff624aSJiri Olsa 		ret = dso_cache_read(dso, machine, offset, p, size);
24054dff624aSJiri Olsa 		if (ret < 0)
24064dff624aSJiri Olsa 			return ret;
24074dff624aSJiri Olsa 
24084dff624aSJiri Olsa 		/* Reached EOF, return what we have. */
24094dff624aSJiri Olsa 		if (!ret)
24104dff624aSJiri Olsa 			break;
24114dff624aSJiri Olsa 
24124dff624aSJiri Olsa 		BUG_ON(ret > size);
24134dff624aSJiri Olsa 
24144dff624aSJiri Olsa 		r      += ret;
24154dff624aSJiri Olsa 		p      += ret;
24164dff624aSJiri Olsa 		offset += ret;
24174dff624aSJiri Olsa 		size   -= ret;
24184dff624aSJiri Olsa 
24194dff624aSJiri Olsa 	} while (size);
24204dff624aSJiri Olsa 
24214dff624aSJiri Olsa 	return r;
2422949d160bSJiri Olsa }
2423949d160bSJiri Olsa 
2424949d160bSJiri Olsa ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
2425949d160bSJiri Olsa 			    struct machine *machine, u64 addr,
2426949d160bSJiri Olsa 			    u8 *data, ssize_t size)
2427949d160bSJiri Olsa {
2428949d160bSJiri Olsa 	u64 offset = map->map_ip(map, addr);
2429949d160bSJiri Olsa 	return dso__data_read_offset(dso, machine, offset, data, size);
2430949d160bSJiri Olsa }
2431