xref: /linux/tools/perf/util/symbol.c (revision 028df76726c5637c6f70a064d94452808ec74f9e)
15aab621bSArnaldo Carvalho de Melo #include <dirent.h>
25aab621bSArnaldo Carvalho de Melo #include <errno.h>
35aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
45aab621bSArnaldo Carvalho de Melo #include <stdio.h>
55aab621bSArnaldo Carvalho de Melo #include <string.h>
65aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
85aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
95aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
105aab621bSArnaldo Carvalho de Melo #include <unistd.h>
119486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
12b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
13e334c726SNamhyung Kim #include "util.h"
148a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1586470930SIngo Molnar #include "symbol.h"
165aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1786470930SIngo Molnar 
1886470930SIngo Molnar #include <libelf.h>
1986470930SIngo Molnar #include <gelf.h>
2086470930SIngo Molnar #include <elf.h>
21f1617b40SArnaldo Carvalho de Melo #include <limits.h>
22439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
232cdbc46dSPeter Zijlstra 
243b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN
25c752d040SRicardo Ribalda Delgado #define KSYM_NAME_LEN 256
263b01a413SArnaldo Carvalho de Melo #endif
273b01a413SArnaldo Carvalho de Melo 
28c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
29c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
30c12e15e7SArnaldo Carvalho de Melo #endif
31c12e15e7SArnaldo Carvalho de Melo 
324dff624aSJiri Olsa static void dso_cache__free(struct rb_root *root);
33aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
3421916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size);
35b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
363610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
37aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
389de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
39aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
40a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
41cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
42cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
43439d473bSArnaldo Carvalho de Melo 
4475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
45d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
46b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
47b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
483e6a2a7fSStephane Eranian 	.annotate_src	  = true,
49ec5761eaSDavid Ahern 	.symfs            = "",
50b32d133aSArnaldo Carvalho de Melo };
51b32d133aSArnaldo Carvalho de Melo 
5244f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = {
5344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__KALLSYMS,
5444f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KALLSYMS,
5544f24cb3SJiri Olsa 	DSO_BINARY_TYPE__JAVA_JIT,
5644f24cb3SJiri Olsa 	DSO_BINARY_TYPE__DEBUGLINK,
5744f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
5844f24cb3SJiri Olsa 	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
5944f24cb3SJiri Olsa 	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
6044f24cb3SJiri Olsa 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
6144f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
6244f24cb3SJiri Olsa 	DSO_BINARY_TYPE__GUEST_KMODULE,
6344f24cb3SJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
6444f24cb3SJiri Olsa 	DSO_BINARY_TYPE__NOT_FOUND,
6544f24cb3SJiri Olsa };
6644f24cb3SJiri Olsa 
67*028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
6844f24cb3SJiri Olsa 
69949d160bSJiri Olsa static enum dso_binary_type binary_type_data[] = {
70949d160bSJiri Olsa 	DSO_BINARY_TYPE__BUILD_ID_CACHE,
71949d160bSJiri Olsa 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
72949d160bSJiri Olsa 	DSO_BINARY_TYPE__NOT_FOUND,
73949d160bSJiri Olsa };
74949d160bSJiri Olsa 
75*028df767SJiri Olsa #define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
76949d160bSJiri Olsa 
77aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso)
788a6c5b26SArnaldo Carvalho de Melo {
791e2dd2f7SDavid Miller 	if (!dso)
801e2dd2f7SDavid Miller 		return strlen("[unknown]");
818a6c5b26SArnaldo Carvalho de Melo 	if (verbose)
82aeafcbafSArnaldo Carvalho de Melo 		return dso->long_name_len;
838a6c5b26SArnaldo Carvalho de Melo 
84aeafcbafSArnaldo Carvalho de Melo 	return dso->short_name_len;
858a6c5b26SArnaldo Carvalho de Melo }
868a6c5b26SArnaldo Carvalho de Melo 
87aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type)
883610583cSArnaldo Carvalho de Melo {
89aeafcbafSArnaldo Carvalho de Melo 	return dso->loaded & (1 << type);
903610583cSArnaldo Carvalho de Melo }
913610583cSArnaldo Carvalho de Melo 
92aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
9379406cd7SArnaldo Carvalho de Melo {
94aeafcbafSArnaldo Carvalho de Melo 	return dso->sorted_by_name & (1 << type);
9579406cd7SArnaldo Carvalho de Melo }
9679406cd7SArnaldo Carvalho de Melo 
97aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
9879406cd7SArnaldo Carvalho de Melo {
99aeafcbafSArnaldo Carvalho de Melo 	dso->sorted_by_name |= (1 << type);
10079406cd7SArnaldo Carvalho de Melo }
10179406cd7SArnaldo Carvalho de Melo 
10236a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
1036893d4eeSArnaldo Carvalho de Melo {
10431877908SAnton Blanchard 	symbol_type = toupper(symbol_type);
10531877908SAnton Blanchard 
1066893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
1076893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1086893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
109f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
11031877908SAnton Blanchard 		return symbol_type == 'D';
1116893d4eeSArnaldo Carvalho de Melo 	default:
1126893d4eeSArnaldo Carvalho de Melo 		return false;
1136893d4eeSArnaldo Carvalho de Melo 	}
1146893d4eeSArnaldo Carvalho de Melo }
1156893d4eeSArnaldo Carvalho de Melo 
116694bf407SAnton Blanchard static int prefix_underscores_count(const char *str)
117694bf407SAnton Blanchard {
118694bf407SAnton Blanchard 	const char *tail = str;
119694bf407SAnton Blanchard 
120694bf407SAnton Blanchard 	while (*tail == '_')
121694bf407SAnton Blanchard 		tail++;
122694bf407SAnton Blanchard 
123694bf407SAnton Blanchard 	return tail - str;
124694bf407SAnton Blanchard }
125694bf407SAnton Blanchard 
126694bf407SAnton Blanchard #define SYMBOL_A 0
127694bf407SAnton Blanchard #define SYMBOL_B 1
128694bf407SAnton Blanchard 
129694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
130694bf407SAnton Blanchard {
131694bf407SAnton Blanchard 	s64 a;
132694bf407SAnton Blanchard 	s64 b;
133694bf407SAnton Blanchard 
134694bf407SAnton Blanchard 	/* Prefer a symbol with non zero length */
135694bf407SAnton Blanchard 	a = syma->end - syma->start;
136694bf407SAnton Blanchard 	b = symb->end - symb->start;
137694bf407SAnton Blanchard 	if ((b == 0) && (a > 0))
138694bf407SAnton Blanchard 		return SYMBOL_A;
139694bf407SAnton Blanchard 	else if ((a == 0) && (b > 0))
140694bf407SAnton Blanchard 		return SYMBOL_B;
141694bf407SAnton Blanchard 
142694bf407SAnton Blanchard 	/* Prefer a non weak symbol over a weak one */
143694bf407SAnton Blanchard 	a = syma->binding == STB_WEAK;
144694bf407SAnton Blanchard 	b = symb->binding == STB_WEAK;
145694bf407SAnton Blanchard 	if (b && !a)
146694bf407SAnton Blanchard 		return SYMBOL_A;
147694bf407SAnton Blanchard 	if (a && !b)
148694bf407SAnton Blanchard 		return SYMBOL_B;
149694bf407SAnton Blanchard 
150694bf407SAnton Blanchard 	/* Prefer a global symbol over a non global one */
151694bf407SAnton Blanchard 	a = syma->binding == STB_GLOBAL;
152694bf407SAnton Blanchard 	b = symb->binding == STB_GLOBAL;
153694bf407SAnton Blanchard 	if (a && !b)
154694bf407SAnton Blanchard 		return SYMBOL_A;
155694bf407SAnton Blanchard 	if (b && !a)
156694bf407SAnton Blanchard 		return SYMBOL_B;
157694bf407SAnton Blanchard 
158694bf407SAnton Blanchard 	/* Prefer a symbol with less underscores */
159694bf407SAnton Blanchard 	a = prefix_underscores_count(syma->name);
160694bf407SAnton Blanchard 	b = prefix_underscores_count(symb->name);
161694bf407SAnton Blanchard 	if (b > a)
162694bf407SAnton Blanchard 		return SYMBOL_A;
163694bf407SAnton Blanchard 	else if (a > b)
164694bf407SAnton Blanchard 		return SYMBOL_B;
165694bf407SAnton Blanchard 
166694bf407SAnton Blanchard 	/* If all else fails, choose the symbol with the longest name */
167694bf407SAnton Blanchard 	if (strlen(syma->name) >= strlen(symb->name))
168694bf407SAnton Blanchard 		return SYMBOL_A;
169694bf407SAnton Blanchard 	else
170694bf407SAnton Blanchard 		return SYMBOL_B;
171694bf407SAnton Blanchard }
172694bf407SAnton Blanchard 
173694bf407SAnton Blanchard static void symbols__fixup_duplicate(struct rb_root *symbols)
174694bf407SAnton Blanchard {
175694bf407SAnton Blanchard 	struct rb_node *nd;
176694bf407SAnton Blanchard 	struct symbol *curr, *next;
177694bf407SAnton Blanchard 
178694bf407SAnton Blanchard 	nd = rb_first(symbols);
179694bf407SAnton Blanchard 
180694bf407SAnton Blanchard 	while (nd) {
181694bf407SAnton Blanchard 		curr = rb_entry(nd, struct symbol, rb_node);
182694bf407SAnton Blanchard again:
183694bf407SAnton Blanchard 		nd = rb_next(&curr->rb_node);
184694bf407SAnton Blanchard 		next = rb_entry(nd, struct symbol, rb_node);
185694bf407SAnton Blanchard 
186694bf407SAnton Blanchard 		if (!nd)
187694bf407SAnton Blanchard 			break;
188694bf407SAnton Blanchard 
189694bf407SAnton Blanchard 		if (curr->start != next->start)
190694bf407SAnton Blanchard 			continue;
191694bf407SAnton Blanchard 
192694bf407SAnton Blanchard 		if (choose_best_symbol(curr, next) == SYMBOL_A) {
193694bf407SAnton Blanchard 			rb_erase(&next->rb_node, symbols);
194694bf407SAnton Blanchard 			goto again;
195694bf407SAnton Blanchard 		} else {
196694bf407SAnton Blanchard 			nd = rb_next(&curr->rb_node);
197694bf407SAnton Blanchard 			rb_erase(&curr->rb_node, symbols);
198694bf407SAnton Blanchard 		}
199694bf407SAnton Blanchard 	}
200694bf407SAnton Blanchard }
201694bf407SAnton Blanchard 
202aeafcbafSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *symbols)
203af427bf5SArnaldo Carvalho de Melo {
204aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(symbols);
2052e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
206af427bf5SArnaldo Carvalho de Melo 
207af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
208af427bf5SArnaldo Carvalho de Melo 		return;
209af427bf5SArnaldo Carvalho de Melo 
2102e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
2112e538c4aSArnaldo Carvalho de Melo 
212af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
2132e538c4aSArnaldo Carvalho de Melo 		prev = curr;
2142e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
215af427bf5SArnaldo Carvalho de Melo 
2163b01a413SArnaldo Carvalho de Melo 		if (prev->end == prev->start && prev->end != curr->start)
217af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
218af427bf5SArnaldo Carvalho de Melo 	}
219af427bf5SArnaldo Carvalho de Melo 
2202e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
2212e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
2222e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
2232e538c4aSArnaldo Carvalho de Melo }
2242e538c4aSArnaldo Carvalho de Melo 
225aeafcbafSArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
226af427bf5SArnaldo Carvalho de Melo {
227af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
228aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
229af427bf5SArnaldo Carvalho de Melo 
230af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
231af427bf5SArnaldo Carvalho de Melo 		return;
232af427bf5SArnaldo Carvalho de Melo 
233af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
234af427bf5SArnaldo Carvalho de Melo 
235af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
236af427bf5SArnaldo Carvalho de Melo 		prev = curr;
237af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
238af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
2392e538c4aSArnaldo Carvalho de Melo 	}
24090c83218SArnaldo Carvalho de Melo 
24190c83218SArnaldo Carvalho de Melo 	/*
24290c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
24390c83218SArnaldo Carvalho de Melo 	 * last map final address.
24490c83218SArnaldo Carvalho de Melo 	 */
2459d1faba5SIan Munsie 	curr->end = ~0ULL;
246af427bf5SArnaldo Carvalho de Melo }
247af427bf5SArnaldo Carvalho de Melo 
248aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg)
24923ea4a3fSArnaldo Carvalho de Melo {
25023ea4a3fSArnaldo Carvalho de Melo 	int i;
25123ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
252aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(mg, i);
25323ea4a3fSArnaldo Carvalho de Melo }
25423ea4a3fSArnaldo Carvalho de Melo 
255c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
256c408fedfSArnaldo Carvalho de Melo 				  const char *name)
25786470930SIngo Molnar {
25886470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
259aeafcbafSArnaldo Carvalho de Melo 	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
260aeafcbafSArnaldo Carvalho de Melo 					sizeof(*sym) + namelen));
261aeafcbafSArnaldo Carvalho de Melo 	if (sym == NULL)
26286470930SIngo Molnar 		return NULL;
26386470930SIngo Molnar 
26475be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
265aeafcbafSArnaldo Carvalho de Melo 		sym = ((void *)sym) + symbol_conf.priv_size;
26636479484SArnaldo Carvalho de Melo 
267aeafcbafSArnaldo Carvalho de Melo 	sym->start   = start;
268aeafcbafSArnaldo Carvalho de Melo 	sym->end     = len ? start + len - 1 : start;
269aeafcbafSArnaldo Carvalho de Melo 	sym->binding = binding;
270aeafcbafSArnaldo Carvalho de Melo 	sym->namelen = namelen - 1;
271e4204992SArnaldo Carvalho de Melo 
272aeafcbafSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
273aeafcbafSArnaldo Carvalho de Melo 		  __func__, name, start, sym->end);
274aeafcbafSArnaldo Carvalho de Melo 	memcpy(sym->name, name, namelen);
275e4204992SArnaldo Carvalho de Melo 
276aeafcbafSArnaldo Carvalho de Melo 	return sym;
27786470930SIngo Molnar }
27886470930SIngo Molnar 
279aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym)
28086470930SIngo Molnar {
281aeafcbafSArnaldo Carvalho de Melo 	free(((void *)sym) - symbol_conf.priv_size);
28286470930SIngo Molnar }
28386470930SIngo Molnar 
284aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
28586470930SIngo Molnar {
2869486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
287aeafcbafSArnaldo Carvalho de Melo 		       sym->start, sym->end,
288aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_GLOBAL ? 'g' :
289aeafcbafSArnaldo Carvalho de Melo 		       sym->binding == STB_LOCAL  ? 'l' : 'w',
290aeafcbafSArnaldo Carvalho de Melo 		       sym->name);
29186470930SIngo Molnar }
29286470930SIngo Molnar 
293a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym,
294a978f2abSAkihiro Nagai 				    const struct addr_location *al, FILE *fp)
295a978f2abSAkihiro Nagai {
296a978f2abSAkihiro Nagai 	unsigned long offset;
297a978f2abSAkihiro Nagai 	size_t length;
298a978f2abSAkihiro Nagai 
299a978f2abSAkihiro Nagai 	if (sym && sym->name) {
300a978f2abSAkihiro Nagai 		length = fprintf(fp, "%s", sym->name);
301a978f2abSAkihiro Nagai 		if (al) {
302a978f2abSAkihiro Nagai 			offset = al->addr - sym->start;
303a978f2abSAkihiro Nagai 			length += fprintf(fp, "+0x%lx", offset);
304a978f2abSAkihiro Nagai 		}
305a978f2abSAkihiro Nagai 		return length;
306a978f2abSAkihiro Nagai 	} else
307a978f2abSAkihiro Nagai 		return fprintf(fp, "[unknown]");
308a978f2abSAkihiro Nagai }
309a978f2abSAkihiro Nagai 
310547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
311547a92e0SAkihiro Nagai {
312a978f2abSAkihiro Nagai 	return symbol__fprintf_symname_offs(sym, NULL, fp);
313547a92e0SAkihiro Nagai }
314547a92e0SAkihiro Nagai 
315aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name)
316cfc10d3bSArnaldo Carvalho de Melo {
317ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
318ef6ae724SArnaldo Carvalho de Melo 		return;
319aeafcbafSArnaldo Carvalho de Melo 	dso->long_name = name;
320aeafcbafSArnaldo Carvalho de Melo 	dso->long_name_len = strlen(name);
321cfc10d3bSArnaldo Carvalho de Melo }
322cfc10d3bSArnaldo Carvalho de Melo 
323aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name)
324b63be8d7SArnaldo Carvalho de Melo {
325b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
326b63be8d7SArnaldo Carvalho de Melo 		return;
327aeafcbafSArnaldo Carvalho de Melo 	dso->short_name = name;
328aeafcbafSArnaldo Carvalho de Melo 	dso->short_name_len = strlen(name);
329b63be8d7SArnaldo Carvalho de Melo }
330b63be8d7SArnaldo Carvalho de Melo 
331aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso)
332cfc10d3bSArnaldo Carvalho de Melo {
333aeafcbafSArnaldo Carvalho de Melo 	dso__set_short_name(dso, basename(dso->long_name));
334cfc10d3bSArnaldo Carvalho de Melo }
335cfc10d3bSArnaldo Carvalho de Melo 
33600a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
33786470930SIngo Molnar {
338aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
33986470930SIngo Molnar 
340aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
3416a4694a4SArnaldo Carvalho de Melo 		int i;
342aeafcbafSArnaldo Carvalho de Melo 		strcpy(dso->name, name);
343aeafcbafSArnaldo Carvalho de Melo 		dso__set_long_name(dso, dso->name);
344aeafcbafSArnaldo Carvalho de Melo 		dso__set_short_name(dso, dso->name);
3456a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
346aeafcbafSArnaldo Carvalho de Melo 			dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
3474dff624aSJiri Olsa 		dso->cache = RB_ROOT;
34844f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
349949d160bSJiri Olsa 		dso->data_type   = DSO_BINARY_TYPE__NOT_FOUND;
350aeafcbafSArnaldo Carvalho de Melo 		dso->loaded = 0;
351aeafcbafSArnaldo Carvalho de Melo 		dso->sorted_by_name = 0;
352aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = 0;
353aeafcbafSArnaldo Carvalho de Melo 		dso->kernel = DSO_TYPE_USER;
3548db4841fSJiri Olsa 		dso->needs_swap = DSO_SWAP__UNSET;
355aeafcbafSArnaldo Carvalho de Melo 		INIT_LIST_HEAD(&dso->node);
35686470930SIngo Molnar 	}
35786470930SIngo Molnar 
358aeafcbafSArnaldo Carvalho de Melo 	return dso;
35986470930SIngo Molnar }
36086470930SIngo Molnar 
361aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols)
36286470930SIngo Molnar {
36386470930SIngo Molnar 	struct symbol *pos;
364aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(symbols);
36586470930SIngo Molnar 
36686470930SIngo Molnar 	while (next) {
36786470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
36886470930SIngo Molnar 		next = rb_next(&pos->rb_node);
369aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, symbols);
37000a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
37186470930SIngo Molnar 	}
37286470930SIngo Molnar }
37386470930SIngo Molnar 
374aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso)
37586470930SIngo Molnar {
3766a4694a4SArnaldo Carvalho de Melo 	int i;
3776a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
378aeafcbafSArnaldo Carvalho de Melo 		symbols__delete(&dso->symbols[i]);
379aeafcbafSArnaldo Carvalho de Melo 	if (dso->sname_alloc)
380aeafcbafSArnaldo Carvalho de Melo 		free((char *)dso->short_name);
381aeafcbafSArnaldo Carvalho de Melo 	if (dso->lname_alloc)
382aeafcbafSArnaldo Carvalho de Melo 		free(dso->long_name);
3834dff624aSJiri Olsa 	dso_cache__free(&dso->cache);
384aeafcbafSArnaldo Carvalho de Melo 	free(dso);
38586470930SIngo Molnar }
38686470930SIngo Molnar 
387aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id)
3888d06367fSArnaldo Carvalho de Melo {
389aeafcbafSArnaldo Carvalho de Melo 	memcpy(dso->build_id, build_id, sizeof(dso->build_id));
390aeafcbafSArnaldo Carvalho de Melo 	dso->has_build_id = 1;
3918d06367fSArnaldo Carvalho de Melo }
3928d06367fSArnaldo Carvalho de Melo 
393aeafcbafSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
39486470930SIngo Molnar {
395aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
39686470930SIngo Molnar 	struct rb_node *parent = NULL;
3979cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
39886470930SIngo Molnar 	struct symbol *s;
39986470930SIngo Molnar 
40086470930SIngo Molnar 	while (*p != NULL) {
40186470930SIngo Molnar 		parent = *p;
40286470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
40386470930SIngo Molnar 		if (ip < s->start)
40486470930SIngo Molnar 			p = &(*p)->rb_left;
40586470930SIngo Molnar 		else
40686470930SIngo Molnar 			p = &(*p)->rb_right;
40786470930SIngo Molnar 	}
40886470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
409aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, symbols);
41086470930SIngo Molnar }
41186470930SIngo Molnar 
412aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
41386470930SIngo Molnar {
41486470930SIngo Molnar 	struct rb_node *n;
41586470930SIngo Molnar 
416aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
41786470930SIngo Molnar 		return NULL;
41886470930SIngo Molnar 
419aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
42086470930SIngo Molnar 
42186470930SIngo Molnar 	while (n) {
42286470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
42386470930SIngo Molnar 
42486470930SIngo Molnar 		if (ip < s->start)
42586470930SIngo Molnar 			n = n->rb_left;
42686470930SIngo Molnar 		else if (ip > s->end)
42786470930SIngo Molnar 			n = n->rb_right;
42886470930SIngo Molnar 		else
42986470930SIngo Molnar 			return s;
43086470930SIngo Molnar 	}
43186470930SIngo Molnar 
43286470930SIngo Molnar 	return NULL;
43386470930SIngo Molnar }
43486470930SIngo Molnar 
43579406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
43679406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
43779406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
43879406cd7SArnaldo Carvalho de Melo };
43979406cd7SArnaldo Carvalho de Melo 
440aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
44179406cd7SArnaldo Carvalho de Melo {
442aeafcbafSArnaldo Carvalho de Melo 	struct rb_node **p = &symbols->rb_node;
44379406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
44402a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
44502a9d037SRabin Vincent 
44602a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
44779406cd7SArnaldo Carvalho de Melo 
44879406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
44979406cd7SArnaldo Carvalho de Melo 		parent = *p;
45079406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
45179406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
45279406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
45379406cd7SArnaldo Carvalho de Melo 		else
45479406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
45579406cd7SArnaldo Carvalho de Melo 	}
45679406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
457aeafcbafSArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, symbols);
45879406cd7SArnaldo Carvalho de Melo }
45979406cd7SArnaldo Carvalho de Melo 
460aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols,
461aeafcbafSArnaldo Carvalho de Melo 				  struct rb_root *source)
46279406cd7SArnaldo Carvalho de Melo {
46379406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
46479406cd7SArnaldo Carvalho de Melo 
46579406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
46679406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
467aeafcbafSArnaldo Carvalho de Melo 		symbols__insert_by_name(symbols, pos);
46879406cd7SArnaldo Carvalho de Melo 	}
46979406cd7SArnaldo Carvalho de Melo }
47079406cd7SArnaldo Carvalho de Melo 
471aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols,
472aeafcbafSArnaldo Carvalho de Melo 					    const char *name)
47379406cd7SArnaldo Carvalho de Melo {
47479406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
47579406cd7SArnaldo Carvalho de Melo 
476aeafcbafSArnaldo Carvalho de Melo 	if (symbols == NULL)
47779406cd7SArnaldo Carvalho de Melo 		return NULL;
47879406cd7SArnaldo Carvalho de Melo 
479aeafcbafSArnaldo Carvalho de Melo 	n = symbols->rb_node;
48079406cd7SArnaldo Carvalho de Melo 
48179406cd7SArnaldo Carvalho de Melo 	while (n) {
48279406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
48379406cd7SArnaldo Carvalho de Melo 		int cmp;
48479406cd7SArnaldo Carvalho de Melo 
48579406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
48679406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
48779406cd7SArnaldo Carvalho de Melo 
48879406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
48979406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
49079406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
49179406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
49279406cd7SArnaldo Carvalho de Melo 		else
49379406cd7SArnaldo Carvalho de Melo 			return &s->sym;
49479406cd7SArnaldo Carvalho de Melo 	}
49579406cd7SArnaldo Carvalho de Melo 
49679406cd7SArnaldo Carvalho de Melo 	return NULL;
49779406cd7SArnaldo Carvalho de Melo }
49879406cd7SArnaldo Carvalho de Melo 
499aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso,
50079406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
501fcf1203aSArnaldo Carvalho de Melo {
502aeafcbafSArnaldo Carvalho de Melo 	return symbols__find(&dso->symbols[type], addr);
503fcf1203aSArnaldo Carvalho de Melo }
504fcf1203aSArnaldo Carvalho de Melo 
505aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
50679406cd7SArnaldo Carvalho de Melo 					const char *name)
50779406cd7SArnaldo Carvalho de Melo {
508aeafcbafSArnaldo Carvalho de Melo 	return symbols__find_by_name(&dso->symbol_names[type], name);
50979406cd7SArnaldo Carvalho de Melo }
51079406cd7SArnaldo Carvalho de Melo 
511aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type)
51279406cd7SArnaldo Carvalho de Melo {
513aeafcbafSArnaldo Carvalho de Melo 	dso__set_sorted_by_name(dso, type);
514aeafcbafSArnaldo Carvalho de Melo 	return symbols__sort_by_name(&dso->symbol_names[type],
515aeafcbafSArnaldo Carvalho de Melo 				     &dso->symbols[type]);
51679406cd7SArnaldo Carvalho de Melo }
51779406cd7SArnaldo Carvalho de Melo 
518aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf)
5198d06367fSArnaldo Carvalho de Melo {
5208d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
521aeafcbafSArnaldo Carvalho de Melo 	const u8 *raw = build_id;
5228d06367fSArnaldo Carvalho de Melo 	int i;
5238d06367fSArnaldo Carvalho de Melo 
5248d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
5258d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
5268d06367fSArnaldo Carvalho de Melo 		++raw;
5278d06367fSArnaldo Carvalho de Melo 		bid += 2;
5288d06367fSArnaldo Carvalho de Melo 	}
5298d06367fSArnaldo Carvalho de Melo 
530aeafcbafSArnaldo Carvalho de Melo 	return raw - build_id;
5318d06367fSArnaldo Carvalho de Melo }
5328d06367fSArnaldo Carvalho de Melo 
533aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
53486470930SIngo Molnar {
5358d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
5368d06367fSArnaldo Carvalho de Melo 
537aeafcbafSArnaldo Carvalho de Melo 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
5389e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
5399e03eb2dSArnaldo Carvalho de Melo }
5409e03eb2dSArnaldo Carvalho de Melo 
541aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso,
542aeafcbafSArnaldo Carvalho de Melo 				    enum map_type type, FILE *fp)
54390f18e63SSrikar Dronamraju {
54490f18e63SSrikar Dronamraju 	size_t ret = 0;
54590f18e63SSrikar Dronamraju 	struct rb_node *nd;
54690f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
54790f18e63SSrikar Dronamraju 
548aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
54990f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
55090f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
55190f18e63SSrikar Dronamraju 	}
55290f18e63SSrikar Dronamraju 
55390f18e63SSrikar Dronamraju 	return ret;
55490f18e63SSrikar Dronamraju }
55590f18e63SSrikar Dronamraju 
556aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
5579e03eb2dSArnaldo Carvalho de Melo {
5589e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
559aeafcbafSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
5609e03eb2dSArnaldo Carvalho de Melo 
561aeafcbafSArnaldo Carvalho de Melo 	if (dso->short_name != dso->long_name)
562aeafcbafSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", dso->long_name);
5633846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
564aeafcbafSArnaldo Carvalho de Melo 		       dso->loaded ? "" : "NOT ");
565aeafcbafSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(dso, fp);
5666a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
567aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
56886470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
56986470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
57086470930SIngo Molnar 	}
57186470930SIngo Molnar 
57286470930SIngo Molnar 	return ret;
57386470930SIngo Molnar }
57486470930SIngo Molnar 
5759e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
5769e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
5773b01a413SArnaldo Carvalho de Melo 					  char type, u64 start, u64 end))
57886470930SIngo Molnar {
57986470930SIngo Molnar 	char *line = NULL;
58086470930SIngo Molnar 	size_t n;
5813b01a413SArnaldo Carvalho de Melo 	int err = -1;
5829e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
58386470930SIngo Molnar 
58486470930SIngo Molnar 	if (file == NULL)
58586470930SIngo Molnar 		goto out_failure;
58686470930SIngo Molnar 
5873b01a413SArnaldo Carvalho de Melo 	err = 0;
5883b01a413SArnaldo Carvalho de Melo 
58986470930SIngo Molnar 	while (!feof(file)) {
5909cffa8d5SPaul Mackerras 		u64 start;
59186470930SIngo Molnar 		int line_len, len;
59286470930SIngo Molnar 		char symbol_type;
5932e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
59486470930SIngo Molnar 
59586470930SIngo Molnar 		line_len = getline(&line, &n, file);
596a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
59786470930SIngo Molnar 			break;
59886470930SIngo Molnar 
59986470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
60086470930SIngo Molnar 
60186470930SIngo Molnar 		len = hex2u64(line, &start);
60286470930SIngo Molnar 
60386470930SIngo Molnar 		len++;
60486470930SIngo Molnar 		if (len + 2 >= line_len)
60586470930SIngo Molnar 			continue;
60686470930SIngo Molnar 
60731877908SAnton Blanchard 		symbol_type = line[len];
6083b01a413SArnaldo Carvalho de Melo 		len += 2;
6093b01a413SArnaldo Carvalho de Melo 		symbol_name = line + len;
6103b01a413SArnaldo Carvalho de Melo 		len = line_len - len;
611682b335aSArnaldo Carvalho de Melo 
6123b01a413SArnaldo Carvalho de Melo 		if (len >= KSYM_NAME_LEN) {
6133b01a413SArnaldo Carvalho de Melo 			err = -1;
6143b01a413SArnaldo Carvalho de Melo 			break;
6153b01a413SArnaldo Carvalho de Melo 		}
6163b01a413SArnaldo Carvalho de Melo 
6173f5a4272SAnton Blanchard 		/*
6183f5a4272SAnton Blanchard 		 * module symbols are not sorted so we add all
6193f5a4272SAnton Blanchard 		 * symbols with zero length and rely on
6203f5a4272SAnton Blanchard 		 * symbols__fixup_end() to fix it up.
6213f5a4272SAnton Blanchard 		 */
6223f5a4272SAnton Blanchard 		err = process_symbol(arg, symbol_name,
6233f5a4272SAnton Blanchard 				     symbol_type, start, start);
624682b335aSArnaldo Carvalho de Melo 		if (err)
625682b335aSArnaldo Carvalho de Melo 			break;
626682b335aSArnaldo Carvalho de Melo 	}
627682b335aSArnaldo Carvalho de Melo 
628682b335aSArnaldo Carvalho de Melo 	free(line);
629682b335aSArnaldo Carvalho de Melo 	fclose(file);
630682b335aSArnaldo Carvalho de Melo 	return err;
631682b335aSArnaldo Carvalho de Melo 
632682b335aSArnaldo Carvalho de Melo out_failure:
633682b335aSArnaldo Carvalho de Melo 	return -1;
634682b335aSArnaldo Carvalho de Melo }
635682b335aSArnaldo Carvalho de Melo 
636682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
637682b335aSArnaldo Carvalho de Melo 	struct map *map;
638682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
639682b335aSArnaldo Carvalho de Melo };
640682b335aSArnaldo Carvalho de Melo 
641c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
642c408fedfSArnaldo Carvalho de Melo {
643c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
644c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
645c408fedfSArnaldo Carvalho de Melo 
646c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
647c408fedfSArnaldo Carvalho de Melo }
648c408fedfSArnaldo Carvalho de Melo 
649682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
6503b01a413SArnaldo Carvalho de Melo 				       char type, u64 start, u64 end)
651682b335aSArnaldo Carvalho de Melo {
652682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
653682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
654682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
655682b335aSArnaldo Carvalho de Melo 
656682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
657682b335aSArnaldo Carvalho de Melo 		return 0;
658682b335aSArnaldo Carvalho de Melo 
6593b01a413SArnaldo Carvalho de Melo 	sym = symbol__new(start, end - start + 1,
6603b01a413SArnaldo Carvalho de Melo 			  kallsyms2elf_type(type), name);
6612e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
662682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
66382164161SArnaldo Carvalho de Melo 	/*
66482164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
6654e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
66682164161SArnaldo Carvalho de Melo 	 */
6674e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
668a1645ce1SZhang, Yanmin 
669682b335aSArnaldo Carvalho de Melo 	return 0;
6702e538c4aSArnaldo Carvalho de Melo }
6712e538c4aSArnaldo Carvalho de Melo 
672682b335aSArnaldo Carvalho de Melo /*
673682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
674682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
675682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
676682b335aSArnaldo Carvalho de Melo  */
677aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
6789e201442SArnaldo Carvalho de Melo 				  struct map *map)
679682b335aSArnaldo Carvalho de Melo {
680aeafcbafSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = dso, };
6819e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
6822e538c4aSArnaldo Carvalho de Melo }
6832e538c4aSArnaldo Carvalho de Melo 
6842e538c4aSArnaldo Carvalho de Melo /*
6852e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
6862e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
6872e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
6882e538c4aSArnaldo Carvalho de Melo  */
689aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map,
6909de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
6912e538c4aSArnaldo Carvalho de Melo {
6929de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
69323346f21SArnaldo Carvalho de Melo 	struct machine *machine = kmaps->machine;
6944e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
6952e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
6968a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
697aeafcbafSArnaldo Carvalho de Melo 	struct rb_root *root = &dso->symbols[map->type];
6984e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
6992e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
7002e538c4aSArnaldo Carvalho de Melo 
7012e538c4aSArnaldo Carvalho de Melo 	while (next) {
7022e538c4aSArnaldo Carvalho de Melo 		char *module;
7032e538c4aSArnaldo Carvalho de Melo 
7042e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
7052e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
7062e538c4aSArnaldo Carvalho de Melo 
7072e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
7082e538c4aSArnaldo Carvalho de Melo 		if (module) {
70975be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
7101de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
7111de8e245SArnaldo Carvalho de Melo 
7122e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
7132e538c4aSArnaldo Carvalho de Melo 
714b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
715a1645ce1SZhang, Yanmin 				if (curr_map != map &&
716aeafcbafSArnaldo Carvalho de Melo 				    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
71723346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
718a1645ce1SZhang, Yanmin 					/*
719a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
720a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
721a1645ce1SZhang, Yanmin 					 * points to a module and all its
722a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
723a1645ce1SZhang, Yanmin 					 * loaded.
724a1645ce1SZhang, Yanmin 					 */
725a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
726a1645ce1SZhang, Yanmin 							curr_map->type);
727af427bf5SArnaldo Carvalho de Melo 				}
728b7cece76SArnaldo Carvalho de Melo 
729a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
730a1645ce1SZhang, Yanmin 							map->type, module);
731a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
7322f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
733a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
734a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
73523346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
736a1645ce1SZhang, Yanmin 					curr_map = map;
737a1645ce1SZhang, Yanmin 					goto discard_symbol;
738a1645ce1SZhang, Yanmin 				}
739a1645ce1SZhang, Yanmin 
740a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
74123346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
742b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
743af427bf5SArnaldo Carvalho de Melo 			}
74486470930SIngo Molnar 			/*
7452e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
7462e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
74786470930SIngo Molnar 			 */
7484e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
7494e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
7504e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
7512e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
752aeafcbafSArnaldo Carvalho de Melo 			struct dso *ndso;
75386470930SIngo Molnar 
7548a953312SArnaldo Carvalho de Melo 			if (count == 0) {
7558a953312SArnaldo Carvalho de Melo 				curr_map = map;
7568a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
7578a953312SArnaldo Carvalho de Melo 			}
7588a953312SArnaldo Carvalho de Melo 
759aeafcbafSArnaldo Carvalho de Melo 			if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
760a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
761a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
762a1645ce1SZhang, Yanmin 					kernel_range++);
763a1645ce1SZhang, Yanmin 			else
764a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
765a1645ce1SZhang, Yanmin 					"[kernel].%d",
7662e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
76786470930SIngo Molnar 
768aeafcbafSArnaldo Carvalho de Melo 			ndso = dso__new(dso_name);
769aeafcbafSArnaldo Carvalho de Melo 			if (ndso == NULL)
7702e538c4aSArnaldo Carvalho de Melo 				return -1;
7712e538c4aSArnaldo Carvalho de Melo 
772aeafcbafSArnaldo Carvalho de Melo 			ndso->kernel = dso->kernel;
773a1645ce1SZhang, Yanmin 
774aeafcbafSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, ndso, map->type);
77537fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
776aeafcbafSArnaldo Carvalho de Melo 				dso__delete(ndso);
7772e538c4aSArnaldo Carvalho de Melo 				return -1;
7782e538c4aSArnaldo Carvalho de Melo 			}
7792e538c4aSArnaldo Carvalho de Melo 
7804e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
7819de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
7822e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
7832e538c4aSArnaldo Carvalho de Melo 		}
7848a953312SArnaldo Carvalho de Melo filter_symbol:
7854e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
7861de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
78700a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
7882e538c4aSArnaldo Carvalho de Melo 		} else {
7894e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
7904e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
7914e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
7928a953312SArnaldo Carvalho de Melo 				++moved;
7938a953312SArnaldo Carvalho de Melo 			} else
7948a953312SArnaldo Carvalho de Melo 				++count;
7959974f496SMike Galbraith 		}
79686470930SIngo Molnar 	}
79786470930SIngo Molnar 
798a1645ce1SZhang, Yanmin 	if (curr_map != map &&
799aeafcbafSArnaldo Carvalho de Melo 	    dso->kernel == DSO_TYPE_GUEST_KERNEL &&
80023346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
801a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
802a1645ce1SZhang, Yanmin 	}
803a1645ce1SZhang, Yanmin 
8048a953312SArnaldo Carvalho de Melo 	return count + moved;
80586470930SIngo Molnar }
80686470930SIngo Molnar 
807ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename,
808ec80fde7SArnaldo Carvalho de Melo 					const char *restricted_filename)
809ec80fde7SArnaldo Carvalho de Melo {
810ec80fde7SArnaldo Carvalho de Melo 	bool restricted = false;
811ec80fde7SArnaldo Carvalho de Melo 
812ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict) {
813ec80fde7SArnaldo Carvalho de Melo 		char *r = realpath(filename, NULL);
814ec80fde7SArnaldo Carvalho de Melo 
815ec80fde7SArnaldo Carvalho de Melo 		if (r != NULL) {
816ec80fde7SArnaldo Carvalho de Melo 			restricted = strcmp(r, restricted_filename) == 0;
817ec80fde7SArnaldo Carvalho de Melo 			free(r);
818ec80fde7SArnaldo Carvalho de Melo 			return restricted;
819ec80fde7SArnaldo Carvalho de Melo 		}
820ec80fde7SArnaldo Carvalho de Melo 	}
821ec80fde7SArnaldo Carvalho de Melo 
822ec80fde7SArnaldo Carvalho de Melo 	return restricted;
823ec80fde7SArnaldo Carvalho de Melo }
824ec80fde7SArnaldo Carvalho de Melo 
825aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename,
8269de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
8272e538c4aSArnaldo Carvalho de Melo {
828ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
829ec80fde7SArnaldo Carvalho de Melo 		return -1;
830ec80fde7SArnaldo Carvalho de Melo 
831aeafcbafSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(dso, filename, map) < 0)
8322e538c4aSArnaldo Carvalho de Melo 		return -1;
8332e538c4aSArnaldo Carvalho de Melo 
834694bf407SAnton Blanchard 	symbols__fixup_duplicate(&dso->symbols[map->type]);
8353f5a4272SAnton Blanchard 	symbols__fixup_end(&dso->symbols[map->type]);
8363f5a4272SAnton Blanchard 
837aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
83844f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
839a1645ce1SZhang, Yanmin 	else
84044f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
8412e538c4aSArnaldo Carvalho de Melo 
842aeafcbafSArnaldo Carvalho de Melo 	return dso__split_kallsyms(dso, map, filter);
843af427bf5SArnaldo Carvalho de Melo }
844af427bf5SArnaldo Carvalho de Melo 
845aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map,
8466beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
84780d496beSPekka Enberg {
84880d496beSPekka Enberg 	char *line = NULL;
84980d496beSPekka Enberg 	size_t n;
85080d496beSPekka Enberg 	FILE *file;
85180d496beSPekka Enberg 	int nr_syms = 0;
85280d496beSPekka Enberg 
853aeafcbafSArnaldo Carvalho de Melo 	file = fopen(dso->long_name, "r");
85480d496beSPekka Enberg 	if (file == NULL)
85580d496beSPekka Enberg 		goto out_failure;
85680d496beSPekka Enberg 
85780d496beSPekka Enberg 	while (!feof(file)) {
8589cffa8d5SPaul Mackerras 		u64 start, size;
85980d496beSPekka Enberg 		struct symbol *sym;
86080d496beSPekka Enberg 		int line_len, len;
86180d496beSPekka Enberg 
86280d496beSPekka Enberg 		line_len = getline(&line, &n, file);
86380d496beSPekka Enberg 		if (line_len < 0)
86480d496beSPekka Enberg 			break;
86580d496beSPekka Enberg 
86680d496beSPekka Enberg 		if (!line)
86780d496beSPekka Enberg 			goto out_failure;
86880d496beSPekka Enberg 
86980d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
87080d496beSPekka Enberg 
87180d496beSPekka Enberg 		len = hex2u64(line, &start);
87280d496beSPekka Enberg 
87380d496beSPekka Enberg 		len++;
87480d496beSPekka Enberg 		if (len + 2 >= line_len)
87580d496beSPekka Enberg 			continue;
87680d496beSPekka Enberg 
87780d496beSPekka Enberg 		len += hex2u64(line + len, &size);
87880d496beSPekka Enberg 
87980d496beSPekka Enberg 		len++;
88080d496beSPekka Enberg 		if (len + 2 >= line_len)
88180d496beSPekka Enberg 			continue;
88280d496beSPekka Enberg 
883c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
88480d496beSPekka Enberg 
88580d496beSPekka Enberg 		if (sym == NULL)
88680d496beSPekka Enberg 			goto out_delete_line;
88780d496beSPekka Enberg 
888439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
88900a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
89080d496beSPekka Enberg 		else {
891aeafcbafSArnaldo Carvalho de Melo 			symbols__insert(&dso->symbols[map->type], sym);
89280d496beSPekka Enberg 			nr_syms++;
89380d496beSPekka Enberg 		}
89480d496beSPekka Enberg 	}
89580d496beSPekka Enberg 
89680d496beSPekka Enberg 	free(line);
89780d496beSPekka Enberg 	fclose(file);
89880d496beSPekka Enberg 
89980d496beSPekka Enberg 	return nr_syms;
90080d496beSPekka Enberg 
90180d496beSPekka Enberg out_delete_line:
90280d496beSPekka Enberg 	free(line);
90380d496beSPekka Enberg out_failure:
90480d496beSPekka Enberg 	return -1;
90580d496beSPekka Enberg }
90680d496beSPekka Enberg 
90786470930SIngo Molnar /**
90886470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
90986470930SIngo Molnar  *
910aeafcbafSArnaldo Carvalho de Melo  * @syms: struct elf_symtab instance to iterate
91183a0944fSIngo Molnar  * @idx: uint32_t idx
91286470930SIngo Molnar  * @sym: GElf_Sym iterator
91386470930SIngo Molnar  */
91483a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
91583a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
91683a0944fSIngo Molnar 	     idx < nr_syms; \
91783a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
91886470930SIngo Molnar 
91986470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
92086470930SIngo Molnar {
92186470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
92286470930SIngo Molnar }
92386470930SIngo Molnar 
92486470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
92586470930SIngo Molnar {
92686470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
92786470930SIngo Molnar 	       sym->st_name != 0 &&
92881833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
92986470930SIngo Molnar }
93086470930SIngo Molnar 
931f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
932f1dfa0b1SArnaldo Carvalho de Melo {
933f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
934f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
935f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
936f1dfa0b1SArnaldo Carvalho de Melo }
937f1dfa0b1SArnaldo Carvalho de Melo 
9386cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
9396cfcc53eSMike Galbraith {
9406cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
9416cfcc53eSMike Galbraith 		sym->st_name != 0 &&
9426cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
9436cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
9446cfcc53eSMike Galbraith }
9456cfcc53eSMike Galbraith 
9466cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
9476cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
9486cfcc53eSMike Galbraith {
9496cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
9506cfcc53eSMike Galbraith }
9516cfcc53eSMike Galbraith 
9526cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
9536cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
9546cfcc53eSMike Galbraith {
9556cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
9566cfcc53eSMike Galbraith }
9576cfcc53eSMike Galbraith 
958f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
959f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
960f1dfa0b1SArnaldo Carvalho de Melo {
961f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
962f1dfa0b1SArnaldo Carvalho de Melo }
963f1dfa0b1SArnaldo Carvalho de Melo 
96486470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
96586470930SIngo Molnar 					const Elf_Data *symstrs)
96686470930SIngo Molnar {
96786470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
96886470930SIngo Molnar }
96986470930SIngo Molnar 
97086470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
97186470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
97283a0944fSIngo Molnar 				    size_t *idx)
97386470930SIngo Molnar {
97486470930SIngo Molnar 	Elf_Scn *sec = NULL;
97586470930SIngo Molnar 	size_t cnt = 1;
97686470930SIngo Molnar 
97786470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
97886470930SIngo Molnar 		char *str;
97986470930SIngo Molnar 
98086470930SIngo Molnar 		gelf_getshdr(sec, shp);
98186470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
98286470930SIngo Molnar 		if (!strcmp(name, str)) {
98383a0944fSIngo Molnar 			if (idx)
98483a0944fSIngo Molnar 				*idx = cnt;
98586470930SIngo Molnar 			break;
98686470930SIngo Molnar 		}
98786470930SIngo Molnar 		++cnt;
98886470930SIngo Molnar 	}
98986470930SIngo Molnar 
99086470930SIngo Molnar 	return sec;
99186470930SIngo Molnar }
99286470930SIngo Molnar 
99386470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
99486470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
99586470930SIngo Molnar 	     idx < nr_entries; \
99686470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
99786470930SIngo Molnar 
99886470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
99986470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
100086470930SIngo Molnar 	     idx < nr_entries; \
100186470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
100286470930SIngo Molnar 
1003a25e46c4SArnaldo Carvalho de Melo /*
1004a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
1005a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
1006a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
1007a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
1008a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
1009a25e46c4SArnaldo Carvalho de Melo  */
101033ff581eSJiri Olsa static int
101133ff581eSJiri Olsa dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
101282164161SArnaldo Carvalho de Melo 			    symbol_filter_t filter)
101386470930SIngo Molnar {
101486470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
101586470930SIngo Molnar 	GElf_Sym sym;
10169cffa8d5SPaul Mackerras 	u64 plt_offset;
101786470930SIngo Molnar 	GElf_Shdr shdr_plt;
101886470930SIngo Molnar 	struct symbol *f;
1019a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
102086470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
1021a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
1022a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
1023a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
102486470930SIngo Molnar 	char sympltname[1024];
1025a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
1026a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
102786470930SIngo Molnar 
1028ec5761eaSDavid Ahern 	fd = open(name, O_RDONLY);
1029a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
1030a25e46c4SArnaldo Carvalho de Melo 		goto out;
1031a25e46c4SArnaldo Carvalho de Melo 
103284087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1033a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
1034a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
1035a25e46c4SArnaldo Carvalho de Melo 
1036a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
1037a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
1038a25e46c4SArnaldo Carvalho de Melo 
1039a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
1040a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
1041a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
1042a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
1043a25e46c4SArnaldo Carvalho de Melo 
1044a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
104586470930SIngo Molnar 					  ".rela.plt", NULL);
104686470930SIngo Molnar 	if (scn_plt_rel == NULL) {
1047a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
104886470930SIngo Molnar 						  ".rel.plt", NULL);
104986470930SIngo Molnar 		if (scn_plt_rel == NULL)
1050a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
105186470930SIngo Molnar 	}
105286470930SIngo Molnar 
1053a25e46c4SArnaldo Carvalho de Melo 	err = -1;
105486470930SIngo Molnar 
1055a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
1056a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
1057a25e46c4SArnaldo Carvalho de Melo 
1058a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
1059a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
106086470930SIngo Molnar 
106186470930SIngo Molnar 	/*
106283a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
106386470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
106486470930SIngo Molnar 	 */
106586470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
106686470930SIngo Molnar 	if (reldata == NULL)
1067a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
106886470930SIngo Molnar 
106986470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
107086470930SIngo Molnar 	if (syms == NULL)
1071a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
107286470930SIngo Molnar 
1073a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
107486470930SIngo Molnar 	if (scn_symstrs == NULL)
1075a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
107686470930SIngo Molnar 
107786470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
107886470930SIngo Molnar 	if (symstrs == NULL)
1079a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
108086470930SIngo Molnar 
108186470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
108286470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
108386470930SIngo Molnar 
108486470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
108586470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
108686470930SIngo Molnar 
108786470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
108886470930SIngo Molnar 					   nr_rel_entries) {
108986470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
109086470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
109186470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
109286470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
109386470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
109486470930SIngo Molnar 
109586470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
1096c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
109786470930SIngo Molnar 			if (!f)
1098a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
109986470930SIngo Molnar 
110082164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
110182164161SArnaldo Carvalho de Melo 				symbol__delete(f);
110282164161SArnaldo Carvalho de Melo 			else {
1103aeafcbafSArnaldo Carvalho de Melo 				symbols__insert(&dso->symbols[map->type], f);
110486470930SIngo Molnar 				++nr;
110586470930SIngo Molnar 			}
110682164161SArnaldo Carvalho de Melo 		}
110786470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
110886470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
110986470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
111086470930SIngo Molnar 					  nr_rel_entries) {
111186470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
111286470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
111386470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
111486470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
111586470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
111686470930SIngo Molnar 
111786470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
1118c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
111986470930SIngo Molnar 			if (!f)
1120a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
112186470930SIngo Molnar 
112282164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
112382164161SArnaldo Carvalho de Melo 				symbol__delete(f);
112482164161SArnaldo Carvalho de Melo 			else {
1125aeafcbafSArnaldo Carvalho de Melo 				symbols__insert(&dso->symbols[map->type], f);
112686470930SIngo Molnar 				++nr;
112786470930SIngo Molnar 			}
112886470930SIngo Molnar 		}
112982164161SArnaldo Carvalho de Melo 	}
113086470930SIngo Molnar 
1131a25e46c4SArnaldo Carvalho de Melo 	err = 0;
1132a25e46c4SArnaldo Carvalho de Melo out_elf_end:
1133a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
1134a25e46c4SArnaldo Carvalho de Melo out_close:
1135a25e46c4SArnaldo Carvalho de Melo 	close(fd);
1136a25e46c4SArnaldo Carvalho de Melo 
1137a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
113886470930SIngo Molnar 		return nr;
1139a25e46c4SArnaldo Carvalho de Melo out:
1140fe2197b8SArnaldo Carvalho de Melo 	pr_debug("%s: problems reading %s PLT info.\n",
1141aeafcbafSArnaldo Carvalho de Melo 		 __func__, dso->long_name);
1142a25e46c4SArnaldo Carvalho de Melo 	return 0;
114386470930SIngo Molnar }
114486470930SIngo Molnar 
1145aeafcbafSArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
1146d45868d3SArnaldo Carvalho de Melo {
1147d45868d3SArnaldo Carvalho de Melo 	switch (type) {
1148d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1149aeafcbafSArnaldo Carvalho de Melo 		return elf_sym__is_function(sym);
1150f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
1151aeafcbafSArnaldo Carvalho de Melo 		return elf_sym__is_object(sym);
1152d45868d3SArnaldo Carvalho de Melo 	default:
1153d45868d3SArnaldo Carvalho de Melo 		return false;
1154d45868d3SArnaldo Carvalho de Melo 	}
1155d45868d3SArnaldo Carvalho de Melo }
1156d45868d3SArnaldo Carvalho de Melo 
1157aeafcbafSArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
1158aeafcbafSArnaldo Carvalho de Melo 			  enum map_type type)
1159d45868d3SArnaldo Carvalho de Melo {
1160d45868d3SArnaldo Carvalho de Melo 	switch (type) {
1161d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
1162aeafcbafSArnaldo Carvalho de Melo 		return elf_sec__is_text(shdr, secstrs);
1163f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
1164aeafcbafSArnaldo Carvalho de Melo 		return elf_sec__is_data(shdr, secstrs);
1165d45868d3SArnaldo Carvalho de Melo 	default:
1166d45868d3SArnaldo Carvalho de Melo 		return false;
1167d45868d3SArnaldo Carvalho de Melo 	}
1168d45868d3SArnaldo Carvalho de Melo }
1169d45868d3SArnaldo Carvalho de Melo 
117070c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
117170c3856bSEric B Munson {
117270c3856bSEric B Munson 	Elf_Scn *sec = NULL;
117370c3856bSEric B Munson 	GElf_Shdr shdr;
117470c3856bSEric B Munson 	size_t cnt = 1;
117570c3856bSEric B Munson 
117670c3856bSEric B Munson 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
117770c3856bSEric B Munson 		gelf_getshdr(sec, &shdr);
117870c3856bSEric B Munson 
117970c3856bSEric B Munson 		if ((addr >= shdr.sh_addr) &&
118070c3856bSEric B Munson 		    (addr < (shdr.sh_addr + shdr.sh_size)))
118170c3856bSEric B Munson 			return cnt;
118270c3856bSEric B Munson 
118370c3856bSEric B Munson 		++cnt;
118470c3856bSEric B Munson 	}
118570c3856bSEric B Munson 
118670c3856bSEric B Munson 	return -1;
118770c3856bSEric B Munson }
118870c3856bSEric B Munson 
11898db4841fSJiri Olsa static int dso__swap_init(struct dso *dso, unsigned char eidata)
11908db4841fSJiri Olsa {
11918db4841fSJiri Olsa 	static unsigned int const endian = 1;
11928db4841fSJiri Olsa 
11938db4841fSJiri Olsa 	dso->needs_swap = DSO_SWAP__NO;
11948db4841fSJiri Olsa 
11958db4841fSJiri Olsa 	switch (eidata) {
11968db4841fSJiri Olsa 	case ELFDATA2LSB:
11978db4841fSJiri Olsa 		/* We are big endian, DSO is little endian. */
11988db4841fSJiri Olsa 		if (*(unsigned char const *)&endian != 1)
11998db4841fSJiri Olsa 			dso->needs_swap = DSO_SWAP__YES;
12008db4841fSJiri Olsa 		break;
12018db4841fSJiri Olsa 
12028db4841fSJiri Olsa 	case ELFDATA2MSB:
12038db4841fSJiri Olsa 		/* We are little endian, DSO is big endian. */
12048db4841fSJiri Olsa 		if (*(unsigned char const *)&endian != 0)
12058db4841fSJiri Olsa 			dso->needs_swap = DSO_SWAP__YES;
12068db4841fSJiri Olsa 		break;
12078db4841fSJiri Olsa 
12088db4841fSJiri Olsa 	default:
12098db4841fSJiri Olsa 		pr_err("unrecognized DSO data encoding %d\n", eidata);
12108db4841fSJiri Olsa 		return -EINVAL;
12118db4841fSJiri Olsa 	}
12128db4841fSJiri Olsa 
12138db4841fSJiri Olsa 	return 0;
12148db4841fSJiri Olsa }
12158db4841fSJiri Olsa 
1216aeafcbafSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
12176da80ce8SDave Martin 			 int fd, symbol_filter_t filter, int kmodule,
12186da80ce8SDave Martin 			 int want_symtab)
121986470930SIngo Molnar {
1220aeafcbafSArnaldo Carvalho de Melo 	struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
12212e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
1222aeafcbafSArnaldo Carvalho de Melo 	struct dso *curr_dso = dso;
12236cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
122486470930SIngo Molnar 	uint32_t nr_syms;
122586470930SIngo Molnar 	int err = -1;
122683a0944fSIngo Molnar 	uint32_t idx;
122786470930SIngo Molnar 	GElf_Ehdr ehdr;
122870c3856bSEric B Munson 	GElf_Shdr shdr, opdshdr;
122970c3856bSEric B Munson 	Elf_Data *syms, *opddata = NULL;
123086470930SIngo Molnar 	GElf_Sym sym;
123170c3856bSEric B Munson 	Elf_Scn *sec, *sec_strndx, *opdsec;
123286470930SIngo Molnar 	Elf *elf;
1233439d473bSArnaldo Carvalho de Melo 	int nr = 0;
123470c3856bSEric B Munson 	size_t opdidx = 0;
123586470930SIngo Molnar 
123684087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
123786470930SIngo Molnar 	if (elf == NULL) {
12388b1389efSDave Martin 		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
123986470930SIngo Molnar 		goto out_close;
124086470930SIngo Molnar 	}
124186470930SIngo Molnar 
124286470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
12438b1389efSDave Martin 		pr_debug("%s: cannot get elf header.\n", __func__);
124486470930SIngo Molnar 		goto out_elf_end;
124586470930SIngo Molnar 	}
124686470930SIngo Molnar 
12478db4841fSJiri Olsa 	if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
12488db4841fSJiri Olsa 		goto out_elf_end;
12498db4841fSJiri Olsa 
12506da80ce8SDave Martin 	/* Always reject images with a mismatched build-id: */
1251aeafcbafSArnaldo Carvalho de Melo 	if (dso->has_build_id) {
125221916c38SDave Martin 		u8 build_id[BUILD_ID_SIZE];
125321916c38SDave Martin 
1254be96ea8fSStephane Eranian 		if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
125521916c38SDave Martin 			goto out_elf_end;
125621916c38SDave Martin 
1257aeafcbafSArnaldo Carvalho de Melo 		if (!dso__build_id_equal(dso, build_id))
125821916c38SDave Martin 			goto out_elf_end;
125921916c38SDave Martin 	}
126021916c38SDave Martin 
126186470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
126286470930SIngo Molnar 	if (sec == NULL) {
12636da80ce8SDave Martin 		if (want_symtab)
12646da80ce8SDave Martin 			goto out_elf_end;
12656da80ce8SDave Martin 
1266a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1267a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
126886470930SIngo Molnar 			goto out_elf_end;
126986470930SIngo Molnar 	}
127086470930SIngo Molnar 
127170c3856bSEric B Munson 	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1272adb09184SAnton Blanchard 	if (opdshdr.sh_type != SHT_PROGBITS)
1273adb09184SAnton Blanchard 		opdsec = NULL;
127470c3856bSEric B Munson 	if (opdsec)
127570c3856bSEric B Munson 		opddata = elf_rawdata(opdsec, NULL);
127670c3856bSEric B Munson 
127786470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
127886470930SIngo Molnar 	if (syms == NULL)
127986470930SIngo Molnar 		goto out_elf_end;
128086470930SIngo Molnar 
128186470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
128286470930SIngo Molnar 	if (sec == NULL)
128386470930SIngo Molnar 		goto out_elf_end;
128486470930SIngo Molnar 
128586470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
128686470930SIngo Molnar 	if (symstrs == NULL)
128786470930SIngo Molnar 		goto out_elf_end;
128886470930SIngo Molnar 
12896cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
12906cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
12916cfcc53eSMike Galbraith 		goto out_elf_end;
12926cfcc53eSMike Galbraith 
12936cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
12949b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
12956cfcc53eSMike Galbraith 		goto out_elf_end;
12966cfcc53eSMike Galbraith 
129786470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
129886470930SIngo Molnar 
1299e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
1300aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_USER) {
1301aeafcbafSArnaldo Carvalho de Melo 		dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
130230d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
1303f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
130430d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
1305aeafcbafSArnaldo Carvalho de Melo 	} else {
1306aeafcbafSArnaldo Carvalho de Melo 		dso->adjust_symbols = 0;
1307aeafcbafSArnaldo Carvalho de Melo 	}
130883a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
130986470930SIngo Molnar 		struct symbol *f;
131056b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
13112e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
13126cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
13136cfcc53eSMike Galbraith 		const char *section_name;
131486470930SIngo Molnar 
13159de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
13169de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
13179de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
131856b03f3cSArnaldo Carvalho de Melo 
1319d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
132086470930SIngo Molnar 			continue;
132186470930SIngo Molnar 
1322696b97a5SDave Martin 		/* Reject ARM ELF "mapping symbols": these aren't unique and
1323696b97a5SDave Martin 		 * don't identify functions, so will confuse the profile
1324696b97a5SDave Martin 		 * output: */
1325696b97a5SDave Martin 		if (ehdr.e_machine == EM_ARM) {
1326696b97a5SDave Martin 			if (!strcmp(elf_name, "$a") ||
1327696b97a5SDave Martin 			    !strcmp(elf_name, "$d") ||
1328696b97a5SDave Martin 			    !strcmp(elf_name, "$t"))
1329696b97a5SDave Martin 				continue;
1330696b97a5SDave Martin 		}
1331696b97a5SDave Martin 
133270c3856bSEric B Munson 		if (opdsec && sym.st_shndx == opdidx) {
133370c3856bSEric B Munson 			u32 offset = sym.st_value - opdshdr.sh_addr;
133470c3856bSEric B Munson 			u64 *opd = opddata->d_buf + offset;
13358db4841fSJiri Olsa 			sym.st_value = DSO__SWAP(dso, u64, *opd);
133670c3856bSEric B Munson 			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
133770c3856bSEric B Munson 		}
133870c3856bSEric B Munson 
133986470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
134086470930SIngo Molnar 		if (!sec)
134186470930SIngo Molnar 			goto out_elf_end;
134286470930SIngo Molnar 
134386470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
13446cfcc53eSMike Galbraith 
1345d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
13466cfcc53eSMike Galbraith 			continue;
13476cfcc53eSMike Galbraith 
13486cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
134986470930SIngo Molnar 
1350b2f8fb23SDr. David Alan Gilbert 		/* On ARM, symbols for thumb functions have 1 added to
1351b2f8fb23SDr. David Alan Gilbert 		 * the symbol address as a flag - remove it */
1352b2f8fb23SDr. David Alan Gilbert 		if ((ehdr.e_machine == EM_ARM) &&
1353b2f8fb23SDr. David Alan Gilbert 		    (map->type == MAP__FUNCTION) &&
1354b2f8fb23SDr. David Alan Gilbert 		    (sym.st_value & 1))
1355b2f8fb23SDr. David Alan Gilbert 			--sym.st_value;
1356b2f8fb23SDr. David Alan Gilbert 
1357aeafcbafSArnaldo Carvalho de Melo 		if (dso->kernel != DSO_TYPE_USER || kmodule) {
13582e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
13592e538c4aSArnaldo Carvalho de Melo 
13602e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1361b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1362aeafcbafSArnaldo Carvalho de Melo 				    dso->short_name_len)) == 0)
13632e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
13642e538c4aSArnaldo Carvalho de Melo 
13652e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
13662e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
1367aeafcbafSArnaldo Carvalho de Melo 				curr_dso = dso;
13682e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1369af427bf5SArnaldo Carvalho de Melo 			}
1370af427bf5SArnaldo Carvalho de Melo 
13712e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
1372aeafcbafSArnaldo Carvalho de Melo 				 "%s%s", dso->short_name, section_name);
13732e538c4aSArnaldo Carvalho de Melo 
13749de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
13752e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
13762e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
13772e538c4aSArnaldo Carvalho de Melo 
13782e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
13792e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
13802e538c4aSArnaldo Carvalho de Melo 
138100a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
13822e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
13832e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1384aeafcbafSArnaldo Carvalho de Melo 				curr_dso->kernel = dso->kernel;
1385aeafcbafSArnaldo Carvalho de Melo 				curr_dso->long_name = dso->long_name;
1386aeafcbafSArnaldo Carvalho de Melo 				curr_dso->long_name_len = dso->long_name_len;
13873610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
13886275ce2dSArnaldo Carvalho de Melo 						     map->type);
13892e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
13902e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
13912e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
13922e538c4aSArnaldo Carvalho de Melo 				}
1393ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1394ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1395aeafcbafSArnaldo Carvalho de Melo 				curr_dso->symtab_type = dso->symtab_type;
13969de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1397aeafcbafSArnaldo Carvalho de Melo 				dsos__add(&dso->node, curr_dso);
13986275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
13992e538c4aSArnaldo Carvalho de Melo 			} else
14002e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
14012e538c4aSArnaldo Carvalho de Melo 
14022e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
14032e538c4aSArnaldo Carvalho de Melo 		}
14042e538c4aSArnaldo Carvalho de Melo 
14052e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
14069486aa38SArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
14079486aa38SArnaldo Carvalho de Melo 				  "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
140829a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
140929a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
141086470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1411af427bf5SArnaldo Carvalho de Melo 		}
141228ac909bSArnaldo Carvalho de Melo 		/*
141328ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
141428ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
141528ac909bSArnaldo Carvalho de Melo 		 * to it...
141628ac909bSArnaldo Carvalho de Melo 		 */
141783a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
141828ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
141983a0944fSIngo Molnar 			elf_name = demangled;
14202e538c4aSArnaldo Carvalho de Melo new_symbol:
1421c408fedfSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size,
1422c408fedfSArnaldo Carvalho de Melo 				GELF_ST_BIND(sym.st_info), elf_name);
142328ac909bSArnaldo Carvalho de Melo 		free(demangled);
142486470930SIngo Molnar 		if (!f)
142586470930SIngo Molnar 			goto out_elf_end;
142686470930SIngo Molnar 
14272e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
142800a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
142986470930SIngo Molnar 		else {
14306a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
143186470930SIngo Molnar 			nr++;
143286470930SIngo Molnar 		}
143386470930SIngo Molnar 	}
143486470930SIngo Molnar 
14352e538c4aSArnaldo Carvalho de Melo 	/*
14362e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
14372e538c4aSArnaldo Carvalho de Melo 	 */
14386275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
1439694bf407SAnton Blanchard 		symbols__fixup_duplicate(&dso->symbols[map->type]);
1440aeafcbafSArnaldo Carvalho de Melo 		symbols__fixup_end(&dso->symbols[map->type]);
14416275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
14426275ce2dSArnaldo Carvalho de Melo 			/*
14436275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
14446275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
14456275ce2dSArnaldo Carvalho de Melo 			 */
14466275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
14476275ce2dSArnaldo Carvalho de Melo 		}
14486275ce2dSArnaldo Carvalho de Melo 	}
144986470930SIngo Molnar 	err = nr;
145086470930SIngo Molnar out_elf_end:
145186470930SIngo Molnar 	elf_end(elf);
145286470930SIngo Molnar out_close:
145386470930SIngo Molnar 	return err;
145486470930SIngo Molnar }
145586470930SIngo Molnar 
1456aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
145778075caaSArnaldo Carvalho de Melo {
1458aeafcbafSArnaldo Carvalho de Melo 	return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
145978075caaSArnaldo Carvalho de Melo }
146078075caaSArnaldo Carvalho de Melo 
1461a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
146257f395a7SFrederic Weisbecker {
1463e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
146457f395a7SFrederic Weisbecker 	struct dso *pos;
146557f395a7SFrederic Weisbecker 
14666122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
14676122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
14686122e4e4SArnaldo Carvalho de Melo 			continue;
1469f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
1470f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
1471f6e1467dSArnaldo Carvalho de Melo 			continue;
1472f6e1467dSArnaldo Carvalho de Melo 		}
1473e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1474e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1475e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1476e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
147757f395a7SFrederic Weisbecker 		}
14786122e4e4SArnaldo Carvalho de Melo 	}
147957f395a7SFrederic Weisbecker 
1480e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
148157f395a7SFrederic Weisbecker }
148257f395a7SFrederic Weisbecker 
1483fd7a346eSArnaldo Carvalho de Melo /*
1484fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1485fd7a346eSArnaldo Carvalho de Melo  */
1486fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1487fd7a346eSArnaldo Carvalho de Melo 
148821916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size)
14894d1e00a8SArnaldo Carvalho de Melo {
149021916c38SDave Martin 	int err = -1;
14914d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
14924d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1493fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
14944d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1495e57cfcdaSPekka Enberg 	Elf_Kind ek;
1496fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
14974d1e00a8SArnaldo Carvalho de Melo 
14982643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
14992643ce11SArnaldo Carvalho de Melo 		goto out;
15002643ce11SArnaldo Carvalho de Melo 
1501e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1502e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
150321916c38SDave Martin 		goto out;
1504e57cfcdaSPekka Enberg 
15054d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
15066beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
150721916c38SDave Martin 		goto out;
15084d1e00a8SArnaldo Carvalho de Melo 	}
15094d1e00a8SArnaldo Carvalho de Melo 
15101388d715SJiri Olsa 	/*
15111388d715SJiri Olsa 	 * Check following sections for notes:
15121388d715SJiri Olsa 	 *   '.note.gnu.build-id'
15131388d715SJiri Olsa 	 *   '.notes'
15141388d715SJiri Olsa 	 *   '.note' (VDSO specific)
15151388d715SJiri Olsa 	 */
15161388d715SJiri Olsa 	do {
15172643ce11SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
15182643ce11SArnaldo Carvalho de Melo 					  ".note.gnu.build-id", NULL);
15191388d715SJiri Olsa 		if (sec)
15201388d715SJiri Olsa 			break;
15211388d715SJiri Olsa 
1522fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1523fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
15241388d715SJiri Olsa 		if (sec)
15251388d715SJiri Olsa 			break;
15261388d715SJiri Olsa 
15271388d715SJiri Olsa 		sec = elf_section_by_name(elf, &ehdr, &shdr,
15281388d715SJiri Olsa 					  ".note", NULL);
15291388d715SJiri Olsa 		if (sec)
15301388d715SJiri Olsa 			break;
15311388d715SJiri Olsa 
15321388d715SJiri Olsa 		return err;
15331388d715SJiri Olsa 
15341388d715SJiri Olsa 	} while (0);
15354d1e00a8SArnaldo Carvalho de Melo 
1536fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1537fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
153821916c38SDave Martin 		goto out;
1539fd7a346eSArnaldo Carvalho de Melo 
1540fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1541fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1542fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1543be96ea8fSStephane Eranian 		size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
1544fd7a346eSArnaldo Carvalho de Melo 		       descsz = NOTE_ALIGN(nhdr->n_descsz);
1545fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1546fd7a346eSArnaldo Carvalho de Melo 
1547fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1548fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1549fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1550fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1551fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1552fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1553be96ea8fSStephane Eranian 				size_t sz = min(size, descsz);
1554be96ea8fSStephane Eranian 				memcpy(bf, ptr, sz);
1555be96ea8fSStephane Eranian 				memset(bf + sz, 0, size - sz);
1556be96ea8fSStephane Eranian 				err = descsz;
1557fd7a346eSArnaldo Carvalho de Melo 				break;
1558fd7a346eSArnaldo Carvalho de Melo 			}
1559fd7a346eSArnaldo Carvalho de Melo 		}
1560fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1561fd7a346eSArnaldo Carvalho de Melo 	}
156221916c38SDave Martin 
156321916c38SDave Martin out:
156421916c38SDave Martin 	return err;
156521916c38SDave Martin }
156621916c38SDave Martin 
156721916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size)
156821916c38SDave Martin {
156921916c38SDave Martin 	int fd, err = -1;
157021916c38SDave Martin 	Elf *elf;
157121916c38SDave Martin 
157221916c38SDave Martin 	if (size < BUILD_ID_SIZE)
157321916c38SDave Martin 		goto out;
157421916c38SDave Martin 
157521916c38SDave Martin 	fd = open(filename, O_RDONLY);
157621916c38SDave Martin 	if (fd < 0)
157721916c38SDave Martin 		goto out;
157821916c38SDave Martin 
157921916c38SDave Martin 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
158021916c38SDave Martin 	if (elf == NULL) {
158121916c38SDave Martin 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
158221916c38SDave Martin 		goto out_close;
158321916c38SDave Martin 	}
158421916c38SDave Martin 
158521916c38SDave Martin 	err = elf_read_build_id(elf, bf, size);
158621916c38SDave Martin 
15872643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
15882643ce11SArnaldo Carvalho de Melo out_close:
15892643ce11SArnaldo Carvalho de Melo 	close(fd);
15902643ce11SArnaldo Carvalho de Melo out:
15912643ce11SArnaldo Carvalho de Melo 	return err;
15922643ce11SArnaldo Carvalho de Melo }
15932643ce11SArnaldo Carvalho de Melo 
1594f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1595f1617b40SArnaldo Carvalho de Melo {
1596f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1597f1617b40SArnaldo Carvalho de Melo 
1598f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1599f1617b40SArnaldo Carvalho de Melo 		goto out;
1600f1617b40SArnaldo Carvalho de Melo 
1601f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1602f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1603f1617b40SArnaldo Carvalho de Melo 		goto out;
1604f1617b40SArnaldo Carvalho de Melo 
1605f1617b40SArnaldo Carvalho de Melo 	while (1) {
1606f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1607f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1608be96ea8fSStephane Eranian 		size_t namesz, descsz;
1609f1617b40SArnaldo Carvalho de Melo 
1610f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1611f1617b40SArnaldo Carvalho de Melo 			break;
1612f1617b40SArnaldo Carvalho de Melo 
1613fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1614fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1615f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1616f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1617be96ea8fSStephane Eranian 			if (read(fd, bf, namesz) != (ssize_t)namesz)
1618f1617b40SArnaldo Carvalho de Melo 				break;
1619f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1620be96ea8fSStephane Eranian 				size_t sz = min(descsz, size);
1621be96ea8fSStephane Eranian 				if (read(fd, build_id, sz) == (ssize_t)sz) {
1622be96ea8fSStephane Eranian 					memset(build_id + sz, 0, size - sz);
1623f1617b40SArnaldo Carvalho de Melo 					err = 0;
1624f1617b40SArnaldo Carvalho de Melo 					break;
1625f1617b40SArnaldo Carvalho de Melo 				}
1626be96ea8fSStephane Eranian 			} else if (read(fd, bf, descsz) != (ssize_t)descsz)
1627f1617b40SArnaldo Carvalho de Melo 				break;
1628f1617b40SArnaldo Carvalho de Melo 		} else {
1629f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1630f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1631f1617b40SArnaldo Carvalho de Melo 				break;
1632f1617b40SArnaldo Carvalho de Melo 		}
1633f1617b40SArnaldo Carvalho de Melo 	}
1634f1617b40SArnaldo Carvalho de Melo 	close(fd);
1635f1617b40SArnaldo Carvalho de Melo out:
1636f1617b40SArnaldo Carvalho de Melo 	return err;
1637f1617b40SArnaldo Carvalho de Melo }
1638f1617b40SArnaldo Carvalho de Melo 
1639209bd9e3SPierre-Loup A. Griffais static int filename__read_debuglink(const char *filename,
1640209bd9e3SPierre-Loup A. Griffais 				    char *debuglink, size_t size)
1641209bd9e3SPierre-Loup A. Griffais {
1642209bd9e3SPierre-Loup A. Griffais 	int fd, err = -1;
1643209bd9e3SPierre-Loup A. Griffais 	Elf *elf;
1644209bd9e3SPierre-Loup A. Griffais 	GElf_Ehdr ehdr;
1645209bd9e3SPierre-Loup A. Griffais 	GElf_Shdr shdr;
1646209bd9e3SPierre-Loup A. Griffais 	Elf_Data *data;
1647209bd9e3SPierre-Loup A. Griffais 	Elf_Scn *sec;
1648209bd9e3SPierre-Loup A. Griffais 	Elf_Kind ek;
1649209bd9e3SPierre-Loup A. Griffais 
1650209bd9e3SPierre-Loup A. Griffais 	fd = open(filename, O_RDONLY);
1651209bd9e3SPierre-Loup A. Griffais 	if (fd < 0)
1652209bd9e3SPierre-Loup A. Griffais 		goto out;
1653209bd9e3SPierre-Loup A. Griffais 
1654209bd9e3SPierre-Loup A. Griffais 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1655209bd9e3SPierre-Loup A. Griffais 	if (elf == NULL) {
1656209bd9e3SPierre-Loup A. Griffais 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1657209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1658209bd9e3SPierre-Loup A. Griffais 	}
1659209bd9e3SPierre-Loup A. Griffais 
1660209bd9e3SPierre-Loup A. Griffais 	ek = elf_kind(elf);
1661209bd9e3SPierre-Loup A. Griffais 	if (ek != ELF_K_ELF)
1662209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1663209bd9e3SPierre-Loup A. Griffais 
1664209bd9e3SPierre-Loup A. Griffais 	if (gelf_getehdr(elf, &ehdr) == NULL) {
1665209bd9e3SPierre-Loup A. Griffais 		pr_err("%s: cannot get elf header.\n", __func__);
1666209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1667209bd9e3SPierre-Loup A. Griffais 	}
1668209bd9e3SPierre-Loup A. Griffais 
1669209bd9e3SPierre-Loup A. Griffais 	sec = elf_section_by_name(elf, &ehdr, &shdr,
1670209bd9e3SPierre-Loup A. Griffais 				  ".gnu_debuglink", NULL);
1671209bd9e3SPierre-Loup A. Griffais 	if (sec == NULL)
1672209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1673209bd9e3SPierre-Loup A. Griffais 
1674209bd9e3SPierre-Loup A. Griffais 	data = elf_getdata(sec, NULL);
1675209bd9e3SPierre-Loup A. Griffais 	if (data == NULL)
1676209bd9e3SPierre-Loup A. Griffais 		goto out_close;
1677209bd9e3SPierre-Loup A. Griffais 
1678209bd9e3SPierre-Loup A. Griffais 	/* the start of this section is a zero-terminated string */
1679209bd9e3SPierre-Loup A. Griffais 	strncpy(debuglink, data->d_buf, size);
1680209bd9e3SPierre-Loup A. Griffais 
1681209bd9e3SPierre-Loup A. Griffais 	elf_end(elf);
1682209bd9e3SPierre-Loup A. Griffais 
1683209bd9e3SPierre-Loup A. Griffais out_close:
1684209bd9e3SPierre-Loup A. Griffais 	close(fd);
1685209bd9e3SPierre-Loup A. Griffais out:
1686209bd9e3SPierre-Loup A. Griffais 	return err;
1687209bd9e3SPierre-Loup A. Griffais }
1688209bd9e3SPierre-Loup A. Griffais 
1689aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso)
169094cb9e38SArnaldo Carvalho de Melo {
169194cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
169244f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__KALLSYMS]		= 'k',
169344f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__JAVA_JIT]		= 'j',
169444f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__DEBUGLINK]		= 'l',
169544f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__BUILD_ID_CACHE]	= 'B',
169644f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__FEDORA_DEBUGINFO]	= 'f',
169744f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__UBUNTU_DEBUGINFO]	= 'u',
169844f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__BUILDID_DEBUGINFO]	= 'b',
169944f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__SYSTEM_PATH_DSO]	= 'd',
170044f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]	= 'K',
170144f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__GUEST_KALLSYMS]	= 'g',
170244f24cb3SJiri Olsa 		[DSO_BINARY_TYPE__GUEST_KMODULE]	= 'G',
170394cb9e38SArnaldo Carvalho de Melo 	};
170494cb9e38SArnaldo Carvalho de Melo 
170544f24cb3SJiri Olsa 	if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
170694cb9e38SArnaldo Carvalho de Melo 		return '!';
1707aeafcbafSArnaldo Carvalho de Melo 	return origin[dso->symtab_type];
170894cb9e38SArnaldo Carvalho de Melo }
170994cb9e38SArnaldo Carvalho de Melo 
171044f24cb3SJiri Olsa int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
171144f24cb3SJiri Olsa 			  char *root_dir, char *file, size_t size)
171244f24cb3SJiri Olsa {
171344f24cb3SJiri Olsa 	char build_id_hex[BUILD_ID_SIZE * 2 + 1];
171444f24cb3SJiri Olsa 	int ret = 0;
171544f24cb3SJiri Olsa 
171644f24cb3SJiri Olsa 	switch (type) {
171744f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__DEBUGLINK: {
171844f24cb3SJiri Olsa 		char *debuglink;
171944f24cb3SJiri Olsa 
172044f24cb3SJiri Olsa 		strncpy(file, dso->long_name, size);
172144f24cb3SJiri Olsa 		debuglink = file + dso->long_name_len;
172244f24cb3SJiri Olsa 		while (debuglink != file && *debuglink != '/')
172344f24cb3SJiri Olsa 			debuglink--;
172444f24cb3SJiri Olsa 		if (*debuglink == '/')
172544f24cb3SJiri Olsa 			debuglink++;
172644f24cb3SJiri Olsa 		filename__read_debuglink(dso->long_name, debuglink,
172744f24cb3SJiri Olsa 					 size - (debuglink - file));
172844f24cb3SJiri Olsa 		}
172944f24cb3SJiri Olsa 		break;
173044f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
173144f24cb3SJiri Olsa 		/* skip the locally configured cache if a symfs is given */
173244f24cb3SJiri Olsa 		if (symbol_conf.symfs[0] ||
173344f24cb3SJiri Olsa 		    (dso__build_id_filename(dso, file, size) == NULL))
173444f24cb3SJiri Olsa 			ret = -1;
173544f24cb3SJiri Olsa 		break;
173644f24cb3SJiri Olsa 
173744f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
173844f24cb3SJiri Olsa 		snprintf(file, size, "%s/usr/lib/debug%s.debug",
173944f24cb3SJiri Olsa 			 symbol_conf.symfs, dso->long_name);
174044f24cb3SJiri Olsa 		break;
174144f24cb3SJiri Olsa 
174244f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
174344f24cb3SJiri Olsa 		snprintf(file, size, "%s/usr/lib/debug%s",
174444f24cb3SJiri Olsa 			 symbol_conf.symfs, dso->long_name);
174544f24cb3SJiri Olsa 		break;
174644f24cb3SJiri Olsa 
174744f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
174844f24cb3SJiri Olsa 		if (!dso->has_build_id) {
174944f24cb3SJiri Olsa 			ret = -1;
175044f24cb3SJiri Olsa 			break;
175144f24cb3SJiri Olsa 		}
175244f24cb3SJiri Olsa 
175344f24cb3SJiri Olsa 		build_id__sprintf(dso->build_id,
175444f24cb3SJiri Olsa 				  sizeof(dso->build_id),
175544f24cb3SJiri Olsa 				  build_id_hex);
175644f24cb3SJiri Olsa 		snprintf(file, size,
175744f24cb3SJiri Olsa 			 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
175844f24cb3SJiri Olsa 			 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
175944f24cb3SJiri Olsa 		break;
176044f24cb3SJiri Olsa 
176144f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
176244f24cb3SJiri Olsa 		snprintf(file, size, "%s%s",
176344f24cb3SJiri Olsa 			 symbol_conf.symfs, dso->long_name);
176444f24cb3SJiri Olsa 		break;
176544f24cb3SJiri Olsa 
176644f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__GUEST_KMODULE:
176744f24cb3SJiri Olsa 		snprintf(file, size, "%s%s%s", symbol_conf.symfs,
176844f24cb3SJiri Olsa 			 root_dir, dso->long_name);
176944f24cb3SJiri Olsa 		break;
177044f24cb3SJiri Olsa 
177144f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
177244f24cb3SJiri Olsa 		snprintf(file, size, "%s%s", symbol_conf.symfs,
177344f24cb3SJiri Olsa 			 dso->long_name);
177444f24cb3SJiri Olsa 		break;
177544f24cb3SJiri Olsa 
177644f24cb3SJiri Olsa 	default:
177744f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__KALLSYMS:
177844f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
177944f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__JAVA_JIT:
178044f24cb3SJiri Olsa 	case DSO_BINARY_TYPE__NOT_FOUND:
178144f24cb3SJiri Olsa 		ret = -1;
178244f24cb3SJiri Olsa 		break;
178344f24cb3SJiri Olsa 	}
178444f24cb3SJiri Olsa 
178544f24cb3SJiri Olsa 	return ret;
178644f24cb3SJiri Olsa }
178744f24cb3SJiri Olsa 
1788aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
178986470930SIngo Molnar {
1790c338aee8SArnaldo Carvalho de Melo 	char *name;
179186470930SIngo Molnar 	int ret = -1;
179286470930SIngo Molnar 	int fd;
179344f24cb3SJiri Olsa 	u_int i;
179423346f21SArnaldo Carvalho de Melo 	struct machine *machine;
179544f24cb3SJiri Olsa 	char *root_dir = (char *) "";
17966da80ce8SDave Martin 	int want_symtab;
179786470930SIngo Molnar 
1798aeafcbafSArnaldo Carvalho de Melo 	dso__set_loaded(dso, map->type);
179966bd8424SArnaldo Carvalho de Melo 
1800aeafcbafSArnaldo Carvalho de Melo 	if (dso->kernel == DSO_TYPE_KERNEL)
1801aeafcbafSArnaldo Carvalho de Melo 		return dso__load_kernel_sym(dso, map, filter);
1802aeafcbafSArnaldo Carvalho de Melo 	else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1803aeafcbafSArnaldo Carvalho de Melo 		return dso__load_guest_kernel_sym(dso, map, filter);
1804a1645ce1SZhang, Yanmin 
180523346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
180623346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1807a1645ce1SZhang, Yanmin 	else
180823346f21SArnaldo Carvalho de Melo 		machine = NULL;
1809c338aee8SArnaldo Carvalho de Melo 
181044f24cb3SJiri Olsa 	name = malloc(PATH_MAX);
181186470930SIngo Molnar 	if (!name)
181286470930SIngo Molnar 		return -1;
181386470930SIngo Molnar 
1814aeafcbafSArnaldo Carvalho de Melo 	dso->adjust_symbols = 0;
1815f5812a7aSArnaldo Carvalho de Melo 
1816aeafcbafSArnaldo Carvalho de Melo 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1817981c1252SPekka Enberg 		struct stat st;
1818981c1252SPekka Enberg 
1819e9b52ef2SVasiliy Kulikov 		if (lstat(dso->name, &st) < 0)
1820981c1252SPekka Enberg 			return -1;
1821981c1252SPekka Enberg 
1822981c1252SPekka Enberg 		if (st.st_uid && (st.st_uid != geteuid())) {
1823981c1252SPekka Enberg 			pr_warning("File %s not owned by current user or root, "
1824981c1252SPekka Enberg 				"ignoring it.\n", dso->name);
1825981c1252SPekka Enberg 			return -1;
1826981c1252SPekka Enberg 		}
1827981c1252SPekka Enberg 
1828aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(dso, map, filter);
182944f24cb3SJiri Olsa 		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
183044f24cb3SJiri Olsa 					     DSO_BINARY_TYPE__NOT_FOUND;
183194cb9e38SArnaldo Carvalho de Melo 		return ret;
183294cb9e38SArnaldo Carvalho de Melo 	}
183394cb9e38SArnaldo Carvalho de Melo 
183444f24cb3SJiri Olsa 	if (machine)
183544f24cb3SJiri Olsa 		root_dir = machine->root_dir;
183644f24cb3SJiri Olsa 
18376da80ce8SDave Martin 	/* Iterate over candidate debug images.
18386da80ce8SDave Martin 	 * On the first pass, only load images if they have a full symtab.
18396da80ce8SDave Martin 	 * Failing that, do a second pass where we accept .dynsym also
18406da80ce8SDave Martin 	 */
184160e4b10cSArnaldo Carvalho de Melo 	want_symtab = 1;
184260e4b10cSArnaldo Carvalho de Melo restart:
184344f24cb3SJiri Olsa 	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
184444f24cb3SJiri Olsa 
184544f24cb3SJiri Olsa 		dso->symtab_type = binary_type_symtab[i];
184644f24cb3SJiri Olsa 
184744f24cb3SJiri Olsa 		if (dso__binary_type_file(dso, dso->symtab_type,
184844f24cb3SJiri Olsa 					  root_dir, name, PATH_MAX))
18496da80ce8SDave Martin 			continue;
185086470930SIngo Molnar 
18516da80ce8SDave Martin 		/* Name is now the name of the next image to try */
18526da80ce8SDave Martin 		fd = open(name, O_RDONLY);
18536da80ce8SDave Martin 		if (fd < 0)
18546da80ce8SDave Martin 			continue;
18556da80ce8SDave Martin 
1856aeafcbafSArnaldo Carvalho de Melo 		ret = dso__load_sym(dso, map, name, fd, filter, 0,
18576da80ce8SDave Martin 				    want_symtab);
185886470930SIngo Molnar 		close(fd);
185986470930SIngo Molnar 
186086470930SIngo Molnar 		/*
18616da80ce8SDave Martin 		 * Some people seem to have debuginfo files _WITHOUT_ debug
18626da80ce8SDave Martin 		 * info!?!?
186386470930SIngo Molnar 		 */
186486470930SIngo Molnar 		if (!ret)
18656da80ce8SDave Martin 			continue;
186686470930SIngo Molnar 
1867a25e46c4SArnaldo Carvalho de Melo 		if (ret > 0) {
186833ff581eSJiri Olsa 			int nr_plt;
186933ff581eSJiri Olsa 
187033ff581eSJiri Olsa 			nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter);
1871a25e46c4SArnaldo Carvalho de Melo 			if (nr_plt > 0)
1872a25e46c4SArnaldo Carvalho de Melo 				ret += nr_plt;
18736da80ce8SDave Martin 			break;
1874a25e46c4SArnaldo Carvalho de Melo 		}
18756da80ce8SDave Martin 	}
18766da80ce8SDave Martin 
187760e4b10cSArnaldo Carvalho de Melo 	/*
187860e4b10cSArnaldo Carvalho de Melo 	 * If we wanted a full symtab but no image had one,
187960e4b10cSArnaldo Carvalho de Melo 	 * relax our requirements and repeat the search.
188060e4b10cSArnaldo Carvalho de Melo 	 */
188160e4b10cSArnaldo Carvalho de Melo 	if (ret <= 0 && want_symtab) {
188260e4b10cSArnaldo Carvalho de Melo 		want_symtab = 0;
188360e4b10cSArnaldo Carvalho de Melo 		goto restart;
188460e4b10cSArnaldo Carvalho de Melo 	}
188560e4b10cSArnaldo Carvalho de Melo 
188686470930SIngo Molnar 	free(name);
1887aeafcbafSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
18881340e6bbSArnaldo Carvalho de Melo 		return 0;
188986470930SIngo Molnar 	return ret;
189086470930SIngo Molnar }
189186470930SIngo Molnar 
1892aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg,
189379406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1894439d473bSArnaldo Carvalho de Melo {
1895439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1896439d473bSArnaldo Carvalho de Melo 
1897aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
1898439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1899439d473bSArnaldo Carvalho de Melo 
1900b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1901439d473bSArnaldo Carvalho de Melo 			return map;
1902439d473bSArnaldo Carvalho de Melo 	}
1903439d473bSArnaldo Carvalho de Melo 
1904439d473bSArnaldo Carvalho de Melo 	return NULL;
1905439d473bSArnaldo Carvalho de Melo }
1906439d473bSArnaldo Carvalho de Melo 
1907aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso,
1908a1645ce1SZhang, Yanmin 					   const char *root_dir)
1909b7cece76SArnaldo Carvalho de Melo {
1910b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1911b7cece76SArnaldo Carvalho de Melo 	/*
1912b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1913b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1914b7cece76SArnaldo Carvalho de Melo 	 */
1915aeafcbafSArnaldo Carvalho de Melo 	const char *name = dso->short_name + 1;
1916b7cece76SArnaldo Carvalho de Melo 
1917b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1918a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1919a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1920b7cece76SArnaldo Carvalho de Melo 
1921aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, dso->build_id,
1922aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
1923aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
1924b7cece76SArnaldo Carvalho de Melo 
1925b7cece76SArnaldo Carvalho de Melo 	return 0;
1926b7cece76SArnaldo Carvalho de Melo }
1927b7cece76SArnaldo Carvalho de Melo 
1928aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg,
1929a1645ce1SZhang, Yanmin 				const char *dir_name)
19306cfcc53eSMike Galbraith {
1931439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
19325aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
193374534341SGui Jianfeng 	int ret = 0;
19346cfcc53eSMike Galbraith 
1935439d473bSArnaldo Carvalho de Melo 	if (!dir) {
19365aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1937439d473bSArnaldo Carvalho de Melo 		return -1;
1938439d473bSArnaldo Carvalho de Melo 	}
19396cfcc53eSMike Galbraith 
1940439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1941439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1942a1645ce1SZhang, Yanmin 		struct stat st;
1943439d473bSArnaldo Carvalho de Melo 
1944a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
19452b600f95SNamhyung Kim 		snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
1946a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1947a1645ce1SZhang, Yanmin 			continue;
1948a1645ce1SZhang, Yanmin 
1949a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1950439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1951439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1952439d473bSArnaldo Carvalho de Melo 				continue;
1953439d473bSArnaldo Carvalho de Melo 
1954aeafcbafSArnaldo Carvalho de Melo 			ret = map_groups__set_modules_path_dir(mg, path);
195574534341SGui Jianfeng 			if (ret < 0)
195674534341SGui Jianfeng 				goto out;
1957439d473bSArnaldo Carvalho de Melo 		} else {
1958439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1959439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1960439d473bSArnaldo Carvalho de Melo 			struct map *map;
1961cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1962439d473bSArnaldo Carvalho de Melo 
1963439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1964439d473bSArnaldo Carvalho de Melo 				continue;
1965439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1966439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1967439d473bSArnaldo Carvalho de Melo 
1968a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
1969aeafcbafSArnaldo Carvalho de Melo 			map = map_groups__find_by_name(mg, MAP__FUNCTION,
1970aeafcbafSArnaldo Carvalho de Melo 						       dso_name);
1971439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1972439d473bSArnaldo Carvalho de Melo 				continue;
1973439d473bSArnaldo Carvalho de Melo 
1974cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
197574534341SGui Jianfeng 			if (long_name == NULL) {
197674534341SGui Jianfeng 				ret = -1;
197774534341SGui Jianfeng 				goto out;
197874534341SGui Jianfeng 			}
1979cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
19806e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1981a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1982439d473bSArnaldo Carvalho de Melo 		}
1983439d473bSArnaldo Carvalho de Melo 	}
1984439d473bSArnaldo Carvalho de Melo 
198574534341SGui Jianfeng out:
1986439d473bSArnaldo Carvalho de Melo 	closedir(dir);
198774534341SGui Jianfeng 	return ret;
1988439d473bSArnaldo Carvalho de Melo }
1989439d473bSArnaldo Carvalho de Melo 
1990a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1991439d473bSArnaldo Carvalho de Melo {
1992a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1993a1645ce1SZhang, Yanmin 	FILE *file;
1994a1645ce1SZhang, Yanmin 	char *name, *tmp;
1995a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1996a1645ce1SZhang, Yanmin 
1997a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1998a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1999a1645ce1SZhang, Yanmin 	if (!file)
2000a1645ce1SZhang, Yanmin 		return NULL;
2001a1645ce1SZhang, Yanmin 
2002a1645ce1SZhang, Yanmin 	version[0] = '\0';
2003a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
2004a1645ce1SZhang, Yanmin 	fclose(file);
2005a1645ce1SZhang, Yanmin 
2006a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
2007a1645ce1SZhang, Yanmin 	if (!name)
2008a1645ce1SZhang, Yanmin 		return NULL;
2009a1645ce1SZhang, Yanmin 	name += strlen(prefix);
2010a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
2011a1645ce1SZhang, Yanmin 	if (tmp)
2012a1645ce1SZhang, Yanmin 		*tmp = '\0';
2013a1645ce1SZhang, Yanmin 
2014a1645ce1SZhang, Yanmin 	return strdup(name);
2015a1645ce1SZhang, Yanmin }
2016a1645ce1SZhang, Yanmin 
2017aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine)
2018a1645ce1SZhang, Yanmin {
2019a1645ce1SZhang, Yanmin 	char *version;
2020439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
2021439d473bSArnaldo Carvalho de Melo 
2022aeafcbafSArnaldo Carvalho de Melo 	version = get_kernel_version(machine->root_dir);
2023a1645ce1SZhang, Yanmin 	if (!version)
2024439d473bSArnaldo Carvalho de Melo 		return -1;
2025439d473bSArnaldo Carvalho de Melo 
2026a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
2027aeafcbafSArnaldo Carvalho de Melo 		 machine->root_dir, version);
2028a1645ce1SZhang, Yanmin 	free(version);
2029439d473bSArnaldo Carvalho de Melo 
2030aeafcbafSArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
2031439d473bSArnaldo Carvalho de Melo }
20326cfcc53eSMike Galbraith 
20336cfcc53eSMike Galbraith /*
2034439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
2035439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
2036439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
20376cfcc53eSMike Galbraith  */
20383610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
2039439d473bSArnaldo Carvalho de Melo {
2040aeafcbafSArnaldo Carvalho de Melo 	struct map *map = calloc(1, (sizeof(*map) +
20415aab621bSArnaldo Carvalho de Melo 				     (dso->kernel ? sizeof(struct kmap) : 0)));
2042aeafcbafSArnaldo Carvalho de Melo 	if (map != NULL) {
2043439d473bSArnaldo Carvalho de Melo 		/*
2044afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
2045439d473bSArnaldo Carvalho de Melo 		 */
2046aeafcbafSArnaldo Carvalho de Melo 		map__init(map, type, start, 0, 0, dso);
2047439d473bSArnaldo Carvalho de Melo 	}
2048afb7b4f0SArnaldo Carvalho de Melo 
2049aeafcbafSArnaldo Carvalho de Melo 	return map;
2050439d473bSArnaldo Carvalho de Melo }
2051439d473bSArnaldo Carvalho de Melo 
2052aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start,
2053d28c6223SArnaldo Carvalho de Melo 				const char *filename)
2054b7cece76SArnaldo Carvalho de Melo {
2055b7cece76SArnaldo Carvalho de Melo 	struct map *map;
2056aeafcbafSArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
2057b7cece76SArnaldo Carvalho de Melo 
2058b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
2059b7cece76SArnaldo Carvalho de Melo 		return NULL;
2060b7cece76SArnaldo Carvalho de Melo 
2061b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
2062b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
2063b7cece76SArnaldo Carvalho de Melo 		return NULL;
2064b7cece76SArnaldo Carvalho de Melo 
2065aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine))
206644f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
2067a1645ce1SZhang, Yanmin 	else
206844f24cb3SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
2069aeafcbafSArnaldo Carvalho de Melo 	map_groups__insert(&machine->kmaps, map);
2070b7cece76SArnaldo Carvalho de Melo 	return map;
2071b7cece76SArnaldo Carvalho de Melo }
2072b7cece76SArnaldo Carvalho de Melo 
2073aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine)
2074439d473bSArnaldo Carvalho de Melo {
2075439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
2076439d473bSArnaldo Carvalho de Melo 	size_t n;
2077a1645ce1SZhang, Yanmin 	FILE *file;
2078439d473bSArnaldo Carvalho de Melo 	struct map *map;
2079a1645ce1SZhang, Yanmin 	const char *modules;
2080a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2081439d473bSArnaldo Carvalho de Melo 
2082aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2083a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
2084a1645ce1SZhang, Yanmin 	else {
2085aeafcbafSArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", machine->root_dir);
2086a1645ce1SZhang, Yanmin 		modules = path;
2087a1645ce1SZhang, Yanmin 	}
2088a1645ce1SZhang, Yanmin 
2089ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(path, "/proc/modules"))
2090ec80fde7SArnaldo Carvalho de Melo 		return -1;
2091ec80fde7SArnaldo Carvalho de Melo 
2092a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
2093439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
2094439d473bSArnaldo Carvalho de Melo 		return -1;
2095439d473bSArnaldo Carvalho de Melo 
2096439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
2097439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
2098439d473bSArnaldo Carvalho de Melo 		u64 start;
2099439d473bSArnaldo Carvalho de Melo 		char *sep;
2100439d473bSArnaldo Carvalho de Melo 		int line_len;
2101439d473bSArnaldo Carvalho de Melo 
2102439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
2103439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
21046cfcc53eSMike Galbraith 			break;
21056cfcc53eSMike Galbraith 
2106439d473bSArnaldo Carvalho de Melo 		if (!line)
2107439d473bSArnaldo Carvalho de Melo 			goto out_failure;
2108439d473bSArnaldo Carvalho de Melo 
2109439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
2110439d473bSArnaldo Carvalho de Melo 
2111439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
2112439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
2113439d473bSArnaldo Carvalho de Melo 			continue;
2114439d473bSArnaldo Carvalho de Melo 
2115439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
2116439d473bSArnaldo Carvalho de Melo 
2117439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
2118439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
2119439d473bSArnaldo Carvalho de Melo 			continue;
2120439d473bSArnaldo Carvalho de Melo 
2121439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
2122439d473bSArnaldo Carvalho de Melo 
2123439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
2124aeafcbafSArnaldo Carvalho de Melo 		map = machine__new_module(machine, start, name);
2125b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
2126439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
2127aeafcbafSArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, machine->root_dir);
21286cfcc53eSMike Galbraith 	}
21296cfcc53eSMike Galbraith 
2130439d473bSArnaldo Carvalho de Melo 	free(line);
2131439d473bSArnaldo Carvalho de Melo 	fclose(file);
2132439d473bSArnaldo Carvalho de Melo 
2133aeafcbafSArnaldo Carvalho de Melo 	return machine__set_modules_path(machine);
2134439d473bSArnaldo Carvalho de Melo 
2135439d473bSArnaldo Carvalho de Melo out_delete_line:
2136439d473bSArnaldo Carvalho de Melo 	free(line);
2137439d473bSArnaldo Carvalho de Melo out_failure:
2138439d473bSArnaldo Carvalho de Melo 	return -1;
21396cfcc53eSMike Galbraith }
21406cfcc53eSMike Galbraith 
2141aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map,
21426beba7adSArnaldo Carvalho de Melo 		      const char *vmlinux, symbol_filter_t filter)
214386470930SIngo Molnar {
2144fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
2145ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
214686470930SIngo Molnar 
2147a639dc64SArnaldo Carvalho de Melo 	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
2148ec5761eaSDavid Ahern 		 symbol_conf.symfs, vmlinux);
2149ec5761eaSDavid Ahern 	fd = open(symfs_vmlinux, O_RDONLY);
215086470930SIngo Molnar 	if (fd < 0)
215186470930SIngo Molnar 		return -1;
215286470930SIngo Molnar 
2153aeafcbafSArnaldo Carvalho de Melo 	dso__set_long_name(dso, (char *)vmlinux);
2154aeafcbafSArnaldo Carvalho de Melo 	dso__set_loaded(dso, map->type);
2155aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
215686470930SIngo Molnar 	close(fd);
215786470930SIngo Molnar 
21583846df2eSArnaldo Carvalho de Melo 	if (err > 0)
2159ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
21603846df2eSArnaldo Carvalho de Melo 
216186470930SIngo Molnar 	return err;
216286470930SIngo Molnar }
216386470930SIngo Molnar 
2164aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map,
21659de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
2166a19afe46SArnaldo Carvalho de Melo {
2167a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
21685ad90e4eSArnaldo Carvalho de Melo 	char *filename;
2169a19afe46SArnaldo Carvalho de Melo 
2170a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
21715ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
21725ad90e4eSArnaldo Carvalho de Melo 
2173aeafcbafSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(dso, NULL, 0);
21745ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
2175aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, filename, filter);
21765ad90e4eSArnaldo Carvalho de Melo 		if (err > 0) {
2177aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, filename);
21785ad90e4eSArnaldo Carvalho de Melo 			goto out;
21795ad90e4eSArnaldo Carvalho de Melo 		}
21805ad90e4eSArnaldo Carvalho de Melo 		free(filename);
21815ad90e4eSArnaldo Carvalho de Melo 	}
2182a19afe46SArnaldo Carvalho de Melo 
2183a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
2184aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
2185a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
2186aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(vmlinux_path[i]));
2187a19afe46SArnaldo Carvalho de Melo 			break;
2188a19afe46SArnaldo Carvalho de Melo 		}
2189a19afe46SArnaldo Carvalho de Melo 	}
21905ad90e4eSArnaldo Carvalho de Melo out:
2191a19afe46SArnaldo Carvalho de Melo 	return err;
2192a19afe46SArnaldo Carvalho de Melo }
2193a19afe46SArnaldo Carvalho de Melo 
2194aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map,
21959de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
219686470930SIngo Molnar {
2197cc612d81SArnaldo Carvalho de Melo 	int err;
21989e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
21999e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
2200dc8d6ab2SArnaldo Carvalho de Melo 	/*
2201b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
2202b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
2203dc8d6ab2SArnaldo Carvalho de Melo 	 *
2204dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
2205dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
2206dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
2207dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
2208dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
2209dc8d6ab2SArnaldo Carvalho de Melo 	 *
2210dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
2211dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
2212dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
2213dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
2214dc8d6ab2SArnaldo Carvalho de Melo 	 */
2215b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
2216b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
2217b226a5a7SDavid Ahern 		goto do_kallsyms;
2218b226a5a7SDavid Ahern 	}
2219b226a5a7SDavid Ahern 
2220dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
2221aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(dso, map,
2222dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
2223e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
2224aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso,
2225e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
2226e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
2227e7dadc00SArnaldo Carvalho de Melo 		}
2228e7dadc00SArnaldo Carvalho de Melo 		return err;
2229dc8d6ab2SArnaldo Carvalho de Melo 	}
2230439d473bSArnaldo Carvalho de Melo 
2231cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
2232aeafcbafSArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(dso, map, filter);
2233a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
2234cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
2235cc612d81SArnaldo Carvalho de Melo 	}
2236cc612d81SArnaldo Carvalho de Melo 
2237ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
2238ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2239ec5761eaSDavid Ahern 		return -1;
2240ec5761eaSDavid Ahern 
2241b7cece76SArnaldo Carvalho de Melo 	/*
2242b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
2243b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
2244b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
2245b7cece76SArnaldo Carvalho de Melo 	 */
2246aeafcbafSArnaldo Carvalho de Melo 	if (dso->has_build_id) {
2247b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
22489e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2249b7cece76SArnaldo Carvalho de Melo 
2250b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
22518d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
2252aeafcbafSArnaldo Carvalho de Melo 			if (dso__build_id_equal(dso, kallsyms_build_id)) {
22539e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
2254b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
22558d0591f6SArnaldo Carvalho de Melo 			}
22569e201442SArnaldo Carvalho de Melo 		}
2257dc8d6ab2SArnaldo Carvalho de Melo 		/*
2258dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
2259dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
2260dc8d6ab2SArnaldo Carvalho de Melo 		 */
2261aeafcbafSArnaldo Carvalho de Melo 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
22629e201442SArnaldo Carvalho de Melo 				  sbuild_id);
22639e201442SArnaldo Carvalho de Melo 
22649e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
22659e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
22663846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
22673846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
22688d0591f6SArnaldo Carvalho de Melo 			return -1;
22693846df2eSArnaldo Carvalho de Melo 		}
22708d0591f6SArnaldo Carvalho de Melo 
227119fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
227219fc2dedSArnaldo Carvalho de Melo 
2273dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
22743846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
22753846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
22769e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
2277dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
2278ef6ae724SArnaldo Carvalho de Melo 		}
2279dc8d6ab2SArnaldo Carvalho de Melo 	} else {
2280dc8d6ab2SArnaldo Carvalho de Melo 		/*
2281dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
2282dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
2283dc8d6ab2SArnaldo Carvalho de Melo 		 */
2284dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
2285dc8d6ab2SArnaldo Carvalho de Melo 	}
2286dc8d6ab2SArnaldo Carvalho de Melo 
2287dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
2288aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
22893846df2eSArnaldo Carvalho de Melo 	if (err > 0)
22903846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
2291dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
2292dc8d6ab2SArnaldo Carvalho de Melo 
2293439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
2294cc612d81SArnaldo Carvalho de Melo out_fixup:
2295e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
2296aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
22976a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
22986a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
2299439d473bSArnaldo Carvalho de Melo 	}
230094cb9e38SArnaldo Carvalho de Melo 
230186470930SIngo Molnar 	return err;
230286470930SIngo Molnar }
230386470930SIngo Molnar 
2304aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
2305a1645ce1SZhang, Yanmin 				      symbol_filter_t filter)
2306a1645ce1SZhang, Yanmin {
2307a1645ce1SZhang, Yanmin 	int err;
2308a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
230923346f21SArnaldo Carvalho de Melo 	struct machine *machine;
2310a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2311a1645ce1SZhang, Yanmin 
2312a1645ce1SZhang, Yanmin 	if (!map->groups) {
2313a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
2314a1645ce1SZhang, Yanmin 		return -1;
2315a1645ce1SZhang, Yanmin 	}
231623346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
2317a1645ce1SZhang, Yanmin 
231823346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
2319a1645ce1SZhang, Yanmin 		/*
2320a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
2321a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
2322a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
2323a1645ce1SZhang, Yanmin 		 */
2324a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
2325aeafcbafSArnaldo Carvalho de Melo 			err = dso__load_vmlinux(dso, map,
2326a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
2327a1645ce1SZhang, Yanmin 			goto out_try_fixup;
2328a1645ce1SZhang, Yanmin 		}
2329a1645ce1SZhang, Yanmin 
2330a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
2331a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
2332a1645ce1SZhang, Yanmin 			return -1;
2333a1645ce1SZhang, Yanmin 	} else {
233423346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2335a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
2336a1645ce1SZhang, Yanmin 	}
2337a1645ce1SZhang, Yanmin 
2338aeafcbafSArnaldo Carvalho de Melo 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
2339a1645ce1SZhang, Yanmin 	if (err > 0)
2340a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
2341a1645ce1SZhang, Yanmin 
2342a1645ce1SZhang, Yanmin out_try_fixup:
2343a1645ce1SZhang, Yanmin 	if (err > 0) {
2344a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
234548ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
2346aeafcbafSArnaldo Carvalho de Melo 			dso__set_long_name(dso, strdup(path));
2347a1645ce1SZhang, Yanmin 		}
2348a1645ce1SZhang, Yanmin 		map__fixup_start(map);
2349a1645ce1SZhang, Yanmin 		map__fixup_end(map);
2350a1645ce1SZhang, Yanmin 	}
2351a1645ce1SZhang, Yanmin 
2352a1645ce1SZhang, Yanmin 	return err;
2353a1645ce1SZhang, Yanmin }
2354cd84c2acSFrederic Weisbecker 
2355b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
2356cd84c2acSFrederic Weisbecker {
2357b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
2358cd84c2acSFrederic Weisbecker }
2359cd84c2acSFrederic Weisbecker 
2360b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
2361cd84c2acSFrederic Weisbecker {
2362cd84c2acSFrederic Weisbecker 	struct dso *pos;
2363cd84c2acSFrederic Weisbecker 
2364b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
2365cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
2366cd84c2acSFrederic Weisbecker 			return pos;
2367cd84c2acSFrederic Weisbecker 	return NULL;
2368cd84c2acSFrederic Weisbecker }
2369cd84c2acSFrederic Weisbecker 
2370a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
2371cd84c2acSFrederic Weisbecker {
2372a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
2373cd84c2acSFrederic Weisbecker 
2374e4204992SArnaldo Carvalho de Melo 	if (!dso) {
237500a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
2376cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
2377a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
2378cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
2379cfc10d3bSArnaldo Carvalho de Melo 		}
2380e4204992SArnaldo Carvalho de Melo 	}
2381cd84c2acSFrederic Weisbecker 
2382cd84c2acSFrederic Weisbecker 	return dso;
2383cd84c2acSFrederic Weisbecker }
2384cd84c2acSFrederic Weisbecker 
23851f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2386cd84c2acSFrederic Weisbecker {
2387cd84c2acSFrederic Weisbecker 	struct dso *pos;
2388cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2389cd84c2acSFrederic Weisbecker 
239095011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
239195011c60SArnaldo Carvalho de Melo 		int i;
239295011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
2393cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
2394cd84c2acSFrederic Weisbecker 	}
2395cd84c2acSFrederic Weisbecker 
2396cbf69680SArnaldo Carvalho de Melo 	return ret;
2397cbf69680SArnaldo Carvalho de Melo }
2398cbf69680SArnaldo Carvalho de Melo 
2399aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
2400b0da954aSArnaldo Carvalho de Melo {
2401a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2402cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2403a1645ce1SZhang, Yanmin 
2404aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
240523346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2406cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2407cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
2408a1645ce1SZhang, Yanmin 	}
2409cbf69680SArnaldo Carvalho de Melo 
2410cbf69680SArnaldo Carvalho de Melo 	return ret;
2411b0da954aSArnaldo Carvalho de Melo }
2412b0da954aSArnaldo Carvalho de Melo 
241388d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
241488d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
24159e03eb2dSArnaldo Carvalho de Melo {
24169e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
24179e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
24189e03eb2dSArnaldo Carvalho de Melo 
2419b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
242088d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
242188d3d9b7SArnaldo Carvalho de Melo 			continue;
24229e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
24239e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
24249e03eb2dSArnaldo Carvalho de Melo 	}
24259e03eb2dSArnaldo Carvalho de Melo 	return ret;
24269e03eb2dSArnaldo Carvalho de Melo }
24279e03eb2dSArnaldo Carvalho de Melo 
2428aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
2429aeafcbafSArnaldo Carvalho de Melo 				     bool with_hits)
2430f869097eSArnaldo Carvalho de Melo {
2431aeafcbafSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
2432aeafcbafSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
2433f869097eSArnaldo Carvalho de Melo }
2434f869097eSArnaldo Carvalho de Melo 
2435aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2436aeafcbafSArnaldo Carvalho de Melo 				      FILE *fp, bool with_hits)
2437b0da954aSArnaldo Carvalho de Melo {
2438a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2439a1645ce1SZhang, Yanmin 	size_t ret = 0;
2440a1645ce1SZhang, Yanmin 
2441aeafcbafSArnaldo Carvalho de Melo 	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
244223346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2443f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2444a1645ce1SZhang, Yanmin 	}
2445a1645ce1SZhang, Yanmin 	return ret;
2446b0da954aSArnaldo Carvalho de Melo }
2447b0da954aSArnaldo Carvalho de Melo 
2448f57b05edSJiri Olsa static struct dso*
2449f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name,
2450f57b05edSJiri Olsa 		    const char *short_name, int dso_type)
2451fd1d908cSArnaldo Carvalho de Melo {
2452f57b05edSJiri Olsa 	/*
2453f57b05edSJiri Olsa 	 * The kernel dso could be created by build_id processing.
2454f57b05edSJiri Olsa 	 */
2455f57b05edSJiri Olsa 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
2456fd1d908cSArnaldo Carvalho de Melo 
2457f57b05edSJiri Olsa 	/*
2458f57b05edSJiri Olsa 	 * We need to run this in all cases, since during the build_id
2459f57b05edSJiri Olsa 	 * processing we had no idea this was the kernel dso.
2460f57b05edSJiri Olsa 	 */
2461aeafcbafSArnaldo Carvalho de Melo 	if (dso != NULL) {
2462f57b05edSJiri Olsa 		dso__set_short_name(dso, short_name);
2463f57b05edSJiri Olsa 		dso->kernel = dso_type;
2464a1645ce1SZhang, Yanmin 	}
2465a1645ce1SZhang, Yanmin 
2466aeafcbafSArnaldo Carvalho de Melo 	return dso;
2467a1645ce1SZhang, Yanmin }
2468a1645ce1SZhang, Yanmin 
2469aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2470a1645ce1SZhang, Yanmin {
2471a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2472a1645ce1SZhang, Yanmin 
247323346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2474a1645ce1SZhang, Yanmin 		return;
247523346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2476aeafcbafSArnaldo Carvalho de Melo 	if (sysfs__read_build_id(path, dso->build_id,
2477aeafcbafSArnaldo Carvalho de Melo 				 sizeof(dso->build_id)) == 0)
2478aeafcbafSArnaldo Carvalho de Melo 		dso->has_build_id = true;
2479fd1d908cSArnaldo Carvalho de Melo }
2480fd1d908cSArnaldo Carvalho de Melo 
2481f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine)
2482cd84c2acSFrederic Weisbecker {
2483a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
2484a1645ce1SZhang, Yanmin 	struct dso *kernel;
2485cd84c2acSFrederic Weisbecker 
2486aeafcbafSArnaldo Carvalho de Melo 	if (machine__is_host(machine)) {
2487a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2488f57b05edSJiri Olsa 		if (!vmlinux_name)
2489f57b05edSJiri Olsa 			vmlinux_name = "[kernel.kallsyms]";
2490f57b05edSJiri Olsa 
2491f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
2492f57b05edSJiri Olsa 					     "[kernel]",
2493f57b05edSJiri Olsa 					     DSO_TYPE_KERNEL);
2494a1645ce1SZhang, Yanmin 	} else {
2495f57b05edSJiri Olsa 		char bf[PATH_MAX];
2496f57b05edSJiri Olsa 
2497aeafcbafSArnaldo Carvalho de Melo 		if (machine__is_default_guest(machine))
2498a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2499f57b05edSJiri Olsa 		if (!vmlinux_name)
2500f57b05edSJiri Olsa 			vmlinux_name = machine__mmap_name(machine, bf,
2501f57b05edSJiri Olsa 							  sizeof(bf));
2502f57b05edSJiri Olsa 
2503f57b05edSJiri Olsa 		kernel = dso__kernel_findnew(machine, vmlinux_name,
2504f57b05edSJiri Olsa 					     "[guest.kernel]",
2505f57b05edSJiri Olsa 					     DSO_TYPE_GUEST_KERNEL);
25068d92c02aSArnaldo Carvalho de Melo 	}
2507cd84c2acSFrederic Weisbecker 
2508f57b05edSJiri Olsa 	if (kernel != NULL && (!kernel->has_build_id))
2509aeafcbafSArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, machine);
2510f57b05edSJiri Olsa 
2511f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2512f1dfa0b1SArnaldo Carvalho de Melo }
2513f1dfa0b1SArnaldo Carvalho de Melo 
2514d214afbdSMing Lei struct process_args {
2515d214afbdSMing Lei 	u64 start;
2516d214afbdSMing Lei };
2517d214afbdSMing Lei 
2518d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name,
25193b01a413SArnaldo Carvalho de Melo 			     char type __used, u64 start, u64 end __used)
2520d214afbdSMing Lei {
2521d214afbdSMing Lei 	struct process_args *args = arg;
2522d214afbdSMing Lei 
2523d214afbdSMing Lei 	if (strchr(name, '['))
2524d214afbdSMing Lei 		return 0;
2525d214afbdSMing Lei 
2526d214afbdSMing Lei 	args->start = start;
2527d214afbdSMing Lei 	return 1;
2528d214afbdSMing Lei }
2529d214afbdSMing Lei 
2530d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */
2531d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine)
2532d214afbdSMing Lei {
2533d214afbdSMing Lei 	const char *filename;
2534d214afbdSMing Lei 	char path[PATH_MAX];
2535d214afbdSMing Lei 	struct process_args args;
2536d214afbdSMing Lei 
2537d214afbdSMing Lei 	if (machine__is_host(machine)) {
2538d214afbdSMing Lei 		filename = "/proc/kallsyms";
2539d214afbdSMing Lei 	} else {
2540d214afbdSMing Lei 		if (machine__is_default_guest(machine))
2541d214afbdSMing Lei 			filename = (char *)symbol_conf.default_guest_kallsyms;
2542d214afbdSMing Lei 		else {
2543d214afbdSMing Lei 			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2544d214afbdSMing Lei 			filename = path;
2545d214afbdSMing Lei 		}
2546d214afbdSMing Lei 	}
2547d214afbdSMing Lei 
2548ec80fde7SArnaldo Carvalho de Melo 	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
2549ec80fde7SArnaldo Carvalho de Melo 		return 0;
2550ec80fde7SArnaldo Carvalho de Melo 
2551d214afbdSMing Lei 	if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2552d214afbdSMing Lei 		return 0;
2553d214afbdSMing Lei 
2554d214afbdSMing Lei 	return args.start;
2555d214afbdSMing Lei }
2556d214afbdSMing Lei 
2557aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
2558f1dfa0b1SArnaldo Carvalho de Melo {
2559de176489SArnaldo Carvalho de Melo 	enum map_type type;
2560aeafcbafSArnaldo Carvalho de Melo 	u64 start = machine__get_kernel_start_addr(machine);
2561f1dfa0b1SArnaldo Carvalho de Melo 
2562de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
25639de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
25649de89fe7SArnaldo Carvalho de Melo 
2565aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = map__new2(start, kernel, type);
2566aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
2567f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2568f1dfa0b1SArnaldo Carvalho de Melo 
2569aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type]->map_ip =
2570aeafcbafSArnaldo Carvalho de Melo 			machine->vmlinux_maps[type]->unmap_ip =
2571aeafcbafSArnaldo Carvalho de Melo 				identity__map_ip;
2572aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
2573aeafcbafSArnaldo Carvalho de Melo 		kmap->kmaps = &machine->kmaps;
2574aeafcbafSArnaldo Carvalho de Melo 		map_groups__insert(&machine->kmaps,
2575aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
2576f1dfa0b1SArnaldo Carvalho de Melo 	}
2577f1dfa0b1SArnaldo Carvalho de Melo 
2578f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
25792446042cSArnaldo Carvalho de Melo }
25802446042cSArnaldo Carvalho de Melo 
2581aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine)
2582076c6e45SArnaldo Carvalho de Melo {
2583076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
2584076c6e45SArnaldo Carvalho de Melo 
2585076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
2586076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
2587076c6e45SArnaldo Carvalho de Melo 
2588aeafcbafSArnaldo Carvalho de Melo 		if (machine->vmlinux_maps[type] == NULL)
2589076c6e45SArnaldo Carvalho de Melo 			continue;
2590076c6e45SArnaldo Carvalho de Melo 
2591aeafcbafSArnaldo Carvalho de Melo 		kmap = map__kmap(machine->vmlinux_maps[type]);
2592aeafcbafSArnaldo Carvalho de Melo 		map_groups__remove(&machine->kmaps,
2593aeafcbafSArnaldo Carvalho de Melo 				   machine->vmlinux_maps[type]);
2594076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
2595076c6e45SArnaldo Carvalho de Melo 			/*
2596076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
2597076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
2598076c6e45SArnaldo Carvalho de Melo 			 */
2599076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
2600076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
2601076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
2602076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
2603076c6e45SArnaldo Carvalho de Melo 			}
2604076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
2605076c6e45SArnaldo Carvalho de Melo 		}
2606076c6e45SArnaldo Carvalho de Melo 
2607aeafcbafSArnaldo Carvalho de Melo 		map__delete(machine->vmlinux_maps[type]);
2608aeafcbafSArnaldo Carvalho de Melo 		machine->vmlinux_maps[type] = NULL;
2609076c6e45SArnaldo Carvalho de Melo 	}
2610076c6e45SArnaldo Carvalho de Melo }
2611076c6e45SArnaldo Carvalho de Melo 
2612aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine)
26135c0541d5SArnaldo Carvalho de Melo {
2614f57b05edSJiri Olsa 	struct dso *kernel = machine__get_kernel(machine);
26155c0541d5SArnaldo Carvalho de Melo 
26165c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
2617aeafcbafSArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(machine, kernel) < 0)
26185c0541d5SArnaldo Carvalho de Melo 		return -1;
26195c0541d5SArnaldo Carvalho de Melo 
2620f51304d3SDavid Ahern 	if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
2621f51304d3SDavid Ahern 		if (machine__is_host(machine))
2622f51304d3SDavid Ahern 			pr_debug("Problems creating module maps, "
2623f51304d3SDavid Ahern 				 "continuing anyway...\n");
2624f51304d3SDavid Ahern 		else
2625f51304d3SDavid Ahern 			pr_debug("Problems creating module maps for guest %d, "
2626f51304d3SDavid Ahern 				 "continuing anyway...\n", machine->pid);
2627f51304d3SDavid Ahern 	}
2628f51304d3SDavid Ahern 
26295c0541d5SArnaldo Carvalho de Melo 	/*
26305c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
26315c0541d5SArnaldo Carvalho de Melo 	 */
2632aeafcbafSArnaldo Carvalho de Melo 	map_groups__fixup_end(&machine->kmaps);
26335c0541d5SArnaldo Carvalho de Melo 	return 0;
26345c0541d5SArnaldo Carvalho de Melo }
26355c0541d5SArnaldo Carvalho de Melo 
2636cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
26372446042cSArnaldo Carvalho de Melo {
2638cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2639cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2640cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2641cc612d81SArnaldo Carvalho de Melo 	}
2642cc612d81SArnaldo Carvalho de Melo 
2643cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2644cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2645cc612d81SArnaldo Carvalho de Melo }
2646cc612d81SArnaldo Carvalho de Melo 
2647cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2648cc612d81SArnaldo Carvalho de Melo {
2649cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2650cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2651cc612d81SArnaldo Carvalho de Melo 
2652cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2653cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2654cc612d81SArnaldo Carvalho de Melo 		return -1;
2655cc612d81SArnaldo Carvalho de Melo 
2656cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2657cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2658cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2659cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2660cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2661cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2662cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2663cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2664ec5761eaSDavid Ahern 
2665ec5761eaSDavid Ahern 	/* only try running kernel version if no symfs was given */
2666ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2667ec5761eaSDavid Ahern 		return 0;
2668ec5761eaSDavid Ahern 
2669ec5761eaSDavid Ahern 	if (uname(&uts) < 0)
2670ec5761eaSDavid Ahern 		return -1;
2671ec5761eaSDavid Ahern 
2672cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2673cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2674cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2675cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2676cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2677cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2678cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2679cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2680cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2681cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2682cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2683cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2684cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2685cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2686cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2687cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2688cc612d81SArnaldo Carvalho de Melo 
2689cc612d81SArnaldo Carvalho de Melo 	return 0;
2690cc612d81SArnaldo Carvalho de Melo 
2691cc612d81SArnaldo Carvalho de Melo out_fail:
2692cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2693cc612d81SArnaldo Carvalho de Melo 	return -1;
2694cc612d81SArnaldo Carvalho de Melo }
2695cc612d81SArnaldo Carvalho de Melo 
2696aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
2697b0a9ab62SArnaldo Carvalho de Melo {
2698b0a9ab62SArnaldo Carvalho de Melo 	int i;
2699b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
2700aeafcbafSArnaldo Carvalho de Melo 	struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
27015ad90e4eSArnaldo Carvalho de Melo 
27025ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
27035ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
27045ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
27055ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
27065ad90e4eSArnaldo Carvalho de Melo 	}
2707b0a9ab62SArnaldo Carvalho de Melo 
2708b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
27095ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
27105ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
2711b0a9ab62SArnaldo Carvalho de Melo 
2712b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2713b0a9ab62SArnaldo Carvalho de Melo }
2714b0a9ab62SArnaldo Carvalho de Melo 
2715655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2716655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2717655000e7SArnaldo Carvalho de Melo {
2718655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2719655000e7SArnaldo Carvalho de Melo 		return 0;
2720655000e7SArnaldo Carvalho de Melo 
2721655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2722655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2723655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2724655000e7SArnaldo Carvalho de Melo 		return -1;
2725655000e7SArnaldo Carvalho de Melo 	}
2726655000e7SArnaldo Carvalho de Melo 	return 0;
2727655000e7SArnaldo Carvalho de Melo }
2728655000e7SArnaldo Carvalho de Melo 
2729ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void)
2730ec80fde7SArnaldo Carvalho de Melo {
2731ec80fde7SArnaldo Carvalho de Melo 	bool value = false;
2732ec80fde7SArnaldo Carvalho de Melo 
2733ec80fde7SArnaldo Carvalho de Melo 	if (geteuid() != 0) {
2734ec80fde7SArnaldo Carvalho de Melo 		FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
2735ec80fde7SArnaldo Carvalho de Melo 		if (fp != NULL) {
2736ec80fde7SArnaldo Carvalho de Melo 			char line[8];
2737ec80fde7SArnaldo Carvalho de Melo 
2738ec80fde7SArnaldo Carvalho de Melo 			if (fgets(line, sizeof(line), fp) != NULL)
2739ec80fde7SArnaldo Carvalho de Melo 				value = atoi(line) != 0;
2740ec80fde7SArnaldo Carvalho de Melo 
2741ec80fde7SArnaldo Carvalho de Melo 			fclose(fp);
2742ec80fde7SArnaldo Carvalho de Melo 		}
2743ec80fde7SArnaldo Carvalho de Melo 	}
2744ec80fde7SArnaldo Carvalho de Melo 
2745ec80fde7SArnaldo Carvalho de Melo 	return value;
2746ec80fde7SArnaldo Carvalho de Melo }
2747ec80fde7SArnaldo Carvalho de Melo 
274875be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2749cc612d81SArnaldo Carvalho de Melo {
2750ec5761eaSDavid Ahern 	const char *symfs;
2751ec5761eaSDavid Ahern 
275285e00b55SJovi Zhang 	if (symbol_conf.initialized)
275385e00b55SJovi Zhang 		return 0;
275485e00b55SJovi Zhang 
27554d439517SDavid S. Miller 	symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
27564d439517SDavid S. Miller 
275795011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
275875be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
275975be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
276079406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2761b32d133aSArnaldo Carvalho de Melo 
276275be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2763cc612d81SArnaldo Carvalho de Melo 		return -1;
2764cc612d81SArnaldo Carvalho de Melo 
2765c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2766c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2767c410a338SArnaldo Carvalho de Melo 		return -1;
2768c410a338SArnaldo Carvalho de Melo 	}
2769c410a338SArnaldo Carvalho de Melo 
2770655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2771655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2772655000e7SArnaldo Carvalho de Melo 		return -1;
2773655000e7SArnaldo Carvalho de Melo 
2774655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2775655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2776655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2777655000e7SArnaldo Carvalho de Melo 
2778655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2779655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2780655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2781655000e7SArnaldo Carvalho de Melo 
2782ec5761eaSDavid Ahern 	/*
2783ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2784ec5761eaSDavid Ahern 	 * reset here for simplicity.
2785ec5761eaSDavid Ahern 	 */
2786ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2787ec5761eaSDavid Ahern 	if (symfs == NULL)
2788ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2789ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2790ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2791ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2792ec5761eaSDavid Ahern 		free((void *)symfs);
2793ec5761eaSDavid Ahern 
2794ec80fde7SArnaldo Carvalho de Melo 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2795ec80fde7SArnaldo Carvalho de Melo 
279685e00b55SJovi Zhang 	symbol_conf.initialized = true;
27974aa65636SArnaldo Carvalho de Melo 	return 0;
2798655000e7SArnaldo Carvalho de Melo 
2799655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2800655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2801d74c896bSNamhyung Kim out_free_dso_list:
2802d74c896bSNamhyung Kim 	strlist__delete(symbol_conf.dso_list);
2803655000e7SArnaldo Carvalho de Melo 	return -1;
2804cc612d81SArnaldo Carvalho de Melo }
2805cc612d81SArnaldo Carvalho de Melo 
2806d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2807d65a458bSArnaldo Carvalho de Melo {
280885e00b55SJovi Zhang 	if (!symbol_conf.initialized)
280985e00b55SJovi Zhang 		return;
2810d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2811d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2812d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2813d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2814d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
281585e00b55SJovi Zhang 	symbol_conf.initialized = false;
2816d65a458bSArnaldo Carvalho de Melo }
2817d65a458bSArnaldo Carvalho de Melo 
2818aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
28194aa65636SArnaldo Carvalho de Melo {
2820aeafcbafSArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(machines, pid);
28219de89fe7SArnaldo Carvalho de Melo 
282223346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2823a1645ce1SZhang, Yanmin 		return -1;
28244aa65636SArnaldo Carvalho de Melo 
28255c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2826cd84c2acSFrederic Weisbecker }
28275aab621bSArnaldo Carvalho de Melo 
28285aab621bSArnaldo Carvalho de Melo static int hex(char ch)
28295aab621bSArnaldo Carvalho de Melo {
28305aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
28315aab621bSArnaldo Carvalho de Melo 		return ch - '0';
28325aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
28335aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
28345aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
28355aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
28365aab621bSArnaldo Carvalho de Melo 	return -1;
28375aab621bSArnaldo Carvalho de Melo }
28385aab621bSArnaldo Carvalho de Melo 
28395aab621bSArnaldo Carvalho de Melo /*
28405aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
28415aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
28425aab621bSArnaldo Carvalho de Melo  */
28435aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
28445aab621bSArnaldo Carvalho de Melo {
28455aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
28465aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
28475aab621bSArnaldo Carvalho de Melo 
28485aab621bSArnaldo Carvalho de Melo 	while (*p) {
28495aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
28505aab621bSArnaldo Carvalho de Melo 
28515aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
28525aab621bSArnaldo Carvalho de Melo 			break;
28535aab621bSArnaldo Carvalho de Melo 
28545aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
28555aab621bSArnaldo Carvalho de Melo 		p++;
28565aab621bSArnaldo Carvalho de Melo 	}
28575aab621bSArnaldo Carvalho de Melo 
28585aab621bSArnaldo Carvalho de Melo 	return p - ptr;
28595aab621bSArnaldo Carvalho de Melo }
28605aab621bSArnaldo Carvalho de Melo 
28615aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
28625aab621bSArnaldo Carvalho de Melo {
28635aab621bSArnaldo Carvalho de Melo 	char *p = s;
28645aab621bSArnaldo Carvalho de Melo 
28655aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
28665aab621bSArnaldo Carvalho de Melo 		*p++ = to;
28675aab621bSArnaldo Carvalho de Melo 
28685aab621bSArnaldo Carvalho de Melo 	return s;
28695aab621bSArnaldo Carvalho de Melo }
2870a1645ce1SZhang, Yanmin 
2871aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines)
2872a1645ce1SZhang, Yanmin {
2873a1645ce1SZhang, Yanmin 	int ret = 0;
2874a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2875a1645ce1SZhang, Yanmin 	int i, items = 0;
2876a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2877a1645ce1SZhang, Yanmin 	pid_t pid;
2878a1645ce1SZhang, Yanmin 
2879a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2880a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2881a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2882aeafcbafSArnaldo Carvalho de Melo 		machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
2883a1645ce1SZhang, Yanmin 	}
2884a1645ce1SZhang, Yanmin 
2885a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2886a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2887a1645ce1SZhang, Yanmin 		if (items <= 0)
2888a1645ce1SZhang, Yanmin 			return -ENOENT;
2889a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2890a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2891a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2892a1645ce1SZhang, Yanmin 				continue;
2893a1645ce1SZhang, Yanmin 			}
2894a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2895a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2896a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2897a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2898a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2899a1645ce1SZhang, Yanmin 			if (ret) {
2900a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2901a1645ce1SZhang, Yanmin 				goto failure;
2902a1645ce1SZhang, Yanmin 			}
2903aeafcbafSArnaldo Carvalho de Melo 			machines__create_kernel_maps(machines, pid);
2904a1645ce1SZhang, Yanmin 		}
2905a1645ce1SZhang, Yanmin failure:
2906a1645ce1SZhang, Yanmin 		free(namelist);
2907a1645ce1SZhang, Yanmin 	}
2908a1645ce1SZhang, Yanmin 
2909a1645ce1SZhang, Yanmin 	return ret;
2910a1645ce1SZhang, Yanmin }
29115c0541d5SArnaldo Carvalho de Melo 
2912aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines)
2913076c6e45SArnaldo Carvalho de Melo {
2914aeafcbafSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(machines);
2915076c6e45SArnaldo Carvalho de Melo 
2916076c6e45SArnaldo Carvalho de Melo 	while (next) {
2917076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2918076c6e45SArnaldo Carvalho de Melo 
2919076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2920aeafcbafSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, machines);
2921076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2922076c6e45SArnaldo Carvalho de Melo 	}
2923076c6e45SArnaldo Carvalho de Melo }
2924076c6e45SArnaldo Carvalho de Melo 
2925aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename,
29265c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
29275c0541d5SArnaldo Carvalho de Melo {
2928aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
29295c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
29305c0541d5SArnaldo Carvalho de Melo 
29315c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
29325c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
29335c0541d5SArnaldo Carvalho de Melo 		/*
29345c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
29355c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
29365c0541d5SArnaldo Carvalho de Melo 		 * sections.
29375c0541d5SArnaldo Carvalho de Melo 		 */
2938aeafcbafSArnaldo Carvalho de Melo 		__map_groups__fixup_end(&machine->kmaps, type);
29395c0541d5SArnaldo Carvalho de Melo 	}
29405c0541d5SArnaldo Carvalho de Melo 
29415c0541d5SArnaldo Carvalho de Melo 	return ret;
29425c0541d5SArnaldo Carvalho de Melo }
29435c0541d5SArnaldo Carvalho de Melo 
2944aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
29455c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
29465c0541d5SArnaldo Carvalho de Melo {
2947aeafcbafSArnaldo Carvalho de Melo 	struct map *map = machine->vmlinux_maps[type];
29485c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
29495c0541d5SArnaldo Carvalho de Melo 
29505c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
29515c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
29525c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
29535c0541d5SArnaldo Carvalho de Melo 	}
29545c0541d5SArnaldo Carvalho de Melo 
29555c0541d5SArnaldo Carvalho de Melo 	return ret;
29565c0541d5SArnaldo Carvalho de Melo }
2957225466f1SSrikar Dronamraju 
2958225466f1SSrikar Dronamraju struct map *dso__new_map(const char *name)
2959225466f1SSrikar Dronamraju {
2960378474e4SSrikar Dronamraju 	struct map *map = NULL;
2961225466f1SSrikar Dronamraju 	struct dso *dso = dso__new(name);
2962378474e4SSrikar Dronamraju 
2963378474e4SSrikar Dronamraju 	if (dso)
2964378474e4SSrikar Dronamraju 		map = map__new2(0, dso, MAP__FUNCTION);
2965225466f1SSrikar Dronamraju 
2966225466f1SSrikar Dronamraju 	return map;
2967225466f1SSrikar Dronamraju }
2968949d160bSJiri Olsa 
2969949d160bSJiri Olsa static int open_dso(struct dso *dso, struct machine *machine)
2970949d160bSJiri Olsa {
2971949d160bSJiri Olsa 	char *root_dir = (char *) "";
2972949d160bSJiri Olsa 	char *name;
2973949d160bSJiri Olsa 	int fd;
2974949d160bSJiri Olsa 
2975949d160bSJiri Olsa 	name = malloc(PATH_MAX);
2976949d160bSJiri Olsa 	if (!name)
2977949d160bSJiri Olsa 		return -ENOMEM;
2978949d160bSJiri Olsa 
2979949d160bSJiri Olsa 	if (machine)
2980949d160bSJiri Olsa 		root_dir = machine->root_dir;
2981949d160bSJiri Olsa 
2982949d160bSJiri Olsa 	if (dso__binary_type_file(dso, dso->data_type,
2983949d160bSJiri Olsa 				  root_dir, name, PATH_MAX)) {
2984949d160bSJiri Olsa 		free(name);
2985949d160bSJiri Olsa 		return -EINVAL;
2986949d160bSJiri Olsa 	}
2987949d160bSJiri Olsa 
2988949d160bSJiri Olsa 	fd = open(name, O_RDONLY);
2989949d160bSJiri Olsa 	free(name);
2990949d160bSJiri Olsa 	return fd;
2991949d160bSJiri Olsa }
2992949d160bSJiri Olsa 
2993949d160bSJiri Olsa int dso__data_fd(struct dso *dso, struct machine *machine)
2994949d160bSJiri Olsa {
2995949d160bSJiri Olsa 	int i = 0;
2996949d160bSJiri Olsa 
2997949d160bSJiri Olsa 	if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
2998949d160bSJiri Olsa 		return open_dso(dso, machine);
2999949d160bSJiri Olsa 
3000949d160bSJiri Olsa 	do {
3001949d160bSJiri Olsa 		int fd;
3002949d160bSJiri Olsa 
3003949d160bSJiri Olsa 		dso->data_type = binary_type_data[i++];
3004949d160bSJiri Olsa 
3005949d160bSJiri Olsa 		fd = open_dso(dso, machine);
3006949d160bSJiri Olsa 		if (fd >= 0)
3007949d160bSJiri Olsa 			return fd;
3008949d160bSJiri Olsa 
3009949d160bSJiri Olsa 	} while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
3010949d160bSJiri Olsa 
3011949d160bSJiri Olsa 	return -EINVAL;
3012949d160bSJiri Olsa }
3013949d160bSJiri Olsa 
30144dff624aSJiri Olsa static void
30154dff624aSJiri Olsa dso_cache__free(struct rb_root *root)
3016949d160bSJiri Olsa {
30174dff624aSJiri Olsa 	struct rb_node *next = rb_first(root);
30184dff624aSJiri Olsa 
30194dff624aSJiri Olsa 	while (next) {
30204dff624aSJiri Olsa 		struct dso_cache *cache;
30214dff624aSJiri Olsa 
30224dff624aSJiri Olsa 		cache = rb_entry(next, struct dso_cache, rb_node);
30234dff624aSJiri Olsa 		next = rb_next(&cache->rb_node);
30244dff624aSJiri Olsa 		rb_erase(&cache->rb_node, root);
30254dff624aSJiri Olsa 		free(cache);
30264dff624aSJiri Olsa 	}
3027949d160bSJiri Olsa }
3028949d160bSJiri Olsa 
30294dff624aSJiri Olsa static struct dso_cache*
30304dff624aSJiri Olsa dso_cache__find(struct rb_root *root, u64 offset)
3031949d160bSJiri Olsa {
30324dff624aSJiri Olsa 	struct rb_node **p = &root->rb_node;
30334dff624aSJiri Olsa 	struct rb_node *parent = NULL;
30344dff624aSJiri Olsa 	struct dso_cache *cache;
30354dff624aSJiri Olsa 
30364dff624aSJiri Olsa 	while (*p != NULL) {
30374dff624aSJiri Olsa 		u64 end;
30384dff624aSJiri Olsa 
30394dff624aSJiri Olsa 		parent = *p;
30404dff624aSJiri Olsa 		cache = rb_entry(parent, struct dso_cache, rb_node);
30414dff624aSJiri Olsa 		end = cache->offset + DSO__DATA_CACHE_SIZE;
30424dff624aSJiri Olsa 
30434dff624aSJiri Olsa 		if (offset < cache->offset)
30444dff624aSJiri Olsa 			p = &(*p)->rb_left;
30454dff624aSJiri Olsa 		else if (offset >= end)
30464dff624aSJiri Olsa 			p = &(*p)->rb_right;
30474dff624aSJiri Olsa 		else
30484dff624aSJiri Olsa 			return cache;
30494dff624aSJiri Olsa 	}
30504dff624aSJiri Olsa 	return NULL;
3051949d160bSJiri Olsa }
3052949d160bSJiri Olsa 
30534dff624aSJiri Olsa static void
30544dff624aSJiri Olsa dso_cache__insert(struct rb_root *root, struct dso_cache *new)
30554dff624aSJiri Olsa {
30564dff624aSJiri Olsa 	struct rb_node **p = &root->rb_node;
30574dff624aSJiri Olsa 	struct rb_node *parent = NULL;
30584dff624aSJiri Olsa 	struct dso_cache *cache;
30594dff624aSJiri Olsa 	u64 offset = new->offset;
30604dff624aSJiri Olsa 
30614dff624aSJiri Olsa 	while (*p != NULL) {
30624dff624aSJiri Olsa 		u64 end;
30634dff624aSJiri Olsa 
30644dff624aSJiri Olsa 		parent = *p;
30654dff624aSJiri Olsa 		cache = rb_entry(parent, struct dso_cache, rb_node);
30664dff624aSJiri Olsa 		end = cache->offset + DSO__DATA_CACHE_SIZE;
30674dff624aSJiri Olsa 
30684dff624aSJiri Olsa 		if (offset < cache->offset)
30694dff624aSJiri Olsa 			p = &(*p)->rb_left;
30704dff624aSJiri Olsa 		else if (offset >= end)
30714dff624aSJiri Olsa 			p = &(*p)->rb_right;
30724dff624aSJiri Olsa 	}
30734dff624aSJiri Olsa 
30744dff624aSJiri Olsa 	rb_link_node(&new->rb_node, parent, p);
30754dff624aSJiri Olsa 	rb_insert_color(&new->rb_node, root);
30764dff624aSJiri Olsa }
30774dff624aSJiri Olsa 
30784dff624aSJiri Olsa static ssize_t
30794dff624aSJiri Olsa dso_cache__memcpy(struct dso_cache *cache, u64 offset,
30804dff624aSJiri Olsa 		  u8 *data, u64 size)
30814dff624aSJiri Olsa {
30824dff624aSJiri Olsa 	u64 cache_offset = offset - cache->offset;
30834dff624aSJiri Olsa 	u64 cache_size   = min(cache->size - cache_offset, size);
30844dff624aSJiri Olsa 
30854dff624aSJiri Olsa 	memcpy(data, cache->data + cache_offset, cache_size);
30864dff624aSJiri Olsa 	return cache_size;
30874dff624aSJiri Olsa }
30884dff624aSJiri Olsa 
30894dff624aSJiri Olsa static ssize_t
30904dff624aSJiri Olsa dso_cache__read(struct dso *dso, struct machine *machine,
3091949d160bSJiri Olsa 		 u64 offset, u8 *data, ssize_t size)
3092949d160bSJiri Olsa {
30934dff624aSJiri Olsa 	struct dso_cache *cache;
30944dff624aSJiri Olsa 	ssize_t ret;
3095949d160bSJiri Olsa 	int fd;
3096949d160bSJiri Olsa 
3097949d160bSJiri Olsa 	fd = dso__data_fd(dso, machine);
3098949d160bSJiri Olsa 	if (fd < 0)
3099949d160bSJiri Olsa 		return -1;
3100949d160bSJiri Olsa 
3101949d160bSJiri Olsa 	do {
31024dff624aSJiri Olsa 		u64 cache_offset;
31034dff624aSJiri Olsa 
31044dff624aSJiri Olsa 		ret = -ENOMEM;
31054dff624aSJiri Olsa 
31064dff624aSJiri Olsa 		cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
31074dff624aSJiri Olsa 		if (!cache)
3108949d160bSJiri Olsa 			break;
3109949d160bSJiri Olsa 
31104dff624aSJiri Olsa 		cache_offset = offset & DSO__DATA_CACHE_MASK;
31114dff624aSJiri Olsa 		ret = -EINVAL;
31124dff624aSJiri Olsa 
31134dff624aSJiri Olsa 		if (-1 == lseek(fd, cache_offset, SEEK_SET))
3114949d160bSJiri Olsa 			break;
3115949d160bSJiri Olsa 
31164dff624aSJiri Olsa 		ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
31174dff624aSJiri Olsa 		if (ret <= 0)
31184dff624aSJiri Olsa 			break;
31194dff624aSJiri Olsa 
31204dff624aSJiri Olsa 		cache->offset = cache_offset;
31214dff624aSJiri Olsa 		cache->size   = ret;
31224dff624aSJiri Olsa 		dso_cache__insert(&dso->cache, cache);
31234dff624aSJiri Olsa 
31244dff624aSJiri Olsa 		ret = dso_cache__memcpy(cache, offset, data, size);
3125949d160bSJiri Olsa 
3126949d160bSJiri Olsa 	} while (0);
3127949d160bSJiri Olsa 
31284dff624aSJiri Olsa 	if (ret <= 0)
31294dff624aSJiri Olsa 		free(cache);
31304dff624aSJiri Olsa 
3131949d160bSJiri Olsa 	close(fd);
31324dff624aSJiri Olsa 	return ret;
31334dff624aSJiri Olsa }
31344dff624aSJiri Olsa 
31354dff624aSJiri Olsa static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
31364dff624aSJiri Olsa 			      u64 offset, u8 *data, ssize_t size)
31374dff624aSJiri Olsa {
31384dff624aSJiri Olsa 	struct dso_cache *cache;
31394dff624aSJiri Olsa 
31404dff624aSJiri Olsa 	cache = dso_cache__find(&dso->cache, offset);
31414dff624aSJiri Olsa 	if (cache)
31424dff624aSJiri Olsa 		return dso_cache__memcpy(cache, offset, data, size);
31434dff624aSJiri Olsa 	else
31444dff624aSJiri Olsa 		return dso_cache__read(dso, machine, offset, data, size);
3145949d160bSJiri Olsa }
3146949d160bSJiri Olsa 
3147949d160bSJiri Olsa ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
3148949d160bSJiri Olsa 			      u64 offset, u8 *data, ssize_t size)
3149949d160bSJiri Olsa {
31504dff624aSJiri Olsa 	ssize_t r = 0;
31514dff624aSJiri Olsa 	u8 *p = data;
31524dff624aSJiri Olsa 
31534dff624aSJiri Olsa 	do {
31544dff624aSJiri Olsa 		ssize_t ret;
31554dff624aSJiri Olsa 
31564dff624aSJiri Olsa 		ret = dso_cache_read(dso, machine, offset, p, size);
31574dff624aSJiri Olsa 		if (ret < 0)
31584dff624aSJiri Olsa 			return ret;
31594dff624aSJiri Olsa 
31604dff624aSJiri Olsa 		/* Reached EOF, return what we have. */
31614dff624aSJiri Olsa 		if (!ret)
31624dff624aSJiri Olsa 			break;
31634dff624aSJiri Olsa 
31644dff624aSJiri Olsa 		BUG_ON(ret > size);
31654dff624aSJiri Olsa 
31664dff624aSJiri Olsa 		r      += ret;
31674dff624aSJiri Olsa 		p      += ret;
31684dff624aSJiri Olsa 		offset += ret;
31694dff624aSJiri Olsa 		size   -= ret;
31704dff624aSJiri Olsa 
31714dff624aSJiri Olsa 	} while (size);
31724dff624aSJiri Olsa 
31734dff624aSJiri Olsa 	return r;
3174949d160bSJiri Olsa }
3175949d160bSJiri Olsa 
3176949d160bSJiri Olsa ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
3177949d160bSJiri Olsa 			    struct machine *machine, u64 addr,
3178949d160bSJiri Olsa 			    u8 *data, ssize_t size)
3179949d160bSJiri Olsa {
3180949d160bSJiri Olsa 	u64 offset = map->map_ip(map, addr);
3181949d160bSJiri Olsa 	return dso__data_read_offset(dso, machine, offset, data, size);
3182949d160bSJiri Olsa }
3183