xref: /linux/tools/perf/util/symbol.c (revision 95011c600740837288a3b34b411244a4d9157c4e)
186470930SIngo Molnar #include "util.h"
286470930SIngo Molnar #include "../perf.h"
386470930SIngo Molnar #include "string.h"
486470930SIngo Molnar #include "symbol.h"
5439d473bSArnaldo Carvalho de Melo #include "thread.h"
686470930SIngo Molnar 
78f28827aSFrederic Weisbecker #include "debug.h"
88f28827aSFrederic Weisbecker 
9b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h>
1086470930SIngo Molnar #include <libelf.h>
1186470930SIngo Molnar #include <gelf.h>
1286470930SIngo Molnar #include <elf.h>
13f1617b40SArnaldo Carvalho de Melo #include <limits.h>
14439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
152cdbc46dSPeter Zijlstra 
16c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
17c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
18c12e15e7SArnaldo Carvalho de Melo #endif
19c12e15e7SArnaldo Carvalho de Melo 
2094cb9e38SArnaldo Carvalho de Melo enum dso_origin {
2194cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_KERNEL = 0,
2294cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_JAVA_JIT,
2394cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_FEDORA,
2494cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_UBUNTU,
2594cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_BUILDID,
2694cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_DSO,
27439d473bSArnaldo Carvalho de Melo 	DSO__ORIG_KMODULE,
2894cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_NOT_FOUND,
2994cb9e38SArnaldo Carvalho de Melo };
3094cb9e38SArnaldo Carvalho de Melo 
31b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
32*95011c60SArnaldo Carvalho de Melo static struct map *thread__find_map_by_name(struct thread *self, char *name);
333610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
346a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
36*95011c60SArnaldo Carvalho de Melo 				struct thread *thread, symbol_filter_t filter);
3700a192b3SArnaldo Carvalho de Melo unsigned int symbol__priv_size;
38cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
39cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
40439d473bSArnaldo Carvalho de Melo 
41b32d133aSArnaldo Carvalho de Melo static struct symbol_conf symbol_conf__defaults = {
42b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
43b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
44b32d133aSArnaldo Carvalho de Melo };
45b32d133aSArnaldo Carvalho de Melo 
46*95011c60SArnaldo Carvalho de Melo static struct thread kthread_mem, *kthread = &kthread_mem;
47af427bf5SArnaldo Carvalho de Melo 
483610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
493610583cSArnaldo Carvalho de Melo {
503610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
513610583cSArnaldo Carvalho de Melo }
523610583cSArnaldo Carvalho de Melo 
533610583cSArnaldo Carvalho de Melo static void dso__set_loaded(struct dso *self, enum map_type type)
543610583cSArnaldo Carvalho de Melo {
553610583cSArnaldo Carvalho de Melo 	self->loaded |= (1 << type);
563610583cSArnaldo Carvalho de Melo }
573610583cSArnaldo Carvalho de Melo 
58fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
59af427bf5SArnaldo Carvalho de Melo {
60fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
612e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
62af427bf5SArnaldo Carvalho de Melo 
63af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
64af427bf5SArnaldo Carvalho de Melo 		return;
65af427bf5SArnaldo Carvalho de Melo 
662e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
672e538c4aSArnaldo Carvalho de Melo 
68af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
692e538c4aSArnaldo Carvalho de Melo 		prev = curr;
702e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
71af427bf5SArnaldo Carvalho de Melo 
72af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
73af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
74af427bf5SArnaldo Carvalho de Melo 	}
75af427bf5SArnaldo Carvalho de Melo 
762e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
772e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
782e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
792e538c4aSArnaldo Carvalho de Melo }
802e538c4aSArnaldo Carvalho de Melo 
81*95011c60SArnaldo Carvalho de Melo static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
82af427bf5SArnaldo Carvalho de Melo {
83af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
84*95011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
85af427bf5SArnaldo Carvalho de Melo 
86af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
87af427bf5SArnaldo Carvalho de Melo 		return;
88af427bf5SArnaldo Carvalho de Melo 
89af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
90af427bf5SArnaldo Carvalho de Melo 
91af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
92af427bf5SArnaldo Carvalho de Melo 		prev = curr;
93af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
94af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
952e538c4aSArnaldo Carvalho de Melo 	}
9690c83218SArnaldo Carvalho de Melo 
9790c83218SArnaldo Carvalho de Melo 	/*
9890c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
9990c83218SArnaldo Carvalho de Melo 	 * last map final address.
10090c83218SArnaldo Carvalho de Melo 	 */
10190c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
102af427bf5SArnaldo Carvalho de Melo }
103af427bf5SArnaldo Carvalho de Melo 
104*95011c60SArnaldo Carvalho de Melo static void thread__fixup_maps_end(struct thread *self)
10523ea4a3fSArnaldo Carvalho de Melo {
10623ea4a3fSArnaldo Carvalho de Melo 	int i;
10723ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
108*95011c60SArnaldo Carvalho de Melo 		__thread__fixup_maps_end(self, i);
10923ea4a3fSArnaldo Carvalho de Melo }
11023ea4a3fSArnaldo Carvalho de Melo 
11100a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name)
11286470930SIngo Molnar {
11386470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
11436479484SArnaldo Carvalho de Melo 	struct symbol *self = zalloc(symbol__priv_size +
11536479484SArnaldo Carvalho de Melo 				     sizeof(*self) + namelen);
11636479484SArnaldo Carvalho de Melo 	if (self == NULL)
11786470930SIngo Molnar 		return NULL;
11886470930SIngo Molnar 
11936479484SArnaldo Carvalho de Melo 	if (symbol__priv_size)
12000a192b3SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol__priv_size;
12136479484SArnaldo Carvalho de Melo 
12286470930SIngo Molnar 	self->start = start;
1236cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
124e4204992SArnaldo Carvalho de Melo 
1256beba7adSArnaldo Carvalho de Melo 	pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
126e4204992SArnaldo Carvalho de Melo 
12786470930SIngo Molnar 	memcpy(self->name, name, namelen);
12886470930SIngo Molnar 
12986470930SIngo Molnar 	return self;
13086470930SIngo Molnar }
13186470930SIngo Molnar 
13200a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self)
13386470930SIngo Molnar {
13400a192b3SArnaldo Carvalho de Melo 	free(((void *)self) - symbol__priv_size);
13586470930SIngo Molnar }
13686470930SIngo Molnar 
13786470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
13886470930SIngo Molnar {
13986470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
14086470930SIngo Molnar 		       self->start, self->end, self->name);
14186470930SIngo Molnar }
14286470930SIngo Molnar 
143cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name)
144cfc10d3bSArnaldo Carvalho de Melo {
145ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
146ef6ae724SArnaldo Carvalho de Melo 		return;
147cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
148cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
149cfc10d3bSArnaldo Carvalho de Melo }
150cfc10d3bSArnaldo Carvalho de Melo 
151cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
152cfc10d3bSArnaldo Carvalho de Melo {
153cfc10d3bSArnaldo Carvalho de Melo 	self->short_name = basename(self->long_name);
154cfc10d3bSArnaldo Carvalho de Melo }
155cfc10d3bSArnaldo Carvalho de Melo 
15600a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
15786470930SIngo Molnar {
15886470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
15986470930SIngo Molnar 
16086470930SIngo Molnar 	if (self != NULL) {
1616a4694a4SArnaldo Carvalho de Melo 		int i;
16286470930SIngo Molnar 		strcpy(self->name, name);
163cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
164439d473bSArnaldo Carvalho de Melo 		self->short_name = self->name;
1656a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
1666a4694a4SArnaldo Carvalho de Melo 			self->symbols[i] = RB_ROOT;
1676a4694a4SArnaldo Carvalho de Melo 		self->find_symbol = dso__find_symbol;
16852d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
16994cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1708d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
1718d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
17286470930SIngo Molnar 	}
17386470930SIngo Molnar 
17486470930SIngo Molnar 	return self;
17586470930SIngo Molnar }
17686470930SIngo Molnar 
177fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
17886470930SIngo Molnar {
17986470930SIngo Molnar 	struct symbol *pos;
180fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
18186470930SIngo Molnar 
18286470930SIngo Molnar 	while (next) {
18386470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
18486470930SIngo Molnar 		next = rb_next(&pos->rb_node);
185fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
18600a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
18786470930SIngo Molnar 	}
18886470930SIngo Molnar }
18986470930SIngo Molnar 
19086470930SIngo Molnar void dso__delete(struct dso *self)
19186470930SIngo Molnar {
1926a4694a4SArnaldo Carvalho de Melo 	int i;
1936a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1946a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
195439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
196439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
19786470930SIngo Molnar 	free(self);
19886470930SIngo Molnar }
19986470930SIngo Molnar 
2008d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2018d06367fSArnaldo Carvalho de Melo {
2028d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2038d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2048d06367fSArnaldo Carvalho de Melo }
2058d06367fSArnaldo Carvalho de Melo 
206fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
20786470930SIngo Molnar {
208fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
20986470930SIngo Molnar 	struct rb_node *parent = NULL;
2109cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
21186470930SIngo Molnar 	struct symbol *s;
21286470930SIngo Molnar 
21386470930SIngo Molnar 	while (*p != NULL) {
21486470930SIngo Molnar 		parent = *p;
21586470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
21686470930SIngo Molnar 		if (ip < s->start)
21786470930SIngo Molnar 			p = &(*p)->rb_left;
21886470930SIngo Molnar 		else
21986470930SIngo Molnar 			p = &(*p)->rb_right;
22086470930SIngo Molnar 	}
22186470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
222fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
22386470930SIngo Molnar }
22486470930SIngo Molnar 
225fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
22686470930SIngo Molnar {
22786470930SIngo Molnar 	struct rb_node *n;
22886470930SIngo Molnar 
22986470930SIngo Molnar 	if (self == NULL)
23086470930SIngo Molnar 		return NULL;
23186470930SIngo Molnar 
232fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
23386470930SIngo Molnar 
23486470930SIngo Molnar 	while (n) {
23586470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
23686470930SIngo Molnar 
23786470930SIngo Molnar 		if (ip < s->start)
23886470930SIngo Molnar 			n = n->rb_left;
23986470930SIngo Molnar 		else if (ip > s->end)
24086470930SIngo Molnar 			n = n->rb_right;
24186470930SIngo Molnar 		else
24286470930SIngo Molnar 			return s;
24386470930SIngo Molnar 	}
24486470930SIngo Molnar 
24586470930SIngo Molnar 	return NULL;
24686470930SIngo Molnar }
24786470930SIngo Molnar 
2486a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
249fcf1203aSArnaldo Carvalho de Melo {
2506a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
251fcf1203aSArnaldo Carvalho de Melo }
252fcf1203aSArnaldo Carvalho de Melo 
2538d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf)
2548d06367fSArnaldo Carvalho de Melo {
2558d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
2568d06367fSArnaldo Carvalho de Melo 	u8 *raw = self;
2578d06367fSArnaldo Carvalho de Melo 	int i;
2588d06367fSArnaldo Carvalho de Melo 
2598d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
2608d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
2618d06367fSArnaldo Carvalho de Melo 		++raw;
2628d06367fSArnaldo Carvalho de Melo 		bid += 2;
2638d06367fSArnaldo Carvalho de Melo 	}
2648d06367fSArnaldo Carvalho de Melo 
2658d06367fSArnaldo Carvalho de Melo 	return raw - self;
2668d06367fSArnaldo Carvalho de Melo }
2678d06367fSArnaldo Carvalho de Melo 
2689e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
26986470930SIngo Molnar {
2708d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2718d06367fSArnaldo Carvalho de Melo 
2728d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
2739e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
2749e03eb2dSArnaldo Carvalho de Melo }
2759e03eb2dSArnaldo Carvalho de Melo 
276*95011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
2779e03eb2dSArnaldo Carvalho de Melo {
2789e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
2799e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
2809e03eb2dSArnaldo Carvalho de Melo 
2819e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
2826a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
283*95011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
28486470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
28586470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
28686470930SIngo Molnar 	}
28786470930SIngo Molnar 
28886470930SIngo Molnar 	return ret;
28986470930SIngo Molnar }
29086470930SIngo Molnar 
2912e538c4aSArnaldo Carvalho de Melo /*
2922e538c4aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
2932e538c4aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
2942e538c4aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
2952e538c4aSArnaldo Carvalho de Melo  */
2964e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map)
29786470930SIngo Molnar {
29886470930SIngo Molnar 	char *line = NULL;
29986470930SIngo Molnar 	size_t n;
3004e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
30186470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
30286470930SIngo Molnar 
30386470930SIngo Molnar 	if (file == NULL)
30486470930SIngo Molnar 		goto out_failure;
30586470930SIngo Molnar 
30686470930SIngo Molnar 	while (!feof(file)) {
3079cffa8d5SPaul Mackerras 		u64 start;
30886470930SIngo Molnar 		struct symbol *sym;
30986470930SIngo Molnar 		int line_len, len;
31086470930SIngo Molnar 		char symbol_type;
3112e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
31286470930SIngo Molnar 
31386470930SIngo Molnar 		line_len = getline(&line, &n, file);
31486470930SIngo Molnar 		if (line_len < 0)
31586470930SIngo Molnar 			break;
31686470930SIngo Molnar 
31786470930SIngo Molnar 		if (!line)
31886470930SIngo Molnar 			goto out_failure;
31986470930SIngo Molnar 
32086470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
32186470930SIngo Molnar 
32286470930SIngo Molnar 		len = hex2u64(line, &start);
32386470930SIngo Molnar 
32486470930SIngo Molnar 		len++;
32586470930SIngo Molnar 		if (len + 2 >= line_len)
32686470930SIngo Molnar 			continue;
32786470930SIngo Molnar 
32886470930SIngo Molnar 		symbol_type = toupper(line[len]);
32986470930SIngo Molnar 		/*
33086470930SIngo Molnar 		 * We're interested only in code ('T'ext)
33186470930SIngo Molnar 		 */
33286470930SIngo Molnar 		if (symbol_type != 'T' && symbol_type != 'W')
33386470930SIngo Molnar 			continue;
334af427bf5SArnaldo Carvalho de Melo 
335af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
3362e538c4aSArnaldo Carvalho de Melo 		/*
3372e538c4aSArnaldo Carvalho de Melo 		 * Will fix up the end later, when we have all symbols sorted.
3382e538c4aSArnaldo Carvalho de Melo 		 */
33900a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, 0, symbol_name);
340af427bf5SArnaldo Carvalho de Melo 
3412e538c4aSArnaldo Carvalho de Melo 		if (sym == NULL)
3422e538c4aSArnaldo Carvalho de Melo 			goto out_delete_line;
34382164161SArnaldo Carvalho de Melo 		/*
34482164161SArnaldo Carvalho de Melo 		 * We will pass the symbols to the filter later, in
3454e06255fSArnaldo Carvalho de Melo 		 * map__split_kallsyms, when we have split the maps per module
34682164161SArnaldo Carvalho de Melo 		 */
3474e06255fSArnaldo Carvalho de Melo 		symbols__insert(root, sym);
3482e538c4aSArnaldo Carvalho de Melo 	}
3492e538c4aSArnaldo Carvalho de Melo 
3502e538c4aSArnaldo Carvalho de Melo 	free(line);
3512e538c4aSArnaldo Carvalho de Melo 	fclose(file);
3522e538c4aSArnaldo Carvalho de Melo 
3532e538c4aSArnaldo Carvalho de Melo 	return 0;
3542e538c4aSArnaldo Carvalho de Melo 
3552e538c4aSArnaldo Carvalho de Melo out_delete_line:
3562e538c4aSArnaldo Carvalho de Melo 	free(line);
3572e538c4aSArnaldo Carvalho de Melo out_failure:
3582e538c4aSArnaldo Carvalho de Melo 	return -1;
3592e538c4aSArnaldo Carvalho de Melo }
3602e538c4aSArnaldo Carvalho de Melo 
3612e538c4aSArnaldo Carvalho de Melo /*
3622e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
3632e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
3642e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
3652e538c4aSArnaldo Carvalho de Melo  */
366*95011c60SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread,
3674e06255fSArnaldo Carvalho de Melo 			       symbol_filter_t filter)
3682e538c4aSArnaldo Carvalho de Melo {
3694e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
3702e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
3712e538c4aSArnaldo Carvalho de Melo 	int count = 0;
3724e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
3734e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
3742e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
3752e538c4aSArnaldo Carvalho de Melo 
3762e538c4aSArnaldo Carvalho de Melo 	while (next) {
3772e538c4aSArnaldo Carvalho de Melo 		char *module;
3782e538c4aSArnaldo Carvalho de Melo 
3792e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
3802e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
3812e538c4aSArnaldo Carvalho de Melo 
3822e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
3832e538c4aSArnaldo Carvalho de Melo 		if (module) {
3842e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
3852e538c4aSArnaldo Carvalho de Melo 
3864e06255fSArnaldo Carvalho de Melo 			if (strcmp(self->name, module)) {
387*95011c60SArnaldo Carvalho de Melo 				curr_map = thread__find_map_by_name(thread, module);
3884e06255fSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
389*95011c60SArnaldo Carvalho de Melo 					pr_debug("/proc/{kallsyms,modules} "
3906beba7adSArnaldo Carvalho de Melo 					         "inconsistency!\n");
391af427bf5SArnaldo Carvalho de Melo 					return -1;
392af427bf5SArnaldo Carvalho de Melo 				}
393af427bf5SArnaldo Carvalho de Melo 			}
39486470930SIngo Molnar 			/*
3952e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
3962e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
39786470930SIngo Molnar 			 */
3984e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
3994e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
4004e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
4012e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
4022e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
40386470930SIngo Molnar 
4042e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
4052e538c4aSArnaldo Carvalho de Melo 				 kernel_range++);
40686470930SIngo Molnar 
40700a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
4082e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
4092e538c4aSArnaldo Carvalho de Melo 				return -1;
4102e538c4aSArnaldo Carvalho de Melo 
4114e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
4122e538c4aSArnaldo Carvalho de Melo 			if (map == NULL) {
4132e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
4142e538c4aSArnaldo Carvalho de Melo 				return -1;
4152e538c4aSArnaldo Carvalho de Melo 			}
4162e538c4aSArnaldo Carvalho de Melo 
4174e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
418*95011c60SArnaldo Carvalho de Melo 			__thread__insert_map(thread, curr_map);
4192e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
4202e538c4aSArnaldo Carvalho de Melo 		}
4212e538c4aSArnaldo Carvalho de Melo 
4224e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
4234e06255fSArnaldo Carvalho de Melo 			rb_erase(&pos->rb_node, root);
42400a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
4252e538c4aSArnaldo Carvalho de Melo 		} else {
4264e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
4274e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
4284e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
4292e538c4aSArnaldo Carvalho de Melo 			}
4309974f496SMike Galbraith 			count++;
4319974f496SMike Galbraith 		}
43286470930SIngo Molnar 	}
43386470930SIngo Molnar 
4349974f496SMike Galbraith 	return count;
43586470930SIngo Molnar }
43686470930SIngo Molnar 
4372e538c4aSArnaldo Carvalho de Melo 
4384e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map,
439*95011c60SArnaldo Carvalho de Melo 			      struct thread *thread, symbol_filter_t filter)
4402e538c4aSArnaldo Carvalho de Melo {
4414e06255fSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, map) < 0)
4422e538c4aSArnaldo Carvalho de Melo 		return -1;
4432e538c4aSArnaldo Carvalho de Melo 
4444e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
4454e06255fSArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_KERNEL;
4462e538c4aSArnaldo Carvalho de Melo 
447*95011c60SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, thread, filter);
44823ea4a3fSArnaldo Carvalho de Melo }
44923ea4a3fSArnaldo Carvalho de Melo 
45023ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp)
45123ea4a3fSArnaldo Carvalho de Melo {
45223ea4a3fSArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "Kernel maps:\n");
453*95011c60SArnaldo Carvalho de Melo 	printed += thread__fprintf_maps(kthread, fp);
4546beba7adSArnaldo Carvalho de Melo 	return printed + fprintf(fp, "END kernel maps\n");
455af427bf5SArnaldo Carvalho de Melo }
456af427bf5SArnaldo Carvalho de Melo 
457439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
4586beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
45980d496beSPekka Enberg {
46080d496beSPekka Enberg 	char *line = NULL;
46180d496beSPekka Enberg 	size_t n;
46280d496beSPekka Enberg 	FILE *file;
46380d496beSPekka Enberg 	int nr_syms = 0;
46480d496beSPekka Enberg 
465439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
46680d496beSPekka Enberg 	if (file == NULL)
46780d496beSPekka Enberg 		goto out_failure;
46880d496beSPekka Enberg 
46980d496beSPekka Enberg 	while (!feof(file)) {
4709cffa8d5SPaul Mackerras 		u64 start, size;
47180d496beSPekka Enberg 		struct symbol *sym;
47280d496beSPekka Enberg 		int line_len, len;
47380d496beSPekka Enberg 
47480d496beSPekka Enberg 		line_len = getline(&line, &n, file);
47580d496beSPekka Enberg 		if (line_len < 0)
47680d496beSPekka Enberg 			break;
47780d496beSPekka Enberg 
47880d496beSPekka Enberg 		if (!line)
47980d496beSPekka Enberg 			goto out_failure;
48080d496beSPekka Enberg 
48180d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
48280d496beSPekka Enberg 
48380d496beSPekka Enberg 		len = hex2u64(line, &start);
48480d496beSPekka Enberg 
48580d496beSPekka Enberg 		len++;
48680d496beSPekka Enberg 		if (len + 2 >= line_len)
48780d496beSPekka Enberg 			continue;
48880d496beSPekka Enberg 
48980d496beSPekka Enberg 		len += hex2u64(line + len, &size);
49080d496beSPekka Enberg 
49180d496beSPekka Enberg 		len++;
49280d496beSPekka Enberg 		if (len + 2 >= line_len)
49380d496beSPekka Enberg 			continue;
49480d496beSPekka Enberg 
49500a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
49680d496beSPekka Enberg 
49780d496beSPekka Enberg 		if (sym == NULL)
49880d496beSPekka Enberg 			goto out_delete_line;
49980d496beSPekka Enberg 
500439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
50100a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
50280d496beSPekka Enberg 		else {
5036a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
50480d496beSPekka Enberg 			nr_syms++;
50580d496beSPekka Enberg 		}
50680d496beSPekka Enberg 	}
50780d496beSPekka Enberg 
50880d496beSPekka Enberg 	free(line);
50980d496beSPekka Enberg 	fclose(file);
51080d496beSPekka Enberg 
51180d496beSPekka Enberg 	return nr_syms;
51280d496beSPekka Enberg 
51380d496beSPekka Enberg out_delete_line:
51480d496beSPekka Enberg 	free(line);
51580d496beSPekka Enberg out_failure:
51680d496beSPekka Enberg 	return -1;
51780d496beSPekka Enberg }
51880d496beSPekka Enberg 
51986470930SIngo Molnar /**
52086470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
52186470930SIngo Molnar  *
52286470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
52383a0944fSIngo Molnar  * @idx: uint32_t idx
52486470930SIngo Molnar  * @sym: GElf_Sym iterator
52586470930SIngo Molnar  */
52683a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
52783a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
52883a0944fSIngo Molnar 	     idx < nr_syms; \
52983a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
53086470930SIngo Molnar 
53186470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
53286470930SIngo Molnar {
53386470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
53486470930SIngo Molnar }
53586470930SIngo Molnar 
53686470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
53786470930SIngo Molnar {
53886470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
53986470930SIngo Molnar 	       sym->st_name != 0 &&
54081833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
54186470930SIngo Molnar }
54286470930SIngo Molnar 
5436cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
5446cfcc53eSMike Galbraith {
5456cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
5466cfcc53eSMike Galbraith 		sym->st_name != 0 &&
5476cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
5486cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
5496cfcc53eSMike Galbraith }
5506cfcc53eSMike Galbraith 
5516cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
5526cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5536cfcc53eSMike Galbraith {
5546cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
5556cfcc53eSMike Galbraith }
5566cfcc53eSMike Galbraith 
5576cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
5586cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5596cfcc53eSMike Galbraith {
5606cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
5616cfcc53eSMike Galbraith }
5626cfcc53eSMike Galbraith 
56386470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
56486470930SIngo Molnar 					const Elf_Data *symstrs)
56586470930SIngo Molnar {
56686470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
56786470930SIngo Molnar }
56886470930SIngo Molnar 
56986470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
57086470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
57183a0944fSIngo Molnar 				    size_t *idx)
57286470930SIngo Molnar {
57386470930SIngo Molnar 	Elf_Scn *sec = NULL;
57486470930SIngo Molnar 	size_t cnt = 1;
57586470930SIngo Molnar 
57686470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
57786470930SIngo Molnar 		char *str;
57886470930SIngo Molnar 
57986470930SIngo Molnar 		gelf_getshdr(sec, shp);
58086470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
58186470930SIngo Molnar 		if (!strcmp(name, str)) {
58283a0944fSIngo Molnar 			if (idx)
58383a0944fSIngo Molnar 				*idx = cnt;
58486470930SIngo Molnar 			break;
58586470930SIngo Molnar 		}
58686470930SIngo Molnar 		++cnt;
58786470930SIngo Molnar 	}
58886470930SIngo Molnar 
58986470930SIngo Molnar 	return sec;
59086470930SIngo Molnar }
59186470930SIngo Molnar 
59286470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
59386470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
59486470930SIngo Molnar 	     idx < nr_entries; \
59586470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
59686470930SIngo Molnar 
59786470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
59886470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
59986470930SIngo Molnar 	     idx < nr_entries; \
60086470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
60186470930SIngo Molnar 
602a25e46c4SArnaldo Carvalho de Melo /*
603a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
604a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
605a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
606a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
607a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
608a25e46c4SArnaldo Carvalho de Melo  */
60982164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
61082164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
61186470930SIngo Molnar {
61286470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
61386470930SIngo Molnar 	GElf_Sym sym;
6149cffa8d5SPaul Mackerras 	u64 plt_offset;
61586470930SIngo Molnar 	GElf_Shdr shdr_plt;
61686470930SIngo Molnar 	struct symbol *f;
617a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
61886470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
619a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
620a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
621a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
62286470930SIngo Molnar 	char sympltname[1024];
623a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
624a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
62586470930SIngo Molnar 
626439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
627a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
628a25e46c4SArnaldo Carvalho de Melo 		goto out;
629a25e46c4SArnaldo Carvalho de Melo 
63084087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
631a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
632a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
633a25e46c4SArnaldo Carvalho de Melo 
634a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
635a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
636a25e46c4SArnaldo Carvalho de Melo 
637a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
638a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
639a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
640a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
641a25e46c4SArnaldo Carvalho de Melo 
642a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
64386470930SIngo Molnar 					  ".rela.plt", NULL);
64486470930SIngo Molnar 	if (scn_plt_rel == NULL) {
645a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
64686470930SIngo Molnar 						  ".rel.plt", NULL);
64786470930SIngo Molnar 		if (scn_plt_rel == NULL)
648a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
64986470930SIngo Molnar 	}
65086470930SIngo Molnar 
651a25e46c4SArnaldo Carvalho de Melo 	err = -1;
65286470930SIngo Molnar 
653a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
654a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
655a25e46c4SArnaldo Carvalho de Melo 
656a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
657a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
65886470930SIngo Molnar 
65986470930SIngo Molnar 	/*
66083a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
66186470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
66286470930SIngo Molnar 	 */
66386470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
66486470930SIngo Molnar 	if (reldata == NULL)
665a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
66686470930SIngo Molnar 
66786470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
66886470930SIngo Molnar 	if (syms == NULL)
669a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
67086470930SIngo Molnar 
671a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
67286470930SIngo Molnar 	if (scn_symstrs == NULL)
673a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
67486470930SIngo Molnar 
67586470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
67686470930SIngo Molnar 	if (symstrs == NULL)
677a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
67886470930SIngo Molnar 
67986470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
68086470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
68186470930SIngo Molnar 
68286470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
68386470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
68486470930SIngo Molnar 
68586470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
68686470930SIngo Molnar 					   nr_rel_entries) {
68786470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
68886470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
68986470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
69086470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
69186470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
69286470930SIngo Molnar 
69386470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
69400a192b3SArnaldo Carvalho de Melo 					sympltname);
69586470930SIngo Molnar 			if (!f)
696a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
69786470930SIngo Molnar 
69882164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
69982164161SArnaldo Carvalho de Melo 				symbol__delete(f);
70082164161SArnaldo Carvalho de Melo 			else {
7016a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
70286470930SIngo Molnar 				++nr;
70386470930SIngo Molnar 			}
70482164161SArnaldo Carvalho de Melo 		}
70586470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
70686470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
70786470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
70886470930SIngo Molnar 					  nr_rel_entries) {
70986470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
71086470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
71186470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
71286470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
71386470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
71486470930SIngo Molnar 
71586470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
71600a192b3SArnaldo Carvalho de Melo 					sympltname);
71786470930SIngo Molnar 			if (!f)
718a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
71986470930SIngo Molnar 
72082164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
72182164161SArnaldo Carvalho de Melo 				symbol__delete(f);
72282164161SArnaldo Carvalho de Melo 			else {
7236a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
72486470930SIngo Molnar 				++nr;
72586470930SIngo Molnar 			}
72686470930SIngo Molnar 		}
72782164161SArnaldo Carvalho de Melo 	}
72886470930SIngo Molnar 
729a25e46c4SArnaldo Carvalho de Melo 	err = 0;
730a25e46c4SArnaldo Carvalho de Melo out_elf_end:
731a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
732a25e46c4SArnaldo Carvalho de Melo out_close:
733a25e46c4SArnaldo Carvalho de Melo 	close(fd);
734a25e46c4SArnaldo Carvalho de Melo 
735a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
73686470930SIngo Molnar 		return nr;
737a25e46c4SArnaldo Carvalho de Melo out:
7386beba7adSArnaldo Carvalho de Melo 	pr_warning("%s: problems reading %s PLT info.\n",
739439d473bSArnaldo Carvalho de Melo 		   __func__, self->long_name);
740a25e46c4SArnaldo Carvalho de Melo 	return 0;
74186470930SIngo Molnar }
74286470930SIngo Molnar 
743*95011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map,
744*95011c60SArnaldo Carvalho de Melo 			 struct thread *thread, const char *name, int fd,
745*95011c60SArnaldo Carvalho de Melo 			 symbol_filter_t filter, int kernel, int kmodule)
74686470930SIngo Molnar {
7472e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
7482e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
7492e538c4aSArnaldo Carvalho de Melo 	size_t dso_name_len = strlen(self->short_name);
7506cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
75186470930SIngo Molnar 	uint32_t nr_syms;
75286470930SIngo Molnar 	int err = -1;
75383a0944fSIngo Molnar 	uint32_t idx;
75486470930SIngo Molnar 	GElf_Ehdr ehdr;
75586470930SIngo Molnar 	GElf_Shdr shdr;
75686470930SIngo Molnar 	Elf_Data *syms;
75786470930SIngo Molnar 	GElf_Sym sym;
758a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
75986470930SIngo Molnar 	Elf *elf;
760439d473bSArnaldo Carvalho de Melo 	int nr = 0;
76186470930SIngo Molnar 
76284087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
76386470930SIngo Molnar 	if (elf == NULL) {
7646beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
76586470930SIngo Molnar 		goto out_close;
76686470930SIngo Molnar 	}
76786470930SIngo Molnar 
76886470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
7696beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
77086470930SIngo Molnar 		goto out_elf_end;
77186470930SIngo Molnar 	}
77286470930SIngo Molnar 
77386470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
77486470930SIngo Molnar 	if (sec == NULL) {
775a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
776a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
77786470930SIngo Molnar 			goto out_elf_end;
77886470930SIngo Molnar 	}
77986470930SIngo Molnar 
78086470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
78186470930SIngo Molnar 	if (syms == NULL)
78286470930SIngo Molnar 		goto out_elf_end;
78386470930SIngo Molnar 
78486470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
78586470930SIngo Molnar 	if (sec == NULL)
78686470930SIngo Molnar 		goto out_elf_end;
78786470930SIngo Molnar 
78886470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
78986470930SIngo Molnar 	if (symstrs == NULL)
79086470930SIngo Molnar 		goto out_elf_end;
79186470930SIngo Molnar 
7926cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
7936cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
7946cfcc53eSMike Galbraith 		goto out_elf_end;
7956cfcc53eSMike Galbraith 
7966cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
7979b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
7986cfcc53eSMike Galbraith 		goto out_elf_end;
7996cfcc53eSMike Galbraith 
80086470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
80186470930SIngo Molnar 
802e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
803d20ff6bdSMike Galbraith 	if (!kernel) {
80430d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
80530d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
806f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
80730d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
808d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
809d20ff6bdSMike Galbraith 
81083a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
81186470930SIngo Molnar 		struct symbol *f;
81283a0944fSIngo Molnar 		const char *elf_name;
8132e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
8146cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
8156cfcc53eSMike Galbraith 		const char *section_name;
81686470930SIngo Molnar 
8176cfcc53eSMike Galbraith 		if (!is_label && !elf_sym__is_function(&sym))
81886470930SIngo Molnar 			continue;
81986470930SIngo Molnar 
82086470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
82186470930SIngo Molnar 		if (!sec)
82286470930SIngo Molnar 			goto out_elf_end;
82386470930SIngo Molnar 
82486470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
8256cfcc53eSMike Galbraith 
8266cfcc53eSMike Galbraith 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
8276cfcc53eSMike Galbraith 			continue;
8286cfcc53eSMike Galbraith 
8292e538c4aSArnaldo Carvalho de Melo 		elf_name = elf_sym__name(&sym, symstrs);
8306cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
83186470930SIngo Molnar 
8322e538c4aSArnaldo Carvalho de Melo 		if (kernel || kmodule) {
8332e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
8342e538c4aSArnaldo Carvalho de Melo 
8352e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
8362e538c4aSArnaldo Carvalho de Melo 				   curr_dso->short_name + dso_name_len) == 0)
8372e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
8382e538c4aSArnaldo Carvalho de Melo 
8392e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
8402e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
8412e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
8422e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
843af427bf5SArnaldo Carvalho de Melo 			}
844af427bf5SArnaldo Carvalho de Melo 
8452e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
8462e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
8472e538c4aSArnaldo Carvalho de Melo 
848*95011c60SArnaldo Carvalho de Melo 			curr_map = thread__find_map_by_name(thread, dso_name);
8492e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
8502e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
8512e538c4aSArnaldo Carvalho de Melo 
8522e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
8532e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
8542e538c4aSArnaldo Carvalho de Melo 
85500a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
8562e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
8572e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8583610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
8593610583cSArnaldo Carvalho de Melo 						     MAP__FUNCTION);
8602e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
8612e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
8622e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8632e538c4aSArnaldo Carvalho de Melo 				}
864ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
865ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
8662e538c4aSArnaldo Carvalho de Melo 				curr_dso->origin = DSO__ORIG_KERNEL;
867*95011c60SArnaldo Carvalho de Melo 				__thread__insert_map(kthread, curr_map);
868b0da954aSArnaldo Carvalho de Melo 				dsos__add(&dsos__kernel, curr_dso);
8692e538c4aSArnaldo Carvalho de Melo 			} else
8702e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
8712e538c4aSArnaldo Carvalho de Melo 
8722e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
8732e538c4aSArnaldo Carvalho de Melo 		}
8742e538c4aSArnaldo Carvalho de Melo 
8752e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
8766beba7adSArnaldo Carvalho de Melo 			pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
8776beba7adSArnaldo Carvalho de Melo 				  "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
8786beba7adSArnaldo Carvalho de Melo 				  (u64)shdr.sh_addr, (u64)shdr.sh_offset);
87986470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
880af427bf5SArnaldo Carvalho de Melo 		}
88128ac909bSArnaldo Carvalho de Melo 		/*
88228ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
88328ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
88428ac909bSArnaldo Carvalho de Melo 		 * to it...
88528ac909bSArnaldo Carvalho de Melo 		 */
88683a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
88728ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
88883a0944fSIngo Molnar 			elf_name = demangled;
8892e538c4aSArnaldo Carvalho de Melo new_symbol:
89000a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
89128ac909bSArnaldo Carvalho de Melo 		free(demangled);
89286470930SIngo Molnar 		if (!f)
89386470930SIngo Molnar 			goto out_elf_end;
89486470930SIngo Molnar 
8952e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
89600a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
89786470930SIngo Molnar 		else {
8986a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
89986470930SIngo Molnar 			nr++;
90086470930SIngo Molnar 		}
90186470930SIngo Molnar 	}
90286470930SIngo Molnar 
9032e538c4aSArnaldo Carvalho de Melo 	/*
9042e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
9052e538c4aSArnaldo Carvalho de Melo 	 */
9062e538c4aSArnaldo Carvalho de Melo 	if (nr > 0)
9076a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
90886470930SIngo Molnar 	err = nr;
90986470930SIngo Molnar out_elf_end:
91086470930SIngo Molnar 	elf_end(elf);
91186470930SIngo Molnar out_close:
91286470930SIngo Molnar 	return err;
91386470930SIngo Molnar }
91486470930SIngo Molnar 
91578075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
91678075caaSArnaldo Carvalho de Melo {
91778075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
91878075caaSArnaldo Carvalho de Melo }
91978075caaSArnaldo Carvalho de Melo 
920b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head)
92157f395a7SFrederic Weisbecker {
922e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
92357f395a7SFrederic Weisbecker 	struct dso *pos;
92457f395a7SFrederic Weisbecker 
925b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
926e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
927e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
928e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
929e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
93057f395a7SFrederic Weisbecker 		}
93157f395a7SFrederic Weisbecker 
932e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
93357f395a7SFrederic Weisbecker }
93457f395a7SFrederic Weisbecker 
935b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void)
936b0da954aSArnaldo Carvalho de Melo {
937b0da954aSArnaldo Carvalho de Melo 	return __dsos__read_build_ids(&dsos__kernel) ||
938b0da954aSArnaldo Carvalho de Melo 	       __dsos__read_build_ids(&dsos__user);
939b0da954aSArnaldo Carvalho de Melo }
940b0da954aSArnaldo Carvalho de Melo 
941fd7a346eSArnaldo Carvalho de Melo /*
942fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
943fd7a346eSArnaldo Carvalho de Melo  */
944fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
945fd7a346eSArnaldo Carvalho de Melo 
9462643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
9474d1e00a8SArnaldo Carvalho de Melo {
9482643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
9494d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
9504d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
951fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
9524d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
953e57cfcdaSPekka Enberg 	Elf_Kind ek;
954fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
9554d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
9564d1e00a8SArnaldo Carvalho de Melo 
9572643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
9582643ce11SArnaldo Carvalho de Melo 		goto out;
9592643ce11SArnaldo Carvalho de Melo 
9602643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
9614d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
9624d1e00a8SArnaldo Carvalho de Melo 		goto out;
9634d1e00a8SArnaldo Carvalho de Melo 
96484087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
9654d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
9668d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
9674d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
9684d1e00a8SArnaldo Carvalho de Melo 	}
9694d1e00a8SArnaldo Carvalho de Melo 
970e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
971e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
972e57cfcdaSPekka Enberg 		goto out_elf_end;
973e57cfcdaSPekka Enberg 
9744d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
9756beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
9764d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
9774d1e00a8SArnaldo Carvalho de Melo 	}
9784d1e00a8SArnaldo Carvalho de Melo 
9792643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
9802643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
981fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
982fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
983fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
9844d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
9854d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
986fd7a346eSArnaldo Carvalho de Melo 	}
9874d1e00a8SArnaldo Carvalho de Melo 
988fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
989fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
9904d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
991fd7a346eSArnaldo Carvalho de Melo 
992fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
993fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
994fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
995fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
996fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
997fd7a346eSArnaldo Carvalho de Melo 		const char *name;
998fd7a346eSArnaldo Carvalho de Melo 
999fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1000fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1001fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1002fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1003fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1004fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1005fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
10062643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1007fd7a346eSArnaldo Carvalho de Melo 				break;
1008fd7a346eSArnaldo Carvalho de Melo 			}
1009fd7a346eSArnaldo Carvalho de Melo 		}
1010fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1011fd7a346eSArnaldo Carvalho de Melo 	}
10122643ce11SArnaldo Carvalho de Melo out_elf_end:
10132643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
10142643ce11SArnaldo Carvalho de Melo out_close:
10152643ce11SArnaldo Carvalho de Melo 	close(fd);
10162643ce11SArnaldo Carvalho de Melo out:
10172643ce11SArnaldo Carvalho de Melo 	return err;
10182643ce11SArnaldo Carvalho de Melo }
10192643ce11SArnaldo Carvalho de Melo 
1020f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1021f1617b40SArnaldo Carvalho de Melo {
1022f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1023f1617b40SArnaldo Carvalho de Melo 
1024f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1025f1617b40SArnaldo Carvalho de Melo 		goto out;
1026f1617b40SArnaldo Carvalho de Melo 
1027f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1028f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1029f1617b40SArnaldo Carvalho de Melo 		goto out;
1030f1617b40SArnaldo Carvalho de Melo 
1031f1617b40SArnaldo Carvalho de Melo 	while (1) {
1032f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1033f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1034f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1035f1617b40SArnaldo Carvalho de Melo 
1036f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1037f1617b40SArnaldo Carvalho de Melo 			break;
1038f1617b40SArnaldo Carvalho de Melo 
1039fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1040fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1041f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1042f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1043f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1044f1617b40SArnaldo Carvalho de Melo 				break;
1045f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1046f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1047f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1048f1617b40SArnaldo Carvalho de Melo 					err = 0;
1049f1617b40SArnaldo Carvalho de Melo 					break;
1050f1617b40SArnaldo Carvalho de Melo 				}
1051f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1052f1617b40SArnaldo Carvalho de Melo 				break;
1053f1617b40SArnaldo Carvalho de Melo 		} else {
1054f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1055f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1056f1617b40SArnaldo Carvalho de Melo 				break;
1057f1617b40SArnaldo Carvalho de Melo 		}
1058f1617b40SArnaldo Carvalho de Melo 	}
1059f1617b40SArnaldo Carvalho de Melo 	close(fd);
1060f1617b40SArnaldo Carvalho de Melo out:
1061f1617b40SArnaldo Carvalho de Melo 	return err;
1062f1617b40SArnaldo Carvalho de Melo }
1063f1617b40SArnaldo Carvalho de Melo 
106494cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
106594cb9e38SArnaldo Carvalho de Melo {
106694cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
106794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
106894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
106994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
107094cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
107194cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
107294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1073439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
107494cb9e38SArnaldo Carvalho de Melo 	};
107594cb9e38SArnaldo Carvalho de Melo 
107694cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
107794cb9e38SArnaldo Carvalho de Melo 		return '!';
107894cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
107994cb9e38SArnaldo Carvalho de Melo }
108094cb9e38SArnaldo Carvalho de Melo 
10816beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
108286470930SIngo Molnar {
10834d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1084c338aee8SArnaldo Carvalho de Melo 	char *name;
1085d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
108686470930SIngo Molnar 	int ret = -1;
108786470930SIngo Molnar 	int fd;
108886470930SIngo Molnar 
10893610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
109066bd8424SArnaldo Carvalho de Melo 
1091c338aee8SArnaldo Carvalho de Melo 	if (self->kernel)
1092*95011c60SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, kthread, filter);
1093c338aee8SArnaldo Carvalho de Melo 
1094c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
109586470930SIngo Molnar 	if (!name)
109686470930SIngo Molnar 		return -1;
109786470930SIngo Molnar 
109830d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1099f5812a7aSArnaldo Carvalho de Melo 
110094cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
11016beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
110294cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
110394cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
110494cb9e38SArnaldo Carvalho de Melo 		return ret;
110594cb9e38SArnaldo Carvalho de Melo 	}
110694cb9e38SArnaldo Carvalho de Melo 
110794cb9e38SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_FEDORA - 1;
110880d496beSPekka Enberg 
110986470930SIngo Molnar more:
111086470930SIngo Molnar 	do {
111194cb9e38SArnaldo Carvalho de Melo 		self->origin++;
111294cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
111394cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1114439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1115439d473bSArnaldo Carvalho de Melo 				 self->long_name);
111686470930SIngo Molnar 			break;
111794cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1118439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1119439d473bSArnaldo Carvalho de Melo 				 self->long_name);
112086470930SIngo Molnar 			break;
112194cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1122d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1123d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1124d3379ab9SArnaldo Carvalho de Melo 				char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1125d3379ab9SArnaldo Carvalho de Melo 
1126d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1127d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
11284d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
11294d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1130d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1131d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
11328d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1133d3379ab9SArnaldo Carvalho de Melo 				break;
11344d1e00a8SArnaldo Carvalho de Melo 			}
113594cb9e38SArnaldo Carvalho de Melo 			self->origin++;
11364d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
113794cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1138439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
113986470930SIngo Molnar 			break;
114086470930SIngo Molnar 
114186470930SIngo Molnar 		default:
114286470930SIngo Molnar 			goto out;
114386470930SIngo Molnar 		}
114486470930SIngo Molnar 
11458d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1146d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1147d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
11488d06367fSArnaldo Carvalho de Melo 				goto more;
11498d06367fSArnaldo Carvalho de Melo compare_build_id:
115078075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
11518d06367fSArnaldo Carvalho de Melo 				goto more;
11528d06367fSArnaldo Carvalho de Melo 		}
11538d06367fSArnaldo Carvalho de Melo 
115486470930SIngo Molnar 		fd = open(name, O_RDONLY);
115586470930SIngo Molnar 	} while (fd < 0);
115686470930SIngo Molnar 
1157*95011c60SArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
115886470930SIngo Molnar 	close(fd);
115986470930SIngo Molnar 
116086470930SIngo Molnar 	/*
116186470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
116286470930SIngo Molnar 	 */
116386470930SIngo Molnar 	if (!ret)
116486470930SIngo Molnar 		goto more;
116586470930SIngo Molnar 
1166a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
116782164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1168a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1169a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1170a25e46c4SArnaldo Carvalho de Melo 	}
117186470930SIngo Molnar out:
117286470930SIngo Molnar 	free(name);
11731340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
11741340e6bbSArnaldo Carvalho de Melo 		return 0;
117586470930SIngo Molnar 	return ret;
117686470930SIngo Molnar }
117786470930SIngo Molnar 
1178*95011c60SArnaldo Carvalho de Melo static struct symbol *thread__find_symbol(struct thread *self, u64 ip,
1179*95011c60SArnaldo Carvalho de Melo 					  enum map_type type, struct map **mapp,
1180c338aee8SArnaldo Carvalho de Melo 					  symbol_filter_t filter)
1181439d473bSArnaldo Carvalho de Melo {
1182*95011c60SArnaldo Carvalho de Melo 	struct map *map = thread__find_map(self, type, ip);
1183439d473bSArnaldo Carvalho de Melo 
1184439d473bSArnaldo Carvalho de Melo 	if (mapp)
1185439d473bSArnaldo Carvalho de Melo 		*mapp = map;
1186439d473bSArnaldo Carvalho de Melo 
11872e538c4aSArnaldo Carvalho de Melo 	if (map) {
11882e538c4aSArnaldo Carvalho de Melo 		ip = map->map_ip(map, ip);
11896a4694a4SArnaldo Carvalho de Melo 		return map__find_symbol(map, ip, filter);
1190*95011c60SArnaldo Carvalho de Melo 	}
11912e538c4aSArnaldo Carvalho de Melo 
11922e538c4aSArnaldo Carvalho de Melo 	return NULL;
1193439d473bSArnaldo Carvalho de Melo }
1194439d473bSArnaldo Carvalho de Melo 
119523ea4a3fSArnaldo Carvalho de Melo struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
119623ea4a3fSArnaldo Carvalho de Melo 					  symbol_filter_t filter)
119723ea4a3fSArnaldo Carvalho de Melo {
1198*95011c60SArnaldo Carvalho de Melo 	return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter);
119923ea4a3fSArnaldo Carvalho de Melo }
120023ea4a3fSArnaldo Carvalho de Melo 
1201*95011c60SArnaldo Carvalho de Melo static struct map *thread__find_map_by_name(struct thread *self, char *name)
1202439d473bSArnaldo Carvalho de Melo {
1203439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1204439d473bSArnaldo Carvalho de Melo 
1205*95011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
1206439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1207439d473bSArnaldo Carvalho de Melo 
1208439d473bSArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->name, name) == 0)
1209439d473bSArnaldo Carvalho de Melo 			return map;
1210439d473bSArnaldo Carvalho de Melo 	}
1211439d473bSArnaldo Carvalho de Melo 
1212439d473bSArnaldo Carvalho de Melo 	return NULL;
1213439d473bSArnaldo Carvalho de Melo }
1214439d473bSArnaldo Carvalho de Melo 
1215c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname)
12166cfcc53eSMike Galbraith {
1217439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
1218439d473bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dirname);
12196cfcc53eSMike Galbraith 
1220439d473bSArnaldo Carvalho de Melo 	if (!dir) {
122187f8ea4cSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1222439d473bSArnaldo Carvalho de Melo 		return -1;
1223439d473bSArnaldo Carvalho de Melo 	}
12246cfcc53eSMike Galbraith 
1225439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1226439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1227439d473bSArnaldo Carvalho de Melo 
1228439d473bSArnaldo Carvalho de Melo 		if (dent->d_type == DT_DIR) {
1229439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1230439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1231439d473bSArnaldo Carvalho de Melo 				continue;
1232439d473bSArnaldo Carvalho de Melo 
1233439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1234439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1235c338aee8SArnaldo Carvalho de Melo 			if (dsos__set_modules_path_dir(path) < 0)
1236439d473bSArnaldo Carvalho de Melo 				goto failure;
1237439d473bSArnaldo Carvalho de Melo 		} else {
1238439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1239439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1240439d473bSArnaldo Carvalho de Melo 			struct map *map;
1241cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1242439d473bSArnaldo Carvalho de Melo 
1243439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1244439d473bSArnaldo Carvalho de Melo 				continue;
1245439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1246439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1247439d473bSArnaldo Carvalho de Melo 
1248a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
1249*95011c60SArnaldo Carvalho de Melo 			map = thread__find_map_by_name(kthread, dso_name);
1250439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1251439d473bSArnaldo Carvalho de Melo 				continue;
1252439d473bSArnaldo Carvalho de Melo 
1253439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1254439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1255439d473bSArnaldo Carvalho de Melo 
1256cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1257cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1258439d473bSArnaldo Carvalho de Melo 				goto failure;
1259cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1260439d473bSArnaldo Carvalho de Melo 		}
1261439d473bSArnaldo Carvalho de Melo 	}
1262439d473bSArnaldo Carvalho de Melo 
1263c338aee8SArnaldo Carvalho de Melo 	return 0;
1264439d473bSArnaldo Carvalho de Melo failure:
1265439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1266439d473bSArnaldo Carvalho de Melo 	return -1;
1267439d473bSArnaldo Carvalho de Melo }
1268439d473bSArnaldo Carvalho de Melo 
1269c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void)
1270439d473bSArnaldo Carvalho de Melo {
1271439d473bSArnaldo Carvalho de Melo 	struct utsname uts;
1272439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1273439d473bSArnaldo Carvalho de Melo 
1274439d473bSArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
1275439d473bSArnaldo Carvalho de Melo 		return -1;
1276439d473bSArnaldo Carvalho de Melo 
1277439d473bSArnaldo Carvalho de Melo 	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1278439d473bSArnaldo Carvalho de Melo 		 uts.release);
1279439d473bSArnaldo Carvalho de Melo 
1280c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path_dir(modules_path);
1281439d473bSArnaldo Carvalho de Melo }
12826cfcc53eSMike Galbraith 
12836cfcc53eSMike Galbraith /*
1284439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1285439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1286439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
12876cfcc53eSMike Galbraith  */
12883610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1289439d473bSArnaldo Carvalho de Melo {
1290439d473bSArnaldo Carvalho de Melo 	struct map *self = malloc(sizeof(*self));
12916cfcc53eSMike Galbraith 
1292439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1293439d473bSArnaldo Carvalho de Melo 		/*
1294afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1295439d473bSArnaldo Carvalho de Melo 		 */
12963610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1297439d473bSArnaldo Carvalho de Melo 	}
1298afb7b4f0SArnaldo Carvalho de Melo 
1299439d473bSArnaldo Carvalho de Melo 	return self;
1300439d473bSArnaldo Carvalho de Melo }
1301439d473bSArnaldo Carvalho de Melo 
1302*95011c60SArnaldo Carvalho de Melo static int thread__create_module_maps(struct thread *self)
1303439d473bSArnaldo Carvalho de Melo {
1304439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1305439d473bSArnaldo Carvalho de Melo 	size_t n;
1306439d473bSArnaldo Carvalho de Melo 	FILE *file = fopen("/proc/modules", "r");
1307439d473bSArnaldo Carvalho de Melo 	struct map *map;
1308439d473bSArnaldo Carvalho de Melo 
1309439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1310439d473bSArnaldo Carvalho de Melo 		return -1;
1311439d473bSArnaldo Carvalho de Melo 
1312439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1313439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1314439d473bSArnaldo Carvalho de Melo 		u64 start;
1315439d473bSArnaldo Carvalho de Melo 		struct dso *dso;
1316439d473bSArnaldo Carvalho de Melo 		char *sep;
1317439d473bSArnaldo Carvalho de Melo 		int line_len;
1318439d473bSArnaldo Carvalho de Melo 
1319439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1320439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
13216cfcc53eSMike Galbraith 			break;
13226cfcc53eSMike Galbraith 
1323439d473bSArnaldo Carvalho de Melo 		if (!line)
1324439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1325439d473bSArnaldo Carvalho de Melo 
1326439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1327439d473bSArnaldo Carvalho de Melo 
1328439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1329439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1330439d473bSArnaldo Carvalho de Melo 			continue;
1331439d473bSArnaldo Carvalho de Melo 
1332439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1333439d473bSArnaldo Carvalho de Melo 
1334439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1335439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1336439d473bSArnaldo Carvalho de Melo 			continue;
1337439d473bSArnaldo Carvalho de Melo 
1338439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1339439d473bSArnaldo Carvalho de Melo 
1340439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
134100a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1342439d473bSArnaldo Carvalho de Melo 
1343439d473bSArnaldo Carvalho de Melo 		if (dso == NULL)
1344439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1345439d473bSArnaldo Carvalho de Melo 
13463610583cSArnaldo Carvalho de Melo 		map = map__new2(start, dso, MAP__FUNCTION);
1347439d473bSArnaldo Carvalho de Melo 		if (map == NULL) {
1348439d473bSArnaldo Carvalho de Melo 			dso__delete(dso);
1349439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
13506cfcc53eSMike Galbraith 		}
13516cfcc53eSMike Galbraith 
1352f1617b40SArnaldo Carvalho de Melo 		snprintf(name, sizeof(name),
1353f1617b40SArnaldo Carvalho de Melo 			 "/sys/module/%s/notes/.note.gnu.build-id", line);
1354f1617b40SArnaldo Carvalho de Melo 		if (sysfs__read_build_id(name, dso->build_id,
1355f1617b40SArnaldo Carvalho de Melo 					 sizeof(dso->build_id)) == 0)
1356f1617b40SArnaldo Carvalho de Melo 			dso->has_build_id = true;
1357f1617b40SArnaldo Carvalho de Melo 
1358439d473bSArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1359*95011c60SArnaldo Carvalho de Melo 		__thread__insert_map(self, map);
1360b0da954aSArnaldo Carvalho de Melo 		dsos__add(&dsos__kernel, dso);
13616cfcc53eSMike Galbraith 	}
13626cfcc53eSMike Galbraith 
1363439d473bSArnaldo Carvalho de Melo 	free(line);
1364439d473bSArnaldo Carvalho de Melo 	fclose(file);
1365439d473bSArnaldo Carvalho de Melo 
1366c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path();
1367439d473bSArnaldo Carvalho de Melo 
1368439d473bSArnaldo Carvalho de Melo out_delete_line:
1369439d473bSArnaldo Carvalho de Melo 	free(line);
1370439d473bSArnaldo Carvalho de Melo out_failure:
1371439d473bSArnaldo Carvalho de Melo 	return -1;
13726cfcc53eSMike Galbraith }
13736cfcc53eSMike Galbraith 
1374*95011c60SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread,
13756beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
137686470930SIngo Molnar {
1377fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
137886470930SIngo Molnar 
1379fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1380fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
138166bd8424SArnaldo Carvalho de Melo 
1382fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1383fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1384fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1385fbd733b8SArnaldo Carvalho de Melo 			return -1;
1386fbd733b8SArnaldo Carvalho de Melo 		}
1387fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1388fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1389fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1390fbd733b8SArnaldo Carvalho de Melo 
1391fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1392fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1393fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1394fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1395fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1396fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1397fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1398fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1399fbd733b8SArnaldo Carvalho de Melo 			return -1;
1400fbd733b8SArnaldo Carvalho de Melo 		}
1401fbd733b8SArnaldo Carvalho de Melo 	}
1402fbd733b8SArnaldo Carvalho de Melo 
1403fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
140486470930SIngo Molnar 	if (fd < 0)
140586470930SIngo Molnar 		return -1;
140686470930SIngo Molnar 
14073610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
1408*95011c60SArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0);
140986470930SIngo Molnar 	close(fd);
141086470930SIngo Molnar 
141186470930SIngo Molnar 	return err;
141286470930SIngo Molnar }
141386470930SIngo Molnar 
1414c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
1415*95011c60SArnaldo Carvalho de Melo 				struct thread *thread, symbol_filter_t filter)
141686470930SIngo Molnar {
1417cc612d81SArnaldo Carvalho de Melo 	int err;
1418cc612d81SArnaldo Carvalho de Melo 	bool is_kallsyms;
1419439d473bSArnaldo Carvalho de Melo 
1420cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
1421cc612d81SArnaldo Carvalho de Melo 		int i;
1422cc612d81SArnaldo Carvalho de Melo 		pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1423cc612d81SArnaldo Carvalho de Melo 			 vmlinux_path__nr_entries);
1424cc612d81SArnaldo Carvalho de Melo 		for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1425*95011c60SArnaldo Carvalho de Melo 			err = dso__load_vmlinux(self, map, thread,
1426*95011c60SArnaldo Carvalho de Melo 						vmlinux_path[i], filter);
1427cc612d81SArnaldo Carvalho de Melo 			if (err > 0) {
1428cc612d81SArnaldo Carvalho de Melo 				pr_debug("Using %s for symbols\n",
1429cc612d81SArnaldo Carvalho de Melo 					 vmlinux_path[i]);
1430cc612d81SArnaldo Carvalho de Melo 				dso__set_long_name(self,
1431cc612d81SArnaldo Carvalho de Melo 						   strdup(vmlinux_path[i]));
1432cc612d81SArnaldo Carvalho de Melo 				goto out_fixup;
1433cc612d81SArnaldo Carvalho de Melo 			}
1434cc612d81SArnaldo Carvalho de Melo 		}
1435cc612d81SArnaldo Carvalho de Melo 	}
1436cc612d81SArnaldo Carvalho de Melo 
1437cc612d81SArnaldo Carvalho de Melo 	is_kallsyms = self->long_name[0] == '[';
1438cc612d81SArnaldo Carvalho de Melo 	if (is_kallsyms)
1439cc612d81SArnaldo Carvalho de Melo 		goto do_kallsyms;
1440cc612d81SArnaldo Carvalho de Melo 
1441*95011c60SArnaldo Carvalho de Melo 	err = dso__load_vmlinux(self, map, thread, self->long_name, filter);
1442ef6ae724SArnaldo Carvalho de Melo 	if (err <= 0) {
1443cc612d81SArnaldo Carvalho de Melo 		pr_info("The file %s cannot be used, "
1444cc612d81SArnaldo Carvalho de Melo 			"trying to use /proc/kallsyms...", self->long_name);
1445cc612d81SArnaldo Carvalho de Melo do_kallsyms:
1446*95011c60SArnaldo Carvalho de Melo 		err = dso__load_kallsyms(self, map, thread, filter);
1447cc612d81SArnaldo Carvalho de Melo 		if (err > 0 && !is_kallsyms)
1448ef6ae724SArnaldo Carvalho de Melo                         dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1449ef6ae724SArnaldo Carvalho de Melo 	}
145086470930SIngo Molnar 
1451439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1452cc612d81SArnaldo Carvalho de Melo out_fixup:
14536a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
14546a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1455439d473bSArnaldo Carvalho de Melo 	}
145694cb9e38SArnaldo Carvalho de Melo 
145786470930SIngo Molnar 	return err;
145886470930SIngo Molnar }
145986470930SIngo Molnar 
1460b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user);
1461b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel);
1462cd84c2acSFrederic Weisbecker struct dso *vdso;
1463cd84c2acSFrederic Weisbecker 
1464b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1465cd84c2acSFrederic Weisbecker {
1466b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1467cd84c2acSFrederic Weisbecker }
1468cd84c2acSFrederic Weisbecker 
1469b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1470cd84c2acSFrederic Weisbecker {
1471cd84c2acSFrederic Weisbecker 	struct dso *pos;
1472cd84c2acSFrederic Weisbecker 
1473b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1474cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
1475cd84c2acSFrederic Weisbecker 			return pos;
1476cd84c2acSFrederic Weisbecker 	return NULL;
1477cd84c2acSFrederic Weisbecker }
1478cd84c2acSFrederic Weisbecker 
147900a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name)
1480cd84c2acSFrederic Weisbecker {
1481b0da954aSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(&dsos__user, name);
1482cd84c2acSFrederic Weisbecker 
1483e4204992SArnaldo Carvalho de Melo 	if (!dso) {
148400a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1485cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1486b0da954aSArnaldo Carvalho de Melo 			dsos__add(&dsos__user, dso);
1487cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1488cfc10d3bSArnaldo Carvalho de Melo 		}
1489e4204992SArnaldo Carvalho de Melo 	}
1490cd84c2acSFrederic Weisbecker 
1491cd84c2acSFrederic Weisbecker 	return dso;
1492cd84c2acSFrederic Weisbecker }
1493cd84c2acSFrederic Weisbecker 
1494b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp)
1495cd84c2acSFrederic Weisbecker {
1496cd84c2acSFrederic Weisbecker 	struct dso *pos;
1497cd84c2acSFrederic Weisbecker 
1498*95011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
1499*95011c60SArnaldo Carvalho de Melo 		int i;
1500*95011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
1501*95011c60SArnaldo Carvalho de Melo 			dso__fprintf(pos, i, fp);
1502*95011c60SArnaldo Carvalho de Melo 	}
1503cd84c2acSFrederic Weisbecker }
1504cd84c2acSFrederic Weisbecker 
1505b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp)
1506b0da954aSArnaldo Carvalho de Melo {
1507b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__kernel, fp);
1508b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__user, fp);
1509b0da954aSArnaldo Carvalho de Melo }
1510b0da954aSArnaldo Carvalho de Melo 
1511b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
15129e03eb2dSArnaldo Carvalho de Melo {
15139e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
15149e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
15159e03eb2dSArnaldo Carvalho de Melo 
1516b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
15179e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
15189e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
15199e03eb2dSArnaldo Carvalho de Melo 	}
15209e03eb2dSArnaldo Carvalho de Melo 	return ret;
15219e03eb2dSArnaldo Carvalho de Melo }
15229e03eb2dSArnaldo Carvalho de Melo 
1523b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp)
1524b0da954aSArnaldo Carvalho de Melo {
1525b0da954aSArnaldo Carvalho de Melo 	return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1526b0da954aSArnaldo Carvalho de Melo 		__dsos__fprintf_buildid(&dsos__user, fp));
1527b0da954aSArnaldo Carvalho de Melo }
1528b0da954aSArnaldo Carvalho de Melo 
1529*95011c60SArnaldo Carvalho de Melo static int thread__create_kernel_map(struct thread *self, const char *vmlinux)
1530cd84c2acSFrederic Weisbecker {
15314e06255fSArnaldo Carvalho de Melo 	struct map *kmap;
1532*95011c60SArnaldo Carvalho de Melo 	struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1533cd84c2acSFrederic Weisbecker 
15342446042cSArnaldo Carvalho de Melo 	if (kernel == NULL)
1535c338aee8SArnaldo Carvalho de Melo 		return -1;
1536c338aee8SArnaldo Carvalho de Melo 
15374e06255fSArnaldo Carvalho de Melo 	kmap = map__new2(0, kernel, MAP__FUNCTION);
15384e06255fSArnaldo Carvalho de Melo 	if (kmap == NULL)
1539c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_dso;
1540c338aee8SArnaldo Carvalho de Melo 
15414e06255fSArnaldo Carvalho de Melo 	kmap->map_ip	   = kmap->unmap_ip = identity__map_ip;
15422446042cSArnaldo Carvalho de Melo 	kernel->short_name = "[kernel]";
1543c338aee8SArnaldo Carvalho de Melo 	kernel->kernel	   = 1;
1544cc612d81SArnaldo Carvalho de Melo 
154500a192b3SArnaldo Carvalho de Melo 	vdso = dso__new("[vdso]");
1546c338aee8SArnaldo Carvalho de Melo 	if (vdso == NULL)
1547c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_map;
15483610583cSArnaldo Carvalho de Melo 	dso__set_loaded(vdso, MAP__FUNCTION);
1549cd84c2acSFrederic Weisbecker 
15502446042cSArnaldo Carvalho de Melo 	if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
15512446042cSArnaldo Carvalho de Melo 				 sizeof(kernel->build_id)) == 0)
15522446042cSArnaldo Carvalho de Melo 		kernel->has_build_id = true;
15532446042cSArnaldo Carvalho de Melo 
1554*95011c60SArnaldo Carvalho de Melo 	__thread__insert_map(self, kmap);
1555b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__kernel, kernel);
1556b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__user, vdso);
1557cd84c2acSFrederic Weisbecker 
1558c338aee8SArnaldo Carvalho de Melo 	return 0;
1559c338aee8SArnaldo Carvalho de Melo 
1560c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map:
15614e06255fSArnaldo Carvalho de Melo 	map__delete(kmap);
1562c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso:
1563c338aee8SArnaldo Carvalho de Melo 	dso__delete(kernel);
1564c338aee8SArnaldo Carvalho de Melo 	return -1;
15652446042cSArnaldo Carvalho de Melo }
15662446042cSArnaldo Carvalho de Melo 
1567cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
15682446042cSArnaldo Carvalho de Melo {
1569cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
1570cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
1571cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
1572cc612d81SArnaldo Carvalho de Melo 	}
1573cc612d81SArnaldo Carvalho de Melo 
1574cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
1575cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
1576cc612d81SArnaldo Carvalho de Melo }
1577cc612d81SArnaldo Carvalho de Melo 
1578cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
1579cc612d81SArnaldo Carvalho de Melo {
1580cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1581cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
1582cc612d81SArnaldo Carvalho de Melo 
1583cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
15842446042cSArnaldo Carvalho de Melo 		return -1;
15852446042cSArnaldo Carvalho de Melo 
1586cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
1587cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1588cc612d81SArnaldo Carvalho de Melo 		return -1;
1589cc612d81SArnaldo Carvalho de Melo 
1590cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1591cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1592cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1593cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1594cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1595cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1596cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1597cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1598cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1599cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1600cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1601cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1602cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1603cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1604cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1605cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1606cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1607cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1608cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1609cc612d81SArnaldo Carvalho de Melo 		 uts.release);
1610cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1611cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1612cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1613cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1614cc612d81SArnaldo Carvalho de Melo 
1615cc612d81SArnaldo Carvalho de Melo 	return 0;
1616cc612d81SArnaldo Carvalho de Melo 
1617cc612d81SArnaldo Carvalho de Melo out_fail:
1618cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1619cc612d81SArnaldo Carvalho de Melo 	return -1;
1620cc612d81SArnaldo Carvalho de Melo }
1621cc612d81SArnaldo Carvalho de Melo 
1622*95011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf)
1623cc612d81SArnaldo Carvalho de Melo {
1624b32d133aSArnaldo Carvalho de Melo 	const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1625b32d133aSArnaldo Carvalho de Melo 
1626*95011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
1627b32d133aSArnaldo Carvalho de Melo 	symbol__priv_size = pconf->priv_size;
1628*95011c60SArnaldo Carvalho de Melo 	thread__init(kthread, 0);
1629b32d133aSArnaldo Carvalho de Melo 
1630b32d133aSArnaldo Carvalho de Melo 	if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1631cc612d81SArnaldo Carvalho de Melo 		return -1;
1632cc612d81SArnaldo Carvalho de Melo 
1633*95011c60SArnaldo Carvalho de Melo 	if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) {
1634cc612d81SArnaldo Carvalho de Melo 		vmlinux_path__exit();
1635cc612d81SArnaldo Carvalho de Melo 		return -1;
1636cc612d81SArnaldo Carvalho de Melo 	}
1637cc612d81SArnaldo Carvalho de Melo 
1638*95011c60SArnaldo Carvalho de Melo 	if (pconf->use_modules && thread__create_module_maps(kthread) < 0)
163987f8ea4cSArnaldo Carvalho de Melo 		pr_debug("Failed to load list of modules in use, "
16406671cb16SArnaldo Carvalho de Melo 			 "continuing...\n");
164190c83218SArnaldo Carvalho de Melo 	/*
164290c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
164390c83218SArnaldo Carvalho de Melo 	 */
1644*95011c60SArnaldo Carvalho de Melo 	thread__fixup_maps_end(kthread);
16456671cb16SArnaldo Carvalho de Melo 	return 0;
1646cd84c2acSFrederic Weisbecker }
1647