xref: /linux/tools/perf/util/symbol.c (revision 9958e1f0aee632c3665162c9c93cf8fde8006a94)
186470930SIngo Molnar #include "util.h"
286470930SIngo Molnar #include "../perf.h"
386470930SIngo Molnar #include "string.h"
486470930SIngo Molnar #include "symbol.h"
5439d473bSArnaldo Carvalho de Melo #include "thread.h"
686470930SIngo Molnar 
78f28827aSFrederic Weisbecker #include "debug.h"
88f28827aSFrederic Weisbecker 
9b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h>
1086470930SIngo Molnar #include <libelf.h>
1186470930SIngo Molnar #include <gelf.h>
1286470930SIngo Molnar #include <elf.h>
13f1617b40SArnaldo Carvalho de Melo #include <limits.h>
14439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
152cdbc46dSPeter Zijlstra 
16c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
17c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
18c12e15e7SArnaldo Carvalho de Melo #endif
19c12e15e7SArnaldo Carvalho de Melo 
2094cb9e38SArnaldo Carvalho de Melo enum dso_origin {
2194cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_KERNEL = 0,
2294cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_JAVA_JIT,
2394cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_FEDORA,
2494cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_UBUNTU,
2594cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_BUILDID,
2694cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_DSO,
27439d473bSArnaldo Carvalho de Melo 	DSO__ORIG_KMODULE,
2894cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_NOT_FOUND,
2994cb9e38SArnaldo Carvalho de Melo };
3094cb9e38SArnaldo Carvalho de Melo 
31b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
32*9958e1f0SArnaldo 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,
36*9958e1f0SArnaldo 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 
46*9958e1f0SArnaldo Carvalho de Melo static struct map_groups kmaps_mem;
47*9958e1f0SArnaldo 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 
59fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
60af427bf5SArnaldo Carvalho de Melo {
61fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
622e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
63af427bf5SArnaldo Carvalho de Melo 
64af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
65af427bf5SArnaldo Carvalho de Melo 		return;
66af427bf5SArnaldo Carvalho de Melo 
672e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
682e538c4aSArnaldo Carvalho de Melo 
69af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
702e538c4aSArnaldo Carvalho de Melo 		prev = curr;
712e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
72af427bf5SArnaldo Carvalho de Melo 
73af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
74af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
75af427bf5SArnaldo Carvalho de Melo 	}
76af427bf5SArnaldo Carvalho de Melo 
772e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
782e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
792e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
802e538c4aSArnaldo Carvalho de Melo }
812e538c4aSArnaldo Carvalho de Melo 
82*9958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
83af427bf5SArnaldo Carvalho de Melo {
84af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
8595011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
86af427bf5SArnaldo Carvalho de Melo 
87af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
88af427bf5SArnaldo Carvalho de Melo 		return;
89af427bf5SArnaldo Carvalho de Melo 
90af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
91af427bf5SArnaldo Carvalho de Melo 
92af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
93af427bf5SArnaldo Carvalho de Melo 		prev = curr;
94af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
95af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
962e538c4aSArnaldo Carvalho de Melo 	}
9790c83218SArnaldo Carvalho de Melo 
9890c83218SArnaldo Carvalho de Melo 	/*
9990c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
10090c83218SArnaldo Carvalho de Melo 	 * last map final address.
10190c83218SArnaldo Carvalho de Melo 	 */
10290c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
103af427bf5SArnaldo Carvalho de Melo }
104af427bf5SArnaldo Carvalho de Melo 
105*9958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
10623ea4a3fSArnaldo Carvalho de Melo {
10723ea4a3fSArnaldo Carvalho de Melo 	int i;
10823ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
109*9958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
11023ea4a3fSArnaldo Carvalho de Melo }
11123ea4a3fSArnaldo Carvalho de Melo 
11200a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name)
11386470930SIngo Molnar {
11486470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
11536479484SArnaldo Carvalho de Melo 	struct symbol *self = zalloc(symbol__priv_size +
11636479484SArnaldo Carvalho de Melo 				     sizeof(*self) + namelen);
11736479484SArnaldo Carvalho de Melo 	if (self == NULL)
11886470930SIngo Molnar 		return NULL;
11986470930SIngo Molnar 
12036479484SArnaldo Carvalho de Melo 	if (symbol__priv_size)
12100a192b3SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol__priv_size;
12236479484SArnaldo Carvalho de Melo 
12386470930SIngo Molnar 	self->start = start;
1246cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
125e4204992SArnaldo Carvalho de Melo 
1266beba7adSArnaldo Carvalho de Melo 	pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
127e4204992SArnaldo Carvalho de Melo 
12886470930SIngo Molnar 	memcpy(self->name, name, namelen);
12986470930SIngo Molnar 
13086470930SIngo Molnar 	return self;
13186470930SIngo Molnar }
13286470930SIngo Molnar 
13300a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self)
13486470930SIngo Molnar {
13500a192b3SArnaldo Carvalho de Melo 	free(((void *)self) - symbol__priv_size);
13686470930SIngo Molnar }
13786470930SIngo Molnar 
13886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
13986470930SIngo Molnar {
14086470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
14186470930SIngo Molnar 		       self->start, self->end, self->name);
14286470930SIngo Molnar }
14386470930SIngo Molnar 
144cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name)
145cfc10d3bSArnaldo Carvalho de Melo {
146ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
147ef6ae724SArnaldo Carvalho de Melo 		return;
148cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
149cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
150cfc10d3bSArnaldo Carvalho de Melo }
151cfc10d3bSArnaldo Carvalho de Melo 
152cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
153cfc10d3bSArnaldo Carvalho de Melo {
154cfc10d3bSArnaldo Carvalho de Melo 	self->short_name = basename(self->long_name);
155cfc10d3bSArnaldo Carvalho de Melo }
156cfc10d3bSArnaldo Carvalho de Melo 
15700a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
15886470930SIngo Molnar {
15986470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
16086470930SIngo Molnar 
16186470930SIngo Molnar 	if (self != NULL) {
1626a4694a4SArnaldo Carvalho de Melo 		int i;
16386470930SIngo Molnar 		strcpy(self->name, name);
164cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
165439d473bSArnaldo Carvalho de Melo 		self->short_name = self->name;
1666a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
1676a4694a4SArnaldo Carvalho de Melo 			self->symbols[i] = RB_ROOT;
1686a4694a4SArnaldo Carvalho de Melo 		self->find_symbol = dso__find_symbol;
16952d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
17094cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1718d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
1728d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
17386470930SIngo Molnar 	}
17486470930SIngo Molnar 
17586470930SIngo Molnar 	return self;
17686470930SIngo Molnar }
17786470930SIngo Molnar 
178fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
17986470930SIngo Molnar {
18086470930SIngo Molnar 	struct symbol *pos;
181fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
18286470930SIngo Molnar 
18386470930SIngo Molnar 	while (next) {
18486470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
18586470930SIngo Molnar 		next = rb_next(&pos->rb_node);
186fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
18700a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
18886470930SIngo Molnar 	}
18986470930SIngo Molnar }
19086470930SIngo Molnar 
19186470930SIngo Molnar void dso__delete(struct dso *self)
19286470930SIngo Molnar {
1936a4694a4SArnaldo Carvalho de Melo 	int i;
1946a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1956a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
196439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
197439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
19886470930SIngo Molnar 	free(self);
19986470930SIngo Molnar }
20086470930SIngo Molnar 
2018d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2028d06367fSArnaldo Carvalho de Melo {
2038d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2048d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2058d06367fSArnaldo Carvalho de Melo }
2068d06367fSArnaldo Carvalho de Melo 
207fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
20886470930SIngo Molnar {
209fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
21086470930SIngo Molnar 	struct rb_node *parent = NULL;
2119cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
21286470930SIngo Molnar 	struct symbol *s;
21386470930SIngo Molnar 
21486470930SIngo Molnar 	while (*p != NULL) {
21586470930SIngo Molnar 		parent = *p;
21686470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
21786470930SIngo Molnar 		if (ip < s->start)
21886470930SIngo Molnar 			p = &(*p)->rb_left;
21986470930SIngo Molnar 		else
22086470930SIngo Molnar 			p = &(*p)->rb_right;
22186470930SIngo Molnar 	}
22286470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
223fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
22486470930SIngo Molnar }
22586470930SIngo Molnar 
226fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
22786470930SIngo Molnar {
22886470930SIngo Molnar 	struct rb_node *n;
22986470930SIngo Molnar 
23086470930SIngo Molnar 	if (self == NULL)
23186470930SIngo Molnar 		return NULL;
23286470930SIngo Molnar 
233fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
23486470930SIngo Molnar 
23586470930SIngo Molnar 	while (n) {
23686470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
23786470930SIngo Molnar 
23886470930SIngo Molnar 		if (ip < s->start)
23986470930SIngo Molnar 			n = n->rb_left;
24086470930SIngo Molnar 		else if (ip > s->end)
24186470930SIngo Molnar 			n = n->rb_right;
24286470930SIngo Molnar 		else
24386470930SIngo Molnar 			return s;
24486470930SIngo Molnar 	}
24586470930SIngo Molnar 
24686470930SIngo Molnar 	return NULL;
24786470930SIngo Molnar }
24886470930SIngo Molnar 
2496a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
250fcf1203aSArnaldo Carvalho de Melo {
2516a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
252fcf1203aSArnaldo Carvalho de Melo }
253fcf1203aSArnaldo Carvalho de Melo 
2548d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf)
2558d06367fSArnaldo Carvalho de Melo {
2568d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
2578d06367fSArnaldo Carvalho de Melo 	u8 *raw = self;
2588d06367fSArnaldo Carvalho de Melo 	int i;
2598d06367fSArnaldo Carvalho de Melo 
2608d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
2618d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
2628d06367fSArnaldo Carvalho de Melo 		++raw;
2638d06367fSArnaldo Carvalho de Melo 		bid += 2;
2648d06367fSArnaldo Carvalho de Melo 	}
2658d06367fSArnaldo Carvalho de Melo 
2668d06367fSArnaldo Carvalho de Melo 	return raw - self;
2678d06367fSArnaldo Carvalho de Melo }
2688d06367fSArnaldo Carvalho de Melo 
2699e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
27086470930SIngo Molnar {
2718d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2728d06367fSArnaldo Carvalho de Melo 
2738d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
2749e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
2759e03eb2dSArnaldo Carvalho de Melo }
2769e03eb2dSArnaldo Carvalho de Melo 
27795011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
2789e03eb2dSArnaldo Carvalho de Melo {
2799e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
2809e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
2819e03eb2dSArnaldo Carvalho de Melo 
2829e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
2836a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
28495011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
28586470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
28686470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
28786470930SIngo Molnar 	}
28886470930SIngo Molnar 
28986470930SIngo Molnar 	return ret;
29086470930SIngo Molnar }
29186470930SIngo Molnar 
2922e538c4aSArnaldo Carvalho de Melo /*
2932e538c4aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
2942e538c4aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
2952e538c4aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
2962e538c4aSArnaldo Carvalho de Melo  */
2974e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map)
29886470930SIngo Molnar {
29986470930SIngo Molnar 	char *line = NULL;
30086470930SIngo Molnar 	size_t n;
3014e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
30286470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
30386470930SIngo Molnar 
30486470930SIngo Molnar 	if (file == NULL)
30586470930SIngo Molnar 		goto out_failure;
30686470930SIngo Molnar 
30786470930SIngo Molnar 	while (!feof(file)) {
3089cffa8d5SPaul Mackerras 		u64 start;
30986470930SIngo Molnar 		struct symbol *sym;
31086470930SIngo Molnar 		int line_len, len;
31186470930SIngo Molnar 		char symbol_type;
3122e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
31386470930SIngo Molnar 
31486470930SIngo Molnar 		line_len = getline(&line, &n, file);
31586470930SIngo Molnar 		if (line_len < 0)
31686470930SIngo Molnar 			break;
31786470930SIngo Molnar 
31886470930SIngo Molnar 		if (!line)
31986470930SIngo Molnar 			goto out_failure;
32086470930SIngo Molnar 
32186470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
32286470930SIngo Molnar 
32386470930SIngo Molnar 		len = hex2u64(line, &start);
32486470930SIngo Molnar 
32586470930SIngo Molnar 		len++;
32686470930SIngo Molnar 		if (len + 2 >= line_len)
32786470930SIngo Molnar 			continue;
32886470930SIngo Molnar 
32986470930SIngo Molnar 		symbol_type = toupper(line[len]);
33086470930SIngo Molnar 		/*
33186470930SIngo Molnar 		 * We're interested only in code ('T'ext)
33286470930SIngo Molnar 		 */
33386470930SIngo Molnar 		if (symbol_type != 'T' && symbol_type != 'W')
33486470930SIngo Molnar 			continue;
335af427bf5SArnaldo Carvalho de Melo 
336af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
3372e538c4aSArnaldo Carvalho de Melo 		/*
3382e538c4aSArnaldo Carvalho de Melo 		 * Will fix up the end later, when we have all symbols sorted.
3392e538c4aSArnaldo Carvalho de Melo 		 */
34000a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, 0, symbol_name);
341af427bf5SArnaldo Carvalho de Melo 
3422e538c4aSArnaldo Carvalho de Melo 		if (sym == NULL)
3432e538c4aSArnaldo Carvalho de Melo 			goto out_delete_line;
34482164161SArnaldo Carvalho de Melo 		/*
34582164161SArnaldo Carvalho de Melo 		 * We will pass the symbols to the filter later, in
3464e06255fSArnaldo Carvalho de Melo 		 * map__split_kallsyms, when we have split the maps per module
34782164161SArnaldo Carvalho de Melo 		 */
3484e06255fSArnaldo Carvalho de Melo 		symbols__insert(root, sym);
3492e538c4aSArnaldo Carvalho de Melo 	}
3502e538c4aSArnaldo Carvalho de Melo 
3512e538c4aSArnaldo Carvalho de Melo 	free(line);
3522e538c4aSArnaldo Carvalho de Melo 	fclose(file);
3532e538c4aSArnaldo Carvalho de Melo 
3542e538c4aSArnaldo Carvalho de Melo 	return 0;
3552e538c4aSArnaldo Carvalho de Melo 
3562e538c4aSArnaldo Carvalho de Melo out_delete_line:
3572e538c4aSArnaldo Carvalho de Melo 	free(line);
3582e538c4aSArnaldo Carvalho de Melo out_failure:
3592e538c4aSArnaldo Carvalho de Melo 	return -1;
3602e538c4aSArnaldo Carvalho de Melo }
3612e538c4aSArnaldo Carvalho de Melo 
3622e538c4aSArnaldo Carvalho de Melo /*
3632e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
3642e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
3652e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
3662e538c4aSArnaldo Carvalho de Melo  */
367*9958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
368*9958e1f0SArnaldo Carvalho de Melo 			       struct map_groups *mg, symbol_filter_t filter)
3692e538c4aSArnaldo Carvalho de Melo {
3704e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
3712e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
3722e538c4aSArnaldo Carvalho de Melo 	int count = 0;
3734e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
3744e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
3752e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
3762e538c4aSArnaldo Carvalho de Melo 
3772e538c4aSArnaldo Carvalho de Melo 	while (next) {
3782e538c4aSArnaldo Carvalho de Melo 		char *module;
3792e538c4aSArnaldo Carvalho de Melo 
3802e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
3812e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
3822e538c4aSArnaldo Carvalho de Melo 
3832e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
3842e538c4aSArnaldo Carvalho de Melo 		if (module) {
385*9958e1f0SArnaldo Carvalho de Melo 			if (!mg->use_modules)
3861de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
3871de8e245SArnaldo Carvalho de Melo 
3882e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
3892e538c4aSArnaldo Carvalho de Melo 
3904e06255fSArnaldo Carvalho de Melo 			if (strcmp(self->name, module)) {
391*9958e1f0SArnaldo Carvalho de Melo 				curr_map = map_groups__find_by_name(mg, module);
3924e06255fSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
39395011c60SArnaldo Carvalho de Melo 					pr_debug("/proc/{kallsyms,modules} "
3946beba7adSArnaldo Carvalho de Melo 					         "inconsistency!\n");
395af427bf5SArnaldo Carvalho de Melo 					return -1;
396af427bf5SArnaldo Carvalho de Melo 				}
397af427bf5SArnaldo Carvalho de Melo 			}
39886470930SIngo Molnar 			/*
3992e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
4002e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
40186470930SIngo Molnar 			 */
4024e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
4034e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
4044e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
4052e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
4062e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
40786470930SIngo Molnar 
4082e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
4092e538c4aSArnaldo Carvalho de Melo 				 kernel_range++);
41086470930SIngo Molnar 
41100a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
4122e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
4132e538c4aSArnaldo Carvalho de Melo 				return -1;
4142e538c4aSArnaldo Carvalho de Melo 
4154e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
4162e538c4aSArnaldo Carvalho de Melo 			if (map == NULL) {
4172e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
4182e538c4aSArnaldo Carvalho de Melo 				return -1;
4192e538c4aSArnaldo Carvalho de Melo 			}
4202e538c4aSArnaldo Carvalho de Melo 
4214e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
422*9958e1f0SArnaldo Carvalho de Melo 			map_groups__insert(mg, curr_map);
4232e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
4242e538c4aSArnaldo Carvalho de Melo 		}
4252e538c4aSArnaldo Carvalho de Melo 
4264e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
4271de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
42800a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
4292e538c4aSArnaldo Carvalho de Melo 		} else {
4304e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
4314e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
4324e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
4332e538c4aSArnaldo Carvalho de Melo 			}
4349974f496SMike Galbraith 			count++;
4359974f496SMike Galbraith 		}
43686470930SIngo Molnar 	}
43786470930SIngo Molnar 
4389974f496SMike Galbraith 	return count;
43986470930SIngo Molnar }
44086470930SIngo Molnar 
4412e538c4aSArnaldo Carvalho de Melo 
4424e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map,
443*9958e1f0SArnaldo Carvalho de Melo 			      struct map_groups *mg, symbol_filter_t filter)
4442e538c4aSArnaldo Carvalho de Melo {
4454e06255fSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, map) < 0)
4462e538c4aSArnaldo Carvalho de Melo 		return -1;
4472e538c4aSArnaldo Carvalho de Melo 
4484e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
4494e06255fSArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_KERNEL;
4502e538c4aSArnaldo Carvalho de Melo 
451*9958e1f0SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, mg, filter);
45223ea4a3fSArnaldo Carvalho de Melo }
45323ea4a3fSArnaldo Carvalho de Melo 
45423ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp)
45523ea4a3fSArnaldo Carvalho de Melo {
45623ea4a3fSArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "Kernel maps:\n");
457*9958e1f0SArnaldo Carvalho de Melo 	printed += map_groups__fprintf_maps(kmaps, fp);
4586beba7adSArnaldo Carvalho de Melo 	return printed + fprintf(fp, "END kernel maps\n");
459af427bf5SArnaldo Carvalho de Melo }
460af427bf5SArnaldo Carvalho de Melo 
461439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
4626beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
46380d496beSPekka Enberg {
46480d496beSPekka Enberg 	char *line = NULL;
46580d496beSPekka Enberg 	size_t n;
46680d496beSPekka Enberg 	FILE *file;
46780d496beSPekka Enberg 	int nr_syms = 0;
46880d496beSPekka Enberg 
469439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
47080d496beSPekka Enberg 	if (file == NULL)
47180d496beSPekka Enberg 		goto out_failure;
47280d496beSPekka Enberg 
47380d496beSPekka Enberg 	while (!feof(file)) {
4749cffa8d5SPaul Mackerras 		u64 start, size;
47580d496beSPekka Enberg 		struct symbol *sym;
47680d496beSPekka Enberg 		int line_len, len;
47780d496beSPekka Enberg 
47880d496beSPekka Enberg 		line_len = getline(&line, &n, file);
47980d496beSPekka Enberg 		if (line_len < 0)
48080d496beSPekka Enberg 			break;
48180d496beSPekka Enberg 
48280d496beSPekka Enberg 		if (!line)
48380d496beSPekka Enberg 			goto out_failure;
48480d496beSPekka Enberg 
48580d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
48680d496beSPekka Enberg 
48780d496beSPekka Enberg 		len = hex2u64(line, &start);
48880d496beSPekka Enberg 
48980d496beSPekka Enberg 		len++;
49080d496beSPekka Enberg 		if (len + 2 >= line_len)
49180d496beSPekka Enberg 			continue;
49280d496beSPekka Enberg 
49380d496beSPekka Enberg 		len += hex2u64(line + len, &size);
49480d496beSPekka Enberg 
49580d496beSPekka Enberg 		len++;
49680d496beSPekka Enberg 		if (len + 2 >= line_len)
49780d496beSPekka Enberg 			continue;
49880d496beSPekka Enberg 
49900a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
50080d496beSPekka Enberg 
50180d496beSPekka Enberg 		if (sym == NULL)
50280d496beSPekka Enberg 			goto out_delete_line;
50380d496beSPekka Enberg 
504439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
50500a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
50680d496beSPekka Enberg 		else {
5076a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
50880d496beSPekka Enberg 			nr_syms++;
50980d496beSPekka Enberg 		}
51080d496beSPekka Enberg 	}
51180d496beSPekka Enberg 
51280d496beSPekka Enberg 	free(line);
51380d496beSPekka Enberg 	fclose(file);
51480d496beSPekka Enberg 
51580d496beSPekka Enberg 	return nr_syms;
51680d496beSPekka Enberg 
51780d496beSPekka Enberg out_delete_line:
51880d496beSPekka Enberg 	free(line);
51980d496beSPekka Enberg out_failure:
52080d496beSPekka Enberg 	return -1;
52180d496beSPekka Enberg }
52280d496beSPekka Enberg 
52386470930SIngo Molnar /**
52486470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
52586470930SIngo Molnar  *
52686470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
52783a0944fSIngo Molnar  * @idx: uint32_t idx
52886470930SIngo Molnar  * @sym: GElf_Sym iterator
52986470930SIngo Molnar  */
53083a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
53183a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
53283a0944fSIngo Molnar 	     idx < nr_syms; \
53383a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
53486470930SIngo Molnar 
53586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
53686470930SIngo Molnar {
53786470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
53886470930SIngo Molnar }
53986470930SIngo Molnar 
54086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
54186470930SIngo Molnar {
54286470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
54386470930SIngo Molnar 	       sym->st_name != 0 &&
54481833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
54586470930SIngo Molnar }
54686470930SIngo Molnar 
5476cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
5486cfcc53eSMike Galbraith {
5496cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
5506cfcc53eSMike Galbraith 		sym->st_name != 0 &&
5516cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
5526cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
5536cfcc53eSMike Galbraith }
5546cfcc53eSMike Galbraith 
5556cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
5566cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5576cfcc53eSMike Galbraith {
5586cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
5596cfcc53eSMike Galbraith }
5606cfcc53eSMike Galbraith 
5616cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
5626cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
5636cfcc53eSMike Galbraith {
5646cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
5656cfcc53eSMike Galbraith }
5666cfcc53eSMike Galbraith 
56786470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
56886470930SIngo Molnar 					const Elf_Data *symstrs)
56986470930SIngo Molnar {
57086470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
57186470930SIngo Molnar }
57286470930SIngo Molnar 
57386470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
57486470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
57583a0944fSIngo Molnar 				    size_t *idx)
57686470930SIngo Molnar {
57786470930SIngo Molnar 	Elf_Scn *sec = NULL;
57886470930SIngo Molnar 	size_t cnt = 1;
57986470930SIngo Molnar 
58086470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
58186470930SIngo Molnar 		char *str;
58286470930SIngo Molnar 
58386470930SIngo Molnar 		gelf_getshdr(sec, shp);
58486470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
58586470930SIngo Molnar 		if (!strcmp(name, str)) {
58683a0944fSIngo Molnar 			if (idx)
58783a0944fSIngo Molnar 				*idx = cnt;
58886470930SIngo Molnar 			break;
58986470930SIngo Molnar 		}
59086470930SIngo Molnar 		++cnt;
59186470930SIngo Molnar 	}
59286470930SIngo Molnar 
59386470930SIngo Molnar 	return sec;
59486470930SIngo Molnar }
59586470930SIngo Molnar 
59686470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
59786470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
59886470930SIngo Molnar 	     idx < nr_entries; \
59986470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
60086470930SIngo Molnar 
60186470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
60286470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
60386470930SIngo Molnar 	     idx < nr_entries; \
60486470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
60586470930SIngo Molnar 
606a25e46c4SArnaldo Carvalho de Melo /*
607a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
608a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
609a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
610a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
611a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
612a25e46c4SArnaldo Carvalho de Melo  */
61382164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
61482164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
61586470930SIngo Molnar {
61686470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
61786470930SIngo Molnar 	GElf_Sym sym;
6189cffa8d5SPaul Mackerras 	u64 plt_offset;
61986470930SIngo Molnar 	GElf_Shdr shdr_plt;
62086470930SIngo Molnar 	struct symbol *f;
621a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
62286470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
623a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
624a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
625a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
62686470930SIngo Molnar 	char sympltname[1024];
627a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
628a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
62986470930SIngo Molnar 
630439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
631a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
632a25e46c4SArnaldo Carvalho de Melo 		goto out;
633a25e46c4SArnaldo Carvalho de Melo 
63484087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
635a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
636a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
637a25e46c4SArnaldo Carvalho de Melo 
638a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
639a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
640a25e46c4SArnaldo Carvalho de Melo 
641a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
642a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
643a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
644a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
645a25e46c4SArnaldo Carvalho de Melo 
646a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
64786470930SIngo Molnar 					  ".rela.plt", NULL);
64886470930SIngo Molnar 	if (scn_plt_rel == NULL) {
649a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
65086470930SIngo Molnar 						  ".rel.plt", NULL);
65186470930SIngo Molnar 		if (scn_plt_rel == NULL)
652a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
65386470930SIngo Molnar 	}
65486470930SIngo Molnar 
655a25e46c4SArnaldo Carvalho de Melo 	err = -1;
65686470930SIngo Molnar 
657a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
658a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
659a25e46c4SArnaldo Carvalho de Melo 
660a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
661a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
66286470930SIngo Molnar 
66386470930SIngo Molnar 	/*
66483a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
66586470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
66686470930SIngo Molnar 	 */
66786470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
66886470930SIngo Molnar 	if (reldata == NULL)
669a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
67086470930SIngo Molnar 
67186470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
67286470930SIngo Molnar 	if (syms == NULL)
673a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
67486470930SIngo Molnar 
675a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
67686470930SIngo Molnar 	if (scn_symstrs == NULL)
677a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
67886470930SIngo Molnar 
67986470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
68086470930SIngo Molnar 	if (symstrs == NULL)
681a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
68286470930SIngo Molnar 
68386470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
68486470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
68586470930SIngo Molnar 
68686470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
68786470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
68886470930SIngo Molnar 
68986470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
69086470930SIngo Molnar 					   nr_rel_entries) {
69186470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
69286470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
69386470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
69486470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
69586470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
69686470930SIngo Molnar 
69786470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
69800a192b3SArnaldo Carvalho de Melo 					sympltname);
69986470930SIngo Molnar 			if (!f)
700a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
70186470930SIngo Molnar 
70282164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
70382164161SArnaldo Carvalho de Melo 				symbol__delete(f);
70482164161SArnaldo Carvalho de Melo 			else {
7056a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
70686470930SIngo Molnar 				++nr;
70786470930SIngo Molnar 			}
70882164161SArnaldo Carvalho de Melo 		}
70986470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
71086470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
71186470930SIngo Molnar 		elf_section__for_each_rel(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 			}
73086470930SIngo Molnar 		}
73182164161SArnaldo Carvalho de Melo 	}
73286470930SIngo Molnar 
733a25e46c4SArnaldo Carvalho de Melo 	err = 0;
734a25e46c4SArnaldo Carvalho de Melo out_elf_end:
735a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
736a25e46c4SArnaldo Carvalho de Melo out_close:
737a25e46c4SArnaldo Carvalho de Melo 	close(fd);
738a25e46c4SArnaldo Carvalho de Melo 
739a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
74086470930SIngo Molnar 		return nr;
741a25e46c4SArnaldo Carvalho de Melo out:
7426beba7adSArnaldo Carvalho de Melo 	pr_warning("%s: problems reading %s PLT info.\n",
743439d473bSArnaldo Carvalho de Melo 		   __func__, self->long_name);
744a25e46c4SArnaldo Carvalho de Melo 	return 0;
74586470930SIngo Molnar }
74686470930SIngo Molnar 
74795011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map,
748*9958e1f0SArnaldo Carvalho de Melo 			 struct map_groups *mg, const char *name, int fd,
74995011c60SArnaldo Carvalho de Melo 			 symbol_filter_t filter, int kernel, int kmodule)
75086470930SIngo Molnar {
7512e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
7522e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
7532e538c4aSArnaldo Carvalho de Melo 	size_t dso_name_len = strlen(self->short_name);
7546cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
75586470930SIngo Molnar 	uint32_t nr_syms;
75686470930SIngo Molnar 	int err = -1;
75783a0944fSIngo Molnar 	uint32_t idx;
75886470930SIngo Molnar 	GElf_Ehdr ehdr;
75986470930SIngo Molnar 	GElf_Shdr shdr;
76086470930SIngo Molnar 	Elf_Data *syms;
76186470930SIngo Molnar 	GElf_Sym sym;
762a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
76386470930SIngo Molnar 	Elf *elf;
764439d473bSArnaldo Carvalho de Melo 	int nr = 0;
76586470930SIngo Molnar 
76684087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
76786470930SIngo Molnar 	if (elf == NULL) {
7686beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
76986470930SIngo Molnar 		goto out_close;
77086470930SIngo Molnar 	}
77186470930SIngo Molnar 
77286470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
7736beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
77486470930SIngo Molnar 		goto out_elf_end;
77586470930SIngo Molnar 	}
77686470930SIngo Molnar 
77786470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
77886470930SIngo Molnar 	if (sec == NULL) {
779a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
780a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
78186470930SIngo Molnar 			goto out_elf_end;
78286470930SIngo Molnar 	}
78386470930SIngo Molnar 
78486470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
78586470930SIngo Molnar 	if (syms == NULL)
78686470930SIngo Molnar 		goto out_elf_end;
78786470930SIngo Molnar 
78886470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
78986470930SIngo Molnar 	if (sec == NULL)
79086470930SIngo Molnar 		goto out_elf_end;
79186470930SIngo Molnar 
79286470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
79386470930SIngo Molnar 	if (symstrs == NULL)
79486470930SIngo Molnar 		goto out_elf_end;
79586470930SIngo Molnar 
7966cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
7976cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
7986cfcc53eSMike Galbraith 		goto out_elf_end;
7996cfcc53eSMike Galbraith 
8006cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
8019b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
8026cfcc53eSMike Galbraith 		goto out_elf_end;
8036cfcc53eSMike Galbraith 
80486470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
80586470930SIngo Molnar 
806e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
807d20ff6bdSMike Galbraith 	if (!kernel) {
80830d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
80930d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
810f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
81130d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
812d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
813d20ff6bdSMike Galbraith 
81483a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
81586470930SIngo Molnar 		struct symbol *f;
81683a0944fSIngo Molnar 		const char *elf_name;
8172e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
8186cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
8196cfcc53eSMike Galbraith 		const char *section_name;
82086470930SIngo Molnar 
8216cfcc53eSMike Galbraith 		if (!is_label && !elf_sym__is_function(&sym))
82286470930SIngo Molnar 			continue;
82386470930SIngo Molnar 
82486470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
82586470930SIngo Molnar 		if (!sec)
82686470930SIngo Molnar 			goto out_elf_end;
82786470930SIngo Molnar 
82886470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
8296cfcc53eSMike Galbraith 
8306cfcc53eSMike Galbraith 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
8316cfcc53eSMike Galbraith 			continue;
8326cfcc53eSMike Galbraith 
8332e538c4aSArnaldo Carvalho de Melo 		elf_name = elf_sym__name(&sym, symstrs);
8346cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
83586470930SIngo Molnar 
8362e538c4aSArnaldo Carvalho de Melo 		if (kernel || kmodule) {
8372e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
8382e538c4aSArnaldo Carvalho de Melo 
8392e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
8402e538c4aSArnaldo Carvalho de Melo 				   curr_dso->short_name + dso_name_len) == 0)
8412e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
8422e538c4aSArnaldo Carvalho de Melo 
8432e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
8442e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
8452e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
8462e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
847af427bf5SArnaldo Carvalho de Melo 			}
848af427bf5SArnaldo Carvalho de Melo 
8492e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
8502e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
8512e538c4aSArnaldo Carvalho de Melo 
852*9958e1f0SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(mg, dso_name);
8532e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
8542e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
8552e538c4aSArnaldo Carvalho de Melo 
8562e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
8572e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
8582e538c4aSArnaldo Carvalho de Melo 
85900a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
8602e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
8612e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8623610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
8633610583cSArnaldo Carvalho de Melo 						     MAP__FUNCTION);
8642e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
8652e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
8662e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
8672e538c4aSArnaldo Carvalho de Melo 				}
868ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
869ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
8702e538c4aSArnaldo Carvalho de Melo 				curr_dso->origin = DSO__ORIG_KERNEL;
871*9958e1f0SArnaldo Carvalho de Melo 				map_groups__insert(kmaps, curr_map);
872b0da954aSArnaldo Carvalho de Melo 				dsos__add(&dsos__kernel, curr_dso);
8732e538c4aSArnaldo Carvalho de Melo 			} else
8742e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
8752e538c4aSArnaldo Carvalho de Melo 
8762e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
8772e538c4aSArnaldo Carvalho de Melo 		}
8782e538c4aSArnaldo Carvalho de Melo 
8792e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
8806beba7adSArnaldo Carvalho de Melo 			pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
8816beba7adSArnaldo Carvalho de Melo 				  "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
8826beba7adSArnaldo Carvalho de Melo 				  (u64)shdr.sh_addr, (u64)shdr.sh_offset);
88386470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
884af427bf5SArnaldo Carvalho de Melo 		}
88528ac909bSArnaldo Carvalho de Melo 		/*
88628ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
88728ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
88828ac909bSArnaldo Carvalho de Melo 		 * to it...
88928ac909bSArnaldo Carvalho de Melo 		 */
89083a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
89128ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
89283a0944fSIngo Molnar 			elf_name = demangled;
8932e538c4aSArnaldo Carvalho de Melo new_symbol:
89400a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
89528ac909bSArnaldo Carvalho de Melo 		free(demangled);
89686470930SIngo Molnar 		if (!f)
89786470930SIngo Molnar 			goto out_elf_end;
89886470930SIngo Molnar 
8992e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
90000a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
90186470930SIngo Molnar 		else {
9026a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
90386470930SIngo Molnar 			nr++;
90486470930SIngo Molnar 		}
90586470930SIngo Molnar 	}
90686470930SIngo Molnar 
9072e538c4aSArnaldo Carvalho de Melo 	/*
9082e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
9092e538c4aSArnaldo Carvalho de Melo 	 */
9102e538c4aSArnaldo Carvalho de Melo 	if (nr > 0)
9116a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
91286470930SIngo Molnar 	err = nr;
91386470930SIngo Molnar out_elf_end:
91486470930SIngo Molnar 	elf_end(elf);
91586470930SIngo Molnar out_close:
91686470930SIngo Molnar 	return err;
91786470930SIngo Molnar }
91886470930SIngo Molnar 
91978075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
92078075caaSArnaldo Carvalho de Melo {
92178075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
92278075caaSArnaldo Carvalho de Melo }
92378075caaSArnaldo Carvalho de Melo 
924b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head)
92557f395a7SFrederic Weisbecker {
926e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
92757f395a7SFrederic Weisbecker 	struct dso *pos;
92857f395a7SFrederic Weisbecker 
929b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
930e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
931e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
932e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
933e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
93457f395a7SFrederic Weisbecker 		}
93557f395a7SFrederic Weisbecker 
936e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
93757f395a7SFrederic Weisbecker }
93857f395a7SFrederic Weisbecker 
939b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void)
940b0da954aSArnaldo Carvalho de Melo {
9418b4825bfSArnaldo Carvalho de Melo 	bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
9428b4825bfSArnaldo Carvalho de Melo 	     ubuildids = __dsos__read_build_ids(&dsos__user);
9438b4825bfSArnaldo Carvalho de Melo 	return kbuildids || ubuildids;
944b0da954aSArnaldo Carvalho de Melo }
945b0da954aSArnaldo Carvalho de Melo 
946fd7a346eSArnaldo Carvalho de Melo /*
947fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
948fd7a346eSArnaldo Carvalho de Melo  */
949fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
950fd7a346eSArnaldo Carvalho de Melo 
9512643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
9524d1e00a8SArnaldo Carvalho de Melo {
9532643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
9544d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
9554d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
956fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
9574d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
958e57cfcdaSPekka Enberg 	Elf_Kind ek;
959fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
9604d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
9614d1e00a8SArnaldo Carvalho de Melo 
9622643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
9632643ce11SArnaldo Carvalho de Melo 		goto out;
9642643ce11SArnaldo Carvalho de Melo 
9652643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
9664d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
9674d1e00a8SArnaldo Carvalho de Melo 		goto out;
9684d1e00a8SArnaldo Carvalho de Melo 
96984087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
9704d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
9718d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
9724d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
9734d1e00a8SArnaldo Carvalho de Melo 	}
9744d1e00a8SArnaldo Carvalho de Melo 
975e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
976e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
977e57cfcdaSPekka Enberg 		goto out_elf_end;
978e57cfcdaSPekka Enberg 
9794d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
9806beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
9814d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
9824d1e00a8SArnaldo Carvalho de Melo 	}
9834d1e00a8SArnaldo Carvalho de Melo 
9842643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
9852643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
986fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
987fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
988fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
9894d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
9904d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
991fd7a346eSArnaldo Carvalho de Melo 	}
9924d1e00a8SArnaldo Carvalho de Melo 
993fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
994fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
9954d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
996fd7a346eSArnaldo Carvalho de Melo 
997fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
998fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
999fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1000fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1001fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1002fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1003fd7a346eSArnaldo Carvalho de Melo 
1004fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1005fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1006fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1007fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1008fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1009fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1010fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
10112643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1012fd7a346eSArnaldo Carvalho de Melo 				break;
1013fd7a346eSArnaldo Carvalho de Melo 			}
1014fd7a346eSArnaldo Carvalho de Melo 		}
1015fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1016fd7a346eSArnaldo Carvalho de Melo 	}
10172643ce11SArnaldo Carvalho de Melo out_elf_end:
10182643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
10192643ce11SArnaldo Carvalho de Melo out_close:
10202643ce11SArnaldo Carvalho de Melo 	close(fd);
10212643ce11SArnaldo Carvalho de Melo out:
10222643ce11SArnaldo Carvalho de Melo 	return err;
10232643ce11SArnaldo Carvalho de Melo }
10242643ce11SArnaldo Carvalho de Melo 
1025f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1026f1617b40SArnaldo Carvalho de Melo {
1027f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1028f1617b40SArnaldo Carvalho de Melo 
1029f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1030f1617b40SArnaldo Carvalho de Melo 		goto out;
1031f1617b40SArnaldo Carvalho de Melo 
1032f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1033f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1034f1617b40SArnaldo Carvalho de Melo 		goto out;
1035f1617b40SArnaldo Carvalho de Melo 
1036f1617b40SArnaldo Carvalho de Melo 	while (1) {
1037f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1038f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1039f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1040f1617b40SArnaldo Carvalho de Melo 
1041f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1042f1617b40SArnaldo Carvalho de Melo 			break;
1043f1617b40SArnaldo Carvalho de Melo 
1044fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1045fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1046f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1047f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1048f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1049f1617b40SArnaldo Carvalho de Melo 				break;
1050f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1051f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1052f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1053f1617b40SArnaldo Carvalho de Melo 					err = 0;
1054f1617b40SArnaldo Carvalho de Melo 					break;
1055f1617b40SArnaldo Carvalho de Melo 				}
1056f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1057f1617b40SArnaldo Carvalho de Melo 				break;
1058f1617b40SArnaldo Carvalho de Melo 		} else {
1059f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1060f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1061f1617b40SArnaldo Carvalho de Melo 				break;
1062f1617b40SArnaldo Carvalho de Melo 		}
1063f1617b40SArnaldo Carvalho de Melo 	}
1064f1617b40SArnaldo Carvalho de Melo 	close(fd);
1065f1617b40SArnaldo Carvalho de Melo out:
1066f1617b40SArnaldo Carvalho de Melo 	return err;
1067f1617b40SArnaldo Carvalho de Melo }
1068f1617b40SArnaldo Carvalho de Melo 
106994cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
107094cb9e38SArnaldo Carvalho de Melo {
107194cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
107294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
107394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
107494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
107594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
107694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
107794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1078439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
107994cb9e38SArnaldo Carvalho de Melo 	};
108094cb9e38SArnaldo Carvalho de Melo 
108194cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
108294cb9e38SArnaldo Carvalho de Melo 		return '!';
108394cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
108494cb9e38SArnaldo Carvalho de Melo }
108594cb9e38SArnaldo Carvalho de Melo 
10866beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
108786470930SIngo Molnar {
10884d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1089c338aee8SArnaldo Carvalho de Melo 	char *name;
1090d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
109186470930SIngo Molnar 	int ret = -1;
109286470930SIngo Molnar 	int fd;
109386470930SIngo Molnar 
10943610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
109566bd8424SArnaldo Carvalho de Melo 
1096c338aee8SArnaldo Carvalho de Melo 	if (self->kernel)
1097*9958e1f0SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, kmaps, filter);
1098c338aee8SArnaldo Carvalho de Melo 
1099c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
110086470930SIngo Molnar 	if (!name)
110186470930SIngo Molnar 		return -1;
110286470930SIngo Molnar 
110330d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1104f5812a7aSArnaldo Carvalho de Melo 
110594cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
11066beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
110794cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
110894cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
110994cb9e38SArnaldo Carvalho de Melo 		return ret;
111094cb9e38SArnaldo Carvalho de Melo 	}
111194cb9e38SArnaldo Carvalho de Melo 
111294cb9e38SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_FEDORA - 1;
111380d496beSPekka Enberg 
111486470930SIngo Molnar more:
111586470930SIngo Molnar 	do {
111694cb9e38SArnaldo Carvalho de Melo 		self->origin++;
111794cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
111894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1119439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1120439d473bSArnaldo Carvalho de Melo 				 self->long_name);
112186470930SIngo Molnar 			break;
112294cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1123439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1124439d473bSArnaldo Carvalho de Melo 				 self->long_name);
112586470930SIngo Molnar 			break;
112694cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1127d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1128d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1129d3379ab9SArnaldo Carvalho de Melo 				char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1130d3379ab9SArnaldo Carvalho de Melo 
1131d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1132d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
11334d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
11344d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1135d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1136d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
11378d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1138d3379ab9SArnaldo Carvalho de Melo 				break;
11394d1e00a8SArnaldo Carvalho de Melo 			}
114094cb9e38SArnaldo Carvalho de Melo 			self->origin++;
11414d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
114294cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1143439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
114486470930SIngo Molnar 			break;
114586470930SIngo Molnar 
114686470930SIngo Molnar 		default:
114786470930SIngo Molnar 			goto out;
114886470930SIngo Molnar 		}
114986470930SIngo Molnar 
11508d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1151d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1152d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
11538d06367fSArnaldo Carvalho de Melo 				goto more;
11548d06367fSArnaldo Carvalho de Melo compare_build_id:
115578075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
11568d06367fSArnaldo Carvalho de Melo 				goto more;
11578d06367fSArnaldo Carvalho de Melo 		}
11588d06367fSArnaldo Carvalho de Melo 
115986470930SIngo Molnar 		fd = open(name, O_RDONLY);
116086470930SIngo Molnar 	} while (fd < 0);
116186470930SIngo Molnar 
116295011c60SArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
116386470930SIngo Molnar 	close(fd);
116486470930SIngo Molnar 
116586470930SIngo Molnar 	/*
116686470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
116786470930SIngo Molnar 	 */
116886470930SIngo Molnar 	if (!ret)
116986470930SIngo Molnar 		goto more;
117086470930SIngo Molnar 
1171a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
117282164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1173a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1174a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1175a25e46c4SArnaldo Carvalho de Melo 	}
117686470930SIngo Molnar out:
117786470930SIngo Molnar 	free(name);
11781340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
11791340e6bbSArnaldo Carvalho de Melo 		return 0;
118086470930SIngo Molnar 	return ret;
118186470930SIngo Molnar }
118286470930SIngo Molnar 
1183*9958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *self, char *name)
1184439d473bSArnaldo Carvalho de Melo {
1185439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1186439d473bSArnaldo Carvalho de Melo 
118795011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
1188439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1189439d473bSArnaldo Carvalho de Melo 
1190439d473bSArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->name, name) == 0)
1191439d473bSArnaldo Carvalho de Melo 			return map;
1192439d473bSArnaldo Carvalho de Melo 	}
1193439d473bSArnaldo Carvalho de Melo 
1194439d473bSArnaldo Carvalho de Melo 	return NULL;
1195439d473bSArnaldo Carvalho de Melo }
1196439d473bSArnaldo Carvalho de Melo 
1197c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname)
11986cfcc53eSMike Galbraith {
1199439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
1200439d473bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dirname);
12016cfcc53eSMike Galbraith 
1202439d473bSArnaldo Carvalho de Melo 	if (!dir) {
120387f8ea4cSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1204439d473bSArnaldo Carvalho de Melo 		return -1;
1205439d473bSArnaldo Carvalho de Melo 	}
12066cfcc53eSMike Galbraith 
1207439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1208439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1209439d473bSArnaldo Carvalho de Melo 
1210439d473bSArnaldo Carvalho de Melo 		if (dent->d_type == DT_DIR) {
1211439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1212439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1213439d473bSArnaldo Carvalho de Melo 				continue;
1214439d473bSArnaldo Carvalho de Melo 
1215439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1216439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1217c338aee8SArnaldo Carvalho de Melo 			if (dsos__set_modules_path_dir(path) < 0)
1218439d473bSArnaldo Carvalho de Melo 				goto failure;
1219439d473bSArnaldo Carvalho de Melo 		} else {
1220439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1221439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1222439d473bSArnaldo Carvalho de Melo 			struct map *map;
1223cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1224439d473bSArnaldo Carvalho de Melo 
1225439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1226439d473bSArnaldo Carvalho de Melo 				continue;
1227439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1228439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1229439d473bSArnaldo Carvalho de Melo 
1230a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
1231*9958e1f0SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(kmaps, dso_name);
1232439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1233439d473bSArnaldo Carvalho de Melo 				continue;
1234439d473bSArnaldo Carvalho de Melo 
1235439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1236439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1237439d473bSArnaldo Carvalho de Melo 
1238cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1239cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1240439d473bSArnaldo Carvalho de Melo 				goto failure;
1241cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1242439d473bSArnaldo Carvalho de Melo 		}
1243439d473bSArnaldo Carvalho de Melo 	}
1244439d473bSArnaldo Carvalho de Melo 
1245c338aee8SArnaldo Carvalho de Melo 	return 0;
1246439d473bSArnaldo Carvalho de Melo failure:
1247439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1248439d473bSArnaldo Carvalho de Melo 	return -1;
1249439d473bSArnaldo Carvalho de Melo }
1250439d473bSArnaldo Carvalho de Melo 
1251c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void)
1252439d473bSArnaldo Carvalho de Melo {
1253439d473bSArnaldo Carvalho de Melo 	struct utsname uts;
1254439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1255439d473bSArnaldo Carvalho de Melo 
1256439d473bSArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
1257439d473bSArnaldo Carvalho de Melo 		return -1;
1258439d473bSArnaldo Carvalho de Melo 
1259439d473bSArnaldo Carvalho de Melo 	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1260439d473bSArnaldo Carvalho de Melo 		 uts.release);
1261439d473bSArnaldo Carvalho de Melo 
1262c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path_dir(modules_path);
1263439d473bSArnaldo Carvalho de Melo }
12646cfcc53eSMike Galbraith 
12656cfcc53eSMike Galbraith /*
1266439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1267439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1268439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
12696cfcc53eSMike Galbraith  */
12703610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1271439d473bSArnaldo Carvalho de Melo {
1272439d473bSArnaldo Carvalho de Melo 	struct map *self = malloc(sizeof(*self));
12736cfcc53eSMike Galbraith 
1274439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1275439d473bSArnaldo Carvalho de Melo 		/*
1276afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1277439d473bSArnaldo Carvalho de Melo 		 */
12783610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1279439d473bSArnaldo Carvalho de Melo 	}
1280afb7b4f0SArnaldo Carvalho de Melo 
1281439d473bSArnaldo Carvalho de Melo 	return self;
1282439d473bSArnaldo Carvalho de Melo }
1283439d473bSArnaldo Carvalho de Melo 
1284*9958e1f0SArnaldo Carvalho de Melo static int map_groups__create_module_maps(struct map_groups *self)
1285439d473bSArnaldo Carvalho de Melo {
1286439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1287439d473bSArnaldo Carvalho de Melo 	size_t n;
1288439d473bSArnaldo Carvalho de Melo 	FILE *file = fopen("/proc/modules", "r");
1289439d473bSArnaldo Carvalho de Melo 	struct map *map;
1290439d473bSArnaldo Carvalho de Melo 
1291439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1292439d473bSArnaldo Carvalho de Melo 		return -1;
1293439d473bSArnaldo Carvalho de Melo 
1294439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1295439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1296439d473bSArnaldo Carvalho de Melo 		u64 start;
1297439d473bSArnaldo Carvalho de Melo 		struct dso *dso;
1298439d473bSArnaldo Carvalho de Melo 		char *sep;
1299439d473bSArnaldo Carvalho de Melo 		int line_len;
1300439d473bSArnaldo Carvalho de Melo 
1301439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1302439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
13036cfcc53eSMike Galbraith 			break;
13046cfcc53eSMike Galbraith 
1305439d473bSArnaldo Carvalho de Melo 		if (!line)
1306439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1307439d473bSArnaldo Carvalho de Melo 
1308439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1309439d473bSArnaldo Carvalho de Melo 
1310439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1311439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1312439d473bSArnaldo Carvalho de Melo 			continue;
1313439d473bSArnaldo Carvalho de Melo 
1314439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1315439d473bSArnaldo Carvalho de Melo 
1316439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1317439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1318439d473bSArnaldo Carvalho de Melo 			continue;
1319439d473bSArnaldo Carvalho de Melo 
1320439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1321439d473bSArnaldo Carvalho de Melo 
1322439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
132300a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1324439d473bSArnaldo Carvalho de Melo 
1325439d473bSArnaldo Carvalho de Melo 		if (dso == NULL)
1326439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1327439d473bSArnaldo Carvalho de Melo 
13283610583cSArnaldo Carvalho de Melo 		map = map__new2(start, dso, MAP__FUNCTION);
1329439d473bSArnaldo Carvalho de Melo 		if (map == NULL) {
1330439d473bSArnaldo Carvalho de Melo 			dso__delete(dso);
1331439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
13326cfcc53eSMike Galbraith 		}
13336cfcc53eSMike Galbraith 
1334f1617b40SArnaldo Carvalho de Melo 		snprintf(name, sizeof(name),
1335f1617b40SArnaldo Carvalho de Melo 			 "/sys/module/%s/notes/.note.gnu.build-id", line);
1336f1617b40SArnaldo Carvalho de Melo 		if (sysfs__read_build_id(name, dso->build_id,
1337f1617b40SArnaldo Carvalho de Melo 					 sizeof(dso->build_id)) == 0)
1338f1617b40SArnaldo Carvalho de Melo 			dso->has_build_id = true;
1339f1617b40SArnaldo Carvalho de Melo 
1340439d473bSArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1341*9958e1f0SArnaldo Carvalho de Melo 		map_groups__insert(self, map);
1342b0da954aSArnaldo Carvalho de Melo 		dsos__add(&dsos__kernel, dso);
13436cfcc53eSMike Galbraith 	}
13446cfcc53eSMike Galbraith 
1345439d473bSArnaldo Carvalho de Melo 	free(line);
1346439d473bSArnaldo Carvalho de Melo 	fclose(file);
1347439d473bSArnaldo Carvalho de Melo 
1348c338aee8SArnaldo Carvalho de Melo 	return dsos__set_modules_path();
1349439d473bSArnaldo Carvalho de Melo 
1350439d473bSArnaldo Carvalho de Melo out_delete_line:
1351439d473bSArnaldo Carvalho de Melo 	free(line);
1352439d473bSArnaldo Carvalho de Melo out_failure:
1353439d473bSArnaldo Carvalho de Melo 	return -1;
13546cfcc53eSMike Galbraith }
13556cfcc53eSMike Galbraith 
1356*9958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
1357*9958e1f0SArnaldo Carvalho de Melo 			     struct map_groups *mg,
13586beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
135986470930SIngo Molnar {
1360fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
136186470930SIngo Molnar 
1362fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1363fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
136466bd8424SArnaldo Carvalho de Melo 
1365fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1366fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1367fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1368fbd733b8SArnaldo Carvalho de Melo 			return -1;
1369fbd733b8SArnaldo Carvalho de Melo 		}
1370fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1371fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1372fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1373fbd733b8SArnaldo Carvalho de Melo 
1374fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1375fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1376fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1377fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1378fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1379fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1380fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1381fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1382fbd733b8SArnaldo Carvalho de Melo 			return -1;
1383fbd733b8SArnaldo Carvalho de Melo 		}
1384fbd733b8SArnaldo Carvalho de Melo 	}
1385fbd733b8SArnaldo Carvalho de Melo 
1386fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
138786470930SIngo Molnar 	if (fd < 0)
138886470930SIngo Molnar 		return -1;
138986470930SIngo Molnar 
13903610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
1391*9958e1f0SArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0);
139286470930SIngo Molnar 	close(fd);
139386470930SIngo Molnar 
139486470930SIngo Molnar 	return err;
139586470930SIngo Molnar }
139686470930SIngo Molnar 
1397c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
1398*9958e1f0SArnaldo Carvalho de Melo 				struct map_groups *mg, symbol_filter_t filter)
139986470930SIngo Molnar {
1400cc612d81SArnaldo Carvalho de Melo 	int err;
1401cc612d81SArnaldo Carvalho de Melo 	bool is_kallsyms;
1402439d473bSArnaldo Carvalho de Melo 
1403cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
1404cc612d81SArnaldo Carvalho de Melo 		int i;
1405cc612d81SArnaldo Carvalho de Melo 		pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1406cc612d81SArnaldo Carvalho de Melo 			 vmlinux_path__nr_entries);
1407cc612d81SArnaldo Carvalho de Melo 		for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1408*9958e1f0SArnaldo Carvalho de Melo 			err = dso__load_vmlinux(self, map, mg,
140995011c60SArnaldo Carvalho de Melo 						vmlinux_path[i], filter);
1410cc612d81SArnaldo Carvalho de Melo 			if (err > 0) {
1411cc612d81SArnaldo Carvalho de Melo 				pr_debug("Using %s for symbols\n",
1412cc612d81SArnaldo Carvalho de Melo 					 vmlinux_path[i]);
1413cc612d81SArnaldo Carvalho de Melo 				dso__set_long_name(self,
1414cc612d81SArnaldo Carvalho de Melo 						   strdup(vmlinux_path[i]));
1415cc612d81SArnaldo Carvalho de Melo 				goto out_fixup;
1416cc612d81SArnaldo Carvalho de Melo 			}
1417cc612d81SArnaldo Carvalho de Melo 		}
1418cc612d81SArnaldo Carvalho de Melo 	}
1419cc612d81SArnaldo Carvalho de Melo 
1420cc612d81SArnaldo Carvalho de Melo 	is_kallsyms = self->long_name[0] == '[';
1421cc612d81SArnaldo Carvalho de Melo 	if (is_kallsyms)
1422cc612d81SArnaldo Carvalho de Melo 		goto do_kallsyms;
1423cc612d81SArnaldo Carvalho de Melo 
1424*9958e1f0SArnaldo Carvalho de Melo 	err = dso__load_vmlinux(self, map, mg, self->long_name, filter);
1425ef6ae724SArnaldo Carvalho de Melo 	if (err <= 0) {
1426cc612d81SArnaldo Carvalho de Melo 		pr_info("The file %s cannot be used, "
1427cc612d81SArnaldo Carvalho de Melo 			"trying to use /proc/kallsyms...", self->long_name);
1428cc612d81SArnaldo Carvalho de Melo do_kallsyms:
1429*9958e1f0SArnaldo Carvalho de Melo 		err = dso__load_kallsyms(self, map, mg, filter);
1430cc612d81SArnaldo Carvalho de Melo 		if (err > 0 && !is_kallsyms)
1431ef6ae724SArnaldo Carvalho de Melo                         dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1432ef6ae724SArnaldo Carvalho de Melo 	}
143386470930SIngo Molnar 
1434439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1435cc612d81SArnaldo Carvalho de Melo out_fixup:
14366a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
14376a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1438439d473bSArnaldo Carvalho de Melo 	}
143994cb9e38SArnaldo Carvalho de Melo 
144086470930SIngo Molnar 	return err;
144186470930SIngo Molnar }
144286470930SIngo Molnar 
1443b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user);
1444b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel);
1445cd84c2acSFrederic Weisbecker struct dso *vdso;
1446cd84c2acSFrederic Weisbecker 
1447b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1448cd84c2acSFrederic Weisbecker {
1449b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1450cd84c2acSFrederic Weisbecker }
1451cd84c2acSFrederic Weisbecker 
1452b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1453cd84c2acSFrederic Weisbecker {
1454cd84c2acSFrederic Weisbecker 	struct dso *pos;
1455cd84c2acSFrederic Weisbecker 
1456b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1457cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
1458cd84c2acSFrederic Weisbecker 			return pos;
1459cd84c2acSFrederic Weisbecker 	return NULL;
1460cd84c2acSFrederic Weisbecker }
1461cd84c2acSFrederic Weisbecker 
146200a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name)
1463cd84c2acSFrederic Weisbecker {
1464b0da954aSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(&dsos__user, name);
1465cd84c2acSFrederic Weisbecker 
1466e4204992SArnaldo Carvalho de Melo 	if (!dso) {
146700a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1468cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1469b0da954aSArnaldo Carvalho de Melo 			dsos__add(&dsos__user, dso);
1470cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1471cfc10d3bSArnaldo Carvalho de Melo 		}
1472e4204992SArnaldo Carvalho de Melo 	}
1473cd84c2acSFrederic Weisbecker 
1474cd84c2acSFrederic Weisbecker 	return dso;
1475cd84c2acSFrederic Weisbecker }
1476cd84c2acSFrederic Weisbecker 
1477b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp)
1478cd84c2acSFrederic Weisbecker {
1479cd84c2acSFrederic Weisbecker 	struct dso *pos;
1480cd84c2acSFrederic Weisbecker 
148195011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
148295011c60SArnaldo Carvalho de Melo 		int i;
148395011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
148495011c60SArnaldo Carvalho de Melo 			dso__fprintf(pos, i, fp);
148595011c60SArnaldo Carvalho de Melo 	}
1486cd84c2acSFrederic Weisbecker }
1487cd84c2acSFrederic Weisbecker 
1488b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp)
1489b0da954aSArnaldo Carvalho de Melo {
1490b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__kernel, fp);
1491b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__user, fp);
1492b0da954aSArnaldo Carvalho de Melo }
1493b0da954aSArnaldo Carvalho de Melo 
1494b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
14959e03eb2dSArnaldo Carvalho de Melo {
14969e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
14979e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
14989e03eb2dSArnaldo Carvalho de Melo 
1499b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
15009e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
15019e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
15029e03eb2dSArnaldo Carvalho de Melo 	}
15039e03eb2dSArnaldo Carvalho de Melo 	return ret;
15049e03eb2dSArnaldo Carvalho de Melo }
15059e03eb2dSArnaldo Carvalho de Melo 
1506b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp)
1507b0da954aSArnaldo Carvalho de Melo {
1508b0da954aSArnaldo Carvalho de Melo 	return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1509b0da954aSArnaldo Carvalho de Melo 		__dsos__fprintf_buildid(&dsos__user, fp));
1510b0da954aSArnaldo Carvalho de Melo }
1511b0da954aSArnaldo Carvalho de Melo 
1512*9958e1f0SArnaldo Carvalho de Melo static int map_groups__create_kernel_map(struct map_groups *self, const char *vmlinux)
1513cd84c2acSFrederic Weisbecker {
15144e06255fSArnaldo Carvalho de Melo 	struct map *kmap;
151595011c60SArnaldo Carvalho de Melo 	struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1516cd84c2acSFrederic Weisbecker 
15172446042cSArnaldo Carvalho de Melo 	if (kernel == NULL)
1518c338aee8SArnaldo Carvalho de Melo 		return -1;
1519c338aee8SArnaldo Carvalho de Melo 
15204e06255fSArnaldo Carvalho de Melo 	kmap = map__new2(0, kernel, MAP__FUNCTION);
15214e06255fSArnaldo Carvalho de Melo 	if (kmap == NULL)
1522c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_dso;
1523c338aee8SArnaldo Carvalho de Melo 
15244e06255fSArnaldo Carvalho de Melo 	kmap->map_ip	   = kmap->unmap_ip = identity__map_ip;
15252446042cSArnaldo Carvalho de Melo 	kernel->short_name = "[kernel]";
1526c338aee8SArnaldo Carvalho de Melo 	kernel->kernel	   = 1;
1527cc612d81SArnaldo Carvalho de Melo 
152800a192b3SArnaldo Carvalho de Melo 	vdso = dso__new("[vdso]");
1529c338aee8SArnaldo Carvalho de Melo 	if (vdso == NULL)
1530c338aee8SArnaldo Carvalho de Melo 		goto out_delete_kernel_map;
15313610583cSArnaldo Carvalho de Melo 	dso__set_loaded(vdso, MAP__FUNCTION);
1532cd84c2acSFrederic Weisbecker 
15332446042cSArnaldo Carvalho de Melo 	if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
15342446042cSArnaldo Carvalho de Melo 				 sizeof(kernel->build_id)) == 0)
15352446042cSArnaldo Carvalho de Melo 		kernel->has_build_id = true;
15362446042cSArnaldo Carvalho de Melo 
1537*9958e1f0SArnaldo Carvalho de Melo 	map_groups__insert(self, kmap);
1538b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__kernel, kernel);
1539b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__user, vdso);
1540cd84c2acSFrederic Weisbecker 
1541c338aee8SArnaldo Carvalho de Melo 	return 0;
1542c338aee8SArnaldo Carvalho de Melo 
1543c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map:
15444e06255fSArnaldo Carvalho de Melo 	map__delete(kmap);
1545c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso:
1546c338aee8SArnaldo Carvalho de Melo 	dso__delete(kernel);
1547c338aee8SArnaldo Carvalho de Melo 	return -1;
15482446042cSArnaldo Carvalho de Melo }
15492446042cSArnaldo Carvalho de Melo 
1550cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
15512446042cSArnaldo Carvalho de Melo {
1552cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
1553cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
1554cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
1555cc612d81SArnaldo Carvalho de Melo 	}
1556cc612d81SArnaldo Carvalho de Melo 
1557cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
1558cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
1559cc612d81SArnaldo Carvalho de Melo }
1560cc612d81SArnaldo Carvalho de Melo 
1561cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
1562cc612d81SArnaldo Carvalho de Melo {
1563cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1564cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
1565cc612d81SArnaldo Carvalho de Melo 
1566cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
15672446042cSArnaldo Carvalho de Melo 		return -1;
15682446042cSArnaldo Carvalho de Melo 
1569cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
1570cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1571cc612d81SArnaldo Carvalho de Melo 		return -1;
1572cc612d81SArnaldo Carvalho de Melo 
1573cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1574cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1575cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1576cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1577cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1578cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1579cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1580cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1581cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1582cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1583cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1584cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1585cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1586cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1587cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1588cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1589cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1590cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1591cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1592cc612d81SArnaldo Carvalho de Melo 		 uts.release);
1593cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1594cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1595cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1596cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1597cc612d81SArnaldo Carvalho de Melo 
1598cc612d81SArnaldo Carvalho de Melo 	return 0;
1599cc612d81SArnaldo Carvalho de Melo 
1600cc612d81SArnaldo Carvalho de Melo out_fail:
1601cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1602cc612d81SArnaldo Carvalho de Melo 	return -1;
1603cc612d81SArnaldo Carvalho de Melo }
1604cc612d81SArnaldo Carvalho de Melo 
160595011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf)
1606cc612d81SArnaldo Carvalho de Melo {
1607b32d133aSArnaldo Carvalho de Melo 	const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1608b32d133aSArnaldo Carvalho de Melo 
160995011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
1610b32d133aSArnaldo Carvalho de Melo 	symbol__priv_size = pconf->priv_size;
1611*9958e1f0SArnaldo Carvalho de Melo 	map_groups__init(kmaps);
1612b32d133aSArnaldo Carvalho de Melo 
1613b32d133aSArnaldo Carvalho de Melo 	if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1614cc612d81SArnaldo Carvalho de Melo 		return -1;
1615cc612d81SArnaldo Carvalho de Melo 
1616*9958e1f0SArnaldo Carvalho de Melo 	if (map_groups__create_kernel_map(kmaps, pconf->vmlinux_name) < 0) {
1617cc612d81SArnaldo Carvalho de Melo 		vmlinux_path__exit();
1618cc612d81SArnaldo Carvalho de Melo 		return -1;
1619cc612d81SArnaldo Carvalho de Melo 	}
1620cc612d81SArnaldo Carvalho de Melo 
1621*9958e1f0SArnaldo Carvalho de Melo 	kmaps->use_modules = pconf->use_modules;
1622*9958e1f0SArnaldo Carvalho de Melo 	if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0)
162387f8ea4cSArnaldo Carvalho de Melo 		pr_debug("Failed to load list of modules in use, "
16246671cb16SArnaldo Carvalho de Melo 			 "continuing...\n");
162590c83218SArnaldo Carvalho de Melo 	/*
162690c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
162790c83218SArnaldo Carvalho de Melo 	 */
1628*9958e1f0SArnaldo Carvalho de Melo 	map_groups__fixup_end(kmaps);
16296671cb16SArnaldo Carvalho de Melo 	return 0;
1630cd84c2acSFrederic Weisbecker }
1631