xref: /linux/tools/perf/util/symbol.c (revision c12e15e71d4b32da045e798ffd21cbb6197d1c65)
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 
986470930SIngo Molnar #include <libelf.h>
1086470930SIngo Molnar #include <gelf.h>
1186470930SIngo Molnar #include <elf.h>
12f1617b40SArnaldo Carvalho de Melo #include <limits.h>
13439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
142cdbc46dSPeter Zijlstra 
15*c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
16*c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
17*c12e15e7SArnaldo Carvalho de Melo #endif
18*c12e15e7SArnaldo Carvalho de Melo 
1994cb9e38SArnaldo Carvalho de Melo enum dso_origin {
2094cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_KERNEL = 0,
2194cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_JAVA_JIT,
2294cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_FEDORA,
2394cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_UBUNTU,
2494cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_BUILDID,
2594cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_DSO,
26439d473bSArnaldo Carvalho de Melo 	DSO__ORIG_KMODULE,
2794cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_NOT_FOUND,
2894cb9e38SArnaldo Carvalho de Melo };
2994cb9e38SArnaldo Carvalho de Melo 
30439d473bSArnaldo Carvalho de Melo static void dsos__add(struct dso *dso);
31439d473bSArnaldo Carvalho de Melo static struct dso *dsos__find(const char *name);
322e538c4aSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso);
332e538c4aSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map);
34c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
35c338aee8SArnaldo Carvalho de Melo 				symbol_filter_t filter);
3600a192b3SArnaldo Carvalho de Melo unsigned int symbol__priv_size;
37439d473bSArnaldo Carvalho de Melo 
38af427bf5SArnaldo Carvalho de Melo static struct rb_root kernel_maps;
39af427bf5SArnaldo Carvalho de Melo 
402e538c4aSArnaldo Carvalho de Melo static void dso__fixup_sym_end(struct dso *self)
41af427bf5SArnaldo Carvalho de Melo {
42af427bf5SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->syms);
432e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
44af427bf5SArnaldo Carvalho de Melo 
45af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
46af427bf5SArnaldo Carvalho de Melo 		return;
47af427bf5SArnaldo Carvalho de Melo 
482e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
492e538c4aSArnaldo Carvalho de Melo 
50af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
512e538c4aSArnaldo Carvalho de Melo 		prev = curr;
522e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
53af427bf5SArnaldo Carvalho de Melo 
54af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
55af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
56af427bf5SArnaldo Carvalho de Melo 	}
57af427bf5SArnaldo Carvalho de Melo 
582e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
592e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
602e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
612e538c4aSArnaldo Carvalho de Melo }
622e538c4aSArnaldo Carvalho de Melo 
632e538c4aSArnaldo Carvalho de Melo static void kernel_maps__fixup_end(void)
64af427bf5SArnaldo Carvalho de Melo {
65af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
66af427bf5SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
67af427bf5SArnaldo Carvalho de Melo 
68af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
69af427bf5SArnaldo Carvalho de Melo 		return;
70af427bf5SArnaldo Carvalho de Melo 
71af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
72af427bf5SArnaldo Carvalho de Melo 
73af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
74af427bf5SArnaldo Carvalho de Melo 		prev = curr;
75af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
76af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
772e538c4aSArnaldo Carvalho de Melo 	}
7890c83218SArnaldo Carvalho de Melo 
7990c83218SArnaldo Carvalho de Melo 	/*
8090c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
8190c83218SArnaldo Carvalho de Melo 	 * last map final address.
8290c83218SArnaldo Carvalho de Melo 	 */
8390c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
84af427bf5SArnaldo Carvalho de Melo }
85af427bf5SArnaldo Carvalho de Melo 
8600a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name)
8786470930SIngo Molnar {
8886470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
8900a192b3SArnaldo Carvalho de Melo 	struct symbol *self = calloc(1, (symbol__priv_size +
9000a192b3SArnaldo Carvalho de Melo 					 sizeof(*self) + namelen));
9186470930SIngo Molnar 	if (!self)
9286470930SIngo Molnar 		return NULL;
9386470930SIngo Molnar 
9400a192b3SArnaldo Carvalho de Melo 	if (symbol__priv_size) {
9500a192b3SArnaldo Carvalho de Melo 		memset(self, 0, symbol__priv_size);
9600a192b3SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol__priv_size;
9786470930SIngo Molnar 	}
9886470930SIngo Molnar 	self->start = start;
996cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
100e4204992SArnaldo Carvalho de Melo 
1016beba7adSArnaldo Carvalho de Melo 	pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
102e4204992SArnaldo Carvalho de Melo 
10386470930SIngo Molnar 	memcpy(self->name, name, namelen);
10486470930SIngo Molnar 
10586470930SIngo Molnar 	return self;
10686470930SIngo Molnar }
10786470930SIngo Molnar 
10800a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self)
10986470930SIngo Molnar {
11000a192b3SArnaldo Carvalho de Melo 	free(((void *)self) - symbol__priv_size);
11186470930SIngo Molnar }
11286470930SIngo Molnar 
11386470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
11486470930SIngo Molnar {
11586470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
11686470930SIngo Molnar 		       self->start, self->end, self->name);
11786470930SIngo Molnar }
11886470930SIngo Molnar 
119cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name)
120cfc10d3bSArnaldo Carvalho de Melo {
121ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
122ef6ae724SArnaldo Carvalho de Melo 		return;
123cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
124cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
125cfc10d3bSArnaldo Carvalho de Melo }
126cfc10d3bSArnaldo Carvalho de Melo 
127cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
128cfc10d3bSArnaldo Carvalho de Melo {
129cfc10d3bSArnaldo Carvalho de Melo 	self->short_name = basename(self->long_name);
130cfc10d3bSArnaldo Carvalho de Melo }
131cfc10d3bSArnaldo Carvalho de Melo 
13200a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
13386470930SIngo Molnar {
13486470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
13586470930SIngo Molnar 
13686470930SIngo Molnar 	if (self != NULL) {
13786470930SIngo Molnar 		strcpy(self->name, name);
138cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
139439d473bSArnaldo Carvalho de Melo 		self->short_name = self->name;
14086470930SIngo Molnar 		self->syms = RB_ROOT;
14186470930SIngo Molnar 		self->find_symbol = dso__find_symbol;
14252d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
14394cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1448d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
1458d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
14686470930SIngo Molnar 	}
14786470930SIngo Molnar 
14886470930SIngo Molnar 	return self;
14986470930SIngo Molnar }
15086470930SIngo Molnar 
15186470930SIngo Molnar static void dso__delete_symbols(struct dso *self)
15286470930SIngo Molnar {
15386470930SIngo Molnar 	struct symbol *pos;
15486470930SIngo Molnar 	struct rb_node *next = rb_first(&self->syms);
15586470930SIngo Molnar 
15686470930SIngo Molnar 	while (next) {
15786470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
15886470930SIngo Molnar 		next = rb_next(&pos->rb_node);
15986470930SIngo Molnar 		rb_erase(&pos->rb_node, &self->syms);
16000a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
16186470930SIngo Molnar 	}
16286470930SIngo Molnar }
16386470930SIngo Molnar 
16486470930SIngo Molnar void dso__delete(struct dso *self)
16586470930SIngo Molnar {
16686470930SIngo Molnar 	dso__delete_symbols(self);
167439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
168439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
16986470930SIngo Molnar 	free(self);
17086470930SIngo Molnar }
17186470930SIngo Molnar 
1728d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
1738d06367fSArnaldo Carvalho de Melo {
1748d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
1758d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
1768d06367fSArnaldo Carvalho de Melo }
1778d06367fSArnaldo Carvalho de Melo 
17886470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym)
17986470930SIngo Molnar {
18086470930SIngo Molnar 	struct rb_node **p = &self->syms.rb_node;
18186470930SIngo Molnar 	struct rb_node *parent = NULL;
1829cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
18386470930SIngo Molnar 	struct symbol *s;
18486470930SIngo Molnar 
18586470930SIngo Molnar 	while (*p != NULL) {
18686470930SIngo Molnar 		parent = *p;
18786470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
18886470930SIngo Molnar 		if (ip < s->start)
18986470930SIngo Molnar 			p = &(*p)->rb_left;
19086470930SIngo Molnar 		else
19186470930SIngo Molnar 			p = &(*p)->rb_right;
19286470930SIngo Molnar 	}
19386470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
19486470930SIngo Molnar 	rb_insert_color(&sym->rb_node, &self->syms);
19586470930SIngo Molnar }
19686470930SIngo Molnar 
1979cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip)
19886470930SIngo Molnar {
19986470930SIngo Molnar 	struct rb_node *n;
20086470930SIngo Molnar 
20186470930SIngo Molnar 	if (self == NULL)
20286470930SIngo Molnar 		return NULL;
20386470930SIngo Molnar 
20486470930SIngo Molnar 	n = self->syms.rb_node;
20586470930SIngo Molnar 
20686470930SIngo Molnar 	while (n) {
20786470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
20886470930SIngo Molnar 
20986470930SIngo Molnar 		if (ip < s->start)
21086470930SIngo Molnar 			n = n->rb_left;
21186470930SIngo Molnar 		else if (ip > s->end)
21286470930SIngo Molnar 			n = n->rb_right;
21386470930SIngo Molnar 		else
21486470930SIngo Molnar 			return s;
21586470930SIngo Molnar 	}
21686470930SIngo Molnar 
21786470930SIngo Molnar 	return NULL;
21886470930SIngo Molnar }
21986470930SIngo Molnar 
2208d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf)
2218d06367fSArnaldo Carvalho de Melo {
2228d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
2238d06367fSArnaldo Carvalho de Melo 	u8 *raw = self;
2248d06367fSArnaldo Carvalho de Melo 	int i;
2258d06367fSArnaldo Carvalho de Melo 
2268d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
2278d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
2288d06367fSArnaldo Carvalho de Melo 		++raw;
2298d06367fSArnaldo Carvalho de Melo 		bid += 2;
2308d06367fSArnaldo Carvalho de Melo 	}
2318d06367fSArnaldo Carvalho de Melo 
2328d06367fSArnaldo Carvalho de Melo 	return raw - self;
2338d06367fSArnaldo Carvalho de Melo }
2348d06367fSArnaldo Carvalho de Melo 
2359e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
23686470930SIngo Molnar {
2378d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2388d06367fSArnaldo Carvalho de Melo 
2398d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
2409e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
2419e03eb2dSArnaldo Carvalho de Melo }
2429e03eb2dSArnaldo Carvalho de Melo 
2439e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, FILE *fp)
2449e03eb2dSArnaldo Carvalho de Melo {
2459e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
2469e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
2479e03eb2dSArnaldo Carvalho de Melo 
2489e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
2499e03eb2dSArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
2508d06367fSArnaldo Carvalho de Melo 
25186470930SIngo Molnar 	for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
25286470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
25386470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
25486470930SIngo Molnar 	}
25586470930SIngo Molnar 
25686470930SIngo Molnar 	return ret;
25786470930SIngo Molnar }
25886470930SIngo Molnar 
2592e538c4aSArnaldo Carvalho de Melo /*
2602e538c4aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
2612e538c4aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
2622e538c4aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
2632e538c4aSArnaldo Carvalho de Melo  */
2646beba7adSArnaldo Carvalho de Melo static int kernel_maps__load_all_kallsyms(void)
26586470930SIngo Molnar {
26686470930SIngo Molnar 	char *line = NULL;
26786470930SIngo Molnar 	size_t n;
26886470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
26986470930SIngo Molnar 
27086470930SIngo Molnar 	if (file == NULL)
27186470930SIngo Molnar 		goto out_failure;
27286470930SIngo Molnar 
27386470930SIngo Molnar 	while (!feof(file)) {
2749cffa8d5SPaul Mackerras 		u64 start;
27586470930SIngo Molnar 		struct symbol *sym;
27686470930SIngo Molnar 		int line_len, len;
27786470930SIngo Molnar 		char symbol_type;
2782e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
27986470930SIngo Molnar 
28086470930SIngo Molnar 		line_len = getline(&line, &n, file);
28186470930SIngo Molnar 		if (line_len < 0)
28286470930SIngo Molnar 			break;
28386470930SIngo Molnar 
28486470930SIngo Molnar 		if (!line)
28586470930SIngo Molnar 			goto out_failure;
28686470930SIngo Molnar 
28786470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
28886470930SIngo Molnar 
28986470930SIngo Molnar 		len = hex2u64(line, &start);
29086470930SIngo Molnar 
29186470930SIngo Molnar 		len++;
29286470930SIngo Molnar 		if (len + 2 >= line_len)
29386470930SIngo Molnar 			continue;
29486470930SIngo Molnar 
29586470930SIngo Molnar 		symbol_type = toupper(line[len]);
29686470930SIngo Molnar 		/*
29786470930SIngo Molnar 		 * We're interested only in code ('T'ext)
29886470930SIngo Molnar 		 */
29986470930SIngo Molnar 		if (symbol_type != 'T' && symbol_type != 'W')
30086470930SIngo Molnar 			continue;
301af427bf5SArnaldo Carvalho de Melo 
302af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
3032e538c4aSArnaldo Carvalho de Melo 		/*
3042e538c4aSArnaldo Carvalho de Melo 		 * Will fix up the end later, when we have all symbols sorted.
3052e538c4aSArnaldo Carvalho de Melo 		 */
30600a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, 0, symbol_name);
307af427bf5SArnaldo Carvalho de Melo 
3082e538c4aSArnaldo Carvalho de Melo 		if (sym == NULL)
3092e538c4aSArnaldo Carvalho de Melo 			goto out_delete_line;
3102e538c4aSArnaldo Carvalho de Melo 
31182164161SArnaldo Carvalho de Melo 		/*
31282164161SArnaldo Carvalho de Melo 		 * We will pass the symbols to the filter later, in
31382164161SArnaldo Carvalho de Melo 		 * kernel_maps__split_kallsyms, when we have split the
31482164161SArnaldo Carvalho de Melo 		 * maps per module
31582164161SArnaldo Carvalho de Melo 		 */
3162e538c4aSArnaldo Carvalho de Melo 		dso__insert_symbol(kernel_map->dso, sym);
3172e538c4aSArnaldo Carvalho de Melo 	}
3182e538c4aSArnaldo Carvalho de Melo 
3192e538c4aSArnaldo Carvalho de Melo 	free(line);
3202e538c4aSArnaldo Carvalho de Melo 	fclose(file);
3212e538c4aSArnaldo Carvalho de Melo 
3222e538c4aSArnaldo Carvalho de Melo 	return 0;
3232e538c4aSArnaldo Carvalho de Melo 
3242e538c4aSArnaldo Carvalho de Melo out_delete_line:
3252e538c4aSArnaldo Carvalho de Melo 	free(line);
3262e538c4aSArnaldo Carvalho de Melo out_failure:
3272e538c4aSArnaldo Carvalho de Melo 	return -1;
3282e538c4aSArnaldo Carvalho de Melo }
3292e538c4aSArnaldo Carvalho de Melo 
3302e538c4aSArnaldo Carvalho de Melo /*
3312e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
3322e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
3332e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
3342e538c4aSArnaldo Carvalho de Melo  */
335c338aee8SArnaldo Carvalho de Melo static int kernel_maps__split_kallsyms(symbol_filter_t filter)
3362e538c4aSArnaldo Carvalho de Melo {
3372e538c4aSArnaldo Carvalho de Melo 	struct map *map = kernel_map;
3382e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
3392e538c4aSArnaldo Carvalho de Melo 	int count = 0;
3402e538c4aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(&kernel_map->dso->syms);
3412e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
3422e538c4aSArnaldo Carvalho de Melo 
3432e538c4aSArnaldo Carvalho de Melo 	while (next) {
3442e538c4aSArnaldo Carvalho de Melo 		char *module;
3452e538c4aSArnaldo Carvalho de Melo 
3462e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
3472e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
3482e538c4aSArnaldo Carvalho de Melo 
3492e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
3502e538c4aSArnaldo Carvalho de Melo 		if (module) {
3512e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
3522e538c4aSArnaldo Carvalho de Melo 
353af427bf5SArnaldo Carvalho de Melo 			if (strcmp(map->dso->name, module)) {
354af427bf5SArnaldo Carvalho de Melo 				map = kernel_maps__find_by_dso_name(module);
355af427bf5SArnaldo Carvalho de Melo 				if (!map) {
3566beba7adSArnaldo Carvalho de Melo 					pr_err("/proc/{kallsyms,modules} "
3576beba7adSArnaldo Carvalho de Melo 					       "inconsistency!\n");
358af427bf5SArnaldo Carvalho de Melo 					return -1;
359af427bf5SArnaldo Carvalho de Melo 				}
360af427bf5SArnaldo Carvalho de Melo 			}
36186470930SIngo Molnar 			/*
3622e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
3632e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
36486470930SIngo Molnar 			 */
3652e538c4aSArnaldo Carvalho de Melo 			pos->start = map->map_ip(map, pos->start);
3662e538c4aSArnaldo Carvalho de Melo 			pos->end   = map->map_ip(map, pos->end);
3672e538c4aSArnaldo Carvalho de Melo 		} else if (map != kernel_map) {
3682e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
3692e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
37086470930SIngo Molnar 
3712e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
3722e538c4aSArnaldo Carvalho de Melo 				 kernel_range++);
37386470930SIngo Molnar 
37400a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
3752e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
3762e538c4aSArnaldo Carvalho de Melo 				return -1;
3772e538c4aSArnaldo Carvalho de Melo 
3782e538c4aSArnaldo Carvalho de Melo 			map = map__new2(pos->start, dso);
3792e538c4aSArnaldo Carvalho de Melo 			if (map == NULL) {
3802e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
3812e538c4aSArnaldo Carvalho de Melo 				return -1;
3822e538c4aSArnaldo Carvalho de Melo 			}
3832e538c4aSArnaldo Carvalho de Melo 
384ed52ce2eSArnaldo Carvalho de Melo 			map->map_ip = map->unmap_ip = identity__map_ip;
3852e538c4aSArnaldo Carvalho de Melo 			kernel_maps__insert(map);
3862e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
3872e538c4aSArnaldo Carvalho de Melo 		}
3882e538c4aSArnaldo Carvalho de Melo 
3892e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(map, pos)) {
3902e538c4aSArnaldo Carvalho de Melo 			rb_erase(&pos->rb_node, &kernel_map->dso->syms);
39100a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
3922e538c4aSArnaldo Carvalho de Melo 		} else {
3932e538c4aSArnaldo Carvalho de Melo 			if (map != kernel_map) {
3942e538c4aSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, &kernel_map->dso->syms);
3952e538c4aSArnaldo Carvalho de Melo 				dso__insert_symbol(map->dso, pos);
3962e538c4aSArnaldo Carvalho de Melo 			}
3979974f496SMike Galbraith 			count++;
3989974f496SMike Galbraith 		}
39986470930SIngo Molnar 	}
40086470930SIngo Molnar 
4019974f496SMike Galbraith 	return count;
40286470930SIngo Molnar }
40386470930SIngo Molnar 
4042e538c4aSArnaldo Carvalho de Melo 
405c338aee8SArnaldo Carvalho de Melo static int kernel_maps__load_kallsyms(symbol_filter_t filter)
4062e538c4aSArnaldo Carvalho de Melo {
4076beba7adSArnaldo Carvalho de Melo 	if (kernel_maps__load_all_kallsyms())
4082e538c4aSArnaldo Carvalho de Melo 		return -1;
4092e538c4aSArnaldo Carvalho de Melo 
4102e538c4aSArnaldo Carvalho de Melo 	dso__fixup_sym_end(kernel_map->dso);
411c338aee8SArnaldo Carvalho de Melo 	kernel_map->dso->origin = DSO__ORIG_KERNEL;
4122e538c4aSArnaldo Carvalho de Melo 
413c338aee8SArnaldo Carvalho de Melo 	return kernel_maps__split_kallsyms(filter);
4142e538c4aSArnaldo Carvalho de Melo }
4152e538c4aSArnaldo Carvalho de Melo 
416c338aee8SArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp)
417af427bf5SArnaldo Carvalho de Melo {
4186beba7adSArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "Kernel maps:\n");
419af427bf5SArnaldo Carvalho de Melo 	struct rb_node *nd;
420af427bf5SArnaldo Carvalho de Melo 
421af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
422af427bf5SArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
423af427bf5SArnaldo Carvalho de Melo 
4242e538c4aSArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
425af427bf5SArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
4266beba7adSArnaldo Carvalho de Melo 		if (verbose > 1) {
427af427bf5SArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, fp);
4282e538c4aSArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
4292e538c4aSArnaldo Carvalho de Melo 		}
430af427bf5SArnaldo Carvalho de Melo 	}
431af427bf5SArnaldo Carvalho de Melo 
4326beba7adSArnaldo Carvalho de Melo 	return printed + fprintf(fp, "END kernel maps\n");
433af427bf5SArnaldo Carvalho de Melo }
434af427bf5SArnaldo Carvalho de Melo 
435439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
4366beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
43780d496beSPekka Enberg {
43880d496beSPekka Enberg 	char *line = NULL;
43980d496beSPekka Enberg 	size_t n;
44080d496beSPekka Enberg 	FILE *file;
44180d496beSPekka Enberg 	int nr_syms = 0;
44280d496beSPekka Enberg 
443439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
44480d496beSPekka Enberg 	if (file == NULL)
44580d496beSPekka Enberg 		goto out_failure;
44680d496beSPekka Enberg 
44780d496beSPekka Enberg 	while (!feof(file)) {
4489cffa8d5SPaul Mackerras 		u64 start, size;
44980d496beSPekka Enberg 		struct symbol *sym;
45080d496beSPekka Enberg 		int line_len, len;
45180d496beSPekka Enberg 
45280d496beSPekka Enberg 		line_len = getline(&line, &n, file);
45380d496beSPekka Enberg 		if (line_len < 0)
45480d496beSPekka Enberg 			break;
45580d496beSPekka Enberg 
45680d496beSPekka Enberg 		if (!line)
45780d496beSPekka Enberg 			goto out_failure;
45880d496beSPekka Enberg 
45980d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
46080d496beSPekka Enberg 
46180d496beSPekka Enberg 		len = hex2u64(line, &start);
46280d496beSPekka Enberg 
46380d496beSPekka Enberg 		len++;
46480d496beSPekka Enberg 		if (len + 2 >= line_len)
46580d496beSPekka Enberg 			continue;
46680d496beSPekka Enberg 
46780d496beSPekka Enberg 		len += hex2u64(line + len, &size);
46880d496beSPekka Enberg 
46980d496beSPekka Enberg 		len++;
47080d496beSPekka Enberg 		if (len + 2 >= line_len)
47180d496beSPekka Enberg 			continue;
47280d496beSPekka Enberg 
47300a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
47480d496beSPekka Enberg 
47580d496beSPekka Enberg 		if (sym == NULL)
47680d496beSPekka Enberg 			goto out_delete_line;
47780d496beSPekka Enberg 
478439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
47900a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
48080d496beSPekka Enberg 		else {
48180d496beSPekka Enberg 			dso__insert_symbol(self, sym);
48280d496beSPekka Enberg 			nr_syms++;
48380d496beSPekka Enberg 		}
48480d496beSPekka Enberg 	}
48580d496beSPekka Enberg 
48680d496beSPekka Enberg 	free(line);
48780d496beSPekka Enberg 	fclose(file);
48880d496beSPekka Enberg 
48980d496beSPekka Enberg 	return nr_syms;
49080d496beSPekka Enberg 
49180d496beSPekka Enberg out_delete_line:
49280d496beSPekka Enberg 	free(line);
49380d496beSPekka Enberg out_failure:
49480d496beSPekka Enberg 	return -1;
49580d496beSPekka Enberg }
49680d496beSPekka Enberg 
49786470930SIngo Molnar /**
49886470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
49986470930SIngo Molnar  *
50086470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
50183a0944fSIngo Molnar  * @idx: uint32_t idx
50286470930SIngo Molnar  * @sym: GElf_Sym iterator
50386470930SIngo Molnar  */
50483a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
50583a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
50683a0944fSIngo Molnar 	     idx < nr_syms; \
50783a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
50886470930SIngo Molnar 
50986470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
51086470930SIngo Molnar {
51186470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
51286470930SIngo Molnar }
51386470930SIngo Molnar 
51486470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
51586470930SIngo Molnar {
51686470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
51786470930SIngo Molnar 	       sym->st_name != 0 &&
51881833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
51986470930SIngo Molnar }
52086470930SIngo Molnar 
5216cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
5226cfcc53eSMike Galbraith {
5236cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
5246cfcc53eSMike Galbraith 		sym->st_name != 0 &&
5256cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
5266cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
5276cfcc53eSMike Galbraith }
5286cfcc53eSMike Galbraith 
5296cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
5306cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5316cfcc53eSMike Galbraith {
5326cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
5336cfcc53eSMike Galbraith }
5346cfcc53eSMike Galbraith 
5356cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
5366cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5376cfcc53eSMike Galbraith {
5386cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
5396cfcc53eSMike Galbraith }
5406cfcc53eSMike Galbraith 
54186470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
54286470930SIngo Molnar 					const Elf_Data *symstrs)
54386470930SIngo Molnar {
54486470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
54586470930SIngo Molnar }
54686470930SIngo Molnar 
54786470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
54886470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
54983a0944fSIngo Molnar 				    size_t *idx)
55086470930SIngo Molnar {
55186470930SIngo Molnar 	Elf_Scn *sec = NULL;
55286470930SIngo Molnar 	size_t cnt = 1;
55386470930SIngo Molnar 
55486470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
55586470930SIngo Molnar 		char *str;
55686470930SIngo Molnar 
55786470930SIngo Molnar 		gelf_getshdr(sec, shp);
55886470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
55986470930SIngo Molnar 		if (!strcmp(name, str)) {
56083a0944fSIngo Molnar 			if (idx)
56183a0944fSIngo Molnar 				*idx = cnt;
56286470930SIngo Molnar 			break;
56386470930SIngo Molnar 		}
56486470930SIngo Molnar 		++cnt;
56586470930SIngo Molnar 	}
56686470930SIngo Molnar 
56786470930SIngo Molnar 	return sec;
56886470930SIngo Molnar }
56986470930SIngo Molnar 
57086470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
57186470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
57286470930SIngo Molnar 	     idx < nr_entries; \
57386470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
57486470930SIngo Molnar 
57586470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
57686470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
57786470930SIngo Molnar 	     idx < nr_entries; \
57886470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
57986470930SIngo Molnar 
580a25e46c4SArnaldo Carvalho de Melo /*
581a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
582a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
583a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
584a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
585a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
586a25e46c4SArnaldo Carvalho de Melo  */
58782164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
58882164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
58986470930SIngo Molnar {
59086470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
59186470930SIngo Molnar 	GElf_Sym sym;
5929cffa8d5SPaul Mackerras 	u64 plt_offset;
59386470930SIngo Molnar 	GElf_Shdr shdr_plt;
59486470930SIngo Molnar 	struct symbol *f;
595a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
59686470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
597a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
598a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
599a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
60086470930SIngo Molnar 	char sympltname[1024];
601a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
602a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
60386470930SIngo Molnar 
604439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
605a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
606a25e46c4SArnaldo Carvalho de Melo 		goto out;
607a25e46c4SArnaldo Carvalho de Melo 
60884087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
609a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
610a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
611a25e46c4SArnaldo Carvalho de Melo 
612a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
613a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
614a25e46c4SArnaldo Carvalho de Melo 
615a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
616a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
617a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
618a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
619a25e46c4SArnaldo Carvalho de Melo 
620a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
62186470930SIngo Molnar 					  ".rela.plt", NULL);
62286470930SIngo Molnar 	if (scn_plt_rel == NULL) {
623a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
62486470930SIngo Molnar 						  ".rel.plt", NULL);
62586470930SIngo Molnar 		if (scn_plt_rel == NULL)
626a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
62786470930SIngo Molnar 	}
62886470930SIngo Molnar 
629a25e46c4SArnaldo Carvalho de Melo 	err = -1;
63086470930SIngo Molnar 
631a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
632a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
633a25e46c4SArnaldo Carvalho de Melo 
634a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
635a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
63686470930SIngo Molnar 
63786470930SIngo Molnar 	/*
63883a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
63986470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
64086470930SIngo Molnar 	 */
64186470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
64286470930SIngo Molnar 	if (reldata == NULL)
643a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
64486470930SIngo Molnar 
64586470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
64686470930SIngo Molnar 	if (syms == NULL)
647a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
64886470930SIngo Molnar 
649a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
65086470930SIngo Molnar 	if (scn_symstrs == NULL)
651a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
65286470930SIngo Molnar 
65386470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
65486470930SIngo Molnar 	if (symstrs == NULL)
655a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
65686470930SIngo Molnar 
65786470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
65886470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
65986470930SIngo Molnar 
66086470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
66186470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
66286470930SIngo Molnar 
66386470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
66486470930SIngo Molnar 					   nr_rel_entries) {
66586470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
66686470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
66786470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
66886470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
66986470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
67086470930SIngo Molnar 
67186470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
67200a192b3SArnaldo Carvalho de Melo 					sympltname);
67386470930SIngo Molnar 			if (!f)
674a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
67586470930SIngo Molnar 
67682164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
67782164161SArnaldo Carvalho de Melo 				symbol__delete(f);
67882164161SArnaldo Carvalho de Melo 			else {
67986470930SIngo Molnar 				dso__insert_symbol(self, f);
68086470930SIngo Molnar 				++nr;
68186470930SIngo Molnar 			}
68282164161SArnaldo Carvalho de Melo 		}
68386470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
68486470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
68586470930SIngo Molnar 		elf_section__for_each_rel(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 {
70186470930SIngo Molnar 				dso__insert_symbol(self, f);
70286470930SIngo Molnar 				++nr;
70386470930SIngo Molnar 			}
70486470930SIngo Molnar 		}
70582164161SArnaldo Carvalho de Melo 	}
70686470930SIngo Molnar 
707a25e46c4SArnaldo Carvalho de Melo 	err = 0;
708a25e46c4SArnaldo Carvalho de Melo out_elf_end:
709a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
710a25e46c4SArnaldo Carvalho de Melo out_close:
711a25e46c4SArnaldo Carvalho de Melo 	close(fd);
712a25e46c4SArnaldo Carvalho de Melo 
713a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
71486470930SIngo Molnar 		return nr;
715a25e46c4SArnaldo Carvalho de Melo out:
7166beba7adSArnaldo Carvalho de Melo 	pr_warning("%s: problems reading %s PLT info.\n",
717439d473bSArnaldo Carvalho de Melo 		   __func__, self->long_name);
718a25e46c4SArnaldo Carvalho de Melo 	return 0;
71986470930SIngo Molnar }
72086470930SIngo Molnar 
721439d473bSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name,
722439d473bSArnaldo Carvalho de Melo 			 int fd, symbol_filter_t filter, int kernel,
7236beba7adSArnaldo Carvalho de Melo 			 int kmodule)
72486470930SIngo Molnar {
7252e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
7262e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
7272e538c4aSArnaldo Carvalho de Melo 	size_t dso_name_len = strlen(self->short_name);
7286cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
72986470930SIngo Molnar 	uint32_t nr_syms;
73086470930SIngo Molnar 	int err = -1;
73183a0944fSIngo Molnar 	uint32_t idx;
73286470930SIngo Molnar 	GElf_Ehdr ehdr;
73386470930SIngo Molnar 	GElf_Shdr shdr;
73486470930SIngo Molnar 	Elf_Data *syms;
73586470930SIngo Molnar 	GElf_Sym sym;
736a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
73786470930SIngo Molnar 	Elf *elf;
738439d473bSArnaldo Carvalho de Melo 	int nr = 0;
73986470930SIngo Molnar 
74084087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
74186470930SIngo Molnar 	if (elf == NULL) {
7426beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
74386470930SIngo Molnar 		goto out_close;
74486470930SIngo Molnar 	}
74586470930SIngo Molnar 
74686470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
7476beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
74886470930SIngo Molnar 		goto out_elf_end;
74986470930SIngo Molnar 	}
75086470930SIngo Molnar 
75186470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
75286470930SIngo Molnar 	if (sec == NULL) {
753a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
754a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
75586470930SIngo Molnar 			goto out_elf_end;
75686470930SIngo Molnar 	}
75786470930SIngo Molnar 
75886470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
75986470930SIngo Molnar 	if (syms == NULL)
76086470930SIngo Molnar 		goto out_elf_end;
76186470930SIngo Molnar 
76286470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
76386470930SIngo Molnar 	if (sec == NULL)
76486470930SIngo Molnar 		goto out_elf_end;
76586470930SIngo Molnar 
76686470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
76786470930SIngo Molnar 	if (symstrs == NULL)
76886470930SIngo Molnar 		goto out_elf_end;
76986470930SIngo Molnar 
7706cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
7716cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
7726cfcc53eSMike Galbraith 		goto out_elf_end;
7736cfcc53eSMike Galbraith 
7746cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
7759b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
7766cfcc53eSMike Galbraith 		goto out_elf_end;
7776cfcc53eSMike Galbraith 
77886470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
77986470930SIngo Molnar 
780e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
781d20ff6bdSMike Galbraith 	if (!kernel) {
78230d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
78330d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
784f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
78530d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
786d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
787d20ff6bdSMike Galbraith 
78883a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
78986470930SIngo Molnar 		struct symbol *f;
79083a0944fSIngo Molnar 		const char *elf_name;
7912e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
7926cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
7936cfcc53eSMike Galbraith 		const char *section_name;
79486470930SIngo Molnar 
7956cfcc53eSMike Galbraith 		if (!is_label && !elf_sym__is_function(&sym))
79686470930SIngo Molnar 			continue;
79786470930SIngo Molnar 
79886470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
79986470930SIngo Molnar 		if (!sec)
80086470930SIngo Molnar 			goto out_elf_end;
80186470930SIngo Molnar 
80286470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
8036cfcc53eSMike Galbraith 
8046cfcc53eSMike Galbraith 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
8056cfcc53eSMike Galbraith 			continue;
8066cfcc53eSMike Galbraith 
8072e538c4aSArnaldo Carvalho de Melo 		elf_name = elf_sym__name(&sym, symstrs);
8086cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
80986470930SIngo Molnar 
8102e538c4aSArnaldo Carvalho de Melo 		if (kernel || kmodule) {
8112e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
8122e538c4aSArnaldo Carvalho de Melo 
8132e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
8142e538c4aSArnaldo Carvalho de Melo 				   curr_dso->short_name + dso_name_len) == 0)
8152e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
8162e538c4aSArnaldo Carvalho de Melo 
8172e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
8182e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
8192e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
8202e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
821af427bf5SArnaldo Carvalho de Melo 			}
822af427bf5SArnaldo Carvalho de Melo 
8232e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
8242e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
8252e538c4aSArnaldo Carvalho de Melo 
8262e538c4aSArnaldo Carvalho de Melo 			curr_map = kernel_maps__find_by_dso_name(dso_name);
8272e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
8282e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
8292e538c4aSArnaldo Carvalho de Melo 
8302e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
8312e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
8322e538c4aSArnaldo Carvalho de Melo 
83300a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
8342e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
8352e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8362e538c4aSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso);
8372e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
8382e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
8392e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8402e538c4aSArnaldo Carvalho de Melo 				}
841ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
842ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
8432e538c4aSArnaldo Carvalho de Melo 				curr_dso->origin = DSO__ORIG_KERNEL;
8442e538c4aSArnaldo Carvalho de Melo 				kernel_maps__insert(curr_map);
8452e538c4aSArnaldo Carvalho de Melo 				dsos__add(curr_dso);
8462e538c4aSArnaldo Carvalho de Melo 			} else
8472e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
8482e538c4aSArnaldo Carvalho de Melo 
8492e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
8502e538c4aSArnaldo Carvalho de Melo 		}
8512e538c4aSArnaldo Carvalho de Melo 
8522e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
8536beba7adSArnaldo Carvalho de Melo 			pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
8546beba7adSArnaldo Carvalho de Melo 				  "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
8556beba7adSArnaldo Carvalho de Melo 				  (u64)shdr.sh_addr, (u64)shdr.sh_offset);
85686470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
857af427bf5SArnaldo Carvalho de Melo 		}
85828ac909bSArnaldo Carvalho de Melo 		/*
85928ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
86028ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
86128ac909bSArnaldo Carvalho de Melo 		 * to it...
86228ac909bSArnaldo Carvalho de Melo 		 */
86383a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
86428ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
86583a0944fSIngo Molnar 			elf_name = demangled;
8662e538c4aSArnaldo Carvalho de Melo new_symbol:
86700a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
86828ac909bSArnaldo Carvalho de Melo 		free(demangled);
86986470930SIngo Molnar 		if (!f)
87086470930SIngo Molnar 			goto out_elf_end;
87186470930SIngo Molnar 
8722e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
87300a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
87486470930SIngo Molnar 		else {
8752e538c4aSArnaldo Carvalho de Melo 			dso__insert_symbol(curr_dso, f);
87686470930SIngo Molnar 			nr++;
87786470930SIngo Molnar 		}
87886470930SIngo Molnar 	}
87986470930SIngo Molnar 
8802e538c4aSArnaldo Carvalho de Melo 	/*
8812e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
8822e538c4aSArnaldo Carvalho de Melo 	 */
8832e538c4aSArnaldo Carvalho de Melo 	if (nr > 0)
8842e538c4aSArnaldo Carvalho de Melo 		dso__fixup_sym_end(self);
88586470930SIngo Molnar 	err = nr;
88686470930SIngo Molnar out_elf_end:
88786470930SIngo Molnar 	elf_end(elf);
88886470930SIngo Molnar out_close:
88986470930SIngo Molnar 	return err;
89086470930SIngo Molnar }
89186470930SIngo Molnar 
89278075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
89378075caaSArnaldo Carvalho de Melo {
89478075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
89578075caaSArnaldo Carvalho de Melo }
89678075caaSArnaldo Carvalho de Melo 
897e30a3d12SArnaldo Carvalho de Melo bool dsos__read_build_ids(void)
89857f395a7SFrederic Weisbecker {
899e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
90057f395a7SFrederic Weisbecker 	struct dso *pos;
90157f395a7SFrederic Weisbecker 
902e30a3d12SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &dsos, node)
903e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
904e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
905e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
906e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
90757f395a7SFrederic Weisbecker 		}
90857f395a7SFrederic Weisbecker 
909e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
91057f395a7SFrederic Weisbecker }
91157f395a7SFrederic Weisbecker 
912fd7a346eSArnaldo Carvalho de Melo /*
913fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
914fd7a346eSArnaldo Carvalho de Melo  */
915fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
916fd7a346eSArnaldo Carvalho de Melo 
9172643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
9184d1e00a8SArnaldo Carvalho de Melo {
9192643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
9204d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
9214d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
922fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
9234d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
924fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
9254d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
9264d1e00a8SArnaldo Carvalho de Melo 
9272643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
9282643ce11SArnaldo Carvalho de Melo 		goto out;
9292643ce11SArnaldo Carvalho de Melo 
9302643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
9314d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
9324d1e00a8SArnaldo Carvalho de Melo 		goto out;
9334d1e00a8SArnaldo Carvalho de Melo 
93484087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
9354d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
9368d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
9374d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
9384d1e00a8SArnaldo Carvalho de Melo 	}
9394d1e00a8SArnaldo Carvalho de Melo 
9404d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
9416beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
9424d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
9434d1e00a8SArnaldo Carvalho de Melo 	}
9444d1e00a8SArnaldo Carvalho de Melo 
9452643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
9462643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
947fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
948fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
949fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
9504d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
9514d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
952fd7a346eSArnaldo Carvalho de Melo 	}
9534d1e00a8SArnaldo Carvalho de Melo 
954fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
955fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
9564d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
957fd7a346eSArnaldo Carvalho de Melo 
958fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
959fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
960fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
961fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
962fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
963fd7a346eSArnaldo Carvalho de Melo 		const char *name;
964fd7a346eSArnaldo Carvalho de Melo 
965fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
966fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
967fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
968fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
969fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
970fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
971fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
9722643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
973fd7a346eSArnaldo Carvalho de Melo 				break;
974fd7a346eSArnaldo Carvalho de Melo 			}
975fd7a346eSArnaldo Carvalho de Melo 		}
976fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
977fd7a346eSArnaldo Carvalho de Melo 	}
9782643ce11SArnaldo Carvalho de Melo out_elf_end:
9792643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
9802643ce11SArnaldo Carvalho de Melo out_close:
9812643ce11SArnaldo Carvalho de Melo 	close(fd);
9822643ce11SArnaldo Carvalho de Melo out:
9832643ce11SArnaldo Carvalho de Melo 	return err;
9842643ce11SArnaldo Carvalho de Melo }
9852643ce11SArnaldo Carvalho de Melo 
986f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
987f1617b40SArnaldo Carvalho de Melo {
988f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
989f1617b40SArnaldo Carvalho de Melo 
990f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
991f1617b40SArnaldo Carvalho de Melo 		goto out;
992f1617b40SArnaldo Carvalho de Melo 
993f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
994f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
995f1617b40SArnaldo Carvalho de Melo 		goto out;
996f1617b40SArnaldo Carvalho de Melo 
997f1617b40SArnaldo Carvalho de Melo 	while (1) {
998f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
999f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1000f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1001f1617b40SArnaldo Carvalho de Melo 
1002f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1003f1617b40SArnaldo Carvalho de Melo 			break;
1004f1617b40SArnaldo Carvalho de Melo 
1005fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1006fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1007f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1008f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1009f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1010f1617b40SArnaldo Carvalho de Melo 				break;
1011f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1012f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1013f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1014f1617b40SArnaldo Carvalho de Melo 					err = 0;
1015f1617b40SArnaldo Carvalho de Melo 					break;
1016f1617b40SArnaldo Carvalho de Melo 				}
1017f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1018f1617b40SArnaldo Carvalho de Melo 				break;
1019f1617b40SArnaldo Carvalho de Melo 		} else {
1020f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1021f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1022f1617b40SArnaldo Carvalho de Melo 				break;
1023f1617b40SArnaldo Carvalho de Melo 		}
1024f1617b40SArnaldo Carvalho de Melo 	}
1025f1617b40SArnaldo Carvalho de Melo 	close(fd);
1026f1617b40SArnaldo Carvalho de Melo out:
1027f1617b40SArnaldo Carvalho de Melo 	return err;
1028f1617b40SArnaldo Carvalho de Melo }
1029f1617b40SArnaldo Carvalho de Melo 
103094cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
103194cb9e38SArnaldo Carvalho de Melo {
103294cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
103394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
103494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
103594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
103694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
103794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
103894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1039439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
104094cb9e38SArnaldo Carvalho de Melo 	};
104194cb9e38SArnaldo Carvalho de Melo 
104294cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
104394cb9e38SArnaldo Carvalho de Melo 		return '!';
104494cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
104594cb9e38SArnaldo Carvalho de Melo }
104694cb9e38SArnaldo Carvalho de Melo 
10476beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
104886470930SIngo Molnar {
10494d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1050c338aee8SArnaldo Carvalho de Melo 	char *name;
1051d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
105286470930SIngo Molnar 	int ret = -1;
105386470930SIngo Molnar 	int fd;
105486470930SIngo Molnar 
10558d06367fSArnaldo Carvalho de Melo 	self->loaded = 1;
105666bd8424SArnaldo Carvalho de Melo 
1057c338aee8SArnaldo Carvalho de Melo 	if (self->kernel)
1058c338aee8SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, filter);
1059c338aee8SArnaldo Carvalho de Melo 
1060c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
106186470930SIngo Molnar 	if (!name)
106286470930SIngo Molnar 		return -1;
106386470930SIngo Molnar 
106430d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1065f5812a7aSArnaldo Carvalho de Melo 
106694cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
10676beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
106894cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
106994cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
107094cb9e38SArnaldo Carvalho de Melo 		return ret;
107194cb9e38SArnaldo Carvalho de Melo 	}
107294cb9e38SArnaldo Carvalho de Melo 
107394cb9e38SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_FEDORA - 1;
107480d496beSPekka Enberg 
107586470930SIngo Molnar more:
107686470930SIngo Molnar 	do {
107794cb9e38SArnaldo Carvalho de Melo 		self->origin++;
107894cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
107994cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1080439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1081439d473bSArnaldo Carvalho de Melo 				 self->long_name);
108286470930SIngo Molnar 			break;
108394cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1084439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1085439d473bSArnaldo Carvalho de Melo 				 self->long_name);
108686470930SIngo Molnar 			break;
108794cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1088d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1089d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1090d3379ab9SArnaldo Carvalho de Melo 				char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1091d3379ab9SArnaldo Carvalho de Melo 
1092d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1093d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
10944d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
10954d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1096d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1097d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
10988d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1099d3379ab9SArnaldo Carvalho de Melo 				break;
11004d1e00a8SArnaldo Carvalho de Melo 			}
110194cb9e38SArnaldo Carvalho de Melo 			self->origin++;
11024d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
110394cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1104439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
110586470930SIngo Molnar 			break;
110686470930SIngo Molnar 
110786470930SIngo Molnar 		default:
110886470930SIngo Molnar 			goto out;
110986470930SIngo Molnar 		}
111086470930SIngo Molnar 
11118d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1112d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1113d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
11148d06367fSArnaldo Carvalho de Melo 				goto more;
11158d06367fSArnaldo Carvalho de Melo compare_build_id:
111678075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
11178d06367fSArnaldo Carvalho de Melo 				goto more;
11188d06367fSArnaldo Carvalho de Melo 		}
11198d06367fSArnaldo Carvalho de Melo 
112086470930SIngo Molnar 		fd = open(name, O_RDONLY);
112186470930SIngo Molnar 	} while (fd < 0);
112286470930SIngo Molnar 
11236beba7adSArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
112486470930SIngo Molnar 	close(fd);
112586470930SIngo Molnar 
112686470930SIngo Molnar 	/*
112786470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
112886470930SIngo Molnar 	 */
112986470930SIngo Molnar 	if (!ret)
113086470930SIngo Molnar 		goto more;
113186470930SIngo Molnar 
1132a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
113382164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1134a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1135a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1136a25e46c4SArnaldo Carvalho de Melo 	}
113786470930SIngo Molnar out:
113886470930SIngo Molnar 	free(name);
11391340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
11401340e6bbSArnaldo Carvalho de Melo 		return 0;
114186470930SIngo Molnar 	return ret;
114286470930SIngo Molnar }
114386470930SIngo Molnar 
1144439d473bSArnaldo Carvalho de Melo struct map *kernel_map;
1145439d473bSArnaldo Carvalho de Melo 
1146439d473bSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map)
1147439d473bSArnaldo Carvalho de Melo {
1148439d473bSArnaldo Carvalho de Melo 	maps__insert(&kernel_maps, map);
1149439d473bSArnaldo Carvalho de Melo }
1150439d473bSArnaldo Carvalho de Melo 
1151c338aee8SArnaldo Carvalho de Melo struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp,
1152c338aee8SArnaldo Carvalho de Melo 					symbol_filter_t filter)
1153439d473bSArnaldo Carvalho de Melo {
1154439d473bSArnaldo Carvalho de Melo 	struct map *map = maps__find(&kernel_maps, ip);
1155439d473bSArnaldo Carvalho de Melo 
1156439d473bSArnaldo Carvalho de Melo 	if (mapp)
1157439d473bSArnaldo Carvalho de Melo 		*mapp = map;
1158439d473bSArnaldo Carvalho de Melo 
11592e538c4aSArnaldo Carvalho de Melo 	if (map) {
11602e538c4aSArnaldo Carvalho de Melo 		ip = map->map_ip(map, ip);
1161c338aee8SArnaldo Carvalho de Melo 		return map__find_symbol(map, ip, filter);
11622e538c4aSArnaldo Carvalho de Melo 	}
11632e538c4aSArnaldo Carvalho de Melo 
11642e538c4aSArnaldo Carvalho de Melo 	return NULL;
1165439d473bSArnaldo Carvalho de Melo }
1166439d473bSArnaldo Carvalho de Melo 
1167439d473bSArnaldo Carvalho de Melo struct map *kernel_maps__find_by_dso_name(const char *name)
1168439d473bSArnaldo Carvalho de Melo {
1169439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1170439d473bSArnaldo Carvalho de Melo 
1171439d473bSArnaldo Carvalho de Melo 	for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
1172439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1173439d473bSArnaldo Carvalho de Melo 
1174439d473bSArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->name, name) == 0)
1175439d473bSArnaldo Carvalho de Melo 			return map;
1176439d473bSArnaldo Carvalho de Melo 	}
1177439d473bSArnaldo Carvalho de Melo 
1178439d473bSArnaldo Carvalho de Melo 	return NULL;
1179439d473bSArnaldo Carvalho de Melo }
1180439d473bSArnaldo Carvalho de Melo 
1181c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname)
11826cfcc53eSMike Galbraith {
1183439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
1184439d473bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dirname);
11856cfcc53eSMike Galbraith 
1186439d473bSArnaldo Carvalho de Melo 	if (!dir) {
11876beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot open %s dir\n", __func__, dirname);
1188439d473bSArnaldo Carvalho de Melo 		return -1;
1189439d473bSArnaldo Carvalho de Melo 	}
11906cfcc53eSMike Galbraith 
1191439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1192439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1193439d473bSArnaldo Carvalho de Melo 
1194439d473bSArnaldo Carvalho de Melo 		if (dent->d_type == DT_DIR) {
1195439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1196439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1197439d473bSArnaldo Carvalho de Melo 				continue;
1198439d473bSArnaldo Carvalho de Melo 
1199439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1200439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1201c338aee8SArnaldo Carvalho de Melo 			if (dsos__set_modules_path_dir(path) < 0)
1202439d473bSArnaldo Carvalho de Melo 				goto failure;
1203439d473bSArnaldo Carvalho de Melo 		} else {
1204439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1205439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1206439d473bSArnaldo Carvalho de Melo 			struct map *map;
1207cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1208439d473bSArnaldo Carvalho de Melo 
1209439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1210439d473bSArnaldo Carvalho de Melo 				continue;
1211439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1212439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1213439d473bSArnaldo Carvalho de Melo 
1214a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
1215439d473bSArnaldo Carvalho de Melo 			map = kernel_maps__find_by_dso_name(dso_name);
1216439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1217439d473bSArnaldo Carvalho de Melo 				continue;
1218439d473bSArnaldo Carvalho de Melo 
1219439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1220439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1221439d473bSArnaldo Carvalho de Melo 
1222cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1223cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1224439d473bSArnaldo Carvalho de Melo 				goto failure;
1225cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1226439d473bSArnaldo Carvalho de Melo 		}
1227439d473bSArnaldo Carvalho de Melo 	}
1228439d473bSArnaldo Carvalho de Melo 
1229c338aee8SArnaldo Carvalho de Melo 	return 0;
1230439d473bSArnaldo Carvalho de Melo failure:
1231439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1232439d473bSArnaldo Carvalho de Melo 	return -1;
1233439d473bSArnaldo Carvalho de Melo }
1234439d473bSArnaldo Carvalho de Melo 
1235c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void)
1236439d473bSArnaldo Carvalho de Melo {
1237439d473bSArnaldo Carvalho de Melo 	struct utsname uts;
1238439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1239439d473bSArnaldo Carvalho de Melo 
1240439d473bSArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
1241439d473bSArnaldo Carvalho de Melo 		return -1;
1242439d473bSArnaldo Carvalho de Melo 
1243439d473bSArnaldo Carvalho de Melo 	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1244439d473bSArnaldo Carvalho de Melo 		 uts.release);
1245439d473bSArnaldo Carvalho de Melo 
1246c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path_dir(modules_path);
1247439d473bSArnaldo Carvalho de Melo }
12486cfcc53eSMike Galbraith 
12496cfcc53eSMike Galbraith /*
1250439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1251439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1252439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
12536cfcc53eSMike Galbraith  */
1254439d473bSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso)
1255439d473bSArnaldo Carvalho de Melo {
1256439d473bSArnaldo Carvalho de Melo 	struct map *self = malloc(sizeof(*self));
12576cfcc53eSMike Galbraith 
1258439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1259439d473bSArnaldo Carvalho de Melo 		/*
1260afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1261439d473bSArnaldo Carvalho de Melo 		 */
1262afb7b4f0SArnaldo Carvalho de Melo 		map__init(self, start, 0, 0, dso);
1263439d473bSArnaldo Carvalho de Melo 	}
1264afb7b4f0SArnaldo Carvalho de Melo 
1265439d473bSArnaldo Carvalho de Melo 	return self;
1266439d473bSArnaldo Carvalho de Melo }
1267439d473bSArnaldo Carvalho de Melo 
1268c338aee8SArnaldo Carvalho de Melo static int kernel_maps__create_module_maps(void)
1269439d473bSArnaldo Carvalho de Melo {
1270439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1271439d473bSArnaldo Carvalho de Melo 	size_t n;
1272439d473bSArnaldo Carvalho de Melo 	FILE *file = fopen("/proc/modules", "r");
1273439d473bSArnaldo Carvalho de Melo 	struct map *map;
1274439d473bSArnaldo Carvalho de Melo 
1275439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1276439d473bSArnaldo Carvalho de Melo 		return -1;
1277439d473bSArnaldo Carvalho de Melo 
1278439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1279439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1280439d473bSArnaldo Carvalho de Melo 		u64 start;
1281439d473bSArnaldo Carvalho de Melo 		struct dso *dso;
1282439d473bSArnaldo Carvalho de Melo 		char *sep;
1283439d473bSArnaldo Carvalho de Melo 		int line_len;
1284439d473bSArnaldo Carvalho de Melo 
1285439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1286439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
12876cfcc53eSMike Galbraith 			break;
12886cfcc53eSMike Galbraith 
1289439d473bSArnaldo Carvalho de Melo 		if (!line)
1290439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1291439d473bSArnaldo Carvalho de Melo 
1292439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1293439d473bSArnaldo Carvalho de Melo 
1294439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1295439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1296439d473bSArnaldo Carvalho de Melo 			continue;
1297439d473bSArnaldo Carvalho de Melo 
1298439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1299439d473bSArnaldo Carvalho de Melo 
1300439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1301439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1302439d473bSArnaldo Carvalho de Melo 			continue;
1303439d473bSArnaldo Carvalho de Melo 
1304439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1305439d473bSArnaldo Carvalho de Melo 
1306439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
130700a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1308439d473bSArnaldo Carvalho de Melo 
1309439d473bSArnaldo Carvalho de Melo 		if (dso == NULL)
1310439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1311439d473bSArnaldo Carvalho de Melo 
1312439d473bSArnaldo Carvalho de Melo 		map = map__new2(start, dso);
1313439d473bSArnaldo Carvalho de Melo 		if (map == NULL) {
1314439d473bSArnaldo Carvalho de Melo 			dso__delete(dso);
1315439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
13166cfcc53eSMike Galbraith 		}
13176cfcc53eSMike Galbraith 
1318f1617b40SArnaldo Carvalho de Melo 		snprintf(name, sizeof(name),
1319f1617b40SArnaldo Carvalho de Melo 			 "/sys/module/%s/notes/.note.gnu.build-id", line);
1320f1617b40SArnaldo Carvalho de Melo 		if (sysfs__read_build_id(name, dso->build_id,
1321f1617b40SArnaldo Carvalho de Melo 					 sizeof(dso->build_id)) == 0)
1322f1617b40SArnaldo Carvalho de Melo 			dso->has_build_id = true;
1323f1617b40SArnaldo Carvalho de Melo 
1324439d473bSArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1325439d473bSArnaldo Carvalho de Melo 		kernel_maps__insert(map);
1326439d473bSArnaldo Carvalho de Melo 		dsos__add(dso);
13276cfcc53eSMike Galbraith 	}
13286cfcc53eSMike Galbraith 
1329439d473bSArnaldo Carvalho de Melo 	free(line);
1330439d473bSArnaldo Carvalho de Melo 	fclose(file);
1331439d473bSArnaldo Carvalho de Melo 
1332c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path();
1333439d473bSArnaldo Carvalho de Melo 
1334439d473bSArnaldo Carvalho de Melo out_delete_line:
1335439d473bSArnaldo Carvalho de Melo 	free(line);
1336439d473bSArnaldo Carvalho de Melo out_failure:
1337439d473bSArnaldo Carvalho de Melo 	return -1;
13386cfcc53eSMike Galbraith }
13396cfcc53eSMike Galbraith 
1340439d473bSArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
13416beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
134286470930SIngo Molnar {
1343fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
134486470930SIngo Molnar 
1345fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1346fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
134766bd8424SArnaldo Carvalho de Melo 
1348fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1349fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1350fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1351fbd733b8SArnaldo Carvalho de Melo 			return -1;
1352fbd733b8SArnaldo Carvalho de Melo 		}
1353fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1354fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1355fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1356fbd733b8SArnaldo Carvalho de Melo 
1357fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1358fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1359fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1360fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1361fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1362fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1363fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1364fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1365fbd733b8SArnaldo Carvalho de Melo 			return -1;
1366fbd733b8SArnaldo Carvalho de Melo 		}
1367fbd733b8SArnaldo Carvalho de Melo 	}
1368fbd733b8SArnaldo Carvalho de Melo 
1369fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
137086470930SIngo Molnar 	if (fd < 0)
137186470930SIngo Molnar 		return -1;
137286470930SIngo Molnar 
1373fbd733b8SArnaldo Carvalho de Melo 	self->loaded = 1;
13746beba7adSArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
13756cfcc53eSMike Galbraith 
137686470930SIngo Molnar 	close(fd);
137786470930SIngo Molnar 
137886470930SIngo Molnar 	return err;
137986470930SIngo Molnar }
138086470930SIngo Molnar 
1381c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
1382c338aee8SArnaldo Carvalho de Melo 				symbol_filter_t filter)
138386470930SIngo Molnar {
1384c338aee8SArnaldo Carvalho de Melo 	int err = dso__load_vmlinux(self, map, self->name, filter);
1385439d473bSArnaldo Carvalho de Melo 
1386ef6ae724SArnaldo Carvalho de Melo 	if (err <= 0) {
1387c338aee8SArnaldo Carvalho de Melo 		err = kernel_maps__load_kallsyms(filter);
1388ef6ae724SArnaldo Carvalho de Melo 		if (err > 0)
1389ef6ae724SArnaldo Carvalho de Melo                         dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1390ef6ae724SArnaldo Carvalho de Melo 	}
139186470930SIngo Molnar 
1392439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1393c338aee8SArnaldo Carvalho de Melo 		map__fixup_start(map);
1394c338aee8SArnaldo Carvalho de Melo 		map__fixup_end(map);
1395439d473bSArnaldo Carvalho de Melo 	}
139694cb9e38SArnaldo Carvalho de Melo 
139786470930SIngo Molnar 	return err;
139886470930SIngo Molnar }
139986470930SIngo Molnar 
1400cd84c2acSFrederic Weisbecker LIST_HEAD(dsos);
1401cd84c2acSFrederic Weisbecker struct dso	*vdso;
1402cd84c2acSFrederic Weisbecker 
140383a0944fSIngo Molnar const char	*vmlinux_name = "vmlinux";
1404cd84c2acSFrederic Weisbecker 
1405cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso)
1406cd84c2acSFrederic Weisbecker {
1407cd84c2acSFrederic Weisbecker 	list_add_tail(&dso->node, &dsos);
1408cd84c2acSFrederic Weisbecker }
1409cd84c2acSFrederic Weisbecker 
1410cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name)
1411cd84c2acSFrederic Weisbecker {
1412cd84c2acSFrederic Weisbecker 	struct dso *pos;
1413cd84c2acSFrederic Weisbecker 
1414cd84c2acSFrederic Weisbecker 	list_for_each_entry(pos, &dsos, node)
1415cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
1416cd84c2acSFrederic Weisbecker 			return pos;
1417cd84c2acSFrederic Weisbecker 	return NULL;
1418cd84c2acSFrederic Weisbecker }
1419cd84c2acSFrederic Weisbecker 
142000a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name)
1421cd84c2acSFrederic Weisbecker {
1422cd84c2acSFrederic Weisbecker 	struct dso *dso = dsos__find(name);
1423cd84c2acSFrederic Weisbecker 
1424e4204992SArnaldo Carvalho de Melo 	if (!dso) {
142500a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1426cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1427cd84c2acSFrederic Weisbecker 			dsos__add(dso);
1428cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1429cfc10d3bSArnaldo Carvalho de Melo 		}
1430e4204992SArnaldo Carvalho de Melo 	}
1431cd84c2acSFrederic Weisbecker 
1432cd84c2acSFrederic Weisbecker 	return dso;
1433cd84c2acSFrederic Weisbecker }
1434cd84c2acSFrederic Weisbecker 
1435cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp)
1436cd84c2acSFrederic Weisbecker {
1437cd84c2acSFrederic Weisbecker 	struct dso *pos;
1438cd84c2acSFrederic Weisbecker 
1439cd84c2acSFrederic Weisbecker 	list_for_each_entry(pos, &dsos, node)
1440cd84c2acSFrederic Weisbecker 		dso__fprintf(pos, fp);
1441cd84c2acSFrederic Weisbecker }
1442cd84c2acSFrederic Weisbecker 
14439e03eb2dSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp)
14449e03eb2dSArnaldo Carvalho de Melo {
14459e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
14469e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
14479e03eb2dSArnaldo Carvalho de Melo 
14489e03eb2dSArnaldo Carvalho de Melo 	list_for_each_entry(pos, &dsos, node) {
14499e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
14509e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
14519e03eb2dSArnaldo Carvalho de Melo 	}
14529e03eb2dSArnaldo Carvalho de Melo 	return ret;
14539e03eb2dSArnaldo Carvalho de Melo }
14549e03eb2dSArnaldo Carvalho de Melo 
1455c338aee8SArnaldo Carvalho de Melo static int kernel_maps__create_kernel_map(void)
1456cd84c2acSFrederic Weisbecker {
14572446042cSArnaldo Carvalho de Melo 	struct dso *kernel = dso__new(vmlinux_name);
1458cd84c2acSFrederic Weisbecker 
14592446042cSArnaldo Carvalho de Melo 	if (kernel == NULL)
1460c338aee8SArnaldo Carvalho de Melo 		return -1;
1461c338aee8SArnaldo Carvalho de Melo 
1462c338aee8SArnaldo Carvalho de Melo 	kernel_map = map__new2(0, kernel);
1463c338aee8SArnaldo Carvalho de Melo 	if (kernel_map == NULL)
1464c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_dso;
1465c338aee8SArnaldo Carvalho de Melo 
1466c338aee8SArnaldo Carvalho de Melo 	kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
14672446042cSArnaldo Carvalho de Melo 
14682446042cSArnaldo Carvalho de Melo 	kernel->short_name = "[kernel]";
1469c338aee8SArnaldo Carvalho de Melo 	kernel->kernel = 1;
147000a192b3SArnaldo Carvalho de Melo 	vdso = dso__new("[vdso]");
1471c338aee8SArnaldo Carvalho de Melo 	if (vdso == NULL)
1472c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_map;
1473cd84c2acSFrederic Weisbecker 
14742446042cSArnaldo Carvalho de Melo 	if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
14752446042cSArnaldo Carvalho de Melo 				 sizeof(kernel->build_id)) == 0)
14762446042cSArnaldo Carvalho de Melo 		kernel->has_build_id = true;
14772446042cSArnaldo Carvalho de Melo 
1478c338aee8SArnaldo Carvalho de Melo 	kernel_maps__insert(kernel_map);
14792446042cSArnaldo Carvalho de Melo 	dsos__add(kernel);
1480cd84c2acSFrederic Weisbecker 	dsos__add(vdso);
1481cd84c2acSFrederic Weisbecker 
1482c338aee8SArnaldo Carvalho de Melo 	return 0;
1483c338aee8SArnaldo Carvalho de Melo 
1484c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map:
1485c338aee8SArnaldo Carvalho de Melo 	map__delete(kernel_map);
1486c338aee8SArnaldo Carvalho de Melo 	kernel_map = NULL;
1487c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso:
1488c338aee8SArnaldo Carvalho de Melo 	dso__delete(kernel);
1489c338aee8SArnaldo Carvalho de Melo 	return -1;
14902446042cSArnaldo Carvalho de Melo }
14912446042cSArnaldo Carvalho de Melo 
1492c338aee8SArnaldo Carvalho de Melo int kernel_maps__init(bool use_modules)
14932446042cSArnaldo Carvalho de Melo {
1494c338aee8SArnaldo Carvalho de Melo 	if (kernel_maps__create_kernel_map() < 0)
14952446042cSArnaldo Carvalho de Melo 		return -1;
14962446042cSArnaldo Carvalho de Melo 
1497c338aee8SArnaldo Carvalho de Melo 	if (use_modules && kernel_maps__create_module_maps() < 0)
14986671cb16SArnaldo Carvalho de Melo 		pr_warning("Failed to load list of modules in use, "
14996671cb16SArnaldo Carvalho de Melo 			   "continuing...\n");
150090c83218SArnaldo Carvalho de Melo 	/*
150190c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
150290c83218SArnaldo Carvalho de Melo 	 */
150390c83218SArnaldo Carvalho de Melo 	kernel_maps__fixup_end();
15046671cb16SArnaldo Carvalho de Melo 	return 0;
1505cd84c2acSFrederic Weisbecker }
1506cd84c2acSFrederic Weisbecker 
150700a192b3SArnaldo Carvalho de Melo void symbol__init(unsigned int priv_size)
150886470930SIngo Molnar {
150986470930SIngo Molnar 	elf_version(EV_CURRENT);
151000a192b3SArnaldo Carvalho de Melo 	symbol__priv_size = priv_size;
151186470930SIngo Molnar }
1512