xref: /linux/tools/perf/util/symbol.c (revision 0ab061cd523a7f2dbf1b59aab0542cb0ab2e4633)
15aab621bSArnaldo Carvalho de Melo #define _GNU_SOURCE
25aab621bSArnaldo Carvalho de Melo #include <ctype.h>
35aab621bSArnaldo Carvalho de Melo #include <dirent.h>
45aab621bSArnaldo Carvalho de Melo #include <errno.h>
55aab621bSArnaldo Carvalho de Melo #include <libgen.h>
65aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
75aab621bSArnaldo Carvalho de Melo #include <stdio.h>
85aab621bSArnaldo Carvalho de Melo #include <string.h>
95aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
105aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
115aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
125aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
135aab621bSArnaldo Carvalho de Melo #include <unistd.h>
1486470930SIngo Molnar #include "symbol.h"
155aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1686470930SIngo Molnar 
1786470930SIngo Molnar #include <libelf.h>
1886470930SIngo Molnar #include <gelf.h>
1986470930SIngo Molnar #include <elf.h>
20f1617b40SArnaldo Carvalho de Melo #include <limits.h>
21439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
222cdbc46dSPeter Zijlstra 
23c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
24c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
25c12e15e7SArnaldo Carvalho de Melo #endif
26c12e15e7SArnaldo Carvalho de Melo 
27b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
283610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
29c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
309de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
31a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
32a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
33cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
34cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
35439d473bSArnaldo Carvalho de Melo 
3675be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
37d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
38b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
39b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
40b32d133aSArnaldo Carvalho de Melo };
41b32d133aSArnaldo Carvalho de Melo 
423610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
433610583cSArnaldo Carvalho de Melo {
443610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
453610583cSArnaldo Carvalho de Melo }
463610583cSArnaldo Carvalho de Melo 
4779406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type)
4879406cd7SArnaldo Carvalho de Melo {
4979406cd7SArnaldo Carvalho de Melo 	return self->sorted_by_name & (1 << type);
5079406cd7SArnaldo Carvalho de Melo }
5179406cd7SArnaldo Carvalho de Melo 
5279406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
5379406cd7SArnaldo Carvalho de Melo {
5479406cd7SArnaldo Carvalho de Melo 	self->sorted_by_name |= (1 << type);
5579406cd7SArnaldo Carvalho de Melo }
5679406cd7SArnaldo Carvalho de Melo 
5736a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
586893d4eeSArnaldo Carvalho de Melo {
596893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
606893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
616893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
62f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
63f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
646893d4eeSArnaldo Carvalho de Melo 	default:
656893d4eeSArnaldo Carvalho de Melo 		return false;
666893d4eeSArnaldo Carvalho de Melo 	}
676893d4eeSArnaldo Carvalho de Melo }
686893d4eeSArnaldo 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;
1255aab621bSArnaldo Carvalho de Melo 	struct symbol *self = calloc(1, (symbol_conf.priv_size +
1265aab621bSArnaldo Carvalho de Melo 					 sizeof(*self) + namelen));
12736479484SArnaldo Carvalho de Melo 	if (self == NULL)
12886470930SIngo Molnar 		return NULL;
12986470930SIngo Molnar 
13075be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
13175be6cf4SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol_conf.priv_size;
13236479484SArnaldo Carvalho de Melo 
13386470930SIngo Molnar 	self->start = start;
1346cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
135e4204992SArnaldo Carvalho de Melo 
13629a9f66dSArnaldo Carvalho de Melo 	pr_debug4("%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 
143628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self)
14486470930SIngo Molnar {
14575be6cf4SArnaldo Carvalho de Melo 	free(((void *)self) - symbol_conf.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 
154b7cece76SArnaldo Carvalho de Melo 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 
162b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name)
163b63be8d7SArnaldo Carvalho de Melo {
164b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
165b63be8d7SArnaldo Carvalho de Melo 		return;
166b63be8d7SArnaldo Carvalho de Melo 	self->short_name = name;
167b63be8d7SArnaldo Carvalho de Melo 	self->short_name_len = strlen(name);
168b63be8d7SArnaldo Carvalho de Melo }
169b63be8d7SArnaldo Carvalho de Melo 
170cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
171cfc10d3bSArnaldo Carvalho de Melo {
172b63be8d7SArnaldo Carvalho de Melo 	dso__set_short_name(self, basename(self->long_name));
173cfc10d3bSArnaldo Carvalho de Melo }
174cfc10d3bSArnaldo Carvalho de Melo 
17500a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
17686470930SIngo Molnar {
1775aab621bSArnaldo Carvalho de Melo 	struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
17886470930SIngo Molnar 
17986470930SIngo Molnar 	if (self != NULL) {
1806a4694a4SArnaldo Carvalho de Melo 		int i;
18186470930SIngo Molnar 		strcpy(self->name, name);
182cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
183b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, self->name);
1846a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
18579406cd7SArnaldo Carvalho de Melo 			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
18652d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
18794cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1888d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
18979406cd7SArnaldo Carvalho de Melo 		self->sorted_by_name = 0;
1908d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
191a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_USER;
192*0ab061cdSMasami Hiramatsu 		INIT_LIST_HEAD(&self->node);
19386470930SIngo Molnar 	}
19486470930SIngo Molnar 
19586470930SIngo Molnar 	return self;
19686470930SIngo Molnar }
19786470930SIngo Molnar 
198fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
19986470930SIngo Molnar {
20086470930SIngo Molnar 	struct symbol *pos;
201fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
20286470930SIngo Molnar 
20386470930SIngo Molnar 	while (next) {
20486470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
20586470930SIngo Molnar 		next = rb_next(&pos->rb_node);
206fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
20700a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
20886470930SIngo Molnar 	}
20986470930SIngo Molnar }
21086470930SIngo Molnar 
21186470930SIngo Molnar void dso__delete(struct dso *self)
21286470930SIngo Molnar {
2136a4694a4SArnaldo Carvalho de Melo 	int i;
2146a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2156a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
216439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
217439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
21886470930SIngo Molnar 	free(self);
21986470930SIngo Molnar }
22086470930SIngo Molnar 
2218d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2228d06367fSArnaldo Carvalho de Melo {
2238d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2248d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2258d06367fSArnaldo Carvalho de Melo }
2268d06367fSArnaldo Carvalho de Melo 
227fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
22886470930SIngo Molnar {
229fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
23086470930SIngo Molnar 	struct rb_node *parent = NULL;
2319cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
23286470930SIngo Molnar 	struct symbol *s;
23386470930SIngo Molnar 
23486470930SIngo Molnar 	while (*p != NULL) {
23586470930SIngo Molnar 		parent = *p;
23686470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
23786470930SIngo Molnar 		if (ip < s->start)
23886470930SIngo Molnar 			p = &(*p)->rb_left;
23986470930SIngo Molnar 		else
24086470930SIngo Molnar 			p = &(*p)->rb_right;
24186470930SIngo Molnar 	}
24286470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
243fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
24486470930SIngo Molnar }
24586470930SIngo Molnar 
246fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
24786470930SIngo Molnar {
24886470930SIngo Molnar 	struct rb_node *n;
24986470930SIngo Molnar 
25086470930SIngo Molnar 	if (self == NULL)
25186470930SIngo Molnar 		return NULL;
25286470930SIngo Molnar 
253fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
25486470930SIngo Molnar 
25586470930SIngo Molnar 	while (n) {
25686470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
25786470930SIngo Molnar 
25886470930SIngo Molnar 		if (ip < s->start)
25986470930SIngo Molnar 			n = n->rb_left;
26086470930SIngo Molnar 		else if (ip > s->end)
26186470930SIngo Molnar 			n = n->rb_right;
26286470930SIngo Molnar 		else
26386470930SIngo Molnar 			return s;
26486470930SIngo Molnar 	}
26586470930SIngo Molnar 
26686470930SIngo Molnar 	return NULL;
26786470930SIngo Molnar }
26886470930SIngo Molnar 
26979406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
27079406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
27179406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
27279406cd7SArnaldo Carvalho de Melo };
27379406cd7SArnaldo Carvalho de Melo 
27479406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
27579406cd7SArnaldo Carvalho de Melo {
27679406cd7SArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
27779406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
27879406cd7SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
27979406cd7SArnaldo Carvalho de Melo 
28079406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
28179406cd7SArnaldo Carvalho de Melo 		parent = *p;
28279406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
28379406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
28479406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
28579406cd7SArnaldo Carvalho de Melo 		else
28679406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
28779406cd7SArnaldo Carvalho de Melo 	}
28879406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
28979406cd7SArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, self);
29079406cd7SArnaldo Carvalho de Melo }
29179406cd7SArnaldo Carvalho de Melo 
29279406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
29379406cd7SArnaldo Carvalho de Melo {
29479406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
29579406cd7SArnaldo Carvalho de Melo 
29679406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
29779406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
29879406cd7SArnaldo Carvalho de Melo 		symbols__insert_by_name(self, pos);
29979406cd7SArnaldo Carvalho de Melo 	}
30079406cd7SArnaldo Carvalho de Melo }
30179406cd7SArnaldo Carvalho de Melo 
30279406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
30379406cd7SArnaldo Carvalho de Melo {
30479406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
30579406cd7SArnaldo Carvalho de Melo 
30679406cd7SArnaldo Carvalho de Melo 	if (self == NULL)
30779406cd7SArnaldo Carvalho de Melo 		return NULL;
30879406cd7SArnaldo Carvalho de Melo 
30979406cd7SArnaldo Carvalho de Melo 	n = self->rb_node;
31079406cd7SArnaldo Carvalho de Melo 
31179406cd7SArnaldo Carvalho de Melo 	while (n) {
31279406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
31379406cd7SArnaldo Carvalho de Melo 		int cmp;
31479406cd7SArnaldo Carvalho de Melo 
31579406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
31679406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
31779406cd7SArnaldo Carvalho de Melo 
31879406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
31979406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
32079406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
32179406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
32279406cd7SArnaldo Carvalho de Melo 		else
32379406cd7SArnaldo Carvalho de Melo 			return &s->sym;
32479406cd7SArnaldo Carvalho de Melo 	}
32579406cd7SArnaldo Carvalho de Melo 
32679406cd7SArnaldo Carvalho de Melo 	return NULL;
32779406cd7SArnaldo Carvalho de Melo }
32879406cd7SArnaldo Carvalho de Melo 
32979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self,
33079406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
331fcf1203aSArnaldo Carvalho de Melo {
3326a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
333fcf1203aSArnaldo Carvalho de Melo }
334fcf1203aSArnaldo Carvalho de Melo 
33579406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
33679406cd7SArnaldo Carvalho de Melo 					const char *name)
33779406cd7SArnaldo Carvalho de Melo {
33879406cd7SArnaldo Carvalho de Melo 	return symbols__find_by_name(&self->symbol_names[type], name);
33979406cd7SArnaldo Carvalho de Melo }
34079406cd7SArnaldo Carvalho de Melo 
34179406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type)
34279406cd7SArnaldo Carvalho de Melo {
34379406cd7SArnaldo Carvalho de Melo 	dso__set_sorted_by_name(self, type);
34479406cd7SArnaldo Carvalho de Melo 	return symbols__sort_by_name(&self->symbol_names[type],
34579406cd7SArnaldo Carvalho de Melo 				     &self->symbols[type]);
34679406cd7SArnaldo Carvalho de Melo }
34779406cd7SArnaldo Carvalho de Melo 
348ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf)
3498d06367fSArnaldo Carvalho de Melo {
3508d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
351ef12a141SArnaldo Carvalho de Melo 	const u8 *raw = self;
3528d06367fSArnaldo Carvalho de Melo 	int i;
3538d06367fSArnaldo Carvalho de Melo 
3548d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
3558d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
3568d06367fSArnaldo Carvalho de Melo 		++raw;
3578d06367fSArnaldo Carvalho de Melo 		bid += 2;
3588d06367fSArnaldo Carvalho de Melo 	}
3598d06367fSArnaldo Carvalho de Melo 
3608d06367fSArnaldo Carvalho de Melo 	return raw - self;
3618d06367fSArnaldo Carvalho de Melo }
3628d06367fSArnaldo Carvalho de Melo 
3639e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
36486470930SIngo Molnar {
3658d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
3668d06367fSArnaldo Carvalho de Melo 
3678d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
3689e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
3699e03eb2dSArnaldo Carvalho de Melo }
3709e03eb2dSArnaldo Carvalho de Melo 
37195011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
3729e03eb2dSArnaldo Carvalho de Melo {
3739e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
3749e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
3759e03eb2dSArnaldo Carvalho de Melo 
3763846df2eSArnaldo Carvalho de Melo 	if (self->short_name != self->long_name)
3773846df2eSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", self->long_name);
3783846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
3793846df2eSArnaldo Carvalho de Melo 		       self->loaded ? "" : "NOT ");
3809e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
3816a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
38295011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
38386470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
38486470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
38586470930SIngo Molnar 	}
38686470930SIngo Molnar 
38786470930SIngo Molnar 	return ret;
38886470930SIngo Molnar }
38986470930SIngo Molnar 
3909e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
3919e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
392682b335aSArnaldo Carvalho de Melo 						     char type, u64 start))
39386470930SIngo Molnar {
39486470930SIngo Molnar 	char *line = NULL;
39586470930SIngo Molnar 	size_t n;
396682b335aSArnaldo Carvalho de Melo 	int err = 0;
3979e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
39886470930SIngo Molnar 
39986470930SIngo Molnar 	if (file == NULL)
40086470930SIngo Molnar 		goto out_failure;
40186470930SIngo Molnar 
40286470930SIngo Molnar 	while (!feof(file)) {
4039cffa8d5SPaul Mackerras 		u64 start;
40486470930SIngo Molnar 		int line_len, len;
40586470930SIngo Molnar 		char symbol_type;
4062e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
40786470930SIngo Molnar 
40886470930SIngo Molnar 		line_len = getline(&line, &n, file);
409a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
41086470930SIngo Molnar 			break;
41186470930SIngo Molnar 
41286470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
41386470930SIngo Molnar 
41486470930SIngo Molnar 		len = hex2u64(line, &start);
41586470930SIngo Molnar 
41686470930SIngo Molnar 		len++;
41786470930SIngo Molnar 		if (len + 2 >= line_len)
41886470930SIngo Molnar 			continue;
41986470930SIngo Molnar 
42086470930SIngo Molnar 		symbol_type = toupper(line[len]);
421af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
422682b335aSArnaldo Carvalho de Melo 
423682b335aSArnaldo Carvalho de Melo 		err = process_symbol(arg, symbol_name, symbol_type, start);
424682b335aSArnaldo Carvalho de Melo 		if (err)
425682b335aSArnaldo Carvalho de Melo 			break;
426682b335aSArnaldo Carvalho de Melo 	}
427682b335aSArnaldo Carvalho de Melo 
428682b335aSArnaldo Carvalho de Melo 	free(line);
429682b335aSArnaldo Carvalho de Melo 	fclose(file);
430682b335aSArnaldo Carvalho de Melo 	return err;
431682b335aSArnaldo Carvalho de Melo 
432682b335aSArnaldo Carvalho de Melo out_failure:
433682b335aSArnaldo Carvalho de Melo 	return -1;
434682b335aSArnaldo Carvalho de Melo }
435682b335aSArnaldo Carvalho de Melo 
436682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
437682b335aSArnaldo Carvalho de Melo 	struct map *map;
438682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
439682b335aSArnaldo Carvalho de Melo };
440682b335aSArnaldo Carvalho de Melo 
441682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
442682b335aSArnaldo Carvalho de Melo 				       char type, u64 start)
443682b335aSArnaldo Carvalho de Melo {
444682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
445682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
446682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
447682b335aSArnaldo Carvalho de Melo 
448682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
449682b335aSArnaldo Carvalho de Melo 		return 0;
450682b335aSArnaldo Carvalho de Melo 
4512e538c4aSArnaldo Carvalho de Melo 	/*
4522e538c4aSArnaldo Carvalho de Melo 	 * Will fix up the end later, when we have all symbols sorted.
4532e538c4aSArnaldo Carvalho de Melo 	 */
454682b335aSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, name);
455af427bf5SArnaldo Carvalho de Melo 
4562e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
457682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
45882164161SArnaldo Carvalho de Melo 	/*
45982164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
4604e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
46182164161SArnaldo Carvalho de Melo 	 */
4624e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
463a1645ce1SZhang, Yanmin 
464682b335aSArnaldo Carvalho de Melo 	return 0;
4652e538c4aSArnaldo Carvalho de Melo }
4662e538c4aSArnaldo Carvalho de Melo 
467682b335aSArnaldo Carvalho de Melo /*
468682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
469682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
470682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
471682b335aSArnaldo Carvalho de Melo  */
4729e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename,
4739e201442SArnaldo Carvalho de Melo 				  struct map *map)
474682b335aSArnaldo Carvalho de Melo {
475682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = self, };
4769e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
4772e538c4aSArnaldo Carvalho de Melo }
4782e538c4aSArnaldo Carvalho de Melo 
4792e538c4aSArnaldo Carvalho de Melo /*
4802e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
4812e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
4822e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
4832e538c4aSArnaldo Carvalho de Melo  */
4849958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
4859de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
4862e538c4aSArnaldo Carvalho de Melo {
4879de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
488a1645ce1SZhang, Yanmin 	struct kernel_info *kerninfo = kmaps->this_kerninfo;
4894e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
4902e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
4912e538c4aSArnaldo Carvalho de Melo 	int count = 0;
4924e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
4934e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
4942e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
4952e538c4aSArnaldo Carvalho de Melo 
4962e538c4aSArnaldo Carvalho de Melo 	while (next) {
4972e538c4aSArnaldo Carvalho de Melo 		char *module;
4982e538c4aSArnaldo Carvalho de Melo 
4992e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
5002e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
5012e538c4aSArnaldo Carvalho de Melo 
5022e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
5032e538c4aSArnaldo Carvalho de Melo 		if (module) {
50475be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
5051de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
5061de8e245SArnaldo Carvalho de Melo 
5072e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
5082e538c4aSArnaldo Carvalho de Melo 
509b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
510a1645ce1SZhang, Yanmin 				if (curr_map != map &&
511a1645ce1SZhang, Yanmin 					self->kernel == DSO_TYPE_GUEST_KERNEL &&
512a1645ce1SZhang, Yanmin 					is_default_guest(kerninfo)) {
513a1645ce1SZhang, Yanmin 					/*
514a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
515a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
516a1645ce1SZhang, Yanmin 					 * points to a module and all its
517a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
518a1645ce1SZhang, Yanmin 					 * loaded.
519a1645ce1SZhang, Yanmin 					 */
520a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
521a1645ce1SZhang, Yanmin 							curr_map->type);
522af427bf5SArnaldo Carvalho de Melo 				}
523b7cece76SArnaldo Carvalho de Melo 
524a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
525a1645ce1SZhang, Yanmin 							map->type, module);
526a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
527a1645ce1SZhang, Yanmin 					pr_err("%s/proc/{kallsyms,modules} "
528a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
529a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
530a1645ce1SZhang, Yanmin 						 kerninfo->root_dir, module);
531a1645ce1SZhang, Yanmin 					curr_map = map;
532a1645ce1SZhang, Yanmin 					goto discard_symbol;
533a1645ce1SZhang, Yanmin 				}
534a1645ce1SZhang, Yanmin 
535a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
536a1645ce1SZhang, Yanmin 					!is_default_guest(kmaps->this_kerninfo))
537b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
538af427bf5SArnaldo Carvalho de Melo 			}
53986470930SIngo Molnar 			/*
5402e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
5412e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
54286470930SIngo Molnar 			 */
5434e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
5444e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
5454e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
5462e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
5472e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
54886470930SIngo Molnar 
549a1645ce1SZhang, Yanmin 			if (self->kernel == DSO_TYPE_GUEST_KERNEL)
550a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
551a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
552a1645ce1SZhang, Yanmin 					kernel_range++);
553a1645ce1SZhang, Yanmin 			else
554a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
555a1645ce1SZhang, Yanmin 					"[kernel].%d",
5562e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
55786470930SIngo Molnar 
55800a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
5592e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
5602e538c4aSArnaldo Carvalho de Melo 				return -1;
5612e538c4aSArnaldo Carvalho de Melo 
562a1645ce1SZhang, Yanmin 			dso->kernel = self->kernel;
563a1645ce1SZhang, Yanmin 
5644e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
56537fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
5662e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
5672e538c4aSArnaldo Carvalho de Melo 				return -1;
5682e538c4aSArnaldo Carvalho de Melo 			}
5692e538c4aSArnaldo Carvalho de Melo 
5704e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
5719de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
5722e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
5732e538c4aSArnaldo Carvalho de Melo 		}
5742e538c4aSArnaldo Carvalho de Melo 
5754e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
5761de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
57700a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
5782e538c4aSArnaldo Carvalho de Melo 		} else {
5794e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
5804e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
5814e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
5822e538c4aSArnaldo Carvalho de Melo 			}
5839974f496SMike Galbraith 			count++;
5849974f496SMike Galbraith 		}
58586470930SIngo Molnar 	}
58686470930SIngo Molnar 
587a1645ce1SZhang, Yanmin 	if (curr_map != map &&
588a1645ce1SZhang, Yanmin 	    self->kernel == DSO_TYPE_GUEST_KERNEL &&
589a1645ce1SZhang, Yanmin 	    is_default_guest(kmaps->this_kerninfo)) {
590a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
591a1645ce1SZhang, Yanmin 	}
592a1645ce1SZhang, Yanmin 
5939974f496SMike Galbraith 	return count;
59486470930SIngo Molnar }
59586470930SIngo Molnar 
5969de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename,
5979de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
5982e538c4aSArnaldo Carvalho de Melo {
5999e201442SArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, filename, map) < 0)
6002e538c4aSArnaldo Carvalho de Melo 		return -1;
6012e538c4aSArnaldo Carvalho de Melo 
6024e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
603a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_GUEST_KERNEL)
604a1645ce1SZhang, Yanmin 		self->origin = DSO__ORIG_GUEST_KERNEL;
605a1645ce1SZhang, Yanmin 	else
6064e06255fSArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_KERNEL;
6072e538c4aSArnaldo Carvalho de Melo 
6089de89fe7SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, filter);
609af427bf5SArnaldo Carvalho de Melo }
610af427bf5SArnaldo Carvalho de Melo 
611439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
6126beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
61380d496beSPekka Enberg {
61480d496beSPekka Enberg 	char *line = NULL;
61580d496beSPekka Enberg 	size_t n;
61680d496beSPekka Enberg 	FILE *file;
61780d496beSPekka Enberg 	int nr_syms = 0;
61880d496beSPekka Enberg 
619439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
62080d496beSPekka Enberg 	if (file == NULL)
62180d496beSPekka Enberg 		goto out_failure;
62280d496beSPekka Enberg 
62380d496beSPekka Enberg 	while (!feof(file)) {
6249cffa8d5SPaul Mackerras 		u64 start, size;
62580d496beSPekka Enberg 		struct symbol *sym;
62680d496beSPekka Enberg 		int line_len, len;
62780d496beSPekka Enberg 
62880d496beSPekka Enberg 		line_len = getline(&line, &n, file);
62980d496beSPekka Enberg 		if (line_len < 0)
63080d496beSPekka Enberg 			break;
63180d496beSPekka Enberg 
63280d496beSPekka Enberg 		if (!line)
63380d496beSPekka Enberg 			goto out_failure;
63480d496beSPekka Enberg 
63580d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
63680d496beSPekka Enberg 
63780d496beSPekka Enberg 		len = hex2u64(line, &start);
63880d496beSPekka Enberg 
63980d496beSPekka Enberg 		len++;
64080d496beSPekka Enberg 		if (len + 2 >= line_len)
64180d496beSPekka Enberg 			continue;
64280d496beSPekka Enberg 
64380d496beSPekka Enberg 		len += hex2u64(line + len, &size);
64480d496beSPekka Enberg 
64580d496beSPekka Enberg 		len++;
64680d496beSPekka Enberg 		if (len + 2 >= line_len)
64780d496beSPekka Enberg 			continue;
64880d496beSPekka Enberg 
64900a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
65080d496beSPekka Enberg 
65180d496beSPekka Enberg 		if (sym == NULL)
65280d496beSPekka Enberg 			goto out_delete_line;
65380d496beSPekka Enberg 
654439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
65500a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
65680d496beSPekka Enberg 		else {
6576a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
65880d496beSPekka Enberg 			nr_syms++;
65980d496beSPekka Enberg 		}
66080d496beSPekka Enberg 	}
66180d496beSPekka Enberg 
66280d496beSPekka Enberg 	free(line);
66380d496beSPekka Enberg 	fclose(file);
66480d496beSPekka Enberg 
66580d496beSPekka Enberg 	return nr_syms;
66680d496beSPekka Enberg 
66780d496beSPekka Enberg out_delete_line:
66880d496beSPekka Enberg 	free(line);
66980d496beSPekka Enberg out_failure:
67080d496beSPekka Enberg 	return -1;
67180d496beSPekka Enberg }
67280d496beSPekka Enberg 
67386470930SIngo Molnar /**
67486470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
67586470930SIngo Molnar  *
67686470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
67783a0944fSIngo Molnar  * @idx: uint32_t idx
67886470930SIngo Molnar  * @sym: GElf_Sym iterator
67986470930SIngo Molnar  */
68083a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
68183a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
68283a0944fSIngo Molnar 	     idx < nr_syms; \
68383a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
68486470930SIngo Molnar 
68586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
68686470930SIngo Molnar {
68786470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
68886470930SIngo Molnar }
68986470930SIngo Molnar 
69086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
69186470930SIngo Molnar {
69286470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
69386470930SIngo Molnar 	       sym->st_name != 0 &&
69481833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
69586470930SIngo Molnar }
69686470930SIngo Molnar 
697f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
698f1dfa0b1SArnaldo Carvalho de Melo {
699f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
700f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
701f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
702f1dfa0b1SArnaldo Carvalho de Melo }
703f1dfa0b1SArnaldo Carvalho de Melo 
7046cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
7056cfcc53eSMike Galbraith {
7066cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
7076cfcc53eSMike Galbraith 		sym->st_name != 0 &&
7086cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
7096cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
7106cfcc53eSMike Galbraith }
7116cfcc53eSMike Galbraith 
7126cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
7136cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7146cfcc53eSMike Galbraith {
7156cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
7166cfcc53eSMike Galbraith }
7176cfcc53eSMike Galbraith 
7186cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
7196cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7206cfcc53eSMike Galbraith {
7216cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
7226cfcc53eSMike Galbraith }
7236cfcc53eSMike Galbraith 
724f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
725f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
726f1dfa0b1SArnaldo Carvalho de Melo {
727f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
728f1dfa0b1SArnaldo Carvalho de Melo }
729f1dfa0b1SArnaldo Carvalho de Melo 
73086470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
73186470930SIngo Molnar 					const Elf_Data *symstrs)
73286470930SIngo Molnar {
73386470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
73486470930SIngo Molnar }
73586470930SIngo Molnar 
73686470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
73786470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
73883a0944fSIngo Molnar 				    size_t *idx)
73986470930SIngo Molnar {
74086470930SIngo Molnar 	Elf_Scn *sec = NULL;
74186470930SIngo Molnar 	size_t cnt = 1;
74286470930SIngo Molnar 
74386470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
74486470930SIngo Molnar 		char *str;
74586470930SIngo Molnar 
74686470930SIngo Molnar 		gelf_getshdr(sec, shp);
74786470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
74886470930SIngo Molnar 		if (!strcmp(name, str)) {
74983a0944fSIngo Molnar 			if (idx)
75083a0944fSIngo Molnar 				*idx = cnt;
75186470930SIngo Molnar 			break;
75286470930SIngo Molnar 		}
75386470930SIngo Molnar 		++cnt;
75486470930SIngo Molnar 	}
75586470930SIngo Molnar 
75686470930SIngo Molnar 	return sec;
75786470930SIngo Molnar }
75886470930SIngo Molnar 
75986470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
76086470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
76186470930SIngo Molnar 	     idx < nr_entries; \
76286470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
76386470930SIngo Molnar 
76486470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
76586470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
76686470930SIngo Molnar 	     idx < nr_entries; \
76786470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
76886470930SIngo Molnar 
769a25e46c4SArnaldo Carvalho de Melo /*
770a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
771a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
772a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
773a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
774a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
775a25e46c4SArnaldo Carvalho de Melo  */
77682164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
77782164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
77886470930SIngo Molnar {
77986470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
78086470930SIngo Molnar 	GElf_Sym sym;
7819cffa8d5SPaul Mackerras 	u64 plt_offset;
78286470930SIngo Molnar 	GElf_Shdr shdr_plt;
78386470930SIngo Molnar 	struct symbol *f;
784a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
78586470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
786a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
787a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
788a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
78986470930SIngo Molnar 	char sympltname[1024];
790a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
791a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
79286470930SIngo Molnar 
793439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
794a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
795a25e46c4SArnaldo Carvalho de Melo 		goto out;
796a25e46c4SArnaldo Carvalho de Melo 
79784087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
798a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
799a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
800a25e46c4SArnaldo Carvalho de Melo 
801a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
802a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
803a25e46c4SArnaldo Carvalho de Melo 
804a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
805a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
806a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
807a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
808a25e46c4SArnaldo Carvalho de Melo 
809a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
81086470930SIngo Molnar 					  ".rela.plt", NULL);
81186470930SIngo Molnar 	if (scn_plt_rel == NULL) {
812a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
81386470930SIngo Molnar 						  ".rel.plt", NULL);
81486470930SIngo Molnar 		if (scn_plt_rel == NULL)
815a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
81686470930SIngo Molnar 	}
81786470930SIngo Molnar 
818a25e46c4SArnaldo Carvalho de Melo 	err = -1;
81986470930SIngo Molnar 
820a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
821a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
822a25e46c4SArnaldo Carvalho de Melo 
823a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
824a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
82586470930SIngo Molnar 
82686470930SIngo Molnar 	/*
82783a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
82886470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
82986470930SIngo Molnar 	 */
83086470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
83186470930SIngo Molnar 	if (reldata == NULL)
832a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
83386470930SIngo Molnar 
83486470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
83586470930SIngo Molnar 	if (syms == NULL)
836a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
83786470930SIngo Molnar 
838a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
83986470930SIngo Molnar 	if (scn_symstrs == NULL)
840a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
84186470930SIngo Molnar 
84286470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
84386470930SIngo Molnar 	if (symstrs == NULL)
844a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
84586470930SIngo Molnar 
84686470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
84786470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
84886470930SIngo Molnar 
84986470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
85086470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
85186470930SIngo Molnar 
85286470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
85386470930SIngo Molnar 					   nr_rel_entries) {
85486470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
85586470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
85686470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
85786470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
85886470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
85986470930SIngo Molnar 
86086470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
86100a192b3SArnaldo Carvalho de Melo 					sympltname);
86286470930SIngo Molnar 			if (!f)
863a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
86486470930SIngo Molnar 
86582164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
86682164161SArnaldo Carvalho de Melo 				symbol__delete(f);
86782164161SArnaldo Carvalho de Melo 			else {
8686a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
86986470930SIngo Molnar 				++nr;
87086470930SIngo Molnar 			}
87182164161SArnaldo Carvalho de Melo 		}
87286470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
87386470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
87486470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
87586470930SIngo Molnar 					  nr_rel_entries) {
87686470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
87786470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
87886470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
87986470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
88086470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
88186470930SIngo Molnar 
88286470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
88300a192b3SArnaldo Carvalho de Melo 					sympltname);
88486470930SIngo Molnar 			if (!f)
885a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
88686470930SIngo Molnar 
88782164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
88882164161SArnaldo Carvalho de Melo 				symbol__delete(f);
88982164161SArnaldo Carvalho de Melo 			else {
8906a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
89186470930SIngo Molnar 				++nr;
89286470930SIngo Molnar 			}
89386470930SIngo Molnar 		}
89482164161SArnaldo Carvalho de Melo 	}
89586470930SIngo Molnar 
896a25e46c4SArnaldo Carvalho de Melo 	err = 0;
897a25e46c4SArnaldo Carvalho de Melo out_elf_end:
898a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
899a25e46c4SArnaldo Carvalho de Melo out_close:
900a25e46c4SArnaldo Carvalho de Melo 	close(fd);
901a25e46c4SArnaldo Carvalho de Melo 
902a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
90386470930SIngo Molnar 		return nr;
904a25e46c4SArnaldo Carvalho de Melo out:
905fe2197b8SArnaldo Carvalho de Melo 	pr_debug("%s: problems reading %s PLT info.\n",
906439d473bSArnaldo Carvalho de Melo 		 __func__, self->long_name);
907a25e46c4SArnaldo Carvalho de Melo 	return 0;
90886470930SIngo Molnar }
90986470930SIngo Molnar 
910d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
911d45868d3SArnaldo Carvalho de Melo {
912d45868d3SArnaldo Carvalho de Melo 	switch (type) {
913d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
914d45868d3SArnaldo Carvalho de Melo 		return elf_sym__is_function(self);
915f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
916f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sym__is_object(self);
917d45868d3SArnaldo Carvalho de Melo 	default:
918d45868d3SArnaldo Carvalho de Melo 		return false;
919d45868d3SArnaldo Carvalho de Melo 	}
920d45868d3SArnaldo Carvalho de Melo }
921d45868d3SArnaldo Carvalho de Melo 
922d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
923d45868d3SArnaldo Carvalho de Melo {
924d45868d3SArnaldo Carvalho de Melo 	switch (type) {
925d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
926d45868d3SArnaldo Carvalho de Melo 		return elf_sec__is_text(self, secstrs);
927f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
928f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sec__is_data(self, secstrs);
929d45868d3SArnaldo Carvalho de Melo 	default:
930d45868d3SArnaldo Carvalho de Melo 		return false;
931d45868d3SArnaldo Carvalho de Melo 	}
932d45868d3SArnaldo Carvalho de Melo }
933d45868d3SArnaldo Carvalho de Melo 
9349de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name,
9359de89fe7SArnaldo Carvalho de Melo 			 int fd, symbol_filter_t filter, int kmodule)
93686470930SIngo Molnar {
9379de89fe7SArnaldo Carvalho de Melo 	struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
9382e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
9392e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
9406cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
94186470930SIngo Molnar 	uint32_t nr_syms;
94286470930SIngo Molnar 	int err = -1;
94383a0944fSIngo Molnar 	uint32_t idx;
94486470930SIngo Molnar 	GElf_Ehdr ehdr;
94586470930SIngo Molnar 	GElf_Shdr shdr;
94686470930SIngo Molnar 	Elf_Data *syms;
94786470930SIngo Molnar 	GElf_Sym sym;
948a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
94986470930SIngo Molnar 	Elf *elf;
950439d473bSArnaldo Carvalho de Melo 	int nr = 0;
95186470930SIngo Molnar 
95284087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
95386470930SIngo Molnar 	if (elf == NULL) {
9546beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
95586470930SIngo Molnar 		goto out_close;
95686470930SIngo Molnar 	}
95786470930SIngo Molnar 
95886470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
9596beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
96086470930SIngo Molnar 		goto out_elf_end;
96186470930SIngo Molnar 	}
96286470930SIngo Molnar 
96386470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
96486470930SIngo Molnar 	if (sec == NULL) {
965a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
966a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
96786470930SIngo Molnar 			goto out_elf_end;
96886470930SIngo Molnar 	}
96986470930SIngo Molnar 
97086470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
97186470930SIngo Molnar 	if (syms == NULL)
97286470930SIngo Molnar 		goto out_elf_end;
97386470930SIngo Molnar 
97486470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
97586470930SIngo Molnar 	if (sec == NULL)
97686470930SIngo Molnar 		goto out_elf_end;
97786470930SIngo Molnar 
97886470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
97986470930SIngo Molnar 	if (symstrs == NULL)
98086470930SIngo Molnar 		goto out_elf_end;
98186470930SIngo Molnar 
9826cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
9836cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
9846cfcc53eSMike Galbraith 		goto out_elf_end;
9856cfcc53eSMike Galbraith 
9866cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
9879b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
9886cfcc53eSMike Galbraith 		goto out_elf_end;
9896cfcc53eSMike Galbraith 
99086470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
99186470930SIngo Molnar 
992e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
993a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_USER) {
99430d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
99530d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
996f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
99730d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
998d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
999d20ff6bdSMike Galbraith 
100083a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
100186470930SIngo Molnar 		struct symbol *f;
100256b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
10032e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
10046cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
10056cfcc53eSMike Galbraith 		const char *section_name;
100686470930SIngo Molnar 
10079de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
10089de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
10099de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
101056b03f3cSArnaldo Carvalho de Melo 
1011d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
101286470930SIngo Molnar 			continue;
101386470930SIngo Molnar 
101486470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
101586470930SIngo Molnar 		if (!sec)
101686470930SIngo Molnar 			goto out_elf_end;
101786470930SIngo Molnar 
101886470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
10196cfcc53eSMike Galbraith 
1020d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
10216cfcc53eSMike Galbraith 			continue;
10226cfcc53eSMike Galbraith 
10236cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
102486470930SIngo Molnar 
1025a1645ce1SZhang, Yanmin 		if (self->kernel != DSO_TYPE_USER || kmodule) {
10262e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
10272e538c4aSArnaldo Carvalho de Melo 
10282e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1029b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1030b63be8d7SArnaldo Carvalho de Melo 				    self->short_name_len)) == 0)
10312e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
10322e538c4aSArnaldo Carvalho de Melo 
10332e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
10342e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
10352e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
10362e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1037af427bf5SArnaldo Carvalho de Melo 			}
1038af427bf5SArnaldo Carvalho de Melo 
10392e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
10402e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
10412e538c4aSArnaldo Carvalho de Melo 
10429de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
10432e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
10442e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
10452e538c4aSArnaldo Carvalho de Melo 
10462e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
10472e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
10482e538c4aSArnaldo Carvalho de Melo 
104900a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
10502e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
10512e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1052a1645ce1SZhang, Yanmin 				curr_dso->kernel = self->kernel;
10533610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
10546275ce2dSArnaldo Carvalho de Melo 						     map->type);
10552e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
10562e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
10572e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
10582e538c4aSArnaldo Carvalho de Melo 				}
1059ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1060ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1061b0a9ab62SArnaldo Carvalho de Melo 				curr_dso->origin = self->origin;
10629de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1063a1645ce1SZhang, Yanmin 				dsos__add(&self->node, curr_dso);
10646275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
10652e538c4aSArnaldo Carvalho de Melo 			} else
10662e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
10672e538c4aSArnaldo Carvalho de Melo 
10682e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
10692e538c4aSArnaldo Carvalho de Melo 		}
10702e538c4aSArnaldo Carvalho de Melo 
10712e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
107229a9f66dSArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#Lx "
107329a9f66dSArnaldo Carvalho de Melo 				  "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
107429a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
107529a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
107686470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1077af427bf5SArnaldo Carvalho de Melo 		}
107828ac909bSArnaldo Carvalho de Melo 		/*
107928ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
108028ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
108128ac909bSArnaldo Carvalho de Melo 		 * to it...
108228ac909bSArnaldo Carvalho de Melo 		 */
108383a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
108428ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
108583a0944fSIngo Molnar 			elf_name = demangled;
10862e538c4aSArnaldo Carvalho de Melo new_symbol:
108700a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
108828ac909bSArnaldo Carvalho de Melo 		free(demangled);
108986470930SIngo Molnar 		if (!f)
109086470930SIngo Molnar 			goto out_elf_end;
109186470930SIngo Molnar 
10922e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
109300a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
109486470930SIngo Molnar 		else {
10956a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
109686470930SIngo Molnar 			nr++;
109786470930SIngo Molnar 		}
109886470930SIngo Molnar 	}
109986470930SIngo Molnar 
11002e538c4aSArnaldo Carvalho de Melo 	/*
11012e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
11022e538c4aSArnaldo Carvalho de Melo 	 */
11036275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
11046a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
11056275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
11066275ce2dSArnaldo Carvalho de Melo 			/*
11076275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
11086275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
11096275ce2dSArnaldo Carvalho de Melo 			 */
11106275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
11116275ce2dSArnaldo Carvalho de Melo 		}
11126275ce2dSArnaldo Carvalho de Melo 	}
111386470930SIngo Molnar 	err = nr;
111486470930SIngo Molnar out_elf_end:
111586470930SIngo Molnar 	elf_end(elf);
111686470930SIngo Molnar out_close:
111786470930SIngo Molnar 	return err;
111886470930SIngo Molnar }
111986470930SIngo Molnar 
112078075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
112178075caaSArnaldo Carvalho de Melo {
112278075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
112378075caaSArnaldo Carvalho de Melo }
112478075caaSArnaldo Carvalho de Melo 
1125a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
112657f395a7SFrederic Weisbecker {
1127e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
112857f395a7SFrederic Weisbecker 	struct dso *pos;
112957f395a7SFrederic Weisbecker 
11306122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
11316122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
11326122e4e4SArnaldo Carvalho de Melo 			continue;
1133e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1134e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1135e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1136e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
113757f395a7SFrederic Weisbecker 		}
11386122e4e4SArnaldo Carvalho de Melo 	}
113957f395a7SFrederic Weisbecker 
1140e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
114157f395a7SFrederic Weisbecker }
114257f395a7SFrederic Weisbecker 
1143fd7a346eSArnaldo Carvalho de Melo /*
1144fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1145fd7a346eSArnaldo Carvalho de Melo  */
1146fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1147fd7a346eSArnaldo Carvalho de Melo 
11482643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
11494d1e00a8SArnaldo Carvalho de Melo {
11502643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
11514d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
11524d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1153fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
11544d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1155e57cfcdaSPekka Enberg 	Elf_Kind ek;
1156fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
11574d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
11584d1e00a8SArnaldo Carvalho de Melo 
11592643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
11602643ce11SArnaldo Carvalho de Melo 		goto out;
11612643ce11SArnaldo Carvalho de Melo 
11622643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
11634d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
11644d1e00a8SArnaldo Carvalho de Melo 		goto out;
11654d1e00a8SArnaldo Carvalho de Melo 
116684087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
11674d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
11688d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
11694d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
11704d1e00a8SArnaldo Carvalho de Melo 	}
11714d1e00a8SArnaldo Carvalho de Melo 
1172e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1173e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
1174e57cfcdaSPekka Enberg 		goto out_elf_end;
1175e57cfcdaSPekka Enberg 
11764d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
11776beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
11784d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
11794d1e00a8SArnaldo Carvalho de Melo 	}
11804d1e00a8SArnaldo Carvalho de Melo 
11812643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
11822643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1183fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1184fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1185fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
11864d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
11874d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
1188fd7a346eSArnaldo Carvalho de Melo 	}
11894d1e00a8SArnaldo Carvalho de Melo 
1190fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1191fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
11924d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
1193fd7a346eSArnaldo Carvalho de Melo 
1194fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1195fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1196fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1197fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1198fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1199fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1200fd7a346eSArnaldo Carvalho de Melo 
1201fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1202fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1203fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1204fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1205fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1206fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1207fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
12082643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1209fd7a346eSArnaldo Carvalho de Melo 				break;
1210fd7a346eSArnaldo Carvalho de Melo 			}
1211fd7a346eSArnaldo Carvalho de Melo 		}
1212fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1213fd7a346eSArnaldo Carvalho de Melo 	}
12142643ce11SArnaldo Carvalho de Melo out_elf_end:
12152643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
12162643ce11SArnaldo Carvalho de Melo out_close:
12172643ce11SArnaldo Carvalho de Melo 	close(fd);
12182643ce11SArnaldo Carvalho de Melo out:
12192643ce11SArnaldo Carvalho de Melo 	return err;
12202643ce11SArnaldo Carvalho de Melo }
12212643ce11SArnaldo Carvalho de Melo 
1222f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1223f1617b40SArnaldo Carvalho de Melo {
1224f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1225f1617b40SArnaldo Carvalho de Melo 
1226f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1227f1617b40SArnaldo Carvalho de Melo 		goto out;
1228f1617b40SArnaldo Carvalho de Melo 
1229f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1230f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1231f1617b40SArnaldo Carvalho de Melo 		goto out;
1232f1617b40SArnaldo Carvalho de Melo 
1233f1617b40SArnaldo Carvalho de Melo 	while (1) {
1234f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1235f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1236f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1237f1617b40SArnaldo Carvalho de Melo 
1238f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1239f1617b40SArnaldo Carvalho de Melo 			break;
1240f1617b40SArnaldo Carvalho de Melo 
1241fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1242fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1243f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1244f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1245f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1246f1617b40SArnaldo Carvalho de Melo 				break;
1247f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1248f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1249f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1250f1617b40SArnaldo Carvalho de Melo 					err = 0;
1251f1617b40SArnaldo Carvalho de Melo 					break;
1252f1617b40SArnaldo Carvalho de Melo 				}
1253f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1254f1617b40SArnaldo Carvalho de Melo 				break;
1255f1617b40SArnaldo Carvalho de Melo 		} else {
1256f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1257f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1258f1617b40SArnaldo Carvalho de Melo 				break;
1259f1617b40SArnaldo Carvalho de Melo 		}
1260f1617b40SArnaldo Carvalho de Melo 	}
1261f1617b40SArnaldo Carvalho de Melo 	close(fd);
1262f1617b40SArnaldo Carvalho de Melo out:
1263f1617b40SArnaldo Carvalho de Melo 	return err;
1264f1617b40SArnaldo Carvalho de Melo }
1265f1617b40SArnaldo Carvalho de Melo 
126694cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
126794cb9e38SArnaldo Carvalho de Melo {
126894cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
126994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
127094cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
12714cf40131SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILD_ID_CACHE] = 'B',
127294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
127394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
127494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
127594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1276439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
1277a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KERNEL] =  'g',
1278a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KMODULE] =  'G',
127994cb9e38SArnaldo Carvalho de Melo 	};
128094cb9e38SArnaldo Carvalho de Melo 
128194cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
128294cb9e38SArnaldo Carvalho de Melo 		return '!';
128394cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
128494cb9e38SArnaldo Carvalho de Melo }
128594cb9e38SArnaldo Carvalho de Melo 
12869de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
128786470930SIngo Molnar {
12884d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1289c338aee8SArnaldo Carvalho de Melo 	char *name;
1290d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
12914cf40131SArnaldo Carvalho de Melo 	char build_id_hex[BUILD_ID_SIZE * 2 + 1];
129286470930SIngo Molnar 	int ret = -1;
129386470930SIngo Molnar 	int fd;
1294a1645ce1SZhang, Yanmin 	struct kernel_info *kerninfo;
1295a1645ce1SZhang, Yanmin 	const char *root_dir;
129686470930SIngo Molnar 
12973610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
129866bd8424SArnaldo Carvalho de Melo 
1299a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_KERNEL)
13009de89fe7SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, filter);
1301a1645ce1SZhang, Yanmin 	else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1302a1645ce1SZhang, Yanmin 		return dso__load_guest_kernel_sym(self, map, filter);
1303a1645ce1SZhang, Yanmin 
1304a1645ce1SZhang, Yanmin 	if (map->groups && map->groups->this_kerninfo)
1305a1645ce1SZhang, Yanmin 		kerninfo = map->groups->this_kerninfo;
1306a1645ce1SZhang, Yanmin 	else
1307a1645ce1SZhang, Yanmin 		kerninfo = NULL;
1308c338aee8SArnaldo Carvalho de Melo 
1309c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
131086470930SIngo Molnar 	if (!name)
131186470930SIngo Molnar 		return -1;
131286470930SIngo Molnar 
131330d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1314f5812a7aSArnaldo Carvalho de Melo 
131594cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
13166beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
131794cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
131894cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
131994cb9e38SArnaldo Carvalho de Melo 		return ret;
132094cb9e38SArnaldo Carvalho de Melo 	}
132194cb9e38SArnaldo Carvalho de Melo 
13224cf40131SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_BUILD_ID_CACHE;
132380d496beSPekka Enberg 
13244cf40131SArnaldo Carvalho de Melo 	if (self->has_build_id) {
13254cf40131SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
13264cf40131SArnaldo Carvalho de Melo 				  build_id_hex);
13274cf40131SArnaldo Carvalho de Melo 		snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
13284cf40131SArnaldo Carvalho de Melo 			 getenv("HOME"), DEBUG_CACHE_DIR,
13294cf40131SArnaldo Carvalho de Melo 			 build_id_hex, build_id_hex + 2);
13304cf40131SArnaldo Carvalho de Melo 		goto open_file;
13314cf40131SArnaldo Carvalho de Melo 	}
133286470930SIngo Molnar more:
133386470930SIngo Molnar 	do {
133494cb9e38SArnaldo Carvalho de Melo 		self->origin++;
133594cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
133694cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1337439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1338439d473bSArnaldo Carvalho de Melo 				 self->long_name);
133986470930SIngo Molnar 			break;
134094cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1341439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1342439d473bSArnaldo Carvalho de Melo 				 self->long_name);
134386470930SIngo Molnar 			break;
134494cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1345d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1346d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1347d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1348d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
13494d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
13504d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1351d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1352d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
13538d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1354d3379ab9SArnaldo Carvalho de Melo 				break;
13554d1e00a8SArnaldo Carvalho de Melo 			}
135694cb9e38SArnaldo Carvalho de Melo 			self->origin++;
13574d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
135894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1359439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
136086470930SIngo Molnar 			break;
1361a1645ce1SZhang, Yanmin 		case DSO__ORIG_GUEST_KMODULE:
1362a1645ce1SZhang, Yanmin 			if (map->groups && map->groups->this_kerninfo)
1363a1645ce1SZhang, Yanmin 				root_dir = map->groups->this_kerninfo->root_dir;
1364a1645ce1SZhang, Yanmin 			else
1365a1645ce1SZhang, Yanmin 				root_dir = "";
1366a1645ce1SZhang, Yanmin 			snprintf(name, size, "%s%s", root_dir, self->long_name);
1367a1645ce1SZhang, Yanmin 			break;
136886470930SIngo Molnar 
136986470930SIngo Molnar 		default:
137086470930SIngo Molnar 			goto out;
137186470930SIngo Molnar 		}
137286470930SIngo Molnar 
13738d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1374d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1375d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
13768d06367fSArnaldo Carvalho de Melo 				goto more;
13778d06367fSArnaldo Carvalho de Melo compare_build_id:
137878075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
13798d06367fSArnaldo Carvalho de Melo 				goto more;
13808d06367fSArnaldo Carvalho de Melo 		}
13814cf40131SArnaldo Carvalho de Melo open_file:
138286470930SIngo Molnar 		fd = open(name, O_RDONLY);
138386470930SIngo Molnar 	} while (fd < 0);
138486470930SIngo Molnar 
13859de89fe7SArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, name, fd, filter, 0);
138686470930SIngo Molnar 	close(fd);
138786470930SIngo Molnar 
138886470930SIngo Molnar 	/*
138986470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
139086470930SIngo Molnar 	 */
139186470930SIngo Molnar 	if (!ret)
139286470930SIngo Molnar 		goto more;
139386470930SIngo Molnar 
1394a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
139582164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1396a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1397a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1398a25e46c4SArnaldo Carvalho de Melo 	}
139986470930SIngo Molnar out:
140086470930SIngo Molnar 	free(name);
14011340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
14021340e6bbSArnaldo Carvalho de Melo 		return 0;
140386470930SIngo Molnar 	return ret;
140486470930SIngo Molnar }
140586470930SIngo Molnar 
140679406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self,
140779406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1408439d473bSArnaldo Carvalho de Melo {
1409439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1410439d473bSArnaldo Carvalho de Melo 
141179406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1412439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1413439d473bSArnaldo Carvalho de Melo 
1414b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1415439d473bSArnaldo Carvalho de Melo 			return map;
1416439d473bSArnaldo Carvalho de Melo 	}
1417439d473bSArnaldo Carvalho de Melo 
1418439d473bSArnaldo Carvalho de Melo 	return NULL;
1419439d473bSArnaldo Carvalho de Melo }
1420439d473bSArnaldo Carvalho de Melo 
1421a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self,
1422a1645ce1SZhang, Yanmin 				const char *root_dir)
1423b7cece76SArnaldo Carvalho de Melo {
1424b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1425b7cece76SArnaldo Carvalho de Melo 	/*
1426b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1427b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1428b7cece76SArnaldo Carvalho de Melo 	 */
1429b7cece76SArnaldo Carvalho de Melo 	const char *name = self->short_name + 1;
1430b7cece76SArnaldo Carvalho de Melo 
1431b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1432a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1433a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1434b7cece76SArnaldo Carvalho de Melo 
1435b7cece76SArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, self->build_id,
1436b7cece76SArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1437b7cece76SArnaldo Carvalho de Melo 		self->has_build_id = true;
1438b7cece76SArnaldo Carvalho de Melo 
1439b7cece76SArnaldo Carvalho de Melo 	return 0;
1440b7cece76SArnaldo Carvalho de Melo }
1441b7cece76SArnaldo Carvalho de Melo 
1442a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self,
1443a1645ce1SZhang, Yanmin 				const char *dir_name)
14446cfcc53eSMike Galbraith {
1445439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
14465aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
14476cfcc53eSMike Galbraith 
1448439d473bSArnaldo Carvalho de Melo 	if (!dir) {
14495aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1450439d473bSArnaldo Carvalho de Melo 		return -1;
1451439d473bSArnaldo Carvalho de Melo 	}
14526cfcc53eSMike Galbraith 
1453439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1454439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1455a1645ce1SZhang, Yanmin 		struct stat st;
1456439d473bSArnaldo Carvalho de Melo 
1457a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
1458a1645ce1SZhang, Yanmin 		sprintf(path, "%s/%s", dir_name, dent->d_name);
1459a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1460a1645ce1SZhang, Yanmin 			continue;
1461a1645ce1SZhang, Yanmin 
1462a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1463439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1464439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1465439d473bSArnaldo Carvalho de Melo 				continue;
1466439d473bSArnaldo Carvalho de Melo 
1467439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
14685aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
14699de89fe7SArnaldo Carvalho de Melo 			if (map_groups__set_modules_path_dir(self, path) < 0)
1470439d473bSArnaldo Carvalho de Melo 				goto failure;
1471439d473bSArnaldo Carvalho de Melo 		} else {
1472439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1473439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1474439d473bSArnaldo Carvalho de Melo 			struct map *map;
1475cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1476439d473bSArnaldo Carvalho de Melo 
1477439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1478439d473bSArnaldo Carvalho de Melo 				continue;
1479439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1480439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1481439d473bSArnaldo Carvalho de Melo 
1482a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
14839de89fe7SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1484439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1485439d473bSArnaldo Carvalho de Melo 				continue;
1486439d473bSArnaldo Carvalho de Melo 
1487439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
14885aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
1489439d473bSArnaldo Carvalho de Melo 
1490cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1491cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1492439d473bSArnaldo Carvalho de Melo 				goto failure;
1493cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1494a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1495439d473bSArnaldo Carvalho de Melo 		}
1496439d473bSArnaldo Carvalho de Melo 	}
1497439d473bSArnaldo Carvalho de Melo 
1498c338aee8SArnaldo Carvalho de Melo 	return 0;
1499439d473bSArnaldo Carvalho de Melo failure:
1500439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1501439d473bSArnaldo Carvalho de Melo 	return -1;
1502439d473bSArnaldo Carvalho de Melo }
1503439d473bSArnaldo Carvalho de Melo 
1504a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1505439d473bSArnaldo Carvalho de Melo {
1506a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1507a1645ce1SZhang, Yanmin 	FILE *file;
1508a1645ce1SZhang, Yanmin 	char *name, *tmp;
1509a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1510a1645ce1SZhang, Yanmin 
1511a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1512a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1513a1645ce1SZhang, Yanmin 	if (!file)
1514a1645ce1SZhang, Yanmin 		return NULL;
1515a1645ce1SZhang, Yanmin 
1516a1645ce1SZhang, Yanmin 	version[0] = '\0';
1517a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1518a1645ce1SZhang, Yanmin 	fclose(file);
1519a1645ce1SZhang, Yanmin 
1520a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1521a1645ce1SZhang, Yanmin 	if (!name)
1522a1645ce1SZhang, Yanmin 		return NULL;
1523a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1524a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1525a1645ce1SZhang, Yanmin 	if (tmp)
1526a1645ce1SZhang, Yanmin 		*tmp = '\0';
1527a1645ce1SZhang, Yanmin 
1528a1645ce1SZhang, Yanmin 	return strdup(name);
1529a1645ce1SZhang, Yanmin }
1530a1645ce1SZhang, Yanmin 
1531a1645ce1SZhang, Yanmin static int map_groups__set_modules_path(struct map_groups *self,
1532a1645ce1SZhang, Yanmin 				const char *root_dir)
1533a1645ce1SZhang, Yanmin {
1534a1645ce1SZhang, Yanmin 	char *version;
1535439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1536439d473bSArnaldo Carvalho de Melo 
1537a1645ce1SZhang, Yanmin 	version = get_kernel_version(root_dir);
1538a1645ce1SZhang, Yanmin 	if (!version)
1539439d473bSArnaldo Carvalho de Melo 		return -1;
1540439d473bSArnaldo Carvalho de Melo 
1541a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1542a1645ce1SZhang, Yanmin 		 root_dir, version);
1543a1645ce1SZhang, Yanmin 	free(version);
1544439d473bSArnaldo Carvalho de Melo 
15459de89fe7SArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(self, modules_path);
1546439d473bSArnaldo Carvalho de Melo }
15476cfcc53eSMike Galbraith 
15486cfcc53eSMike Galbraith /*
1549439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1550439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1551439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
15526cfcc53eSMike Galbraith  */
15533610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1554439d473bSArnaldo Carvalho de Melo {
15555aab621bSArnaldo Carvalho de Melo 	struct map *self = calloc(1, (sizeof(*self) +
15565aab621bSArnaldo Carvalho de Melo 				      (dso->kernel ? sizeof(struct kmap) : 0)));
1557439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1558439d473bSArnaldo Carvalho de Melo 		/*
1559afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1560439d473bSArnaldo Carvalho de Melo 		 */
15613610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1562439d473bSArnaldo Carvalho de Melo 	}
1563afb7b4f0SArnaldo Carvalho de Melo 
1564439d473bSArnaldo Carvalho de Melo 	return self;
1565439d473bSArnaldo Carvalho de Melo }
1566439d473bSArnaldo Carvalho de Melo 
15679de89fe7SArnaldo Carvalho de Melo struct map *map_groups__new_module(struct map_groups *self, u64 start,
1568a1645ce1SZhang, Yanmin 				const char *filename,
1569a1645ce1SZhang, Yanmin 				struct kernel_info *kerninfo)
1570b7cece76SArnaldo Carvalho de Melo {
1571b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1572a1645ce1SZhang, Yanmin 	struct dso *dso;
1573b7cece76SArnaldo Carvalho de Melo 
1574a1645ce1SZhang, Yanmin 	dso = __dsos__findnew(&kerninfo->dsos__kernel, filename);
1575b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1576b7cece76SArnaldo Carvalho de Melo 		return NULL;
1577b7cece76SArnaldo Carvalho de Melo 
1578b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1579b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1580b7cece76SArnaldo Carvalho de Melo 		return NULL;
1581b7cece76SArnaldo Carvalho de Melo 
1582a1645ce1SZhang, Yanmin 	if (is_host_kernel(kerninfo))
1583b7cece76SArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1584a1645ce1SZhang, Yanmin 	else
1585a1645ce1SZhang, Yanmin 		dso->origin = DSO__ORIG_GUEST_KMODULE;
15869de89fe7SArnaldo Carvalho de Melo 	map_groups__insert(self, map);
1587b7cece76SArnaldo Carvalho de Melo 	return map;
1588b7cece76SArnaldo Carvalho de Melo }
1589b7cece76SArnaldo Carvalho de Melo 
1590a1645ce1SZhang, Yanmin static int map_groups__create_modules(struct kernel_info *kerninfo)
1591439d473bSArnaldo Carvalho de Melo {
1592439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1593439d473bSArnaldo Carvalho de Melo 	size_t n;
1594a1645ce1SZhang, Yanmin 	FILE *file;
1595439d473bSArnaldo Carvalho de Melo 	struct map *map;
1596a1645ce1SZhang, Yanmin 	const char *root_dir;
1597a1645ce1SZhang, Yanmin 	const char *modules;
1598a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1599439d473bSArnaldo Carvalho de Melo 
1600a1645ce1SZhang, Yanmin 	if (is_default_guest(kerninfo))
1601a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
1602a1645ce1SZhang, Yanmin 	else {
1603a1645ce1SZhang, Yanmin 		sprintf(path, "%s/proc/modules", kerninfo->root_dir);
1604a1645ce1SZhang, Yanmin 		modules = path;
1605a1645ce1SZhang, Yanmin 	}
1606a1645ce1SZhang, Yanmin 
1607a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
1608439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1609439d473bSArnaldo Carvalho de Melo 		return -1;
1610439d473bSArnaldo Carvalho de Melo 
1611a1645ce1SZhang, Yanmin 	root_dir = kerninfo->root_dir;
1612a1645ce1SZhang, Yanmin 
1613439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1614439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1615439d473bSArnaldo Carvalho de Melo 		u64 start;
1616439d473bSArnaldo Carvalho de Melo 		char *sep;
1617439d473bSArnaldo Carvalho de Melo 		int line_len;
1618439d473bSArnaldo Carvalho de Melo 
1619439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1620439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
16216cfcc53eSMike Galbraith 			break;
16226cfcc53eSMike Galbraith 
1623439d473bSArnaldo Carvalho de Melo 		if (!line)
1624439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1625439d473bSArnaldo Carvalho de Melo 
1626439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1627439d473bSArnaldo Carvalho de Melo 
1628439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1629439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1630439d473bSArnaldo Carvalho de Melo 			continue;
1631439d473bSArnaldo Carvalho de Melo 
1632439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1633439d473bSArnaldo Carvalho de Melo 
1634439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1635439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1636439d473bSArnaldo Carvalho de Melo 			continue;
1637439d473bSArnaldo Carvalho de Melo 
1638439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1639439d473bSArnaldo Carvalho de Melo 
1640439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
1641a1645ce1SZhang, Yanmin 		map = map_groups__new_module(&kerninfo->kmaps,
1642a1645ce1SZhang, Yanmin 				start, name, kerninfo);
1643b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1644439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1645a1645ce1SZhang, Yanmin 		dso__kernel_module_get_build_id(map->dso, root_dir);
16466cfcc53eSMike Galbraith 	}
16476cfcc53eSMike Galbraith 
1648439d473bSArnaldo Carvalho de Melo 	free(line);
1649439d473bSArnaldo Carvalho de Melo 	fclose(file);
1650439d473bSArnaldo Carvalho de Melo 
1651a1645ce1SZhang, Yanmin 	return map_groups__set_modules_path(&kerninfo->kmaps, root_dir);
1652439d473bSArnaldo Carvalho de Melo 
1653439d473bSArnaldo Carvalho de Melo out_delete_line:
1654439d473bSArnaldo Carvalho de Melo 	free(line);
1655439d473bSArnaldo Carvalho de Melo out_failure:
1656439d473bSArnaldo Carvalho de Melo 	return -1;
16576cfcc53eSMike Galbraith }
16586cfcc53eSMike Galbraith 
16599958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
16606beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
166186470930SIngo Molnar {
1662fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
166386470930SIngo Molnar 
1664fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1665fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
166666bd8424SArnaldo Carvalho de Melo 
1667fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1668fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1669fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1670fbd733b8SArnaldo Carvalho de Melo 			return -1;
1671fbd733b8SArnaldo Carvalho de Melo 		}
1672fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1673fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1674fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1675fbd733b8SArnaldo Carvalho de Melo 
1676fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1677fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1678fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1679fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1680fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1681fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1682fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1683fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1684fbd733b8SArnaldo Carvalho de Melo 			return -1;
1685fbd733b8SArnaldo Carvalho de Melo 		}
1686fbd733b8SArnaldo Carvalho de Melo 	}
1687fbd733b8SArnaldo Carvalho de Melo 
1688fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
168986470930SIngo Molnar 	if (fd < 0)
169086470930SIngo Molnar 		return -1;
169186470930SIngo Molnar 
16923610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
16939de89fe7SArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
169486470930SIngo Molnar 	close(fd);
169586470930SIngo Molnar 
16963846df2eSArnaldo Carvalho de Melo 	if (err > 0)
16973846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", vmlinux);
16983846df2eSArnaldo Carvalho de Melo 
169986470930SIngo Molnar 	return err;
170086470930SIngo Molnar }
170186470930SIngo Molnar 
1702a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map,
17039de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1704a19afe46SArnaldo Carvalho de Melo {
1705a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
1706a19afe46SArnaldo Carvalho de Melo 
1707a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1708a19afe46SArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries);
1709a19afe46SArnaldo Carvalho de Melo 
1710a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
17119de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1712a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1713a19afe46SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(vmlinux_path[i]));
1714a19afe46SArnaldo Carvalho de Melo 			break;
1715a19afe46SArnaldo Carvalho de Melo 		}
1716a19afe46SArnaldo Carvalho de Melo 	}
1717a19afe46SArnaldo Carvalho de Melo 
1718a19afe46SArnaldo Carvalho de Melo 	return err;
1719a19afe46SArnaldo Carvalho de Melo }
1720a19afe46SArnaldo Carvalho de Melo 
1721c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
17229de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
172386470930SIngo Molnar {
1724cc612d81SArnaldo Carvalho de Melo 	int err;
17259e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
17269e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1727dc8d6ab2SArnaldo Carvalho de Melo 	/*
1728dc8d6ab2SArnaldo Carvalho de Melo 	 * Step 1: if the user specified a vmlinux filename, use it and only
1729dc8d6ab2SArnaldo Carvalho de Melo 	 * it, reporting errors to the user if it cannot be used.
1730dc8d6ab2SArnaldo Carvalho de Melo 	 *
1731dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1732dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1733dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1734dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1735dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1736dc8d6ab2SArnaldo Carvalho de Melo 	 *
1737dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1738dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1739dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1740dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1741dc8d6ab2SArnaldo Carvalho de Melo 	 */
1742dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
17439de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map,
1744dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1745dc8d6ab2SArnaldo Carvalho de Melo 		goto out_try_fixup;
1746dc8d6ab2SArnaldo Carvalho de Melo 	}
1747439d473bSArnaldo Carvalho de Melo 
1748cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
17499de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(self, map, filter);
1750a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1751cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1752cc612d81SArnaldo Carvalho de Melo 	}
1753cc612d81SArnaldo Carvalho de Melo 
1754b7cece76SArnaldo Carvalho de Melo 	/*
1755b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1756b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1757b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1758b7cece76SArnaldo Carvalho de Melo 	 */
1759b7cece76SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1760b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
17619e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1762b7cece76SArnaldo Carvalho de Melo 
1763b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
17648d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
17659e201442SArnaldo Carvalho de Melo 			if (dso__build_id_equal(self, kallsyms_build_id)) {
17669e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1767b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
17688d0591f6SArnaldo Carvalho de Melo 			}
17699e201442SArnaldo Carvalho de Melo 		}
1770dc8d6ab2SArnaldo Carvalho de Melo 		/*
1771dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1772dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1773dc8d6ab2SArnaldo Carvalho de Melo 		 */
17749e201442SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
17759e201442SArnaldo Carvalho de Melo 				  sbuild_id);
17769e201442SArnaldo Carvalho de Melo 
17779e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
17789e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
17793846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
17803846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
17818d0591f6SArnaldo Carvalho de Melo 			return -1;
17823846df2eSArnaldo Carvalho de Melo 		}
17838d0591f6SArnaldo Carvalho de Melo 
178419fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
178519fc2dedSArnaldo Carvalho de Melo 
1786dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
17873846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
17883846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
17899e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
1790dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
1791ef6ae724SArnaldo Carvalho de Melo 		}
1792dc8d6ab2SArnaldo Carvalho de Melo 	} else {
1793dc8d6ab2SArnaldo Carvalho de Melo 		/*
1794dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
1795dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
1796dc8d6ab2SArnaldo Carvalho de Melo 		 */
1797dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
1798dc8d6ab2SArnaldo Carvalho de Melo 	}
1799dc8d6ab2SArnaldo Carvalho de Melo 
1800dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
18019de89fe7SArnaldo Carvalho de Melo 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
18023846df2eSArnaldo Carvalho de Melo 	if (err > 0)
18033846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1804dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1805dc8d6ab2SArnaldo Carvalho de Melo 
1806dc8d6ab2SArnaldo Carvalho de Melo out_try_fixup:
1807439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1808cc612d81SArnaldo Carvalho de Melo out_fixup:
1809e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
1810dc8d6ab2SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup("[kernel.kallsyms]"));
18116a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
18126a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1813439d473bSArnaldo Carvalho de Melo 	}
181494cb9e38SArnaldo Carvalho de Melo 
181586470930SIngo Molnar 	return err;
181686470930SIngo Molnar }
181786470930SIngo Molnar 
1818a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1819a1645ce1SZhang, Yanmin 				symbol_filter_t filter)
1820a1645ce1SZhang, Yanmin {
1821a1645ce1SZhang, Yanmin 	int err;
1822a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
1823a1645ce1SZhang, Yanmin 	struct kernel_info *kerninfo;
1824a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1825a1645ce1SZhang, Yanmin 
1826a1645ce1SZhang, Yanmin 	if (!map->groups) {
1827a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1828a1645ce1SZhang, Yanmin 		return -1;
1829a1645ce1SZhang, Yanmin 	}
1830a1645ce1SZhang, Yanmin 	kerninfo = map->groups->this_kerninfo;
1831a1645ce1SZhang, Yanmin 
1832a1645ce1SZhang, Yanmin 	if (is_default_guest(kerninfo)) {
1833a1645ce1SZhang, Yanmin 		/*
1834a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1835a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1836a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1837a1645ce1SZhang, Yanmin 		 */
1838a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1839a1645ce1SZhang, Yanmin 			err = dso__load_vmlinux(self, map,
1840a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
1841a1645ce1SZhang, Yanmin 			goto out_try_fixup;
1842a1645ce1SZhang, Yanmin 		}
1843a1645ce1SZhang, Yanmin 
1844a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1845a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1846a1645ce1SZhang, Yanmin 			return -1;
1847a1645ce1SZhang, Yanmin 	} else {
1848a1645ce1SZhang, Yanmin 		sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
1849a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1850a1645ce1SZhang, Yanmin 	}
1851a1645ce1SZhang, Yanmin 
1852a1645ce1SZhang, Yanmin 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1853a1645ce1SZhang, Yanmin 	if (err > 0)
1854a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1855a1645ce1SZhang, Yanmin 
1856a1645ce1SZhang, Yanmin out_try_fixup:
1857a1645ce1SZhang, Yanmin 	if (err > 0) {
1858a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
1859a1645ce1SZhang, Yanmin 			kern_mmap_name(kerninfo, path);
1860a1645ce1SZhang, Yanmin 			dso__set_long_name(self,
1861a1645ce1SZhang, Yanmin 				strdup(path));
1862a1645ce1SZhang, Yanmin 		}
1863a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1864a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1865a1645ce1SZhang, Yanmin 	}
1866a1645ce1SZhang, Yanmin 
1867a1645ce1SZhang, Yanmin 	return err;
1868a1645ce1SZhang, Yanmin }
1869cd84c2acSFrederic Weisbecker 
1870b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1871cd84c2acSFrederic Weisbecker {
1872b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1873cd84c2acSFrederic Weisbecker }
1874cd84c2acSFrederic Weisbecker 
1875b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1876cd84c2acSFrederic Weisbecker {
1877cd84c2acSFrederic Weisbecker 	struct dso *pos;
1878cd84c2acSFrederic Weisbecker 
1879b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1880cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
1881cd84c2acSFrederic Weisbecker 			return pos;
1882cd84c2acSFrederic Weisbecker 	return NULL;
1883cd84c2acSFrederic Weisbecker }
1884cd84c2acSFrederic Weisbecker 
1885a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
1886cd84c2acSFrederic Weisbecker {
1887a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
1888cd84c2acSFrederic Weisbecker 
1889e4204992SArnaldo Carvalho de Melo 	if (!dso) {
189000a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1891cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1892a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
1893cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1894cfc10d3bSArnaldo Carvalho de Melo 		}
1895e4204992SArnaldo Carvalho de Melo 	}
1896cd84c2acSFrederic Weisbecker 
1897cd84c2acSFrederic Weisbecker 	return dso;
1898cd84c2acSFrederic Weisbecker }
1899cd84c2acSFrederic Weisbecker 
1900b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp)
1901cd84c2acSFrederic Weisbecker {
1902cd84c2acSFrederic Weisbecker 	struct dso *pos;
1903cd84c2acSFrederic Weisbecker 
190495011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
190595011c60SArnaldo Carvalho de Melo 		int i;
190695011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
190795011c60SArnaldo Carvalho de Melo 			dso__fprintf(pos, i, fp);
190895011c60SArnaldo Carvalho de Melo 	}
1909cd84c2acSFrederic Weisbecker }
1910cd84c2acSFrederic Weisbecker 
1911a1645ce1SZhang, Yanmin void dsos__fprintf(struct rb_root *kerninfo_root, FILE *fp)
1912b0da954aSArnaldo Carvalho de Melo {
1913a1645ce1SZhang, Yanmin 	struct rb_node *nd;
1914a1645ce1SZhang, Yanmin 
1915a1645ce1SZhang, Yanmin 	for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) {
1916a1645ce1SZhang, Yanmin 		struct kernel_info *pos = rb_entry(nd, struct kernel_info,
1917a1645ce1SZhang, Yanmin 				rb_node);
1918a1645ce1SZhang, Yanmin 		__dsos__fprintf(&pos->dsos__kernel, fp);
1919a1645ce1SZhang, Yanmin 		__dsos__fprintf(&pos->dsos__user, fp);
1920a1645ce1SZhang, Yanmin 	}
1921b0da954aSArnaldo Carvalho de Melo }
1922b0da954aSArnaldo Carvalho de Melo 
192388d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
192488d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
19259e03eb2dSArnaldo Carvalho de Melo {
19269e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
19279e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
19289e03eb2dSArnaldo Carvalho de Melo 
1929b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
193088d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
193188d3d9b7SArnaldo Carvalho de Melo 			continue;
19329e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
19339e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
19349e03eb2dSArnaldo Carvalho de Melo 	}
19359e03eb2dSArnaldo Carvalho de Melo 	return ret;
19369e03eb2dSArnaldo Carvalho de Melo }
19379e03eb2dSArnaldo Carvalho de Melo 
1938a1645ce1SZhang, Yanmin size_t dsos__fprintf_buildid(struct rb_root *kerninfo_root,
1939a1645ce1SZhang, Yanmin 		FILE *fp, bool with_hits)
1940b0da954aSArnaldo Carvalho de Melo {
1941a1645ce1SZhang, Yanmin 	struct rb_node *nd;
1942a1645ce1SZhang, Yanmin 	size_t ret = 0;
1943a1645ce1SZhang, Yanmin 
1944a1645ce1SZhang, Yanmin 	for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) {
1945a1645ce1SZhang, Yanmin 		struct kernel_info *pos = rb_entry(nd, struct kernel_info,
1946a1645ce1SZhang, Yanmin 				rb_node);
1947a1645ce1SZhang, Yanmin 		ret += __dsos__fprintf_buildid(&pos->dsos__kernel,
1948a1645ce1SZhang, Yanmin 					fp, with_hits);
1949a1645ce1SZhang, Yanmin 		ret += __dsos__fprintf_buildid(&pos->dsos__user,
1950a1645ce1SZhang, Yanmin 					fp, with_hits);
1951a1645ce1SZhang, Yanmin 	}
1952a1645ce1SZhang, Yanmin 	return ret;
1953b0da954aSArnaldo Carvalho de Melo }
1954b0da954aSArnaldo Carvalho de Melo 
1955fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name)
1956fd1d908cSArnaldo Carvalho de Melo {
1957fd1d908cSArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1958fd1d908cSArnaldo Carvalho de Melo 
1959fd1d908cSArnaldo Carvalho de Melo 	if (self != NULL) {
1960b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, "[kernel]");
1961a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_KERNEL;
1962fd1d908cSArnaldo Carvalho de Melo 	}
1963fd1d908cSArnaldo Carvalho de Melo 
1964fd1d908cSArnaldo Carvalho de Melo 	return self;
1965fd1d908cSArnaldo Carvalho de Melo }
1966fd1d908cSArnaldo Carvalho de Melo 
1967a1645ce1SZhang, Yanmin static struct dso *dso__new_guest_kernel(struct kernel_info *kerninfo,
1968a1645ce1SZhang, Yanmin 					const char *name)
1969fd1d908cSArnaldo Carvalho de Melo {
1970a1645ce1SZhang, Yanmin 	char buff[PATH_MAX];
1971a1645ce1SZhang, Yanmin 	struct dso *self;
1972a1645ce1SZhang, Yanmin 
1973a1645ce1SZhang, Yanmin 	kern_mmap_name(kerninfo, buff);
1974a1645ce1SZhang, Yanmin 	self = dso__new(name ?: buff);
1975a1645ce1SZhang, Yanmin 	if (self != NULL) {
1976a1645ce1SZhang, Yanmin 		dso__set_short_name(self, "[guest.kernel]");
1977a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_GUEST_KERNEL;
1978a1645ce1SZhang, Yanmin 	}
1979a1645ce1SZhang, Yanmin 
1980a1645ce1SZhang, Yanmin 	return self;
1981a1645ce1SZhang, Yanmin }
1982a1645ce1SZhang, Yanmin 
1983a1645ce1SZhang, Yanmin void dso__read_running_kernel_build_id(struct dso *self,
1984a1645ce1SZhang, Yanmin 			struct kernel_info *kerninfo)
1985a1645ce1SZhang, Yanmin {
1986a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1987a1645ce1SZhang, Yanmin 
1988a1645ce1SZhang, Yanmin 	if (is_default_guest(kerninfo))
1989a1645ce1SZhang, Yanmin 		return;
1990a1645ce1SZhang, Yanmin 	sprintf(path, "%s/sys/kernel/notes", kerninfo->root_dir);
1991a1645ce1SZhang, Yanmin 	if (sysfs__read_build_id(path, self->build_id,
1992fd1d908cSArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1993fd1d908cSArnaldo Carvalho de Melo 		self->has_build_id = true;
1994fd1d908cSArnaldo Carvalho de Melo }
1995fd1d908cSArnaldo Carvalho de Melo 
1996a1645ce1SZhang, Yanmin static struct dso *dsos__create_kernel(struct kernel_info *kerninfo)
1997cd84c2acSFrederic Weisbecker {
1998a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
1999a1645ce1SZhang, Yanmin 	struct dso *kernel;
2000cd84c2acSFrederic Weisbecker 
2001a1645ce1SZhang, Yanmin 	if (is_host_kernel(kerninfo)) {
2002a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2003a1645ce1SZhang, Yanmin 		kernel = dso__new_kernel(vmlinux_name);
2004a1645ce1SZhang, Yanmin 	} else {
2005a1645ce1SZhang, Yanmin 		if (is_default_guest(kerninfo))
2006a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2007a1645ce1SZhang, Yanmin 		kernel = dso__new_guest_kernel(kerninfo, vmlinux_name);
20088d92c02aSArnaldo Carvalho de Melo 	}
2009cd84c2acSFrederic Weisbecker 
2010a1645ce1SZhang, Yanmin 	if (kernel != NULL) {
2011a1645ce1SZhang, Yanmin 		dso__read_running_kernel_build_id(kernel, kerninfo);
2012a1645ce1SZhang, Yanmin 		dsos__add(&kerninfo->dsos__kernel, kernel);
2013a1645ce1SZhang, Yanmin 	}
2014f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2015f1dfa0b1SArnaldo Carvalho de Melo }
2016f1dfa0b1SArnaldo Carvalho de Melo 
2017b7cece76SArnaldo Carvalho de Melo int __map_groups__create_kernel_maps(struct map_groups *self,
2018de176489SArnaldo Carvalho de Melo 				     struct map *vmlinux_maps[MAP__NR_TYPES],
2019b7cece76SArnaldo Carvalho de Melo 				     struct dso *kernel)
2020f1dfa0b1SArnaldo Carvalho de Melo {
2021de176489SArnaldo Carvalho de Melo 	enum map_type type;
2022f1dfa0b1SArnaldo Carvalho de Melo 
2023de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
20249de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
20259de89fe7SArnaldo Carvalho de Melo 
2026de176489SArnaldo Carvalho de Melo 		vmlinux_maps[type] = map__new2(0, kernel, type);
2027de176489SArnaldo Carvalho de Melo 		if (vmlinux_maps[type] == NULL)
2028f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2029f1dfa0b1SArnaldo Carvalho de Melo 
2030de176489SArnaldo Carvalho de Melo 		vmlinux_maps[type]->map_ip =
2031de176489SArnaldo Carvalho de Melo 			vmlinux_maps[type]->unmap_ip = identity__map_ip;
20329de89fe7SArnaldo Carvalho de Melo 
20339de89fe7SArnaldo Carvalho de Melo 		kmap = map__kmap(vmlinux_maps[type]);
20349de89fe7SArnaldo Carvalho de Melo 		kmap->kmaps = self;
2035de176489SArnaldo Carvalho de Melo 		map_groups__insert(self, vmlinux_maps[type]);
2036f1dfa0b1SArnaldo Carvalho de Melo 	}
2037f1dfa0b1SArnaldo Carvalho de Melo 
2038f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
20392446042cSArnaldo Carvalho de Melo }
20402446042cSArnaldo Carvalho de Melo 
2041cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
20422446042cSArnaldo Carvalho de Melo {
2043cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2044cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2045cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2046cc612d81SArnaldo Carvalho de Melo 	}
2047cc612d81SArnaldo Carvalho de Melo 
2048cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2049cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2050cc612d81SArnaldo Carvalho de Melo }
2051cc612d81SArnaldo Carvalho de Melo 
2052cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2053cc612d81SArnaldo Carvalho de Melo {
2054cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2055cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2056cc612d81SArnaldo Carvalho de Melo 
2057cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
20582446042cSArnaldo Carvalho de Melo 		return -1;
20592446042cSArnaldo Carvalho de Melo 
2060cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2061cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2062cc612d81SArnaldo Carvalho de Melo 		return -1;
2063cc612d81SArnaldo Carvalho de Melo 
2064cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2065cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2066cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2067cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2068cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2069cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2070cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2071cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2072cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2073cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2074cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2075cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2076cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2077cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2078cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2079cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2080cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2081cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2082cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2083cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2084cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2085cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2086cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2087cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2088cc612d81SArnaldo Carvalho de Melo 
2089cc612d81SArnaldo Carvalho de Melo 	return 0;
2090cc612d81SArnaldo Carvalho de Melo 
2091cc612d81SArnaldo Carvalho de Melo out_fail:
2092cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2093cc612d81SArnaldo Carvalho de Melo 	return -1;
2094cc612d81SArnaldo Carvalho de Melo }
2095cc612d81SArnaldo Carvalho de Melo 
2096b0a9ab62SArnaldo Carvalho de Melo size_t vmlinux_path__fprintf(FILE *fp)
2097b0a9ab62SArnaldo Carvalho de Melo {
2098b0a9ab62SArnaldo Carvalho de Melo 	int i;
2099b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
2100b0a9ab62SArnaldo Carvalho de Melo 
2101b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
2102b0a9ab62SArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n", i, vmlinux_path[i]);
2103b0a9ab62SArnaldo Carvalho de Melo 
2104b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2105b0a9ab62SArnaldo Carvalho de Melo }
2106b0a9ab62SArnaldo Carvalho de Melo 
2107655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2108655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2109655000e7SArnaldo Carvalho de Melo {
2110655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2111655000e7SArnaldo Carvalho de Melo 		return 0;
2112655000e7SArnaldo Carvalho de Melo 
2113655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2114655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2115655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2116655000e7SArnaldo Carvalho de Melo 		return -1;
2117655000e7SArnaldo Carvalho de Melo 	}
2118655000e7SArnaldo Carvalho de Melo 	return 0;
2119655000e7SArnaldo Carvalho de Melo }
2120655000e7SArnaldo Carvalho de Melo 
212175be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2122cc612d81SArnaldo Carvalho de Melo {
212395011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
212475be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
212575be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
212679406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2127b32d133aSArnaldo Carvalho de Melo 
212875be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2129cc612d81SArnaldo Carvalho de Melo 		return -1;
2130cc612d81SArnaldo Carvalho de Melo 
2131c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2132c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2133c410a338SArnaldo Carvalho de Melo 		return -1;
2134c410a338SArnaldo Carvalho de Melo 	}
2135c410a338SArnaldo Carvalho de Melo 
2136655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2137655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2138655000e7SArnaldo Carvalho de Melo 		return -1;
2139655000e7SArnaldo Carvalho de Melo 
2140655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2141655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2142655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2143655000e7SArnaldo Carvalho de Melo 
2144655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2145655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2146655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2147655000e7SArnaldo Carvalho de Melo 
21484aa65636SArnaldo Carvalho de Melo 	return 0;
2149655000e7SArnaldo Carvalho de Melo 
2150655000e7SArnaldo Carvalho de Melo out_free_dso_list:
2151655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2152655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2153655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2154655000e7SArnaldo Carvalho de Melo 	return -1;
2155cc612d81SArnaldo Carvalho de Melo }
2156cc612d81SArnaldo Carvalho de Melo 
2157a1645ce1SZhang, Yanmin int map_groups__create_kernel_maps(struct rb_root *kerninfo_root, pid_t pid)
21584aa65636SArnaldo Carvalho de Melo {
2159a1645ce1SZhang, Yanmin 	struct kernel_info *kerninfo;
2160a1645ce1SZhang, Yanmin 	struct dso *kernel;
21619de89fe7SArnaldo Carvalho de Melo 
2162a1645ce1SZhang, Yanmin 	kerninfo = kerninfo__findnew(kerninfo_root, pid);
2163a1645ce1SZhang, Yanmin 	if (kerninfo == NULL)
2164a1645ce1SZhang, Yanmin 		return -1;
2165a1645ce1SZhang, Yanmin 	kernel = dsos__create_kernel(kerninfo);
21669de89fe7SArnaldo Carvalho de Melo 	if (kernel == NULL)
21674aa65636SArnaldo Carvalho de Melo 		return -1;
21684aa65636SArnaldo Carvalho de Melo 
2169a1645ce1SZhang, Yanmin 	if (__map_groups__create_kernel_maps(&kerninfo->kmaps,
2170a1645ce1SZhang, Yanmin 			kerninfo->vmlinux_maps, kernel) < 0)
21719de89fe7SArnaldo Carvalho de Melo 		return -1;
21729de89fe7SArnaldo Carvalho de Melo 
2173a1645ce1SZhang, Yanmin 	if (symbol_conf.use_modules &&
2174a1645ce1SZhang, Yanmin 		map_groups__create_modules(kerninfo) < 0)
217510fe12efSArnaldo Carvalho de Melo 		pr_debug("Problems creating module maps, continuing anyway...\n");
217690c83218SArnaldo Carvalho de Melo 	/*
217790c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
217890c83218SArnaldo Carvalho de Melo 	 */
2179a1645ce1SZhang, Yanmin 	map_groups__fixup_end(&kerninfo->kmaps);
21806671cb16SArnaldo Carvalho de Melo 	return 0;
2181cd84c2acSFrederic Weisbecker }
21825aab621bSArnaldo Carvalho de Melo 
21835aab621bSArnaldo Carvalho de Melo static int hex(char ch)
21845aab621bSArnaldo Carvalho de Melo {
21855aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
21865aab621bSArnaldo Carvalho de Melo 		return ch - '0';
21875aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
21885aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
21895aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
21905aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
21915aab621bSArnaldo Carvalho de Melo 	return -1;
21925aab621bSArnaldo Carvalho de Melo }
21935aab621bSArnaldo Carvalho de Melo 
21945aab621bSArnaldo Carvalho de Melo /*
21955aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
21965aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
21975aab621bSArnaldo Carvalho de Melo  */
21985aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
21995aab621bSArnaldo Carvalho de Melo {
22005aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
22015aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
22025aab621bSArnaldo Carvalho de Melo 
22035aab621bSArnaldo Carvalho de Melo 	while (*p) {
22045aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
22055aab621bSArnaldo Carvalho de Melo 
22065aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
22075aab621bSArnaldo Carvalho de Melo 			break;
22085aab621bSArnaldo Carvalho de Melo 
22095aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
22105aab621bSArnaldo Carvalho de Melo 		p++;
22115aab621bSArnaldo Carvalho de Melo 	}
22125aab621bSArnaldo Carvalho de Melo 
22135aab621bSArnaldo Carvalho de Melo 	return p - ptr;
22145aab621bSArnaldo Carvalho de Melo }
22155aab621bSArnaldo Carvalho de Melo 
22165aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
22175aab621bSArnaldo Carvalho de Melo {
22185aab621bSArnaldo Carvalho de Melo 	char *p = s;
22195aab621bSArnaldo Carvalho de Melo 
22205aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
22215aab621bSArnaldo Carvalho de Melo 		*p++ = to;
22225aab621bSArnaldo Carvalho de Melo 
22235aab621bSArnaldo Carvalho de Melo 	return s;
22245aab621bSArnaldo Carvalho de Melo }
2225a1645ce1SZhang, Yanmin 
2226a1645ce1SZhang, Yanmin int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root)
2227a1645ce1SZhang, Yanmin {
2228a1645ce1SZhang, Yanmin 	int ret = 0;
2229a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2230a1645ce1SZhang, Yanmin 	int i, items = 0;
2231a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2232a1645ce1SZhang, Yanmin 	pid_t pid;
2233a1645ce1SZhang, Yanmin 
2234a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2235a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2236a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2237a1645ce1SZhang, Yanmin 		map_groups__create_kernel_maps(kerninfo_root,
2238a1645ce1SZhang, Yanmin 					DEFAULT_GUEST_KERNEL_ID);
2239a1645ce1SZhang, Yanmin 	}
2240a1645ce1SZhang, Yanmin 
2241a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2242a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2243a1645ce1SZhang, Yanmin 		if (items <= 0)
2244a1645ce1SZhang, Yanmin 			return -ENOENT;
2245a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2246a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2247a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2248a1645ce1SZhang, Yanmin 				continue;
2249a1645ce1SZhang, Yanmin 			}
2250a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2251a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2252a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2253a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2254a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2255a1645ce1SZhang, Yanmin 			if (ret) {
2256a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2257a1645ce1SZhang, Yanmin 				goto failure;
2258a1645ce1SZhang, Yanmin 			}
2259a1645ce1SZhang, Yanmin 			map_groups__create_kernel_maps(kerninfo_root,
2260a1645ce1SZhang, Yanmin 							pid);
2261a1645ce1SZhang, Yanmin 		}
2262a1645ce1SZhang, Yanmin failure:
2263a1645ce1SZhang, Yanmin 		free(namelist);
2264a1645ce1SZhang, Yanmin 	}
2265a1645ce1SZhang, Yanmin 
2266a1645ce1SZhang, Yanmin 	return ret;
2267a1645ce1SZhang, Yanmin }
2268