xref: /linux/tools/perf/util/symbol.c (revision f1dfa0b1c1a90d4d3bf515ab04a6b6222e086293)
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);
329958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *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,
369958e1f0SArnaldo Carvalho de Melo 				struct map_groups *mg, 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 
469958e1f0SArnaldo Carvalho de Melo static struct map_groups kmaps_mem;
479958e1f0SArnaldo Carvalho de Melo struct map_groups *kmaps = &kmaps_mem;
48af427bf5SArnaldo Carvalho de Melo 
493610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
503610583cSArnaldo Carvalho de Melo {
513610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
523610583cSArnaldo Carvalho de Melo }
533610583cSArnaldo Carvalho de Melo 
543610583cSArnaldo Carvalho de Melo static void dso__set_loaded(struct dso *self, enum map_type type)
553610583cSArnaldo Carvalho de Melo {
563610583cSArnaldo Carvalho de Melo 	self->loaded |= (1 << type);
573610583cSArnaldo Carvalho de Melo }
583610583cSArnaldo Carvalho de Melo 
596893d4eeSArnaldo Carvalho de Melo static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
606893d4eeSArnaldo Carvalho de Melo {
616893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
626893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
636893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
64*f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
65*f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
666893d4eeSArnaldo Carvalho de Melo 	default:
676893d4eeSArnaldo Carvalho de Melo 		return false;
686893d4eeSArnaldo Carvalho de Melo 	}
696893d4eeSArnaldo Carvalho de Melo }
706893d4eeSArnaldo Carvalho de Melo 
71fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
72af427bf5SArnaldo Carvalho de Melo {
73fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
742e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
75af427bf5SArnaldo Carvalho de Melo 
76af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
77af427bf5SArnaldo Carvalho de Melo 		return;
78af427bf5SArnaldo Carvalho de Melo 
792e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
802e538c4aSArnaldo Carvalho de Melo 
81af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
822e538c4aSArnaldo Carvalho de Melo 		prev = curr;
832e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
84af427bf5SArnaldo Carvalho de Melo 
85af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
86af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
87af427bf5SArnaldo Carvalho de Melo 	}
88af427bf5SArnaldo Carvalho de Melo 
892e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
902e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
912e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
922e538c4aSArnaldo Carvalho de Melo }
932e538c4aSArnaldo Carvalho de Melo 
949958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
95af427bf5SArnaldo Carvalho de Melo {
96af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
9795011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
98af427bf5SArnaldo Carvalho de Melo 
99af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
100af427bf5SArnaldo Carvalho de Melo 		return;
101af427bf5SArnaldo Carvalho de Melo 
102af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
103af427bf5SArnaldo Carvalho de Melo 
104af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
105af427bf5SArnaldo Carvalho de Melo 		prev = curr;
106af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
107af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1082e538c4aSArnaldo Carvalho de Melo 	}
10990c83218SArnaldo Carvalho de Melo 
11090c83218SArnaldo Carvalho de Melo 	/*
11190c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
11290c83218SArnaldo Carvalho de Melo 	 * last map final address.
11390c83218SArnaldo Carvalho de Melo 	 */
11490c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
115af427bf5SArnaldo Carvalho de Melo }
116af427bf5SArnaldo Carvalho de Melo 
1179958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
11823ea4a3fSArnaldo Carvalho de Melo {
11923ea4a3fSArnaldo Carvalho de Melo 	int i;
12023ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1219958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
12223ea4a3fSArnaldo Carvalho de Melo }
12323ea4a3fSArnaldo Carvalho de Melo 
12400a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name)
12586470930SIngo Molnar {
12686470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
12736479484SArnaldo Carvalho de Melo 	struct symbol *self = zalloc(symbol__priv_size +
12836479484SArnaldo Carvalho de Melo 				     sizeof(*self) + namelen);
12936479484SArnaldo Carvalho de Melo 	if (self == NULL)
13086470930SIngo Molnar 		return NULL;
13186470930SIngo Molnar 
13236479484SArnaldo Carvalho de Melo 	if (symbol__priv_size)
13300a192b3SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol__priv_size;
13436479484SArnaldo Carvalho de Melo 
13586470930SIngo Molnar 	self->start = start;
1366cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
137e4204992SArnaldo Carvalho de Melo 
1386beba7adSArnaldo Carvalho de Melo 	pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
139e4204992SArnaldo Carvalho de Melo 
14086470930SIngo Molnar 	memcpy(self->name, name, namelen);
14186470930SIngo Molnar 
14286470930SIngo Molnar 	return self;
14386470930SIngo Molnar }
14486470930SIngo Molnar 
14500a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self)
14686470930SIngo Molnar {
14700a192b3SArnaldo Carvalho de Melo 	free(((void *)self) - symbol__priv_size);
14886470930SIngo Molnar }
14986470930SIngo Molnar 
15086470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
15186470930SIngo Molnar {
15286470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
15386470930SIngo Molnar 		       self->start, self->end, self->name);
15486470930SIngo Molnar }
15586470930SIngo Molnar 
156cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name)
157cfc10d3bSArnaldo Carvalho de Melo {
158ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
159ef6ae724SArnaldo Carvalho de Melo 		return;
160cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
161cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
162cfc10d3bSArnaldo Carvalho de Melo }
163cfc10d3bSArnaldo Carvalho de Melo 
164cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
165cfc10d3bSArnaldo Carvalho de Melo {
166cfc10d3bSArnaldo Carvalho de Melo 	self->short_name = basename(self->long_name);
167cfc10d3bSArnaldo Carvalho de Melo }
168cfc10d3bSArnaldo Carvalho de Melo 
16900a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
17086470930SIngo Molnar {
17186470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
17286470930SIngo Molnar 
17386470930SIngo Molnar 	if (self != NULL) {
1746a4694a4SArnaldo Carvalho de Melo 		int i;
17586470930SIngo Molnar 		strcpy(self->name, name);
176cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
177439d473bSArnaldo Carvalho de Melo 		self->short_name = self->name;
1786a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
1796a4694a4SArnaldo Carvalho de Melo 			self->symbols[i] = RB_ROOT;
1806a4694a4SArnaldo Carvalho de Melo 		self->find_symbol = dso__find_symbol;
18152d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
18294cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1838d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
1848d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
18586470930SIngo Molnar 	}
18686470930SIngo Molnar 
18786470930SIngo Molnar 	return self;
18886470930SIngo Molnar }
18986470930SIngo Molnar 
190fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
19186470930SIngo Molnar {
19286470930SIngo Molnar 	struct symbol *pos;
193fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
19486470930SIngo Molnar 
19586470930SIngo Molnar 	while (next) {
19686470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
19786470930SIngo Molnar 		next = rb_next(&pos->rb_node);
198fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
19900a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
20086470930SIngo Molnar 	}
20186470930SIngo Molnar }
20286470930SIngo Molnar 
20386470930SIngo Molnar void dso__delete(struct dso *self)
20486470930SIngo Molnar {
2056a4694a4SArnaldo Carvalho de Melo 	int i;
2066a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2076a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
208439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
209439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
21086470930SIngo Molnar 	free(self);
21186470930SIngo Molnar }
21286470930SIngo Molnar 
2138d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2148d06367fSArnaldo Carvalho de Melo {
2158d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2168d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2178d06367fSArnaldo Carvalho de Melo }
2188d06367fSArnaldo Carvalho de Melo 
219fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
22086470930SIngo Molnar {
221fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
22286470930SIngo Molnar 	struct rb_node *parent = NULL;
2239cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
22486470930SIngo Molnar 	struct symbol *s;
22586470930SIngo Molnar 
22686470930SIngo Molnar 	while (*p != NULL) {
22786470930SIngo Molnar 		parent = *p;
22886470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
22986470930SIngo Molnar 		if (ip < s->start)
23086470930SIngo Molnar 			p = &(*p)->rb_left;
23186470930SIngo Molnar 		else
23286470930SIngo Molnar 			p = &(*p)->rb_right;
23386470930SIngo Molnar 	}
23486470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
235fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
23686470930SIngo Molnar }
23786470930SIngo Molnar 
238fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
23986470930SIngo Molnar {
24086470930SIngo Molnar 	struct rb_node *n;
24186470930SIngo Molnar 
24286470930SIngo Molnar 	if (self == NULL)
24386470930SIngo Molnar 		return NULL;
24486470930SIngo Molnar 
245fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
24686470930SIngo Molnar 
24786470930SIngo Molnar 	while (n) {
24886470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
24986470930SIngo Molnar 
25086470930SIngo Molnar 		if (ip < s->start)
25186470930SIngo Molnar 			n = n->rb_left;
25286470930SIngo Molnar 		else if (ip > s->end)
25386470930SIngo Molnar 			n = n->rb_right;
25486470930SIngo Molnar 		else
25586470930SIngo Molnar 			return s;
25686470930SIngo Molnar 	}
25786470930SIngo Molnar 
25886470930SIngo Molnar 	return NULL;
25986470930SIngo Molnar }
26086470930SIngo Molnar 
2616a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
262fcf1203aSArnaldo Carvalho de Melo {
2636a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
264fcf1203aSArnaldo Carvalho de Melo }
265fcf1203aSArnaldo Carvalho de Melo 
2668d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf)
2678d06367fSArnaldo Carvalho de Melo {
2688d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
2698d06367fSArnaldo Carvalho de Melo 	u8 *raw = self;
2708d06367fSArnaldo Carvalho de Melo 	int i;
2718d06367fSArnaldo Carvalho de Melo 
2728d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
2738d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
2748d06367fSArnaldo Carvalho de Melo 		++raw;
2758d06367fSArnaldo Carvalho de Melo 		bid += 2;
2768d06367fSArnaldo Carvalho de Melo 	}
2778d06367fSArnaldo Carvalho de Melo 
2788d06367fSArnaldo Carvalho de Melo 	return raw - self;
2798d06367fSArnaldo Carvalho de Melo }
2808d06367fSArnaldo Carvalho de Melo 
2819e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
28286470930SIngo Molnar {
2838d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2848d06367fSArnaldo Carvalho de Melo 
2858d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
2869e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
2879e03eb2dSArnaldo Carvalho de Melo }
2889e03eb2dSArnaldo Carvalho de Melo 
28995011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
2909e03eb2dSArnaldo Carvalho de Melo {
2919e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
2929e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
2939e03eb2dSArnaldo Carvalho de Melo 
2949e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
2956a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
29695011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
29786470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
29886470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
29986470930SIngo Molnar 	}
30086470930SIngo Molnar 
30186470930SIngo Molnar 	return ret;
30286470930SIngo Molnar }
30386470930SIngo Molnar 
3042e538c4aSArnaldo Carvalho de Melo /*
3052e538c4aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
3062e538c4aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
3072e538c4aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
3082e538c4aSArnaldo Carvalho de Melo  */
3094e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map)
31086470930SIngo Molnar {
31186470930SIngo Molnar 	char *line = NULL;
31286470930SIngo Molnar 	size_t n;
3134e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
31486470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
31586470930SIngo Molnar 
31686470930SIngo Molnar 	if (file == NULL)
31786470930SIngo Molnar 		goto out_failure;
31886470930SIngo Molnar 
31986470930SIngo Molnar 	while (!feof(file)) {
3209cffa8d5SPaul Mackerras 		u64 start;
32186470930SIngo Molnar 		struct symbol *sym;
32286470930SIngo Molnar 		int line_len, len;
32386470930SIngo Molnar 		char symbol_type;
3242e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
32586470930SIngo Molnar 
32686470930SIngo Molnar 		line_len = getline(&line, &n, file);
32786470930SIngo Molnar 		if (line_len < 0)
32886470930SIngo Molnar 			break;
32986470930SIngo Molnar 
33086470930SIngo Molnar 		if (!line)
33186470930SIngo Molnar 			goto out_failure;
33286470930SIngo Molnar 
33386470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
33486470930SIngo Molnar 
33586470930SIngo Molnar 		len = hex2u64(line, &start);
33686470930SIngo Molnar 
33786470930SIngo Molnar 		len++;
33886470930SIngo Molnar 		if (len + 2 >= line_len)
33986470930SIngo Molnar 			continue;
34086470930SIngo Molnar 
34186470930SIngo Molnar 		symbol_type = toupper(line[len]);
3426893d4eeSArnaldo Carvalho de Melo 		if (!symbol_type__is_a(symbol_type, map->type))
34386470930SIngo Molnar 			continue;
344af427bf5SArnaldo Carvalho de Melo 
345af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
3462e538c4aSArnaldo Carvalho de Melo 		/*
3472e538c4aSArnaldo Carvalho de Melo 		 * Will fix up the end later, when we have all symbols sorted.
3482e538c4aSArnaldo Carvalho de Melo 		 */
34900a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, 0, symbol_name);
350af427bf5SArnaldo Carvalho de Melo 
3512e538c4aSArnaldo Carvalho de Melo 		if (sym == NULL)
3522e538c4aSArnaldo Carvalho de Melo 			goto out_delete_line;
35382164161SArnaldo Carvalho de Melo 		/*
35482164161SArnaldo Carvalho de Melo 		 * We will pass the symbols to the filter later, in
3554e06255fSArnaldo Carvalho de Melo 		 * map__split_kallsyms, when we have split the maps per module
35682164161SArnaldo Carvalho de Melo 		 */
3574e06255fSArnaldo Carvalho de Melo 		symbols__insert(root, sym);
3582e538c4aSArnaldo Carvalho de Melo 	}
3592e538c4aSArnaldo Carvalho de Melo 
3602e538c4aSArnaldo Carvalho de Melo 	free(line);
3612e538c4aSArnaldo Carvalho de Melo 	fclose(file);
3622e538c4aSArnaldo Carvalho de Melo 
3632e538c4aSArnaldo Carvalho de Melo 	return 0;
3642e538c4aSArnaldo Carvalho de Melo 
3652e538c4aSArnaldo Carvalho de Melo out_delete_line:
3662e538c4aSArnaldo Carvalho de Melo 	free(line);
3672e538c4aSArnaldo Carvalho de Melo out_failure:
3682e538c4aSArnaldo Carvalho de Melo 	return -1;
3692e538c4aSArnaldo Carvalho de Melo }
3702e538c4aSArnaldo Carvalho de Melo 
3712e538c4aSArnaldo Carvalho de Melo /*
3722e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
3732e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
3742e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
3752e538c4aSArnaldo Carvalho de Melo  */
3769958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
3779958e1f0SArnaldo Carvalho de Melo 			       struct map_groups *mg, symbol_filter_t filter)
3782e538c4aSArnaldo Carvalho de Melo {
3794e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
3802e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
3812e538c4aSArnaldo Carvalho de Melo 	int count = 0;
3824e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
3834e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
3842e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
3852e538c4aSArnaldo Carvalho de Melo 
3862e538c4aSArnaldo Carvalho de Melo 	while (next) {
3872e538c4aSArnaldo Carvalho de Melo 		char *module;
3882e538c4aSArnaldo Carvalho de Melo 
3892e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
3902e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
3912e538c4aSArnaldo Carvalho de Melo 
3922e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
3932e538c4aSArnaldo Carvalho de Melo 		if (module) {
3949958e1f0SArnaldo Carvalho de Melo 			if (!mg->use_modules)
3951de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
3961de8e245SArnaldo Carvalho de Melo 
3972e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
3982e538c4aSArnaldo Carvalho de Melo 
3994e06255fSArnaldo Carvalho de Melo 			if (strcmp(self->name, module)) {
4009958e1f0SArnaldo Carvalho de Melo 				curr_map = map_groups__find_by_name(mg, module);
4014e06255fSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
40295011c60SArnaldo Carvalho de Melo 					pr_debug("/proc/{kallsyms,modules} "
4036beba7adSArnaldo Carvalho de Melo 					         "inconsistency!\n");
404af427bf5SArnaldo Carvalho de Melo 					return -1;
405af427bf5SArnaldo Carvalho de Melo 				}
406af427bf5SArnaldo Carvalho de Melo 			}
40786470930SIngo Molnar 			/*
4082e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
4092e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
41086470930SIngo Molnar 			 */
4114e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
4124e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
4134e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
4142e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
4152e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
41686470930SIngo Molnar 
4172e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
4182e538c4aSArnaldo Carvalho de Melo 				 kernel_range++);
41986470930SIngo Molnar 
42000a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
4212e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
4222e538c4aSArnaldo Carvalho de Melo 				return -1;
4232e538c4aSArnaldo Carvalho de Melo 
4244e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
4252e538c4aSArnaldo Carvalho de Melo 			if (map == NULL) {
4262e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
4272e538c4aSArnaldo Carvalho de Melo 				return -1;
4282e538c4aSArnaldo Carvalho de Melo 			}
4292e538c4aSArnaldo Carvalho de Melo 
4304e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
4319958e1f0SArnaldo Carvalho de Melo 			map_groups__insert(mg, curr_map);
4322e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
4332e538c4aSArnaldo Carvalho de Melo 		}
4342e538c4aSArnaldo Carvalho de Melo 
4354e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
4361de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
43700a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
4382e538c4aSArnaldo Carvalho de Melo 		} else {
4394e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
4404e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
4414e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
4422e538c4aSArnaldo Carvalho de Melo 			}
4439974f496SMike Galbraith 			count++;
4449974f496SMike Galbraith 		}
44586470930SIngo Molnar 	}
44686470930SIngo Molnar 
4479974f496SMike Galbraith 	return count;
44886470930SIngo Molnar }
44986470930SIngo Molnar 
4502e538c4aSArnaldo Carvalho de Melo 
4514e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map,
4529958e1f0SArnaldo Carvalho de Melo 			      struct map_groups *mg, symbol_filter_t filter)
4532e538c4aSArnaldo Carvalho de Melo {
4544e06255fSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, map) < 0)
4552e538c4aSArnaldo Carvalho de Melo 		return -1;
4562e538c4aSArnaldo Carvalho de Melo 
4574e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
4584e06255fSArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_KERNEL;
4592e538c4aSArnaldo Carvalho de Melo 
4609958e1f0SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, mg, filter);
46123ea4a3fSArnaldo Carvalho de Melo }
46223ea4a3fSArnaldo Carvalho de Melo 
46323ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp)
46423ea4a3fSArnaldo Carvalho de Melo {
46523ea4a3fSArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "Kernel maps:\n");
4669958e1f0SArnaldo Carvalho de Melo 	printed += map_groups__fprintf_maps(kmaps, fp);
4676beba7adSArnaldo Carvalho de Melo 	return printed + fprintf(fp, "END kernel maps\n");
468af427bf5SArnaldo Carvalho de Melo }
469af427bf5SArnaldo Carvalho de Melo 
470439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
4716beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
47280d496beSPekka Enberg {
47380d496beSPekka Enberg 	char *line = NULL;
47480d496beSPekka Enberg 	size_t n;
47580d496beSPekka Enberg 	FILE *file;
47680d496beSPekka Enberg 	int nr_syms = 0;
47780d496beSPekka Enberg 
478439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
47980d496beSPekka Enberg 	if (file == NULL)
48080d496beSPekka Enberg 		goto out_failure;
48180d496beSPekka Enberg 
48280d496beSPekka Enberg 	while (!feof(file)) {
4839cffa8d5SPaul Mackerras 		u64 start, size;
48480d496beSPekka Enberg 		struct symbol *sym;
48580d496beSPekka Enberg 		int line_len, len;
48680d496beSPekka Enberg 
48780d496beSPekka Enberg 		line_len = getline(&line, &n, file);
48880d496beSPekka Enberg 		if (line_len < 0)
48980d496beSPekka Enberg 			break;
49080d496beSPekka Enberg 
49180d496beSPekka Enberg 		if (!line)
49280d496beSPekka Enberg 			goto out_failure;
49380d496beSPekka Enberg 
49480d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
49580d496beSPekka Enberg 
49680d496beSPekka Enberg 		len = hex2u64(line, &start);
49780d496beSPekka Enberg 
49880d496beSPekka Enberg 		len++;
49980d496beSPekka Enberg 		if (len + 2 >= line_len)
50080d496beSPekka Enberg 			continue;
50180d496beSPekka Enberg 
50280d496beSPekka Enberg 		len += hex2u64(line + len, &size);
50380d496beSPekka Enberg 
50480d496beSPekka Enberg 		len++;
50580d496beSPekka Enberg 		if (len + 2 >= line_len)
50680d496beSPekka Enberg 			continue;
50780d496beSPekka Enberg 
50800a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
50980d496beSPekka Enberg 
51080d496beSPekka Enberg 		if (sym == NULL)
51180d496beSPekka Enberg 			goto out_delete_line;
51280d496beSPekka Enberg 
513439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
51400a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
51580d496beSPekka Enberg 		else {
5166a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
51780d496beSPekka Enberg 			nr_syms++;
51880d496beSPekka Enberg 		}
51980d496beSPekka Enberg 	}
52080d496beSPekka Enberg 
52180d496beSPekka Enberg 	free(line);
52280d496beSPekka Enberg 	fclose(file);
52380d496beSPekka Enberg 
52480d496beSPekka Enberg 	return nr_syms;
52580d496beSPekka Enberg 
52680d496beSPekka Enberg out_delete_line:
52780d496beSPekka Enberg 	free(line);
52880d496beSPekka Enberg out_failure:
52980d496beSPekka Enberg 	return -1;
53080d496beSPekka Enberg }
53180d496beSPekka Enberg 
53286470930SIngo Molnar /**
53386470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
53486470930SIngo Molnar  *
53586470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
53683a0944fSIngo Molnar  * @idx: uint32_t idx
53786470930SIngo Molnar  * @sym: GElf_Sym iterator
53886470930SIngo Molnar  */
53983a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
54083a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
54183a0944fSIngo Molnar 	     idx < nr_syms; \
54283a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
54386470930SIngo Molnar 
54486470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
54586470930SIngo Molnar {
54686470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
54786470930SIngo Molnar }
54886470930SIngo Molnar 
54986470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
55086470930SIngo Molnar {
55186470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
55286470930SIngo Molnar 	       sym->st_name != 0 &&
55381833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
55486470930SIngo Molnar }
55586470930SIngo Molnar 
556*f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
557*f1dfa0b1SArnaldo Carvalho de Melo {
558*f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
559*f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
560*f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
561*f1dfa0b1SArnaldo Carvalho de Melo }
562*f1dfa0b1SArnaldo Carvalho de Melo 
5636cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
5646cfcc53eSMike Galbraith {
5656cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
5666cfcc53eSMike Galbraith 		sym->st_name != 0 &&
5676cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
5686cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
5696cfcc53eSMike Galbraith }
5706cfcc53eSMike Galbraith 
5716cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
5726cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5736cfcc53eSMike Galbraith {
5746cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
5756cfcc53eSMike Galbraith }
5766cfcc53eSMike Galbraith 
5776cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
5786cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5796cfcc53eSMike Galbraith {
5806cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
5816cfcc53eSMike Galbraith }
5826cfcc53eSMike Galbraith 
583*f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
584*f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
585*f1dfa0b1SArnaldo Carvalho de Melo {
586*f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
587*f1dfa0b1SArnaldo Carvalho de Melo }
588*f1dfa0b1SArnaldo Carvalho de Melo 
58986470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
59086470930SIngo Molnar 					const Elf_Data *symstrs)
59186470930SIngo Molnar {
59286470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
59386470930SIngo Molnar }
59486470930SIngo Molnar 
59586470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
59686470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
59783a0944fSIngo Molnar 				    size_t *idx)
59886470930SIngo Molnar {
59986470930SIngo Molnar 	Elf_Scn *sec = NULL;
60086470930SIngo Molnar 	size_t cnt = 1;
60186470930SIngo Molnar 
60286470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
60386470930SIngo Molnar 		char *str;
60486470930SIngo Molnar 
60586470930SIngo Molnar 		gelf_getshdr(sec, shp);
60686470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
60786470930SIngo Molnar 		if (!strcmp(name, str)) {
60883a0944fSIngo Molnar 			if (idx)
60983a0944fSIngo Molnar 				*idx = cnt;
61086470930SIngo Molnar 			break;
61186470930SIngo Molnar 		}
61286470930SIngo Molnar 		++cnt;
61386470930SIngo Molnar 	}
61486470930SIngo Molnar 
61586470930SIngo Molnar 	return sec;
61686470930SIngo Molnar }
61786470930SIngo Molnar 
61886470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
61986470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
62086470930SIngo Molnar 	     idx < nr_entries; \
62186470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
62286470930SIngo Molnar 
62386470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
62486470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
62586470930SIngo Molnar 	     idx < nr_entries; \
62686470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
62786470930SIngo Molnar 
628a25e46c4SArnaldo Carvalho de Melo /*
629a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
630a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
631a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
632a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
633a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
634a25e46c4SArnaldo Carvalho de Melo  */
63582164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
63682164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
63786470930SIngo Molnar {
63886470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
63986470930SIngo Molnar 	GElf_Sym sym;
6409cffa8d5SPaul Mackerras 	u64 plt_offset;
64186470930SIngo Molnar 	GElf_Shdr shdr_plt;
64286470930SIngo Molnar 	struct symbol *f;
643a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
64486470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
645a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
646a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
647a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
64886470930SIngo Molnar 	char sympltname[1024];
649a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
650a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
65186470930SIngo Molnar 
652439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
653a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
654a25e46c4SArnaldo Carvalho de Melo 		goto out;
655a25e46c4SArnaldo Carvalho de Melo 
65684087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
657a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
658a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
659a25e46c4SArnaldo Carvalho de Melo 
660a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
661a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
662a25e46c4SArnaldo Carvalho de Melo 
663a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
664a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
665a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
666a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
667a25e46c4SArnaldo Carvalho de Melo 
668a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
66986470930SIngo Molnar 					  ".rela.plt", NULL);
67086470930SIngo Molnar 	if (scn_plt_rel == NULL) {
671a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
67286470930SIngo Molnar 						  ".rel.plt", NULL);
67386470930SIngo Molnar 		if (scn_plt_rel == NULL)
674a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
67586470930SIngo Molnar 	}
67686470930SIngo Molnar 
677a25e46c4SArnaldo Carvalho de Melo 	err = -1;
67886470930SIngo Molnar 
679a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
680a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
681a25e46c4SArnaldo Carvalho de Melo 
682a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
683a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
68486470930SIngo Molnar 
68586470930SIngo Molnar 	/*
68683a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
68786470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
68886470930SIngo Molnar 	 */
68986470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
69086470930SIngo Molnar 	if (reldata == NULL)
691a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
69286470930SIngo Molnar 
69386470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
69486470930SIngo Molnar 	if (syms == NULL)
695a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
69686470930SIngo Molnar 
697a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
69886470930SIngo Molnar 	if (scn_symstrs == NULL)
699a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
70086470930SIngo Molnar 
70186470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
70286470930SIngo Molnar 	if (symstrs == NULL)
703a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
70486470930SIngo Molnar 
70586470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
70686470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
70786470930SIngo Molnar 
70886470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
70986470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
71086470930SIngo Molnar 
71186470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
71286470930SIngo Molnar 					   nr_rel_entries) {
71386470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
71486470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
71586470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
71686470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
71786470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
71886470930SIngo Molnar 
71986470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
72000a192b3SArnaldo Carvalho de Melo 					sympltname);
72186470930SIngo Molnar 			if (!f)
722a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
72386470930SIngo Molnar 
72482164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
72582164161SArnaldo Carvalho de Melo 				symbol__delete(f);
72682164161SArnaldo Carvalho de Melo 			else {
7276a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
72886470930SIngo Molnar 				++nr;
72986470930SIngo Molnar 			}
73082164161SArnaldo Carvalho de Melo 		}
73186470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
73286470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
73386470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
73486470930SIngo Molnar 					  nr_rel_entries) {
73586470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
73686470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
73786470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
73886470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
73986470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
74086470930SIngo Molnar 
74186470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
74200a192b3SArnaldo Carvalho de Melo 					sympltname);
74386470930SIngo Molnar 			if (!f)
744a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
74586470930SIngo Molnar 
74682164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
74782164161SArnaldo Carvalho de Melo 				symbol__delete(f);
74882164161SArnaldo Carvalho de Melo 			else {
7496a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
75086470930SIngo Molnar 				++nr;
75186470930SIngo Molnar 			}
75286470930SIngo Molnar 		}
75382164161SArnaldo Carvalho de Melo 	}
75486470930SIngo Molnar 
755a25e46c4SArnaldo Carvalho de Melo 	err = 0;
756a25e46c4SArnaldo Carvalho de Melo out_elf_end:
757a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
758a25e46c4SArnaldo Carvalho de Melo out_close:
759a25e46c4SArnaldo Carvalho de Melo 	close(fd);
760a25e46c4SArnaldo Carvalho de Melo 
761a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
76286470930SIngo Molnar 		return nr;
763a25e46c4SArnaldo Carvalho de Melo out:
7646beba7adSArnaldo Carvalho de Melo 	pr_warning("%s: problems reading %s PLT info.\n",
765439d473bSArnaldo Carvalho de Melo 		   __func__, self->long_name);
766a25e46c4SArnaldo Carvalho de Melo 	return 0;
76786470930SIngo Molnar }
76886470930SIngo Molnar 
769d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
770d45868d3SArnaldo Carvalho de Melo {
771d45868d3SArnaldo Carvalho de Melo 	switch (type) {
772d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
773d45868d3SArnaldo Carvalho de Melo 		return elf_sym__is_function(self);
774*f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
775*f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sym__is_object(self);
776d45868d3SArnaldo Carvalho de Melo 	default:
777d45868d3SArnaldo Carvalho de Melo 		return false;
778d45868d3SArnaldo Carvalho de Melo 	}
779d45868d3SArnaldo Carvalho de Melo }
780d45868d3SArnaldo Carvalho de Melo 
781d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
782d45868d3SArnaldo Carvalho de Melo {
783d45868d3SArnaldo Carvalho de Melo 	switch (type) {
784d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
785d45868d3SArnaldo Carvalho de Melo 		return elf_sec__is_text(self, secstrs);
786*f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
787*f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sec__is_data(self, secstrs);
788d45868d3SArnaldo Carvalho de Melo 	default:
789d45868d3SArnaldo Carvalho de Melo 		return false;
790d45868d3SArnaldo Carvalho de Melo 	}
791d45868d3SArnaldo Carvalho de Melo }
792d45868d3SArnaldo Carvalho de Melo 
79395011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map,
7949958e1f0SArnaldo Carvalho de Melo 			 struct map_groups *mg, const char *name, int fd,
79595011c60SArnaldo Carvalho de Melo 			 symbol_filter_t filter, int kernel, int kmodule)
79686470930SIngo Molnar {
7972e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
7982e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
7992e538c4aSArnaldo Carvalho de Melo 	size_t dso_name_len = strlen(self->short_name);
8006cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
80186470930SIngo Molnar 	uint32_t nr_syms;
80286470930SIngo Molnar 	int err = -1;
80383a0944fSIngo Molnar 	uint32_t idx;
80486470930SIngo Molnar 	GElf_Ehdr ehdr;
80586470930SIngo Molnar 	GElf_Shdr shdr;
80686470930SIngo Molnar 	Elf_Data *syms;
80786470930SIngo Molnar 	GElf_Sym sym;
808a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
80986470930SIngo Molnar 	Elf *elf;
810439d473bSArnaldo Carvalho de Melo 	int nr = 0;
81186470930SIngo Molnar 
81284087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
81386470930SIngo Molnar 	if (elf == NULL) {
8146beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
81586470930SIngo Molnar 		goto out_close;
81686470930SIngo Molnar 	}
81786470930SIngo Molnar 
81886470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
8196beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
82086470930SIngo Molnar 		goto out_elf_end;
82186470930SIngo Molnar 	}
82286470930SIngo Molnar 
82386470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
82486470930SIngo Molnar 	if (sec == NULL) {
825a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
826a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
82786470930SIngo Molnar 			goto out_elf_end;
82886470930SIngo Molnar 	}
82986470930SIngo Molnar 
83086470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
83186470930SIngo Molnar 	if (syms == NULL)
83286470930SIngo Molnar 		goto out_elf_end;
83386470930SIngo Molnar 
83486470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
83586470930SIngo Molnar 	if (sec == NULL)
83686470930SIngo Molnar 		goto out_elf_end;
83786470930SIngo Molnar 
83886470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
83986470930SIngo Molnar 	if (symstrs == NULL)
84086470930SIngo Molnar 		goto out_elf_end;
84186470930SIngo Molnar 
8426cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
8436cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
8446cfcc53eSMike Galbraith 		goto out_elf_end;
8456cfcc53eSMike Galbraith 
8466cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
8479b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
8486cfcc53eSMike Galbraith 		goto out_elf_end;
8496cfcc53eSMike Galbraith 
85086470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
85186470930SIngo Molnar 
852e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
853d20ff6bdSMike Galbraith 	if (!kernel) {
85430d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
85530d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
856f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
85730d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
858d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
859d20ff6bdSMike Galbraith 
86083a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
86186470930SIngo Molnar 		struct symbol *f;
86283a0944fSIngo Molnar 		const char *elf_name;
8632e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
8646cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
8656cfcc53eSMike Galbraith 		const char *section_name;
86686470930SIngo Molnar 
867d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
86886470930SIngo Molnar 			continue;
86986470930SIngo Molnar 
87086470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
87186470930SIngo Molnar 		if (!sec)
87286470930SIngo Molnar 			goto out_elf_end;
87386470930SIngo Molnar 
87486470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
8756cfcc53eSMike Galbraith 
876d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
8776cfcc53eSMike Galbraith 			continue;
8786cfcc53eSMike Galbraith 
8792e538c4aSArnaldo Carvalho de Melo 		elf_name = elf_sym__name(&sym, symstrs);
8806cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
88186470930SIngo Molnar 
8822e538c4aSArnaldo Carvalho de Melo 		if (kernel || kmodule) {
8832e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
8842e538c4aSArnaldo Carvalho de Melo 
8852e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
8862e538c4aSArnaldo Carvalho de Melo 				   curr_dso->short_name + dso_name_len) == 0)
8872e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
8882e538c4aSArnaldo Carvalho de Melo 
8892e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
8902e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
8912e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
8922e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
893af427bf5SArnaldo Carvalho de Melo 			}
894af427bf5SArnaldo Carvalho de Melo 
8952e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
8962e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
8972e538c4aSArnaldo Carvalho de Melo 
8989958e1f0SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(mg, dso_name);
8992e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
9002e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
9012e538c4aSArnaldo Carvalho de Melo 
9022e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
9032e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
9042e538c4aSArnaldo Carvalho de Melo 
90500a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
9062e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
9072e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
9083610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
9093610583cSArnaldo Carvalho de Melo 						     MAP__FUNCTION);
9102e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
9112e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
9122e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
9132e538c4aSArnaldo Carvalho de Melo 				}
914ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
915ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
9162e538c4aSArnaldo Carvalho de Melo 				curr_dso->origin = DSO__ORIG_KERNEL;
9179958e1f0SArnaldo Carvalho de Melo 				map_groups__insert(kmaps, curr_map);
918b0da954aSArnaldo Carvalho de Melo 				dsos__add(&dsos__kernel, curr_dso);
9192e538c4aSArnaldo Carvalho de Melo 			} else
9202e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
9212e538c4aSArnaldo Carvalho de Melo 
9222e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
9232e538c4aSArnaldo Carvalho de Melo 		}
9242e538c4aSArnaldo Carvalho de Melo 
9252e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
9266beba7adSArnaldo Carvalho de Melo 			pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
9276beba7adSArnaldo Carvalho de Melo 				  "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
9286beba7adSArnaldo Carvalho de Melo 				  (u64)shdr.sh_addr, (u64)shdr.sh_offset);
92986470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
930af427bf5SArnaldo Carvalho de Melo 		}
93128ac909bSArnaldo Carvalho de Melo 		/*
93228ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
93328ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
93428ac909bSArnaldo Carvalho de Melo 		 * to it...
93528ac909bSArnaldo Carvalho de Melo 		 */
93683a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
93728ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
93883a0944fSIngo Molnar 			elf_name = demangled;
9392e538c4aSArnaldo Carvalho de Melo new_symbol:
94000a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
94128ac909bSArnaldo Carvalho de Melo 		free(demangled);
94286470930SIngo Molnar 		if (!f)
94386470930SIngo Molnar 			goto out_elf_end;
94486470930SIngo Molnar 
9452e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
94600a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
94786470930SIngo Molnar 		else {
9486a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
94986470930SIngo Molnar 			nr++;
95086470930SIngo Molnar 		}
95186470930SIngo Molnar 	}
95286470930SIngo Molnar 
9532e538c4aSArnaldo Carvalho de Melo 	/*
9542e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
9552e538c4aSArnaldo Carvalho de Melo 	 */
9562e538c4aSArnaldo Carvalho de Melo 	if (nr > 0)
9576a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
95886470930SIngo Molnar 	err = nr;
95986470930SIngo Molnar out_elf_end:
96086470930SIngo Molnar 	elf_end(elf);
96186470930SIngo Molnar out_close:
96286470930SIngo Molnar 	return err;
96386470930SIngo Molnar }
96486470930SIngo Molnar 
96578075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
96678075caaSArnaldo Carvalho de Melo {
96778075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
96878075caaSArnaldo Carvalho de Melo }
96978075caaSArnaldo Carvalho de Melo 
970b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head)
97157f395a7SFrederic Weisbecker {
972e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
97357f395a7SFrederic Weisbecker 	struct dso *pos;
97457f395a7SFrederic Weisbecker 
975b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
976e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
977e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
978e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
979e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
98057f395a7SFrederic Weisbecker 		}
98157f395a7SFrederic Weisbecker 
982e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
98357f395a7SFrederic Weisbecker }
98457f395a7SFrederic Weisbecker 
985b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void)
986b0da954aSArnaldo Carvalho de Melo {
9878b4825bfSArnaldo Carvalho de Melo 	bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
9888b4825bfSArnaldo Carvalho de Melo 	     ubuildids = __dsos__read_build_ids(&dsos__user);
9898b4825bfSArnaldo Carvalho de Melo 	return kbuildids || ubuildids;
990b0da954aSArnaldo Carvalho de Melo }
991b0da954aSArnaldo Carvalho de Melo 
992fd7a346eSArnaldo Carvalho de Melo /*
993fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
994fd7a346eSArnaldo Carvalho de Melo  */
995fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
996fd7a346eSArnaldo Carvalho de Melo 
9972643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
9984d1e00a8SArnaldo Carvalho de Melo {
9992643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
10004d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
10014d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1002fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
10034d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1004e57cfcdaSPekka Enberg 	Elf_Kind ek;
1005fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
10064d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
10074d1e00a8SArnaldo Carvalho de Melo 
10082643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
10092643ce11SArnaldo Carvalho de Melo 		goto out;
10102643ce11SArnaldo Carvalho de Melo 
10112643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
10124d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
10134d1e00a8SArnaldo Carvalho de Melo 		goto out;
10144d1e00a8SArnaldo Carvalho de Melo 
101584087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
10164d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
10178d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
10184d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
10194d1e00a8SArnaldo Carvalho de Melo 	}
10204d1e00a8SArnaldo Carvalho de Melo 
1021e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1022e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
1023e57cfcdaSPekka Enberg 		goto out_elf_end;
1024e57cfcdaSPekka Enberg 
10254d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
10266beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
10274d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
10284d1e00a8SArnaldo Carvalho de Melo 	}
10294d1e00a8SArnaldo Carvalho de Melo 
10302643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
10312643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1032fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1033fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1034fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
10354d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
10364d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
1037fd7a346eSArnaldo Carvalho de Melo 	}
10384d1e00a8SArnaldo Carvalho de Melo 
1039fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1040fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
10414d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
1042fd7a346eSArnaldo Carvalho de Melo 
1043fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1044fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1045fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1046fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1047fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1048fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1049fd7a346eSArnaldo Carvalho de Melo 
1050fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1051fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1052fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1053fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1054fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1055fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1056fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
10572643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1058fd7a346eSArnaldo Carvalho de Melo 				break;
1059fd7a346eSArnaldo Carvalho de Melo 			}
1060fd7a346eSArnaldo Carvalho de Melo 		}
1061fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1062fd7a346eSArnaldo Carvalho de Melo 	}
10632643ce11SArnaldo Carvalho de Melo out_elf_end:
10642643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
10652643ce11SArnaldo Carvalho de Melo out_close:
10662643ce11SArnaldo Carvalho de Melo 	close(fd);
10672643ce11SArnaldo Carvalho de Melo out:
10682643ce11SArnaldo Carvalho de Melo 	return err;
10692643ce11SArnaldo Carvalho de Melo }
10702643ce11SArnaldo Carvalho de Melo 
1071f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1072f1617b40SArnaldo Carvalho de Melo {
1073f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1074f1617b40SArnaldo Carvalho de Melo 
1075f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1076f1617b40SArnaldo Carvalho de Melo 		goto out;
1077f1617b40SArnaldo Carvalho de Melo 
1078f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1079f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1080f1617b40SArnaldo Carvalho de Melo 		goto out;
1081f1617b40SArnaldo Carvalho de Melo 
1082f1617b40SArnaldo Carvalho de Melo 	while (1) {
1083f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1084f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1085f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1086f1617b40SArnaldo Carvalho de Melo 
1087f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1088f1617b40SArnaldo Carvalho de Melo 			break;
1089f1617b40SArnaldo Carvalho de Melo 
1090fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1091fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1092f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1093f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1094f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1095f1617b40SArnaldo Carvalho de Melo 				break;
1096f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1097f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1098f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1099f1617b40SArnaldo Carvalho de Melo 					err = 0;
1100f1617b40SArnaldo Carvalho de Melo 					break;
1101f1617b40SArnaldo Carvalho de Melo 				}
1102f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1103f1617b40SArnaldo Carvalho de Melo 				break;
1104f1617b40SArnaldo Carvalho de Melo 		} else {
1105f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1106f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1107f1617b40SArnaldo Carvalho de Melo 				break;
1108f1617b40SArnaldo Carvalho de Melo 		}
1109f1617b40SArnaldo Carvalho de Melo 	}
1110f1617b40SArnaldo Carvalho de Melo 	close(fd);
1111f1617b40SArnaldo Carvalho de Melo out:
1112f1617b40SArnaldo Carvalho de Melo 	return err;
1113f1617b40SArnaldo Carvalho de Melo }
1114f1617b40SArnaldo Carvalho de Melo 
111594cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
111694cb9e38SArnaldo Carvalho de Melo {
111794cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
111894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
111994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
112094cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
112194cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
112294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
112394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1124439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
112594cb9e38SArnaldo Carvalho de Melo 	};
112694cb9e38SArnaldo Carvalho de Melo 
112794cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
112894cb9e38SArnaldo Carvalho de Melo 		return '!';
112994cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
113094cb9e38SArnaldo Carvalho de Melo }
113194cb9e38SArnaldo Carvalho de Melo 
11326beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
113386470930SIngo Molnar {
11344d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1135c338aee8SArnaldo Carvalho de Melo 	char *name;
1136d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
113786470930SIngo Molnar 	int ret = -1;
113886470930SIngo Molnar 	int fd;
113986470930SIngo Molnar 
11403610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
114166bd8424SArnaldo Carvalho de Melo 
1142c338aee8SArnaldo Carvalho de Melo 	if (self->kernel)
11439958e1f0SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, kmaps, filter);
1144c338aee8SArnaldo Carvalho de Melo 
1145c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
114686470930SIngo Molnar 	if (!name)
114786470930SIngo Molnar 		return -1;
114886470930SIngo Molnar 
114930d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1150f5812a7aSArnaldo Carvalho de Melo 
115194cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
11526beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
115394cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
115494cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
115594cb9e38SArnaldo Carvalho de Melo 		return ret;
115694cb9e38SArnaldo Carvalho de Melo 	}
115794cb9e38SArnaldo Carvalho de Melo 
115894cb9e38SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_FEDORA - 1;
115980d496beSPekka Enberg 
116086470930SIngo Molnar more:
116186470930SIngo Molnar 	do {
116294cb9e38SArnaldo Carvalho de Melo 		self->origin++;
116394cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
116494cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1165439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1166439d473bSArnaldo Carvalho de Melo 				 self->long_name);
116786470930SIngo Molnar 			break;
116894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1169439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1170439d473bSArnaldo Carvalho de Melo 				 self->long_name);
117186470930SIngo Molnar 			break;
117294cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1173d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1174d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1175d3379ab9SArnaldo Carvalho de Melo 				char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1176d3379ab9SArnaldo Carvalho de Melo 
1177d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1178d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
11794d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
11804d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1181d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1182d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
11838d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1184d3379ab9SArnaldo Carvalho de Melo 				break;
11854d1e00a8SArnaldo Carvalho de Melo 			}
118694cb9e38SArnaldo Carvalho de Melo 			self->origin++;
11874d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
118894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1189439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
119086470930SIngo Molnar 			break;
119186470930SIngo Molnar 
119286470930SIngo Molnar 		default:
119386470930SIngo Molnar 			goto out;
119486470930SIngo Molnar 		}
119586470930SIngo Molnar 
11968d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1197d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1198d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
11998d06367fSArnaldo Carvalho de Melo 				goto more;
12008d06367fSArnaldo Carvalho de Melo compare_build_id:
120178075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
12028d06367fSArnaldo Carvalho de Melo 				goto more;
12038d06367fSArnaldo Carvalho de Melo 		}
12048d06367fSArnaldo Carvalho de Melo 
120586470930SIngo Molnar 		fd = open(name, O_RDONLY);
120686470930SIngo Molnar 	} while (fd < 0);
120786470930SIngo Molnar 
120895011c60SArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
120986470930SIngo Molnar 	close(fd);
121086470930SIngo Molnar 
121186470930SIngo Molnar 	/*
121286470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
121386470930SIngo Molnar 	 */
121486470930SIngo Molnar 	if (!ret)
121586470930SIngo Molnar 		goto more;
121686470930SIngo Molnar 
1217a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
121882164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1219a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1220a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1221a25e46c4SArnaldo Carvalho de Melo 	}
122286470930SIngo Molnar out:
122386470930SIngo Molnar 	free(name);
12241340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
12251340e6bbSArnaldo Carvalho de Melo 		return 0;
122686470930SIngo Molnar 	return ret;
122786470930SIngo Molnar }
122886470930SIngo Molnar 
12299958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *self, char *name)
1230439d473bSArnaldo Carvalho de Melo {
1231439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1232439d473bSArnaldo Carvalho de Melo 
123395011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
1234439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1235439d473bSArnaldo Carvalho de Melo 
1236439d473bSArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->name, name) == 0)
1237439d473bSArnaldo Carvalho de Melo 			return map;
1238439d473bSArnaldo Carvalho de Melo 	}
1239439d473bSArnaldo Carvalho de Melo 
1240439d473bSArnaldo Carvalho de Melo 	return NULL;
1241439d473bSArnaldo Carvalho de Melo }
1242439d473bSArnaldo Carvalho de Melo 
1243c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname)
12446cfcc53eSMike Galbraith {
1245439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
1246439d473bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dirname);
12476cfcc53eSMike Galbraith 
1248439d473bSArnaldo Carvalho de Melo 	if (!dir) {
124987f8ea4cSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1250439d473bSArnaldo Carvalho de Melo 		return -1;
1251439d473bSArnaldo Carvalho de Melo 	}
12526cfcc53eSMike Galbraith 
1253439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1254439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1255439d473bSArnaldo Carvalho de Melo 
1256439d473bSArnaldo Carvalho de Melo 		if (dent->d_type == DT_DIR) {
1257439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1258439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1259439d473bSArnaldo Carvalho de Melo 				continue;
1260439d473bSArnaldo Carvalho de Melo 
1261439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1262439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1263c338aee8SArnaldo Carvalho de Melo 			if (dsos__set_modules_path_dir(path) < 0)
1264439d473bSArnaldo Carvalho de Melo 				goto failure;
1265439d473bSArnaldo Carvalho de Melo 		} else {
1266439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1267439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1268439d473bSArnaldo Carvalho de Melo 			struct map *map;
1269cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1270439d473bSArnaldo Carvalho de Melo 
1271439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1272439d473bSArnaldo Carvalho de Melo 				continue;
1273439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1274439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1275439d473bSArnaldo Carvalho de Melo 
1276a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
12779958e1f0SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(kmaps, dso_name);
1278439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1279439d473bSArnaldo Carvalho de Melo 				continue;
1280439d473bSArnaldo Carvalho de Melo 
1281439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1282439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1283439d473bSArnaldo Carvalho de Melo 
1284cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1285cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1286439d473bSArnaldo Carvalho de Melo 				goto failure;
1287cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1288439d473bSArnaldo Carvalho de Melo 		}
1289439d473bSArnaldo Carvalho de Melo 	}
1290439d473bSArnaldo Carvalho de Melo 
1291c338aee8SArnaldo Carvalho de Melo 	return 0;
1292439d473bSArnaldo Carvalho de Melo failure:
1293439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1294439d473bSArnaldo Carvalho de Melo 	return -1;
1295439d473bSArnaldo Carvalho de Melo }
1296439d473bSArnaldo Carvalho de Melo 
1297c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void)
1298439d473bSArnaldo Carvalho de Melo {
1299439d473bSArnaldo Carvalho de Melo 	struct utsname uts;
1300439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1301439d473bSArnaldo Carvalho de Melo 
1302439d473bSArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
1303439d473bSArnaldo Carvalho de Melo 		return -1;
1304439d473bSArnaldo Carvalho de Melo 
1305439d473bSArnaldo Carvalho de Melo 	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1306439d473bSArnaldo Carvalho de Melo 		 uts.release);
1307439d473bSArnaldo Carvalho de Melo 
1308c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path_dir(modules_path);
1309439d473bSArnaldo Carvalho de Melo }
13106cfcc53eSMike Galbraith 
13116cfcc53eSMike Galbraith /*
1312439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1313439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1314439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
13156cfcc53eSMike Galbraith  */
13163610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1317439d473bSArnaldo Carvalho de Melo {
1318439d473bSArnaldo Carvalho de Melo 	struct map *self = malloc(sizeof(*self));
13196cfcc53eSMike Galbraith 
1320439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1321439d473bSArnaldo Carvalho de Melo 		/*
1322afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1323439d473bSArnaldo Carvalho de Melo 		 */
13243610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1325439d473bSArnaldo Carvalho de Melo 	}
1326afb7b4f0SArnaldo Carvalho de Melo 
1327439d473bSArnaldo Carvalho de Melo 	return self;
1328439d473bSArnaldo Carvalho de Melo }
1329439d473bSArnaldo Carvalho de Melo 
13309958e1f0SArnaldo Carvalho de Melo static int map_groups__create_module_maps(struct map_groups *self)
1331439d473bSArnaldo Carvalho de Melo {
1332439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1333439d473bSArnaldo Carvalho de Melo 	size_t n;
1334439d473bSArnaldo Carvalho de Melo 	FILE *file = fopen("/proc/modules", "r");
1335439d473bSArnaldo Carvalho de Melo 	struct map *map;
1336439d473bSArnaldo Carvalho de Melo 
1337439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1338439d473bSArnaldo Carvalho de Melo 		return -1;
1339439d473bSArnaldo Carvalho de Melo 
1340439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1341439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1342439d473bSArnaldo Carvalho de Melo 		u64 start;
1343439d473bSArnaldo Carvalho de Melo 		struct dso *dso;
1344439d473bSArnaldo Carvalho de Melo 		char *sep;
1345439d473bSArnaldo Carvalho de Melo 		int line_len;
1346439d473bSArnaldo Carvalho de Melo 
1347439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1348439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
13496cfcc53eSMike Galbraith 			break;
13506cfcc53eSMike Galbraith 
1351439d473bSArnaldo Carvalho de Melo 		if (!line)
1352439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1353439d473bSArnaldo Carvalho de Melo 
1354439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1355439d473bSArnaldo Carvalho de Melo 
1356439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1357439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1358439d473bSArnaldo Carvalho de Melo 			continue;
1359439d473bSArnaldo Carvalho de Melo 
1360439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1361439d473bSArnaldo Carvalho de Melo 
1362439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1363439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1364439d473bSArnaldo Carvalho de Melo 			continue;
1365439d473bSArnaldo Carvalho de Melo 
1366439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1367439d473bSArnaldo Carvalho de Melo 
1368439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
136900a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1370439d473bSArnaldo Carvalho de Melo 
1371439d473bSArnaldo Carvalho de Melo 		if (dso == NULL)
1372439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1373439d473bSArnaldo Carvalho de Melo 
13743610583cSArnaldo Carvalho de Melo 		map = map__new2(start, dso, MAP__FUNCTION);
1375439d473bSArnaldo Carvalho de Melo 		if (map == NULL) {
1376439d473bSArnaldo Carvalho de Melo 			dso__delete(dso);
1377439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
13786cfcc53eSMike Galbraith 		}
13796cfcc53eSMike Galbraith 
1380f1617b40SArnaldo Carvalho de Melo 		snprintf(name, sizeof(name),
1381f1617b40SArnaldo Carvalho de Melo 			 "/sys/module/%s/notes/.note.gnu.build-id", line);
1382f1617b40SArnaldo Carvalho de Melo 		if (sysfs__read_build_id(name, dso->build_id,
1383f1617b40SArnaldo Carvalho de Melo 					 sizeof(dso->build_id)) == 0)
1384f1617b40SArnaldo Carvalho de Melo 			dso->has_build_id = true;
1385f1617b40SArnaldo Carvalho de Melo 
1386439d473bSArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
13879958e1f0SArnaldo Carvalho de Melo 		map_groups__insert(self, map);
1388b0da954aSArnaldo Carvalho de Melo 		dsos__add(&dsos__kernel, dso);
13896cfcc53eSMike Galbraith 	}
13906cfcc53eSMike Galbraith 
1391439d473bSArnaldo Carvalho de Melo 	free(line);
1392439d473bSArnaldo Carvalho de Melo 	fclose(file);
1393439d473bSArnaldo Carvalho de Melo 
1394c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path();
1395439d473bSArnaldo Carvalho de Melo 
1396439d473bSArnaldo Carvalho de Melo out_delete_line:
1397439d473bSArnaldo Carvalho de Melo 	free(line);
1398439d473bSArnaldo Carvalho de Melo out_failure:
1399439d473bSArnaldo Carvalho de Melo 	return -1;
14006cfcc53eSMike Galbraith }
14016cfcc53eSMike Galbraith 
14029958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
14039958e1f0SArnaldo Carvalho de Melo 			     struct map_groups *mg,
14046beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
140586470930SIngo Molnar {
1406fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
140786470930SIngo Molnar 
1408fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1409fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
141066bd8424SArnaldo Carvalho de Melo 
1411fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1412fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1413fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1414fbd733b8SArnaldo Carvalho de Melo 			return -1;
1415fbd733b8SArnaldo Carvalho de Melo 		}
1416fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1417fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1418fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1419fbd733b8SArnaldo Carvalho de Melo 
1420fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1421fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1422fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1423fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1424fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1425fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1426fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1427fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1428fbd733b8SArnaldo Carvalho de Melo 			return -1;
1429fbd733b8SArnaldo Carvalho de Melo 		}
1430fbd733b8SArnaldo Carvalho de Melo 	}
1431fbd733b8SArnaldo Carvalho de Melo 
1432fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
143386470930SIngo Molnar 	if (fd < 0)
143486470930SIngo Molnar 		return -1;
143586470930SIngo Molnar 
14363610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
14379958e1f0SArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0);
143886470930SIngo Molnar 	close(fd);
143986470930SIngo Molnar 
144086470930SIngo Molnar 	return err;
144186470930SIngo Molnar }
144286470930SIngo Molnar 
1443c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
14449958e1f0SArnaldo Carvalho de Melo 				struct map_groups *mg, symbol_filter_t filter)
144586470930SIngo Molnar {
1446cc612d81SArnaldo Carvalho de Melo 	int err;
1447cc612d81SArnaldo Carvalho de Melo 	bool is_kallsyms;
1448439d473bSArnaldo Carvalho de Melo 
1449cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
1450cc612d81SArnaldo Carvalho de Melo 		int i;
1451cc612d81SArnaldo Carvalho de Melo 		pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1452cc612d81SArnaldo Carvalho de Melo 			 vmlinux_path__nr_entries);
1453cc612d81SArnaldo Carvalho de Melo 		for (i = 0; i < vmlinux_path__nr_entries; ++i) {
14549958e1f0SArnaldo Carvalho de Melo 			err = dso__load_vmlinux(self, map, mg,
145595011c60SArnaldo Carvalho de Melo 						vmlinux_path[i], filter);
1456cc612d81SArnaldo Carvalho de Melo 			if (err > 0) {
1457cc612d81SArnaldo Carvalho de Melo 				pr_debug("Using %s for symbols\n",
1458cc612d81SArnaldo Carvalho de Melo 					 vmlinux_path[i]);
1459cc612d81SArnaldo Carvalho de Melo 				dso__set_long_name(self,
1460cc612d81SArnaldo Carvalho de Melo 						   strdup(vmlinux_path[i]));
1461cc612d81SArnaldo Carvalho de Melo 				goto out_fixup;
1462cc612d81SArnaldo Carvalho de Melo 			}
1463cc612d81SArnaldo Carvalho de Melo 		}
1464cc612d81SArnaldo Carvalho de Melo 	}
1465cc612d81SArnaldo Carvalho de Melo 
1466cc612d81SArnaldo Carvalho de Melo 	is_kallsyms = self->long_name[0] == '[';
1467cc612d81SArnaldo Carvalho de Melo 	if (is_kallsyms)
1468cc612d81SArnaldo Carvalho de Melo 		goto do_kallsyms;
1469cc612d81SArnaldo Carvalho de Melo 
14709958e1f0SArnaldo Carvalho de Melo 	err = dso__load_vmlinux(self, map, mg, self->long_name, filter);
1471ef6ae724SArnaldo Carvalho de Melo 	if (err <= 0) {
1472cc612d81SArnaldo Carvalho de Melo 		pr_info("The file %s cannot be used, "
1473cc612d81SArnaldo Carvalho de Melo 			"trying to use /proc/kallsyms...", self->long_name);
1474cc612d81SArnaldo Carvalho de Melo do_kallsyms:
14759958e1f0SArnaldo Carvalho de Melo 		err = dso__load_kallsyms(self, map, mg, filter);
1476cc612d81SArnaldo Carvalho de Melo 		if (err > 0 && !is_kallsyms)
1477ef6ae724SArnaldo Carvalho de Melo                         dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1478ef6ae724SArnaldo Carvalho de Melo 	}
147986470930SIngo Molnar 
1480439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1481cc612d81SArnaldo Carvalho de Melo out_fixup:
14826a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
14836a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1484439d473bSArnaldo Carvalho de Melo 	}
148594cb9e38SArnaldo Carvalho de Melo 
148686470930SIngo Molnar 	return err;
148786470930SIngo Molnar }
148886470930SIngo Molnar 
1489b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user);
1490b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel);
1491cd84c2acSFrederic Weisbecker struct dso *vdso;
1492cd84c2acSFrederic Weisbecker 
1493b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1494cd84c2acSFrederic Weisbecker {
1495b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1496cd84c2acSFrederic Weisbecker }
1497cd84c2acSFrederic Weisbecker 
1498b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1499cd84c2acSFrederic Weisbecker {
1500cd84c2acSFrederic Weisbecker 	struct dso *pos;
1501cd84c2acSFrederic Weisbecker 
1502b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1503cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
1504cd84c2acSFrederic Weisbecker 			return pos;
1505cd84c2acSFrederic Weisbecker 	return NULL;
1506cd84c2acSFrederic Weisbecker }
1507cd84c2acSFrederic Weisbecker 
150800a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name)
1509cd84c2acSFrederic Weisbecker {
1510b0da954aSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(&dsos__user, name);
1511cd84c2acSFrederic Weisbecker 
1512e4204992SArnaldo Carvalho de Melo 	if (!dso) {
151300a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1514cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1515b0da954aSArnaldo Carvalho de Melo 			dsos__add(&dsos__user, dso);
1516cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1517cfc10d3bSArnaldo Carvalho de Melo 		}
1518e4204992SArnaldo Carvalho de Melo 	}
1519cd84c2acSFrederic Weisbecker 
1520cd84c2acSFrederic Weisbecker 	return dso;
1521cd84c2acSFrederic Weisbecker }
1522cd84c2acSFrederic Weisbecker 
1523b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp)
1524cd84c2acSFrederic Weisbecker {
1525cd84c2acSFrederic Weisbecker 	struct dso *pos;
1526cd84c2acSFrederic Weisbecker 
152795011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
152895011c60SArnaldo Carvalho de Melo 		int i;
152995011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
153095011c60SArnaldo Carvalho de Melo 			dso__fprintf(pos, i, fp);
153195011c60SArnaldo Carvalho de Melo 	}
1532cd84c2acSFrederic Weisbecker }
1533cd84c2acSFrederic Weisbecker 
1534b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp)
1535b0da954aSArnaldo Carvalho de Melo {
1536b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__kernel, fp);
1537b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__user, fp);
1538b0da954aSArnaldo Carvalho de Melo }
1539b0da954aSArnaldo Carvalho de Melo 
1540b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
15419e03eb2dSArnaldo Carvalho de Melo {
15429e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
15439e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
15449e03eb2dSArnaldo Carvalho de Melo 
1545b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
15469e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
15479e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
15489e03eb2dSArnaldo Carvalho de Melo 	}
15499e03eb2dSArnaldo Carvalho de Melo 	return ret;
15509e03eb2dSArnaldo Carvalho de Melo }
15519e03eb2dSArnaldo Carvalho de Melo 
1552b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp)
1553b0da954aSArnaldo Carvalho de Melo {
1554b0da954aSArnaldo Carvalho de Melo 	return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1555b0da954aSArnaldo Carvalho de Melo 		__dsos__fprintf_buildid(&dsos__user, fp));
1556b0da954aSArnaldo Carvalho de Melo }
1557b0da954aSArnaldo Carvalho de Melo 
1558*f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel( const char *vmlinux)
1559cd84c2acSFrederic Weisbecker {
156095011c60SArnaldo Carvalho de Melo 	struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1561cd84c2acSFrederic Weisbecker 
15622446042cSArnaldo Carvalho de Melo 	if (kernel == NULL)
1563*f1dfa0b1SArnaldo Carvalho de Melo 		return NULL;
1564c338aee8SArnaldo Carvalho de Melo 
15652446042cSArnaldo Carvalho de Melo 	kernel->short_name = "[kernel]";
1566c338aee8SArnaldo Carvalho de Melo 	kernel->kernel	   = 1;
1567cc612d81SArnaldo Carvalho de Melo 
156800a192b3SArnaldo Carvalho de Melo 	vdso = dso__new("[vdso]");
1569c338aee8SArnaldo Carvalho de Melo 	if (vdso == NULL)
1570*f1dfa0b1SArnaldo Carvalho de Melo 		goto out_delete_kernel_dso;
15713610583cSArnaldo Carvalho de Melo 	dso__set_loaded(vdso, MAP__FUNCTION);
1572cd84c2acSFrederic Weisbecker 
15732446042cSArnaldo Carvalho de Melo 	if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
15742446042cSArnaldo Carvalho de Melo 				 sizeof(kernel->build_id)) == 0)
15752446042cSArnaldo Carvalho de Melo 		kernel->has_build_id = true;
15762446042cSArnaldo Carvalho de Melo 
1577b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__kernel, kernel);
1578b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__user, vdso);
1579cd84c2acSFrederic Weisbecker 
1580*f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
1581c338aee8SArnaldo Carvalho de Melo 
1582c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso:
1583c338aee8SArnaldo Carvalho de Melo 	dso__delete(kernel);
1584*f1dfa0b1SArnaldo Carvalho de Melo 	return NULL;
1585*f1dfa0b1SArnaldo Carvalho de Melo }
1586*f1dfa0b1SArnaldo Carvalho de Melo 
1587*f1dfa0b1SArnaldo Carvalho de Melo static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1588*f1dfa0b1SArnaldo Carvalho de Melo {
1589*f1dfa0b1SArnaldo Carvalho de Melo 	struct map *functions, *variables;
1590*f1dfa0b1SArnaldo Carvalho de Melo 	struct dso *kernel = dsos__create_kernel(vmlinux);
1591*f1dfa0b1SArnaldo Carvalho de Melo 
1592*f1dfa0b1SArnaldo Carvalho de Melo 	if (kernel == NULL)
1593c338aee8SArnaldo Carvalho de Melo 		return -1;
1594*f1dfa0b1SArnaldo Carvalho de Melo 
1595*f1dfa0b1SArnaldo Carvalho de Melo 	functions = map__new2(0, kernel, MAP__FUNCTION);
1596*f1dfa0b1SArnaldo Carvalho de Melo 	if (functions == NULL)
1597*f1dfa0b1SArnaldo Carvalho de Melo 		return -1;
1598*f1dfa0b1SArnaldo Carvalho de Melo 
1599*f1dfa0b1SArnaldo Carvalho de Melo 	variables = map__new2(0, kernel, MAP__VARIABLE);
1600*f1dfa0b1SArnaldo Carvalho de Melo 	if (variables == NULL) {
1601*f1dfa0b1SArnaldo Carvalho de Melo 		map__delete(functions);
1602*f1dfa0b1SArnaldo Carvalho de Melo 		return -1;
1603*f1dfa0b1SArnaldo Carvalho de Melo 	}
1604*f1dfa0b1SArnaldo Carvalho de Melo 
1605*f1dfa0b1SArnaldo Carvalho de Melo 	functions->map_ip = functions->unmap_ip =
1606*f1dfa0b1SArnaldo Carvalho de Melo 		variables->map_ip = variables->unmap_ip = identity__map_ip;
1607*f1dfa0b1SArnaldo Carvalho de Melo 	map_groups__insert(self, functions);
1608*f1dfa0b1SArnaldo Carvalho de Melo 	map_groups__insert(self, variables);
1609*f1dfa0b1SArnaldo Carvalho de Melo 
1610*f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
16112446042cSArnaldo Carvalho de Melo }
16122446042cSArnaldo Carvalho de Melo 
1613cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
16142446042cSArnaldo Carvalho de Melo {
1615cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
1616cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
1617cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
1618cc612d81SArnaldo Carvalho de Melo 	}
1619cc612d81SArnaldo Carvalho de Melo 
1620cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
1621cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
1622cc612d81SArnaldo Carvalho de Melo }
1623cc612d81SArnaldo Carvalho de Melo 
1624cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
1625cc612d81SArnaldo Carvalho de Melo {
1626cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1627cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
1628cc612d81SArnaldo Carvalho de Melo 
1629cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
16302446042cSArnaldo Carvalho de Melo 		return -1;
16312446042cSArnaldo Carvalho de Melo 
1632cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
1633cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1634cc612d81SArnaldo Carvalho de Melo 		return -1;
1635cc612d81SArnaldo Carvalho de Melo 
1636cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1637cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1638cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1639cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1640cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1641cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1642cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1643cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1644cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1645cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1646cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1647cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1648cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1649cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1650cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1651cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1652cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1653cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1654cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1655cc612d81SArnaldo Carvalho de Melo 		 uts.release);
1656cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1657cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1658cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1659cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1660cc612d81SArnaldo Carvalho de Melo 
1661cc612d81SArnaldo Carvalho de Melo 	return 0;
1662cc612d81SArnaldo Carvalho de Melo 
1663cc612d81SArnaldo Carvalho de Melo out_fail:
1664cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1665cc612d81SArnaldo Carvalho de Melo 	return -1;
1666cc612d81SArnaldo Carvalho de Melo }
1667cc612d81SArnaldo Carvalho de Melo 
166895011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf)
1669cc612d81SArnaldo Carvalho de Melo {
1670b32d133aSArnaldo Carvalho de Melo 	const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1671b32d133aSArnaldo Carvalho de Melo 
167295011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
1673b32d133aSArnaldo Carvalho de Melo 	symbol__priv_size = pconf->priv_size;
16749958e1f0SArnaldo Carvalho de Melo 	map_groups__init(kmaps);
1675b32d133aSArnaldo Carvalho de Melo 
1676b32d133aSArnaldo Carvalho de Melo 	if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1677cc612d81SArnaldo Carvalho de Melo 		return -1;
1678cc612d81SArnaldo Carvalho de Melo 
1679*f1dfa0b1SArnaldo Carvalho de Melo 	if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) {
1680cc612d81SArnaldo Carvalho de Melo 		vmlinux_path__exit();
1681cc612d81SArnaldo Carvalho de Melo 		return -1;
1682cc612d81SArnaldo Carvalho de Melo 	}
1683cc612d81SArnaldo Carvalho de Melo 
16849958e1f0SArnaldo Carvalho de Melo 	kmaps->use_modules = pconf->use_modules;
16859958e1f0SArnaldo Carvalho de Melo 	if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0)
168687f8ea4cSArnaldo Carvalho de Melo 		pr_debug("Failed to load list of modules in use, "
16876671cb16SArnaldo Carvalho de Melo 			 "continuing...\n");
168890c83218SArnaldo Carvalho de Melo 	/*
168990c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
169090c83218SArnaldo Carvalho de Melo 	 */
16919958e1f0SArnaldo Carvalho de Melo 	map_groups__fixup_end(kmaps);
16926671cb16SArnaldo Carvalho de Melo 	return 0;
1693cd84c2acSFrederic Weisbecker }
1694