xref: /linux/tools/perf/util/symbol.c (revision 6893d4ee67cc100348088328cac73d56f7186aa3)
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 
59*6893d4eeSArnaldo Carvalho de Melo static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
60*6893d4eeSArnaldo Carvalho de Melo {
61*6893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
62*6893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
63*6893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
64*6893d4eeSArnaldo Carvalho de Melo 	default:
65*6893d4eeSArnaldo Carvalho de Melo 		return false;
66*6893d4eeSArnaldo Carvalho de Melo 	}
67*6893d4eeSArnaldo Carvalho de Melo }
68*6893d4eeSArnaldo Carvalho de Melo 
69fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
70af427bf5SArnaldo Carvalho de Melo {
71fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
722e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
73af427bf5SArnaldo Carvalho de Melo 
74af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
75af427bf5SArnaldo Carvalho de Melo 		return;
76af427bf5SArnaldo Carvalho de Melo 
772e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
782e538c4aSArnaldo Carvalho de Melo 
79af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
802e538c4aSArnaldo Carvalho de Melo 		prev = curr;
812e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
82af427bf5SArnaldo Carvalho de Melo 
83af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
84af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
85af427bf5SArnaldo Carvalho de Melo 	}
86af427bf5SArnaldo Carvalho de Melo 
872e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
882e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
892e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
902e538c4aSArnaldo Carvalho de Melo }
912e538c4aSArnaldo Carvalho de Melo 
929958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
93af427bf5SArnaldo Carvalho de Melo {
94af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
9595011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
96af427bf5SArnaldo Carvalho de Melo 
97af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
98af427bf5SArnaldo Carvalho de Melo 		return;
99af427bf5SArnaldo Carvalho de Melo 
100af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
101af427bf5SArnaldo Carvalho de Melo 
102af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
103af427bf5SArnaldo Carvalho de Melo 		prev = curr;
104af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
105af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1062e538c4aSArnaldo Carvalho de Melo 	}
10790c83218SArnaldo Carvalho de Melo 
10890c83218SArnaldo Carvalho de Melo 	/*
10990c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
11090c83218SArnaldo Carvalho de Melo 	 * last map final address.
11190c83218SArnaldo Carvalho de Melo 	 */
11290c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
113af427bf5SArnaldo Carvalho de Melo }
114af427bf5SArnaldo Carvalho de Melo 
1159958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
11623ea4a3fSArnaldo Carvalho de Melo {
11723ea4a3fSArnaldo Carvalho de Melo 	int i;
11823ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1199958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
12023ea4a3fSArnaldo Carvalho de Melo }
12123ea4a3fSArnaldo Carvalho de Melo 
12200a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name)
12386470930SIngo Molnar {
12486470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
12536479484SArnaldo Carvalho de Melo 	struct symbol *self = zalloc(symbol__priv_size +
12636479484SArnaldo Carvalho de Melo 				     sizeof(*self) + namelen);
12736479484SArnaldo Carvalho de Melo 	if (self == NULL)
12886470930SIngo Molnar 		return NULL;
12986470930SIngo Molnar 
13036479484SArnaldo Carvalho de Melo 	if (symbol__priv_size)
13100a192b3SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol__priv_size;
13236479484SArnaldo Carvalho de Melo 
13386470930SIngo Molnar 	self->start = start;
1346cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
135e4204992SArnaldo Carvalho de Melo 
1366beba7adSArnaldo Carvalho de Melo 	pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
137e4204992SArnaldo Carvalho de Melo 
13886470930SIngo Molnar 	memcpy(self->name, name, namelen);
13986470930SIngo Molnar 
14086470930SIngo Molnar 	return self;
14186470930SIngo Molnar }
14286470930SIngo Molnar 
14300a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self)
14486470930SIngo Molnar {
14500a192b3SArnaldo Carvalho de Melo 	free(((void *)self) - symbol__priv_size);
14686470930SIngo Molnar }
14786470930SIngo Molnar 
14886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
14986470930SIngo Molnar {
15086470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
15186470930SIngo Molnar 		       self->start, self->end, self->name);
15286470930SIngo Molnar }
15386470930SIngo Molnar 
154cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name)
155cfc10d3bSArnaldo Carvalho de Melo {
156ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
157ef6ae724SArnaldo Carvalho de Melo 		return;
158cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
159cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
160cfc10d3bSArnaldo Carvalho de Melo }
161cfc10d3bSArnaldo Carvalho de Melo 
162cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
163cfc10d3bSArnaldo Carvalho de Melo {
164cfc10d3bSArnaldo Carvalho de Melo 	self->short_name = basename(self->long_name);
165cfc10d3bSArnaldo Carvalho de Melo }
166cfc10d3bSArnaldo Carvalho de Melo 
16700a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
16886470930SIngo Molnar {
16986470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
17086470930SIngo Molnar 
17186470930SIngo Molnar 	if (self != NULL) {
1726a4694a4SArnaldo Carvalho de Melo 		int i;
17386470930SIngo Molnar 		strcpy(self->name, name);
174cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
175439d473bSArnaldo Carvalho de Melo 		self->short_name = self->name;
1766a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
1776a4694a4SArnaldo Carvalho de Melo 			self->symbols[i] = RB_ROOT;
1786a4694a4SArnaldo Carvalho de Melo 		self->find_symbol = dso__find_symbol;
17952d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
18094cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1818d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
1828d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
18386470930SIngo Molnar 	}
18486470930SIngo Molnar 
18586470930SIngo Molnar 	return self;
18686470930SIngo Molnar }
18786470930SIngo Molnar 
188fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
18986470930SIngo Molnar {
19086470930SIngo Molnar 	struct symbol *pos;
191fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
19286470930SIngo Molnar 
19386470930SIngo Molnar 	while (next) {
19486470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
19586470930SIngo Molnar 		next = rb_next(&pos->rb_node);
196fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
19700a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
19886470930SIngo Molnar 	}
19986470930SIngo Molnar }
20086470930SIngo Molnar 
20186470930SIngo Molnar void dso__delete(struct dso *self)
20286470930SIngo Molnar {
2036a4694a4SArnaldo Carvalho de Melo 	int i;
2046a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2056a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
206439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
207439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
20886470930SIngo Molnar 	free(self);
20986470930SIngo Molnar }
21086470930SIngo Molnar 
2118d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2128d06367fSArnaldo Carvalho de Melo {
2138d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2148d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2158d06367fSArnaldo Carvalho de Melo }
2168d06367fSArnaldo Carvalho de Melo 
217fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
21886470930SIngo Molnar {
219fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
22086470930SIngo Molnar 	struct rb_node *parent = NULL;
2219cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
22286470930SIngo Molnar 	struct symbol *s;
22386470930SIngo Molnar 
22486470930SIngo Molnar 	while (*p != NULL) {
22586470930SIngo Molnar 		parent = *p;
22686470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
22786470930SIngo Molnar 		if (ip < s->start)
22886470930SIngo Molnar 			p = &(*p)->rb_left;
22986470930SIngo Molnar 		else
23086470930SIngo Molnar 			p = &(*p)->rb_right;
23186470930SIngo Molnar 	}
23286470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
233fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
23486470930SIngo Molnar }
23586470930SIngo Molnar 
236fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
23786470930SIngo Molnar {
23886470930SIngo Molnar 	struct rb_node *n;
23986470930SIngo Molnar 
24086470930SIngo Molnar 	if (self == NULL)
24186470930SIngo Molnar 		return NULL;
24286470930SIngo Molnar 
243fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
24486470930SIngo Molnar 
24586470930SIngo Molnar 	while (n) {
24686470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
24786470930SIngo Molnar 
24886470930SIngo Molnar 		if (ip < s->start)
24986470930SIngo Molnar 			n = n->rb_left;
25086470930SIngo Molnar 		else if (ip > s->end)
25186470930SIngo Molnar 			n = n->rb_right;
25286470930SIngo Molnar 		else
25386470930SIngo Molnar 			return s;
25486470930SIngo Molnar 	}
25586470930SIngo Molnar 
25686470930SIngo Molnar 	return NULL;
25786470930SIngo Molnar }
25886470930SIngo Molnar 
2596a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
260fcf1203aSArnaldo Carvalho de Melo {
2616a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
262fcf1203aSArnaldo Carvalho de Melo }
263fcf1203aSArnaldo Carvalho de Melo 
2648d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf)
2658d06367fSArnaldo Carvalho de Melo {
2668d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
2678d06367fSArnaldo Carvalho de Melo 	u8 *raw = self;
2688d06367fSArnaldo Carvalho de Melo 	int i;
2698d06367fSArnaldo Carvalho de Melo 
2708d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
2718d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
2728d06367fSArnaldo Carvalho de Melo 		++raw;
2738d06367fSArnaldo Carvalho de Melo 		bid += 2;
2748d06367fSArnaldo Carvalho de Melo 	}
2758d06367fSArnaldo Carvalho de Melo 
2768d06367fSArnaldo Carvalho de Melo 	return raw - self;
2778d06367fSArnaldo Carvalho de Melo }
2788d06367fSArnaldo Carvalho de Melo 
2799e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
28086470930SIngo Molnar {
2818d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2828d06367fSArnaldo Carvalho de Melo 
2838d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
2849e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
2859e03eb2dSArnaldo Carvalho de Melo }
2869e03eb2dSArnaldo Carvalho de Melo 
28795011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
2889e03eb2dSArnaldo Carvalho de Melo {
2899e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
2909e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
2919e03eb2dSArnaldo Carvalho de Melo 
2929e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
2936a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
29495011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
29586470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
29686470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
29786470930SIngo Molnar 	}
29886470930SIngo Molnar 
29986470930SIngo Molnar 	return ret;
30086470930SIngo Molnar }
30186470930SIngo Molnar 
3022e538c4aSArnaldo Carvalho de Melo /*
3032e538c4aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
3042e538c4aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
3052e538c4aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
3062e538c4aSArnaldo Carvalho de Melo  */
3074e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map)
30886470930SIngo Molnar {
30986470930SIngo Molnar 	char *line = NULL;
31086470930SIngo Molnar 	size_t n;
3114e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
31286470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
31386470930SIngo Molnar 
31486470930SIngo Molnar 	if (file == NULL)
31586470930SIngo Molnar 		goto out_failure;
31686470930SIngo Molnar 
31786470930SIngo Molnar 	while (!feof(file)) {
3189cffa8d5SPaul Mackerras 		u64 start;
31986470930SIngo Molnar 		struct symbol *sym;
32086470930SIngo Molnar 		int line_len, len;
32186470930SIngo Molnar 		char symbol_type;
3222e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
32386470930SIngo Molnar 
32486470930SIngo Molnar 		line_len = getline(&line, &n, file);
32586470930SIngo Molnar 		if (line_len < 0)
32686470930SIngo Molnar 			break;
32786470930SIngo Molnar 
32886470930SIngo Molnar 		if (!line)
32986470930SIngo Molnar 			goto out_failure;
33086470930SIngo Molnar 
33186470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
33286470930SIngo Molnar 
33386470930SIngo Molnar 		len = hex2u64(line, &start);
33486470930SIngo Molnar 
33586470930SIngo Molnar 		len++;
33686470930SIngo Molnar 		if (len + 2 >= line_len)
33786470930SIngo Molnar 			continue;
33886470930SIngo Molnar 
33986470930SIngo Molnar 		symbol_type = toupper(line[len]);
340*6893d4eeSArnaldo Carvalho de Melo 		if (!symbol_type__is_a(symbol_type, map->type))
34186470930SIngo Molnar 			continue;
342af427bf5SArnaldo Carvalho de Melo 
343af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
3442e538c4aSArnaldo Carvalho de Melo 		/*
3452e538c4aSArnaldo Carvalho de Melo 		 * Will fix up the end later, when we have all symbols sorted.
3462e538c4aSArnaldo Carvalho de Melo 		 */
34700a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, 0, symbol_name);
348af427bf5SArnaldo Carvalho de Melo 
3492e538c4aSArnaldo Carvalho de Melo 		if (sym == NULL)
3502e538c4aSArnaldo Carvalho de Melo 			goto out_delete_line;
35182164161SArnaldo Carvalho de Melo 		/*
35282164161SArnaldo Carvalho de Melo 		 * We will pass the symbols to the filter later, in
3534e06255fSArnaldo Carvalho de Melo 		 * map__split_kallsyms, when we have split the maps per module
35482164161SArnaldo Carvalho de Melo 		 */
3554e06255fSArnaldo Carvalho de Melo 		symbols__insert(root, sym);
3562e538c4aSArnaldo Carvalho de Melo 	}
3572e538c4aSArnaldo Carvalho de Melo 
3582e538c4aSArnaldo Carvalho de Melo 	free(line);
3592e538c4aSArnaldo Carvalho de Melo 	fclose(file);
3602e538c4aSArnaldo Carvalho de Melo 
3612e538c4aSArnaldo Carvalho de Melo 	return 0;
3622e538c4aSArnaldo Carvalho de Melo 
3632e538c4aSArnaldo Carvalho de Melo out_delete_line:
3642e538c4aSArnaldo Carvalho de Melo 	free(line);
3652e538c4aSArnaldo Carvalho de Melo out_failure:
3662e538c4aSArnaldo Carvalho de Melo 	return -1;
3672e538c4aSArnaldo Carvalho de Melo }
3682e538c4aSArnaldo Carvalho de Melo 
3692e538c4aSArnaldo Carvalho de Melo /*
3702e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
3712e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
3722e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
3732e538c4aSArnaldo Carvalho de Melo  */
3749958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
3759958e1f0SArnaldo Carvalho de Melo 			       struct map_groups *mg, symbol_filter_t filter)
3762e538c4aSArnaldo Carvalho de Melo {
3774e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
3782e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
3792e538c4aSArnaldo Carvalho de Melo 	int count = 0;
3804e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
3814e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
3822e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
3832e538c4aSArnaldo Carvalho de Melo 
3842e538c4aSArnaldo Carvalho de Melo 	while (next) {
3852e538c4aSArnaldo Carvalho de Melo 		char *module;
3862e538c4aSArnaldo Carvalho de Melo 
3872e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
3882e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
3892e538c4aSArnaldo Carvalho de Melo 
3902e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
3912e538c4aSArnaldo Carvalho de Melo 		if (module) {
3929958e1f0SArnaldo Carvalho de Melo 			if (!mg->use_modules)
3931de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
3941de8e245SArnaldo Carvalho de Melo 
3952e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
3962e538c4aSArnaldo Carvalho de Melo 
3974e06255fSArnaldo Carvalho de Melo 			if (strcmp(self->name, module)) {
3989958e1f0SArnaldo Carvalho de Melo 				curr_map = map_groups__find_by_name(mg, module);
3994e06255fSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
40095011c60SArnaldo Carvalho de Melo 					pr_debug("/proc/{kallsyms,modules} "
4016beba7adSArnaldo Carvalho de Melo 					         "inconsistency!\n");
402af427bf5SArnaldo Carvalho de Melo 					return -1;
403af427bf5SArnaldo Carvalho de Melo 				}
404af427bf5SArnaldo Carvalho de Melo 			}
40586470930SIngo Molnar 			/*
4062e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
4072e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
40886470930SIngo Molnar 			 */
4094e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
4104e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
4114e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
4122e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
4132e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
41486470930SIngo Molnar 
4152e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
4162e538c4aSArnaldo Carvalho de Melo 				 kernel_range++);
41786470930SIngo Molnar 
41800a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
4192e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
4202e538c4aSArnaldo Carvalho de Melo 				return -1;
4212e538c4aSArnaldo Carvalho de Melo 
4224e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
4232e538c4aSArnaldo Carvalho de Melo 			if (map == NULL) {
4242e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
4252e538c4aSArnaldo Carvalho de Melo 				return -1;
4262e538c4aSArnaldo Carvalho de Melo 			}
4272e538c4aSArnaldo Carvalho de Melo 
4284e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
4299958e1f0SArnaldo Carvalho de Melo 			map_groups__insert(mg, curr_map);
4302e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
4312e538c4aSArnaldo Carvalho de Melo 		}
4322e538c4aSArnaldo Carvalho de Melo 
4334e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
4341de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
43500a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
4362e538c4aSArnaldo Carvalho de Melo 		} else {
4374e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
4384e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
4394e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
4402e538c4aSArnaldo Carvalho de Melo 			}
4419974f496SMike Galbraith 			count++;
4429974f496SMike Galbraith 		}
44386470930SIngo Molnar 	}
44486470930SIngo Molnar 
4459974f496SMike Galbraith 	return count;
44686470930SIngo Molnar }
44786470930SIngo Molnar 
4482e538c4aSArnaldo Carvalho de Melo 
4494e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map,
4509958e1f0SArnaldo Carvalho de Melo 			      struct map_groups *mg, symbol_filter_t filter)
4512e538c4aSArnaldo Carvalho de Melo {
4524e06255fSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, map) < 0)
4532e538c4aSArnaldo Carvalho de Melo 		return -1;
4542e538c4aSArnaldo Carvalho de Melo 
4554e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
4564e06255fSArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_KERNEL;
4572e538c4aSArnaldo Carvalho de Melo 
4589958e1f0SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, mg, filter);
45923ea4a3fSArnaldo Carvalho de Melo }
46023ea4a3fSArnaldo Carvalho de Melo 
46123ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp)
46223ea4a3fSArnaldo Carvalho de Melo {
46323ea4a3fSArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "Kernel maps:\n");
4649958e1f0SArnaldo Carvalho de Melo 	printed += map_groups__fprintf_maps(kmaps, fp);
4656beba7adSArnaldo Carvalho de Melo 	return printed + fprintf(fp, "END kernel maps\n");
466af427bf5SArnaldo Carvalho de Melo }
467af427bf5SArnaldo Carvalho de Melo 
468439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
4696beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
47080d496beSPekka Enberg {
47180d496beSPekka Enberg 	char *line = NULL;
47280d496beSPekka Enberg 	size_t n;
47380d496beSPekka Enberg 	FILE *file;
47480d496beSPekka Enberg 	int nr_syms = 0;
47580d496beSPekka Enberg 
476439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
47780d496beSPekka Enberg 	if (file == NULL)
47880d496beSPekka Enberg 		goto out_failure;
47980d496beSPekka Enberg 
48080d496beSPekka Enberg 	while (!feof(file)) {
4819cffa8d5SPaul Mackerras 		u64 start, size;
48280d496beSPekka Enberg 		struct symbol *sym;
48380d496beSPekka Enberg 		int line_len, len;
48480d496beSPekka Enberg 
48580d496beSPekka Enberg 		line_len = getline(&line, &n, file);
48680d496beSPekka Enberg 		if (line_len < 0)
48780d496beSPekka Enberg 			break;
48880d496beSPekka Enberg 
48980d496beSPekka Enberg 		if (!line)
49080d496beSPekka Enberg 			goto out_failure;
49180d496beSPekka Enberg 
49280d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
49380d496beSPekka Enberg 
49480d496beSPekka Enberg 		len = hex2u64(line, &start);
49580d496beSPekka Enberg 
49680d496beSPekka Enberg 		len++;
49780d496beSPekka Enberg 		if (len + 2 >= line_len)
49880d496beSPekka Enberg 			continue;
49980d496beSPekka Enberg 
50080d496beSPekka Enberg 		len += hex2u64(line + len, &size);
50180d496beSPekka Enberg 
50280d496beSPekka Enberg 		len++;
50380d496beSPekka Enberg 		if (len + 2 >= line_len)
50480d496beSPekka Enberg 			continue;
50580d496beSPekka Enberg 
50600a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
50780d496beSPekka Enberg 
50880d496beSPekka Enberg 		if (sym == NULL)
50980d496beSPekka Enberg 			goto out_delete_line;
51080d496beSPekka Enberg 
511439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
51200a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
51380d496beSPekka Enberg 		else {
5146a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
51580d496beSPekka Enberg 			nr_syms++;
51680d496beSPekka Enberg 		}
51780d496beSPekka Enberg 	}
51880d496beSPekka Enberg 
51980d496beSPekka Enberg 	free(line);
52080d496beSPekka Enberg 	fclose(file);
52180d496beSPekka Enberg 
52280d496beSPekka Enberg 	return nr_syms;
52380d496beSPekka Enberg 
52480d496beSPekka Enberg out_delete_line:
52580d496beSPekka Enberg 	free(line);
52680d496beSPekka Enberg out_failure:
52780d496beSPekka Enberg 	return -1;
52880d496beSPekka Enberg }
52980d496beSPekka Enberg 
53086470930SIngo Molnar /**
53186470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
53286470930SIngo Molnar  *
53386470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
53483a0944fSIngo Molnar  * @idx: uint32_t idx
53586470930SIngo Molnar  * @sym: GElf_Sym iterator
53686470930SIngo Molnar  */
53783a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
53883a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
53983a0944fSIngo Molnar 	     idx < nr_syms; \
54083a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
54186470930SIngo Molnar 
54286470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
54386470930SIngo Molnar {
54486470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
54586470930SIngo Molnar }
54686470930SIngo Molnar 
54786470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
54886470930SIngo Molnar {
54986470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
55086470930SIngo Molnar 	       sym->st_name != 0 &&
55181833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
55286470930SIngo Molnar }
55386470930SIngo Molnar 
5546cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
5556cfcc53eSMike Galbraith {
5566cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
5576cfcc53eSMike Galbraith 		sym->st_name != 0 &&
5586cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
5596cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
5606cfcc53eSMike Galbraith }
5616cfcc53eSMike Galbraith 
5626cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
5636cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5646cfcc53eSMike Galbraith {
5656cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
5666cfcc53eSMike Galbraith }
5676cfcc53eSMike Galbraith 
5686cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
5696cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5706cfcc53eSMike Galbraith {
5716cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
5726cfcc53eSMike Galbraith }
5736cfcc53eSMike Galbraith 
57486470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
57586470930SIngo Molnar 					const Elf_Data *symstrs)
57686470930SIngo Molnar {
57786470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
57886470930SIngo Molnar }
57986470930SIngo Molnar 
58086470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
58186470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
58283a0944fSIngo Molnar 				    size_t *idx)
58386470930SIngo Molnar {
58486470930SIngo Molnar 	Elf_Scn *sec = NULL;
58586470930SIngo Molnar 	size_t cnt = 1;
58686470930SIngo Molnar 
58786470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
58886470930SIngo Molnar 		char *str;
58986470930SIngo Molnar 
59086470930SIngo Molnar 		gelf_getshdr(sec, shp);
59186470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
59286470930SIngo Molnar 		if (!strcmp(name, str)) {
59383a0944fSIngo Molnar 			if (idx)
59483a0944fSIngo Molnar 				*idx = cnt;
59586470930SIngo Molnar 			break;
59686470930SIngo Molnar 		}
59786470930SIngo Molnar 		++cnt;
59886470930SIngo Molnar 	}
59986470930SIngo Molnar 
60086470930SIngo Molnar 	return sec;
60186470930SIngo Molnar }
60286470930SIngo Molnar 
60386470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
60486470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
60586470930SIngo Molnar 	     idx < nr_entries; \
60686470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
60786470930SIngo Molnar 
60886470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
60986470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
61086470930SIngo Molnar 	     idx < nr_entries; \
61186470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
61286470930SIngo Molnar 
613a25e46c4SArnaldo Carvalho de Melo /*
614a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
615a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
616a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
617a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
618a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
619a25e46c4SArnaldo Carvalho de Melo  */
62082164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
62182164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
62286470930SIngo Molnar {
62386470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
62486470930SIngo Molnar 	GElf_Sym sym;
6259cffa8d5SPaul Mackerras 	u64 plt_offset;
62686470930SIngo Molnar 	GElf_Shdr shdr_plt;
62786470930SIngo Molnar 	struct symbol *f;
628a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
62986470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
630a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
631a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
632a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
63386470930SIngo Molnar 	char sympltname[1024];
634a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
635a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
63686470930SIngo Molnar 
637439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
638a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
639a25e46c4SArnaldo Carvalho de Melo 		goto out;
640a25e46c4SArnaldo Carvalho de Melo 
64184087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
642a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
643a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
644a25e46c4SArnaldo Carvalho de Melo 
645a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
646a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
647a25e46c4SArnaldo Carvalho de Melo 
648a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
649a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
650a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
651a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
652a25e46c4SArnaldo Carvalho de Melo 
653a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
65486470930SIngo Molnar 					  ".rela.plt", NULL);
65586470930SIngo Molnar 	if (scn_plt_rel == NULL) {
656a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
65786470930SIngo Molnar 						  ".rel.plt", NULL);
65886470930SIngo Molnar 		if (scn_plt_rel == NULL)
659a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
66086470930SIngo Molnar 	}
66186470930SIngo Molnar 
662a25e46c4SArnaldo Carvalho de Melo 	err = -1;
66386470930SIngo Molnar 
664a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
665a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
666a25e46c4SArnaldo Carvalho de Melo 
667a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
668a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
66986470930SIngo Molnar 
67086470930SIngo Molnar 	/*
67183a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
67286470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
67386470930SIngo Molnar 	 */
67486470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
67586470930SIngo Molnar 	if (reldata == NULL)
676a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
67786470930SIngo Molnar 
67886470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
67986470930SIngo Molnar 	if (syms == NULL)
680a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
68186470930SIngo Molnar 
682a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
68386470930SIngo Molnar 	if (scn_symstrs == NULL)
684a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
68586470930SIngo Molnar 
68686470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
68786470930SIngo Molnar 	if (symstrs == NULL)
688a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
68986470930SIngo Molnar 
69086470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
69186470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
69286470930SIngo Molnar 
69386470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
69486470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
69586470930SIngo Molnar 
69686470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
69786470930SIngo Molnar 					   nr_rel_entries) {
69886470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
69986470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
70086470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
70186470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
70286470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
70386470930SIngo Molnar 
70486470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
70500a192b3SArnaldo Carvalho de Melo 					sympltname);
70686470930SIngo Molnar 			if (!f)
707a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
70886470930SIngo Molnar 
70982164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
71082164161SArnaldo Carvalho de Melo 				symbol__delete(f);
71182164161SArnaldo Carvalho de Melo 			else {
7126a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
71386470930SIngo Molnar 				++nr;
71486470930SIngo Molnar 			}
71582164161SArnaldo Carvalho de Melo 		}
71686470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
71786470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
71886470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
71986470930SIngo Molnar 					  nr_rel_entries) {
72086470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
72186470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
72286470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
72386470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
72486470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
72586470930SIngo Molnar 
72686470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
72700a192b3SArnaldo Carvalho de Melo 					sympltname);
72886470930SIngo Molnar 			if (!f)
729a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
73086470930SIngo Molnar 
73182164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
73282164161SArnaldo Carvalho de Melo 				symbol__delete(f);
73382164161SArnaldo Carvalho de Melo 			else {
7346a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
73586470930SIngo Molnar 				++nr;
73686470930SIngo Molnar 			}
73786470930SIngo Molnar 		}
73882164161SArnaldo Carvalho de Melo 	}
73986470930SIngo Molnar 
740a25e46c4SArnaldo Carvalho de Melo 	err = 0;
741a25e46c4SArnaldo Carvalho de Melo out_elf_end:
742a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
743a25e46c4SArnaldo Carvalho de Melo out_close:
744a25e46c4SArnaldo Carvalho de Melo 	close(fd);
745a25e46c4SArnaldo Carvalho de Melo 
746a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
74786470930SIngo Molnar 		return nr;
748a25e46c4SArnaldo Carvalho de Melo out:
7496beba7adSArnaldo Carvalho de Melo 	pr_warning("%s: problems reading %s PLT info.\n",
750439d473bSArnaldo Carvalho de Melo 		   __func__, self->long_name);
751a25e46c4SArnaldo Carvalho de Melo 	return 0;
75286470930SIngo Molnar }
75386470930SIngo Molnar 
75495011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map,
7559958e1f0SArnaldo Carvalho de Melo 			 struct map_groups *mg, const char *name, int fd,
75695011c60SArnaldo Carvalho de Melo 			 symbol_filter_t filter, int kernel, int kmodule)
75786470930SIngo Molnar {
7582e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
7592e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
7602e538c4aSArnaldo Carvalho de Melo 	size_t dso_name_len = strlen(self->short_name);
7616cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
76286470930SIngo Molnar 	uint32_t nr_syms;
76386470930SIngo Molnar 	int err = -1;
76483a0944fSIngo Molnar 	uint32_t idx;
76586470930SIngo Molnar 	GElf_Ehdr ehdr;
76686470930SIngo Molnar 	GElf_Shdr shdr;
76786470930SIngo Molnar 	Elf_Data *syms;
76886470930SIngo Molnar 	GElf_Sym sym;
769a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
77086470930SIngo Molnar 	Elf *elf;
771439d473bSArnaldo Carvalho de Melo 	int nr = 0;
77286470930SIngo Molnar 
77384087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
77486470930SIngo Molnar 	if (elf == NULL) {
7756beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
77686470930SIngo Molnar 		goto out_close;
77786470930SIngo Molnar 	}
77886470930SIngo Molnar 
77986470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
7806beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
78186470930SIngo Molnar 		goto out_elf_end;
78286470930SIngo Molnar 	}
78386470930SIngo Molnar 
78486470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
78586470930SIngo Molnar 	if (sec == NULL) {
786a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
787a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
78886470930SIngo Molnar 			goto out_elf_end;
78986470930SIngo Molnar 	}
79086470930SIngo Molnar 
79186470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
79286470930SIngo Molnar 	if (syms == NULL)
79386470930SIngo Molnar 		goto out_elf_end;
79486470930SIngo Molnar 
79586470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
79686470930SIngo Molnar 	if (sec == NULL)
79786470930SIngo Molnar 		goto out_elf_end;
79886470930SIngo Molnar 
79986470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
80086470930SIngo Molnar 	if (symstrs == NULL)
80186470930SIngo Molnar 		goto out_elf_end;
80286470930SIngo Molnar 
8036cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
8046cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
8056cfcc53eSMike Galbraith 		goto out_elf_end;
8066cfcc53eSMike Galbraith 
8076cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
8089b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
8096cfcc53eSMike Galbraith 		goto out_elf_end;
8106cfcc53eSMike Galbraith 
81186470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
81286470930SIngo Molnar 
813e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
814d20ff6bdSMike Galbraith 	if (!kernel) {
81530d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
81630d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
817f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
81830d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
819d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
820d20ff6bdSMike Galbraith 
82183a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
82286470930SIngo Molnar 		struct symbol *f;
82383a0944fSIngo Molnar 		const char *elf_name;
8242e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
8256cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
8266cfcc53eSMike Galbraith 		const char *section_name;
82786470930SIngo Molnar 
8286cfcc53eSMike Galbraith 		if (!is_label && !elf_sym__is_function(&sym))
82986470930SIngo Molnar 			continue;
83086470930SIngo Molnar 
83186470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
83286470930SIngo Molnar 		if (!sec)
83386470930SIngo Molnar 			goto out_elf_end;
83486470930SIngo Molnar 
83586470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
8366cfcc53eSMike Galbraith 
8376cfcc53eSMike Galbraith 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
8386cfcc53eSMike Galbraith 			continue;
8396cfcc53eSMike Galbraith 
8402e538c4aSArnaldo Carvalho de Melo 		elf_name = elf_sym__name(&sym, symstrs);
8416cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
84286470930SIngo Molnar 
8432e538c4aSArnaldo Carvalho de Melo 		if (kernel || kmodule) {
8442e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
8452e538c4aSArnaldo Carvalho de Melo 
8462e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
8472e538c4aSArnaldo Carvalho de Melo 				   curr_dso->short_name + dso_name_len) == 0)
8482e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
8492e538c4aSArnaldo Carvalho de Melo 
8502e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
8512e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
8522e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
8532e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
854af427bf5SArnaldo Carvalho de Melo 			}
855af427bf5SArnaldo Carvalho de Melo 
8562e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
8572e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
8582e538c4aSArnaldo Carvalho de Melo 
8599958e1f0SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(mg, dso_name);
8602e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
8612e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
8622e538c4aSArnaldo Carvalho de Melo 
8632e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
8642e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
8652e538c4aSArnaldo Carvalho de Melo 
86600a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
8672e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
8682e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8693610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
8703610583cSArnaldo Carvalho de Melo 						     MAP__FUNCTION);
8712e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
8722e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
8732e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8742e538c4aSArnaldo Carvalho de Melo 				}
875ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
876ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
8772e538c4aSArnaldo Carvalho de Melo 				curr_dso->origin = DSO__ORIG_KERNEL;
8789958e1f0SArnaldo Carvalho de Melo 				map_groups__insert(kmaps, curr_map);
879b0da954aSArnaldo Carvalho de Melo 				dsos__add(&dsos__kernel, curr_dso);
8802e538c4aSArnaldo Carvalho de Melo 			} else
8812e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
8822e538c4aSArnaldo Carvalho de Melo 
8832e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
8842e538c4aSArnaldo Carvalho de Melo 		}
8852e538c4aSArnaldo Carvalho de Melo 
8862e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
8876beba7adSArnaldo Carvalho de Melo 			pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
8886beba7adSArnaldo Carvalho de Melo 				  "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
8896beba7adSArnaldo Carvalho de Melo 				  (u64)shdr.sh_addr, (u64)shdr.sh_offset);
89086470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
891af427bf5SArnaldo Carvalho de Melo 		}
89228ac909bSArnaldo Carvalho de Melo 		/*
89328ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
89428ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
89528ac909bSArnaldo Carvalho de Melo 		 * to it...
89628ac909bSArnaldo Carvalho de Melo 		 */
89783a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
89828ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
89983a0944fSIngo Molnar 			elf_name = demangled;
9002e538c4aSArnaldo Carvalho de Melo new_symbol:
90100a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
90228ac909bSArnaldo Carvalho de Melo 		free(demangled);
90386470930SIngo Molnar 		if (!f)
90486470930SIngo Molnar 			goto out_elf_end;
90586470930SIngo Molnar 
9062e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
90700a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
90886470930SIngo Molnar 		else {
9096a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
91086470930SIngo Molnar 			nr++;
91186470930SIngo Molnar 		}
91286470930SIngo Molnar 	}
91386470930SIngo Molnar 
9142e538c4aSArnaldo Carvalho de Melo 	/*
9152e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
9162e538c4aSArnaldo Carvalho de Melo 	 */
9172e538c4aSArnaldo Carvalho de Melo 	if (nr > 0)
9186a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
91986470930SIngo Molnar 	err = nr;
92086470930SIngo Molnar out_elf_end:
92186470930SIngo Molnar 	elf_end(elf);
92286470930SIngo Molnar out_close:
92386470930SIngo Molnar 	return err;
92486470930SIngo Molnar }
92586470930SIngo Molnar 
92678075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
92778075caaSArnaldo Carvalho de Melo {
92878075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
92978075caaSArnaldo Carvalho de Melo }
93078075caaSArnaldo Carvalho de Melo 
931b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head)
93257f395a7SFrederic Weisbecker {
933e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
93457f395a7SFrederic Weisbecker 	struct dso *pos;
93557f395a7SFrederic Weisbecker 
936b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
937e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
938e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
939e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
940e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
94157f395a7SFrederic Weisbecker 		}
94257f395a7SFrederic Weisbecker 
943e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
94457f395a7SFrederic Weisbecker }
94557f395a7SFrederic Weisbecker 
946b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void)
947b0da954aSArnaldo Carvalho de Melo {
9488b4825bfSArnaldo Carvalho de Melo 	bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
9498b4825bfSArnaldo Carvalho de Melo 	     ubuildids = __dsos__read_build_ids(&dsos__user);
9508b4825bfSArnaldo Carvalho de Melo 	return kbuildids || ubuildids;
951b0da954aSArnaldo Carvalho de Melo }
952b0da954aSArnaldo Carvalho de Melo 
953fd7a346eSArnaldo Carvalho de Melo /*
954fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
955fd7a346eSArnaldo Carvalho de Melo  */
956fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
957fd7a346eSArnaldo Carvalho de Melo 
9582643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
9594d1e00a8SArnaldo Carvalho de Melo {
9602643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
9614d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
9624d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
963fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
9644d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
965e57cfcdaSPekka Enberg 	Elf_Kind ek;
966fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
9674d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
9684d1e00a8SArnaldo Carvalho de Melo 
9692643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
9702643ce11SArnaldo Carvalho de Melo 		goto out;
9712643ce11SArnaldo Carvalho de Melo 
9722643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
9734d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
9744d1e00a8SArnaldo Carvalho de Melo 		goto out;
9754d1e00a8SArnaldo Carvalho de Melo 
97684087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
9774d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
9788d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
9794d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
9804d1e00a8SArnaldo Carvalho de Melo 	}
9814d1e00a8SArnaldo Carvalho de Melo 
982e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
983e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
984e57cfcdaSPekka Enberg 		goto out_elf_end;
985e57cfcdaSPekka Enberg 
9864d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
9876beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
9884d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
9894d1e00a8SArnaldo Carvalho de Melo 	}
9904d1e00a8SArnaldo Carvalho de Melo 
9912643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
9922643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
993fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
994fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
995fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
9964d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
9974d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
998fd7a346eSArnaldo Carvalho de Melo 	}
9994d1e00a8SArnaldo Carvalho de Melo 
1000fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1001fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
10024d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
1003fd7a346eSArnaldo Carvalho de Melo 
1004fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1005fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1006fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1007fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1008fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1009fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1010fd7a346eSArnaldo Carvalho de Melo 
1011fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1012fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1013fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1014fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1015fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1016fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1017fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
10182643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1019fd7a346eSArnaldo Carvalho de Melo 				break;
1020fd7a346eSArnaldo Carvalho de Melo 			}
1021fd7a346eSArnaldo Carvalho de Melo 		}
1022fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1023fd7a346eSArnaldo Carvalho de Melo 	}
10242643ce11SArnaldo Carvalho de Melo out_elf_end:
10252643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
10262643ce11SArnaldo Carvalho de Melo out_close:
10272643ce11SArnaldo Carvalho de Melo 	close(fd);
10282643ce11SArnaldo Carvalho de Melo out:
10292643ce11SArnaldo Carvalho de Melo 	return err;
10302643ce11SArnaldo Carvalho de Melo }
10312643ce11SArnaldo Carvalho de Melo 
1032f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1033f1617b40SArnaldo Carvalho de Melo {
1034f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1035f1617b40SArnaldo Carvalho de Melo 
1036f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1037f1617b40SArnaldo Carvalho de Melo 		goto out;
1038f1617b40SArnaldo Carvalho de Melo 
1039f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1040f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1041f1617b40SArnaldo Carvalho de Melo 		goto out;
1042f1617b40SArnaldo Carvalho de Melo 
1043f1617b40SArnaldo Carvalho de Melo 	while (1) {
1044f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1045f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1046f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1047f1617b40SArnaldo Carvalho de Melo 
1048f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1049f1617b40SArnaldo Carvalho de Melo 			break;
1050f1617b40SArnaldo Carvalho de Melo 
1051fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1052fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1053f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1054f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1055f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1056f1617b40SArnaldo Carvalho de Melo 				break;
1057f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1058f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1059f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1060f1617b40SArnaldo Carvalho de Melo 					err = 0;
1061f1617b40SArnaldo Carvalho de Melo 					break;
1062f1617b40SArnaldo Carvalho de Melo 				}
1063f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1064f1617b40SArnaldo Carvalho de Melo 				break;
1065f1617b40SArnaldo Carvalho de Melo 		} else {
1066f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1067f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1068f1617b40SArnaldo Carvalho de Melo 				break;
1069f1617b40SArnaldo Carvalho de Melo 		}
1070f1617b40SArnaldo Carvalho de Melo 	}
1071f1617b40SArnaldo Carvalho de Melo 	close(fd);
1072f1617b40SArnaldo Carvalho de Melo out:
1073f1617b40SArnaldo Carvalho de Melo 	return err;
1074f1617b40SArnaldo Carvalho de Melo }
1075f1617b40SArnaldo Carvalho de Melo 
107694cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
107794cb9e38SArnaldo Carvalho de Melo {
107894cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
107994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
108094cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
108194cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
108294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
108394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
108494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1085439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
108694cb9e38SArnaldo Carvalho de Melo 	};
108794cb9e38SArnaldo Carvalho de Melo 
108894cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
108994cb9e38SArnaldo Carvalho de Melo 		return '!';
109094cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
109194cb9e38SArnaldo Carvalho de Melo }
109294cb9e38SArnaldo Carvalho de Melo 
10936beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
109486470930SIngo Molnar {
10954d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1096c338aee8SArnaldo Carvalho de Melo 	char *name;
1097d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
109886470930SIngo Molnar 	int ret = -1;
109986470930SIngo Molnar 	int fd;
110086470930SIngo Molnar 
11013610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
110266bd8424SArnaldo Carvalho de Melo 
1103c338aee8SArnaldo Carvalho de Melo 	if (self->kernel)
11049958e1f0SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, kmaps, filter);
1105c338aee8SArnaldo Carvalho de Melo 
1106c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
110786470930SIngo Molnar 	if (!name)
110886470930SIngo Molnar 		return -1;
110986470930SIngo Molnar 
111030d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1111f5812a7aSArnaldo Carvalho de Melo 
111294cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
11136beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
111494cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
111594cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
111694cb9e38SArnaldo Carvalho de Melo 		return ret;
111794cb9e38SArnaldo Carvalho de Melo 	}
111894cb9e38SArnaldo Carvalho de Melo 
111994cb9e38SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_FEDORA - 1;
112080d496beSPekka Enberg 
112186470930SIngo Molnar more:
112286470930SIngo Molnar 	do {
112394cb9e38SArnaldo Carvalho de Melo 		self->origin++;
112494cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
112594cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1126439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1127439d473bSArnaldo Carvalho de Melo 				 self->long_name);
112886470930SIngo Molnar 			break;
112994cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1130439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1131439d473bSArnaldo Carvalho de Melo 				 self->long_name);
113286470930SIngo Molnar 			break;
113394cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1134d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1135d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1136d3379ab9SArnaldo Carvalho de Melo 				char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1137d3379ab9SArnaldo Carvalho de Melo 
1138d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1139d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
11404d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
11414d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1142d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1143d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
11448d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1145d3379ab9SArnaldo Carvalho de Melo 				break;
11464d1e00a8SArnaldo Carvalho de Melo 			}
114794cb9e38SArnaldo Carvalho de Melo 			self->origin++;
11484d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
114994cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1150439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
115186470930SIngo Molnar 			break;
115286470930SIngo Molnar 
115386470930SIngo Molnar 		default:
115486470930SIngo Molnar 			goto out;
115586470930SIngo Molnar 		}
115686470930SIngo Molnar 
11578d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1158d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1159d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
11608d06367fSArnaldo Carvalho de Melo 				goto more;
11618d06367fSArnaldo Carvalho de Melo compare_build_id:
116278075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
11638d06367fSArnaldo Carvalho de Melo 				goto more;
11648d06367fSArnaldo Carvalho de Melo 		}
11658d06367fSArnaldo Carvalho de Melo 
116686470930SIngo Molnar 		fd = open(name, O_RDONLY);
116786470930SIngo Molnar 	} while (fd < 0);
116886470930SIngo Molnar 
116995011c60SArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
117086470930SIngo Molnar 	close(fd);
117186470930SIngo Molnar 
117286470930SIngo Molnar 	/*
117386470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
117486470930SIngo Molnar 	 */
117586470930SIngo Molnar 	if (!ret)
117686470930SIngo Molnar 		goto more;
117786470930SIngo Molnar 
1178a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
117982164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1180a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1181a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1182a25e46c4SArnaldo Carvalho de Melo 	}
118386470930SIngo Molnar out:
118486470930SIngo Molnar 	free(name);
11851340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
11861340e6bbSArnaldo Carvalho de Melo 		return 0;
118786470930SIngo Molnar 	return ret;
118886470930SIngo Molnar }
118986470930SIngo Molnar 
11909958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *self, char *name)
1191439d473bSArnaldo Carvalho de Melo {
1192439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1193439d473bSArnaldo Carvalho de Melo 
119495011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
1195439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1196439d473bSArnaldo Carvalho de Melo 
1197439d473bSArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->name, name) == 0)
1198439d473bSArnaldo Carvalho de Melo 			return map;
1199439d473bSArnaldo Carvalho de Melo 	}
1200439d473bSArnaldo Carvalho de Melo 
1201439d473bSArnaldo Carvalho de Melo 	return NULL;
1202439d473bSArnaldo Carvalho de Melo }
1203439d473bSArnaldo Carvalho de Melo 
1204c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname)
12056cfcc53eSMike Galbraith {
1206439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
1207439d473bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dirname);
12086cfcc53eSMike Galbraith 
1209439d473bSArnaldo Carvalho de Melo 	if (!dir) {
121087f8ea4cSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1211439d473bSArnaldo Carvalho de Melo 		return -1;
1212439d473bSArnaldo Carvalho de Melo 	}
12136cfcc53eSMike Galbraith 
1214439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1215439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1216439d473bSArnaldo Carvalho de Melo 
1217439d473bSArnaldo Carvalho de Melo 		if (dent->d_type == DT_DIR) {
1218439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1219439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1220439d473bSArnaldo Carvalho de Melo 				continue;
1221439d473bSArnaldo Carvalho de Melo 
1222439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1223439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1224c338aee8SArnaldo Carvalho de Melo 			if (dsos__set_modules_path_dir(path) < 0)
1225439d473bSArnaldo Carvalho de Melo 				goto failure;
1226439d473bSArnaldo Carvalho de Melo 		} else {
1227439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1228439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1229439d473bSArnaldo Carvalho de Melo 			struct map *map;
1230cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1231439d473bSArnaldo Carvalho de Melo 
1232439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1233439d473bSArnaldo Carvalho de Melo 				continue;
1234439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1235439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1236439d473bSArnaldo Carvalho de Melo 
1237a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
12389958e1f0SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(kmaps, dso_name);
1239439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1240439d473bSArnaldo Carvalho de Melo 				continue;
1241439d473bSArnaldo Carvalho de Melo 
1242439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1243439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1244439d473bSArnaldo Carvalho de Melo 
1245cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1246cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1247439d473bSArnaldo Carvalho de Melo 				goto failure;
1248cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1249439d473bSArnaldo Carvalho de Melo 		}
1250439d473bSArnaldo Carvalho de Melo 	}
1251439d473bSArnaldo Carvalho de Melo 
1252c338aee8SArnaldo Carvalho de Melo 	return 0;
1253439d473bSArnaldo Carvalho de Melo failure:
1254439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1255439d473bSArnaldo Carvalho de Melo 	return -1;
1256439d473bSArnaldo Carvalho de Melo }
1257439d473bSArnaldo Carvalho de Melo 
1258c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void)
1259439d473bSArnaldo Carvalho de Melo {
1260439d473bSArnaldo Carvalho de Melo 	struct utsname uts;
1261439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1262439d473bSArnaldo Carvalho de Melo 
1263439d473bSArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
1264439d473bSArnaldo Carvalho de Melo 		return -1;
1265439d473bSArnaldo Carvalho de Melo 
1266439d473bSArnaldo Carvalho de Melo 	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1267439d473bSArnaldo Carvalho de Melo 		 uts.release);
1268439d473bSArnaldo Carvalho de Melo 
1269c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path_dir(modules_path);
1270439d473bSArnaldo Carvalho de Melo }
12716cfcc53eSMike Galbraith 
12726cfcc53eSMike Galbraith /*
1273439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1274439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1275439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
12766cfcc53eSMike Galbraith  */
12773610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1278439d473bSArnaldo Carvalho de Melo {
1279439d473bSArnaldo Carvalho de Melo 	struct map *self = malloc(sizeof(*self));
12806cfcc53eSMike Galbraith 
1281439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1282439d473bSArnaldo Carvalho de Melo 		/*
1283afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1284439d473bSArnaldo Carvalho de Melo 		 */
12853610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1286439d473bSArnaldo Carvalho de Melo 	}
1287afb7b4f0SArnaldo Carvalho de Melo 
1288439d473bSArnaldo Carvalho de Melo 	return self;
1289439d473bSArnaldo Carvalho de Melo }
1290439d473bSArnaldo Carvalho de Melo 
12919958e1f0SArnaldo Carvalho de Melo static int map_groups__create_module_maps(struct map_groups *self)
1292439d473bSArnaldo Carvalho de Melo {
1293439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1294439d473bSArnaldo Carvalho de Melo 	size_t n;
1295439d473bSArnaldo Carvalho de Melo 	FILE *file = fopen("/proc/modules", "r");
1296439d473bSArnaldo Carvalho de Melo 	struct map *map;
1297439d473bSArnaldo Carvalho de Melo 
1298439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1299439d473bSArnaldo Carvalho de Melo 		return -1;
1300439d473bSArnaldo Carvalho de Melo 
1301439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1302439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1303439d473bSArnaldo Carvalho de Melo 		u64 start;
1304439d473bSArnaldo Carvalho de Melo 		struct dso *dso;
1305439d473bSArnaldo Carvalho de Melo 		char *sep;
1306439d473bSArnaldo Carvalho de Melo 		int line_len;
1307439d473bSArnaldo Carvalho de Melo 
1308439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1309439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
13106cfcc53eSMike Galbraith 			break;
13116cfcc53eSMike Galbraith 
1312439d473bSArnaldo Carvalho de Melo 		if (!line)
1313439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1314439d473bSArnaldo Carvalho de Melo 
1315439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1316439d473bSArnaldo Carvalho de Melo 
1317439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1318439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1319439d473bSArnaldo Carvalho de Melo 			continue;
1320439d473bSArnaldo Carvalho de Melo 
1321439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1322439d473bSArnaldo Carvalho de Melo 
1323439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1324439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1325439d473bSArnaldo Carvalho de Melo 			continue;
1326439d473bSArnaldo Carvalho de Melo 
1327439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1328439d473bSArnaldo Carvalho de Melo 
1329439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
133000a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1331439d473bSArnaldo Carvalho de Melo 
1332439d473bSArnaldo Carvalho de Melo 		if (dso == NULL)
1333439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1334439d473bSArnaldo Carvalho de Melo 
13353610583cSArnaldo Carvalho de Melo 		map = map__new2(start, dso, MAP__FUNCTION);
1336439d473bSArnaldo Carvalho de Melo 		if (map == NULL) {
1337439d473bSArnaldo Carvalho de Melo 			dso__delete(dso);
1338439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
13396cfcc53eSMike Galbraith 		}
13406cfcc53eSMike Galbraith 
1341f1617b40SArnaldo Carvalho de Melo 		snprintf(name, sizeof(name),
1342f1617b40SArnaldo Carvalho de Melo 			 "/sys/module/%s/notes/.note.gnu.build-id", line);
1343f1617b40SArnaldo Carvalho de Melo 		if (sysfs__read_build_id(name, dso->build_id,
1344f1617b40SArnaldo Carvalho de Melo 					 sizeof(dso->build_id)) == 0)
1345f1617b40SArnaldo Carvalho de Melo 			dso->has_build_id = true;
1346f1617b40SArnaldo Carvalho de Melo 
1347439d473bSArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
13489958e1f0SArnaldo Carvalho de Melo 		map_groups__insert(self, map);
1349b0da954aSArnaldo Carvalho de Melo 		dsos__add(&dsos__kernel, dso);
13506cfcc53eSMike Galbraith 	}
13516cfcc53eSMike Galbraith 
1352439d473bSArnaldo Carvalho de Melo 	free(line);
1353439d473bSArnaldo Carvalho de Melo 	fclose(file);
1354439d473bSArnaldo Carvalho de Melo 
1355c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path();
1356439d473bSArnaldo Carvalho de Melo 
1357439d473bSArnaldo Carvalho de Melo out_delete_line:
1358439d473bSArnaldo Carvalho de Melo 	free(line);
1359439d473bSArnaldo Carvalho de Melo out_failure:
1360439d473bSArnaldo Carvalho de Melo 	return -1;
13616cfcc53eSMike Galbraith }
13626cfcc53eSMike Galbraith 
13639958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
13649958e1f0SArnaldo Carvalho de Melo 			     struct map_groups *mg,
13656beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
136686470930SIngo Molnar {
1367fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
136886470930SIngo Molnar 
1369fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1370fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
137166bd8424SArnaldo Carvalho de Melo 
1372fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1373fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1374fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1375fbd733b8SArnaldo Carvalho de Melo 			return -1;
1376fbd733b8SArnaldo Carvalho de Melo 		}
1377fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1378fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1379fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1380fbd733b8SArnaldo Carvalho de Melo 
1381fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1382fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1383fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1384fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1385fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1386fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1387fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1388fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1389fbd733b8SArnaldo Carvalho de Melo 			return -1;
1390fbd733b8SArnaldo Carvalho de Melo 		}
1391fbd733b8SArnaldo Carvalho de Melo 	}
1392fbd733b8SArnaldo Carvalho de Melo 
1393fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
139486470930SIngo Molnar 	if (fd < 0)
139586470930SIngo Molnar 		return -1;
139686470930SIngo Molnar 
13973610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
13989958e1f0SArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0);
139986470930SIngo Molnar 	close(fd);
140086470930SIngo Molnar 
140186470930SIngo Molnar 	return err;
140286470930SIngo Molnar }
140386470930SIngo Molnar 
1404c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
14059958e1f0SArnaldo Carvalho de Melo 				struct map_groups *mg, symbol_filter_t filter)
140686470930SIngo Molnar {
1407cc612d81SArnaldo Carvalho de Melo 	int err;
1408cc612d81SArnaldo Carvalho de Melo 	bool is_kallsyms;
1409439d473bSArnaldo Carvalho de Melo 
1410cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
1411cc612d81SArnaldo Carvalho de Melo 		int i;
1412cc612d81SArnaldo Carvalho de Melo 		pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1413cc612d81SArnaldo Carvalho de Melo 			 vmlinux_path__nr_entries);
1414cc612d81SArnaldo Carvalho de Melo 		for (i = 0; i < vmlinux_path__nr_entries; ++i) {
14159958e1f0SArnaldo Carvalho de Melo 			err = dso__load_vmlinux(self, map, mg,
141695011c60SArnaldo Carvalho de Melo 						vmlinux_path[i], filter);
1417cc612d81SArnaldo Carvalho de Melo 			if (err > 0) {
1418cc612d81SArnaldo Carvalho de Melo 				pr_debug("Using %s for symbols\n",
1419cc612d81SArnaldo Carvalho de Melo 					 vmlinux_path[i]);
1420cc612d81SArnaldo Carvalho de Melo 				dso__set_long_name(self,
1421cc612d81SArnaldo Carvalho de Melo 						   strdup(vmlinux_path[i]));
1422cc612d81SArnaldo Carvalho de Melo 				goto out_fixup;
1423cc612d81SArnaldo Carvalho de Melo 			}
1424cc612d81SArnaldo Carvalho de Melo 		}
1425cc612d81SArnaldo Carvalho de Melo 	}
1426cc612d81SArnaldo Carvalho de Melo 
1427cc612d81SArnaldo Carvalho de Melo 	is_kallsyms = self->long_name[0] == '[';
1428cc612d81SArnaldo Carvalho de Melo 	if (is_kallsyms)
1429cc612d81SArnaldo Carvalho de Melo 		goto do_kallsyms;
1430cc612d81SArnaldo Carvalho de Melo 
14319958e1f0SArnaldo Carvalho de Melo 	err = dso__load_vmlinux(self, map, mg, self->long_name, filter);
1432ef6ae724SArnaldo Carvalho de Melo 	if (err <= 0) {
1433cc612d81SArnaldo Carvalho de Melo 		pr_info("The file %s cannot be used, "
1434cc612d81SArnaldo Carvalho de Melo 			"trying to use /proc/kallsyms...", self->long_name);
1435cc612d81SArnaldo Carvalho de Melo do_kallsyms:
14369958e1f0SArnaldo Carvalho de Melo 		err = dso__load_kallsyms(self, map, mg, filter);
1437cc612d81SArnaldo Carvalho de Melo 		if (err > 0 && !is_kallsyms)
1438ef6ae724SArnaldo Carvalho de Melo                         dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1439ef6ae724SArnaldo Carvalho de Melo 	}
144086470930SIngo Molnar 
1441439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1442cc612d81SArnaldo Carvalho de Melo out_fixup:
14436a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
14446a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1445439d473bSArnaldo Carvalho de Melo 	}
144694cb9e38SArnaldo Carvalho de Melo 
144786470930SIngo Molnar 	return err;
144886470930SIngo Molnar }
144986470930SIngo Molnar 
1450b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user);
1451b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel);
1452cd84c2acSFrederic Weisbecker struct dso *vdso;
1453cd84c2acSFrederic Weisbecker 
1454b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1455cd84c2acSFrederic Weisbecker {
1456b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1457cd84c2acSFrederic Weisbecker }
1458cd84c2acSFrederic Weisbecker 
1459b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1460cd84c2acSFrederic Weisbecker {
1461cd84c2acSFrederic Weisbecker 	struct dso *pos;
1462cd84c2acSFrederic Weisbecker 
1463b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1464cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
1465cd84c2acSFrederic Weisbecker 			return pos;
1466cd84c2acSFrederic Weisbecker 	return NULL;
1467cd84c2acSFrederic Weisbecker }
1468cd84c2acSFrederic Weisbecker 
146900a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name)
1470cd84c2acSFrederic Weisbecker {
1471b0da954aSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(&dsos__user, name);
1472cd84c2acSFrederic Weisbecker 
1473e4204992SArnaldo Carvalho de Melo 	if (!dso) {
147400a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1475cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1476b0da954aSArnaldo Carvalho de Melo 			dsos__add(&dsos__user, dso);
1477cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1478cfc10d3bSArnaldo Carvalho de Melo 		}
1479e4204992SArnaldo Carvalho de Melo 	}
1480cd84c2acSFrederic Weisbecker 
1481cd84c2acSFrederic Weisbecker 	return dso;
1482cd84c2acSFrederic Weisbecker }
1483cd84c2acSFrederic Weisbecker 
1484b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp)
1485cd84c2acSFrederic Weisbecker {
1486cd84c2acSFrederic Weisbecker 	struct dso *pos;
1487cd84c2acSFrederic Weisbecker 
148895011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
148995011c60SArnaldo Carvalho de Melo 		int i;
149095011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
149195011c60SArnaldo Carvalho de Melo 			dso__fprintf(pos, i, fp);
149295011c60SArnaldo Carvalho de Melo 	}
1493cd84c2acSFrederic Weisbecker }
1494cd84c2acSFrederic Weisbecker 
1495b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp)
1496b0da954aSArnaldo Carvalho de Melo {
1497b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__kernel, fp);
1498b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__user, fp);
1499b0da954aSArnaldo Carvalho de Melo }
1500b0da954aSArnaldo Carvalho de Melo 
1501b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
15029e03eb2dSArnaldo Carvalho de Melo {
15039e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
15049e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
15059e03eb2dSArnaldo Carvalho de Melo 
1506b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
15079e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
15089e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
15099e03eb2dSArnaldo Carvalho de Melo 	}
15109e03eb2dSArnaldo Carvalho de Melo 	return ret;
15119e03eb2dSArnaldo Carvalho de Melo }
15129e03eb2dSArnaldo Carvalho de Melo 
1513b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp)
1514b0da954aSArnaldo Carvalho de Melo {
1515b0da954aSArnaldo Carvalho de Melo 	return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1516b0da954aSArnaldo Carvalho de Melo 		__dsos__fprintf_buildid(&dsos__user, fp));
1517b0da954aSArnaldo Carvalho de Melo }
1518b0da954aSArnaldo Carvalho de Melo 
15199958e1f0SArnaldo Carvalho de Melo static int map_groups__create_kernel_map(struct map_groups *self, const char *vmlinux)
1520cd84c2acSFrederic Weisbecker {
15214e06255fSArnaldo Carvalho de Melo 	struct map *kmap;
152295011c60SArnaldo Carvalho de Melo 	struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1523cd84c2acSFrederic Weisbecker 
15242446042cSArnaldo Carvalho de Melo 	if (kernel == NULL)
1525c338aee8SArnaldo Carvalho de Melo 		return -1;
1526c338aee8SArnaldo Carvalho de Melo 
15274e06255fSArnaldo Carvalho de Melo 	kmap = map__new2(0, kernel, MAP__FUNCTION);
15284e06255fSArnaldo Carvalho de Melo 	if (kmap == NULL)
1529c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_dso;
1530c338aee8SArnaldo Carvalho de Melo 
15314e06255fSArnaldo Carvalho de Melo 	kmap->map_ip	   = kmap->unmap_ip = identity__map_ip;
15322446042cSArnaldo Carvalho de Melo 	kernel->short_name = "[kernel]";
1533c338aee8SArnaldo Carvalho de Melo 	kernel->kernel	   = 1;
1534cc612d81SArnaldo Carvalho de Melo 
153500a192b3SArnaldo Carvalho de Melo 	vdso = dso__new("[vdso]");
1536c338aee8SArnaldo Carvalho de Melo 	if (vdso == NULL)
1537c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_map;
15383610583cSArnaldo Carvalho de Melo 	dso__set_loaded(vdso, MAP__FUNCTION);
1539cd84c2acSFrederic Weisbecker 
15402446042cSArnaldo Carvalho de Melo 	if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
15412446042cSArnaldo Carvalho de Melo 				 sizeof(kernel->build_id)) == 0)
15422446042cSArnaldo Carvalho de Melo 		kernel->has_build_id = true;
15432446042cSArnaldo Carvalho de Melo 
15449958e1f0SArnaldo Carvalho de Melo 	map_groups__insert(self, kmap);
1545b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__kernel, kernel);
1546b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__user, vdso);
1547cd84c2acSFrederic Weisbecker 
1548c338aee8SArnaldo Carvalho de Melo 	return 0;
1549c338aee8SArnaldo Carvalho de Melo 
1550c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map:
15514e06255fSArnaldo Carvalho de Melo 	map__delete(kmap);
1552c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso:
1553c338aee8SArnaldo Carvalho de Melo 	dso__delete(kernel);
1554c338aee8SArnaldo Carvalho de Melo 	return -1;
15552446042cSArnaldo Carvalho de Melo }
15562446042cSArnaldo Carvalho de Melo 
1557cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
15582446042cSArnaldo Carvalho de Melo {
1559cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
1560cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
1561cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
1562cc612d81SArnaldo Carvalho de Melo 	}
1563cc612d81SArnaldo Carvalho de Melo 
1564cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
1565cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
1566cc612d81SArnaldo Carvalho de Melo }
1567cc612d81SArnaldo Carvalho de Melo 
1568cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
1569cc612d81SArnaldo Carvalho de Melo {
1570cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1571cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
1572cc612d81SArnaldo Carvalho de Melo 
1573cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
15742446042cSArnaldo Carvalho de Melo 		return -1;
15752446042cSArnaldo Carvalho de Melo 
1576cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
1577cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1578cc612d81SArnaldo Carvalho de Melo 		return -1;
1579cc612d81SArnaldo Carvalho de Melo 
1580cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1581cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1582cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1583cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1584cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1585cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1586cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1587cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1588cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1589cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1590cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1591cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1592cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1593cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1594cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1595cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1596cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1597cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1598cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1599cc612d81SArnaldo Carvalho de Melo 		 uts.release);
1600cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1601cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1602cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1603cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1604cc612d81SArnaldo Carvalho de Melo 
1605cc612d81SArnaldo Carvalho de Melo 	return 0;
1606cc612d81SArnaldo Carvalho de Melo 
1607cc612d81SArnaldo Carvalho de Melo out_fail:
1608cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1609cc612d81SArnaldo Carvalho de Melo 	return -1;
1610cc612d81SArnaldo Carvalho de Melo }
1611cc612d81SArnaldo Carvalho de Melo 
161295011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf)
1613cc612d81SArnaldo Carvalho de Melo {
1614b32d133aSArnaldo Carvalho de Melo 	const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1615b32d133aSArnaldo Carvalho de Melo 
161695011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
1617b32d133aSArnaldo Carvalho de Melo 	symbol__priv_size = pconf->priv_size;
16189958e1f0SArnaldo Carvalho de Melo 	map_groups__init(kmaps);
1619b32d133aSArnaldo Carvalho de Melo 
1620b32d133aSArnaldo Carvalho de Melo 	if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1621cc612d81SArnaldo Carvalho de Melo 		return -1;
1622cc612d81SArnaldo Carvalho de Melo 
16239958e1f0SArnaldo Carvalho de Melo 	if (map_groups__create_kernel_map(kmaps, pconf->vmlinux_name) < 0) {
1624cc612d81SArnaldo Carvalho de Melo 		vmlinux_path__exit();
1625cc612d81SArnaldo Carvalho de Melo 		return -1;
1626cc612d81SArnaldo Carvalho de Melo 	}
1627cc612d81SArnaldo Carvalho de Melo 
16289958e1f0SArnaldo Carvalho de Melo 	kmaps->use_modules = pconf->use_modules;
16299958e1f0SArnaldo Carvalho de Melo 	if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0)
163087f8ea4cSArnaldo Carvalho de Melo 		pr_debug("Failed to load list of modules in use, "
16316671cb16SArnaldo Carvalho de Melo 			 "continuing...\n");
163290c83218SArnaldo Carvalho de Melo 	/*
163390c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
163490c83218SArnaldo Carvalho de Melo 	 */
16359958e1f0SArnaldo Carvalho de Melo 	map_groups__fixup_end(kmaps);
16366671cb16SArnaldo Carvalho de Melo 	return 0;
1637cd84c2acSFrederic Weisbecker }
1638