xref: /linux/tools/perf/util/symbol.c (revision ec5761eab318e50e69fcf8e63e9edaef5949c067)
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>
14b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
158a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1686470930SIngo Molnar #include "symbol.h"
175aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1886470930SIngo Molnar 
1986470930SIngo Molnar #include <libelf.h>
2086470930SIngo Molnar #include <gelf.h>
2186470930SIngo Molnar #include <elf.h>
22f1617b40SArnaldo Carvalho de Melo #include <limits.h>
23439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
242cdbc46dSPeter Zijlstra 
25c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
26c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
27c12e15e7SArnaldo Carvalho de Melo #endif
28c12e15e7SArnaldo Carvalho de Melo 
2921916c38SDave Martin static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
3021916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size);
31b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
323610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
33c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
349de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
35a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
36a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
37cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
38cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
39439d473bSArnaldo Carvalho de Melo 
4075be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
41d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
42b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
43b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
44*ec5761eaSDavid Ahern 	.symfs            = "",
45b32d133aSArnaldo Carvalho de Melo };
46b32d133aSArnaldo Carvalho de Melo 
478a6c5b26SArnaldo Carvalho de Melo int dso__name_len(const struct dso *self)
488a6c5b26SArnaldo Carvalho de Melo {
498a6c5b26SArnaldo Carvalho de Melo 	if (verbose)
508a6c5b26SArnaldo Carvalho de Melo 		return self->long_name_len;
518a6c5b26SArnaldo Carvalho de Melo 
528a6c5b26SArnaldo Carvalho de Melo 	return self->short_name_len;
538a6c5b26SArnaldo Carvalho de Melo }
548a6c5b26SArnaldo Carvalho de Melo 
553610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
563610583cSArnaldo Carvalho de Melo {
573610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
583610583cSArnaldo Carvalho de Melo }
593610583cSArnaldo Carvalho de Melo 
6079406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type)
6179406cd7SArnaldo Carvalho de Melo {
6279406cd7SArnaldo Carvalho de Melo 	return self->sorted_by_name & (1 << type);
6379406cd7SArnaldo Carvalho de Melo }
6479406cd7SArnaldo Carvalho de Melo 
6579406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
6679406cd7SArnaldo Carvalho de Melo {
6779406cd7SArnaldo Carvalho de Melo 	self->sorted_by_name |= (1 << type);
6879406cd7SArnaldo Carvalho de Melo }
6979406cd7SArnaldo Carvalho de Melo 
7036a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
716893d4eeSArnaldo Carvalho de Melo {
726893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
736893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
746893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
75f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
76f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
776893d4eeSArnaldo Carvalho de Melo 	default:
786893d4eeSArnaldo Carvalho de Melo 		return false;
796893d4eeSArnaldo Carvalho de Melo 	}
806893d4eeSArnaldo Carvalho de Melo }
816893d4eeSArnaldo Carvalho de Melo 
82fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
83af427bf5SArnaldo Carvalho de Melo {
84fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
852e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
86af427bf5SArnaldo Carvalho de Melo 
87af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
88af427bf5SArnaldo Carvalho de Melo 		return;
89af427bf5SArnaldo Carvalho de Melo 
902e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
912e538c4aSArnaldo Carvalho de Melo 
92af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
932e538c4aSArnaldo Carvalho de Melo 		prev = curr;
942e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
95af427bf5SArnaldo Carvalho de Melo 
96af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
97af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
98af427bf5SArnaldo Carvalho de Melo 	}
99af427bf5SArnaldo Carvalho de Melo 
1002e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
1012e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
1022e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
1032e538c4aSArnaldo Carvalho de Melo }
1042e538c4aSArnaldo Carvalho de Melo 
1059958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
106af427bf5SArnaldo Carvalho de Melo {
107af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
10895011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
109af427bf5SArnaldo Carvalho de Melo 
110af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
111af427bf5SArnaldo Carvalho de Melo 		return;
112af427bf5SArnaldo Carvalho de Melo 
113af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
114af427bf5SArnaldo Carvalho de Melo 
115af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
116af427bf5SArnaldo Carvalho de Melo 		prev = curr;
117af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
118af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1192e538c4aSArnaldo Carvalho de Melo 	}
12090c83218SArnaldo Carvalho de Melo 
12190c83218SArnaldo Carvalho de Melo 	/*
12290c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
12390c83218SArnaldo Carvalho de Melo 	 * last map final address.
12490c83218SArnaldo Carvalho de Melo 	 */
1259d1faba5SIan Munsie 	curr->end = ~0ULL;
126af427bf5SArnaldo Carvalho de Melo }
127af427bf5SArnaldo Carvalho de Melo 
1289958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
12923ea4a3fSArnaldo Carvalho de Melo {
13023ea4a3fSArnaldo Carvalho de Melo 	int i;
13123ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1329958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
13323ea4a3fSArnaldo Carvalho de Melo }
13423ea4a3fSArnaldo Carvalho de Melo 
135c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
136c408fedfSArnaldo Carvalho de Melo 				  const char *name)
13786470930SIngo Molnar {
13886470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
1395aab621bSArnaldo Carvalho de Melo 	struct symbol *self = calloc(1, (symbol_conf.priv_size +
1405aab621bSArnaldo Carvalho de Melo 					 sizeof(*self) + namelen));
14136479484SArnaldo Carvalho de Melo 	if (self == NULL)
14286470930SIngo Molnar 		return NULL;
14386470930SIngo Molnar 
14475be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
14575be6cf4SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol_conf.priv_size;
14636479484SArnaldo Carvalho de Melo 
14786470930SIngo Molnar 	self->start   = start;
1486cfcc53eSMike Galbraith 	self->end     = len ? start + len - 1 : start;
149c408fedfSArnaldo Carvalho de Melo 	self->binding = binding;
150fefb0b94SArnaldo Carvalho de Melo 	self->namelen = namelen - 1;
151e4204992SArnaldo Carvalho de Melo 
15229a9f66dSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
153e4204992SArnaldo Carvalho de Melo 
15486470930SIngo Molnar 	memcpy(self->name, name, namelen);
15586470930SIngo Molnar 
15686470930SIngo Molnar 	return self;
15786470930SIngo Molnar }
15886470930SIngo Molnar 
159628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self)
16086470930SIngo Molnar {
16175be6cf4SArnaldo Carvalho de Melo 	free(((void *)self) - symbol_conf.priv_size);
16286470930SIngo Molnar }
16386470930SIngo Molnar 
16486470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
16586470930SIngo Molnar {
166c408fedfSArnaldo Carvalho de Melo 	return fprintf(fp, " %llx-%llx %c %s\n",
167c408fedfSArnaldo Carvalho de Melo 		       self->start, self->end,
168c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_GLOBAL ? 'g' :
169c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_LOCAL  ? 'l' : 'w',
170c408fedfSArnaldo Carvalho de Melo 		       self->name);
17186470930SIngo Molnar }
17286470930SIngo Molnar 
173b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name)
174cfc10d3bSArnaldo Carvalho de Melo {
175ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
176ef6ae724SArnaldo Carvalho de Melo 		return;
177cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
178cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
179cfc10d3bSArnaldo Carvalho de Melo }
180cfc10d3bSArnaldo Carvalho de Melo 
181b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name)
182b63be8d7SArnaldo Carvalho de Melo {
183b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
184b63be8d7SArnaldo Carvalho de Melo 		return;
185b63be8d7SArnaldo Carvalho de Melo 	self->short_name = name;
186b63be8d7SArnaldo Carvalho de Melo 	self->short_name_len = strlen(name);
187b63be8d7SArnaldo Carvalho de Melo }
188b63be8d7SArnaldo Carvalho de Melo 
189cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
190cfc10d3bSArnaldo Carvalho de Melo {
191b63be8d7SArnaldo Carvalho de Melo 	dso__set_short_name(self, basename(self->long_name));
192cfc10d3bSArnaldo Carvalho de Melo }
193cfc10d3bSArnaldo Carvalho de Melo 
19400a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
19586470930SIngo Molnar {
1965aab621bSArnaldo Carvalho de Melo 	struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
19786470930SIngo Molnar 
19886470930SIngo Molnar 	if (self != NULL) {
1996a4694a4SArnaldo Carvalho de Melo 		int i;
20086470930SIngo Molnar 		strcpy(self->name, name);
201cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
202b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, self->name);
2036a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
20479406cd7SArnaldo Carvalho de Melo 			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
20552d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
20694cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
2078d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
20879406cd7SArnaldo Carvalho de Melo 		self->sorted_by_name = 0;
2098d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
210a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_USER;
2110ab061cdSMasami Hiramatsu 		INIT_LIST_HEAD(&self->node);
21286470930SIngo Molnar 	}
21386470930SIngo Molnar 
21486470930SIngo Molnar 	return self;
21586470930SIngo Molnar }
21686470930SIngo Molnar 
217fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
21886470930SIngo Molnar {
21986470930SIngo Molnar 	struct symbol *pos;
220fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
22186470930SIngo Molnar 
22286470930SIngo Molnar 	while (next) {
22386470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
22486470930SIngo Molnar 		next = rb_next(&pos->rb_node);
225fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
22600a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
22786470930SIngo Molnar 	}
22886470930SIngo Molnar }
22986470930SIngo Molnar 
23086470930SIngo Molnar void dso__delete(struct dso *self)
23186470930SIngo Molnar {
2326a4694a4SArnaldo Carvalho de Melo 	int i;
2336a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2346a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
2356e406257SArnaldo Carvalho de Melo 	if (self->sname_alloc)
2366e406257SArnaldo Carvalho de Melo 		free((char *)self->short_name);
2376e406257SArnaldo Carvalho de Melo 	if (self->lname_alloc)
238439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
23986470930SIngo Molnar 	free(self);
24086470930SIngo Molnar }
24186470930SIngo Molnar 
2428d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2438d06367fSArnaldo Carvalho de Melo {
2448d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2458d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2468d06367fSArnaldo Carvalho de Melo }
2478d06367fSArnaldo Carvalho de Melo 
248fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
24986470930SIngo Molnar {
250fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
25186470930SIngo Molnar 	struct rb_node *parent = NULL;
2529cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
25386470930SIngo Molnar 	struct symbol *s;
25486470930SIngo Molnar 
25586470930SIngo Molnar 	while (*p != NULL) {
25686470930SIngo Molnar 		parent = *p;
25786470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
25886470930SIngo Molnar 		if (ip < s->start)
25986470930SIngo Molnar 			p = &(*p)->rb_left;
26086470930SIngo Molnar 		else
26186470930SIngo Molnar 			p = &(*p)->rb_right;
26286470930SIngo Molnar 	}
26386470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
264fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
26586470930SIngo Molnar }
26686470930SIngo Molnar 
267fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
26886470930SIngo Molnar {
26986470930SIngo Molnar 	struct rb_node *n;
27086470930SIngo Molnar 
27186470930SIngo Molnar 	if (self == NULL)
27286470930SIngo Molnar 		return NULL;
27386470930SIngo Molnar 
274fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
27586470930SIngo Molnar 
27686470930SIngo Molnar 	while (n) {
27786470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
27886470930SIngo Molnar 
27986470930SIngo Molnar 		if (ip < s->start)
28086470930SIngo Molnar 			n = n->rb_left;
28186470930SIngo Molnar 		else if (ip > s->end)
28286470930SIngo Molnar 			n = n->rb_right;
28386470930SIngo Molnar 		else
28486470930SIngo Molnar 			return s;
28586470930SIngo Molnar 	}
28686470930SIngo Molnar 
28786470930SIngo Molnar 	return NULL;
28886470930SIngo Molnar }
28986470930SIngo Molnar 
29079406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
29179406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
29279406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
29379406cd7SArnaldo Carvalho de Melo };
29479406cd7SArnaldo Carvalho de Melo 
29579406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
29679406cd7SArnaldo Carvalho de Melo {
29779406cd7SArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
29879406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
29902a9d037SRabin Vincent 	struct symbol_name_rb_node *symn, *s;
30002a9d037SRabin Vincent 
30102a9d037SRabin Vincent 	symn = container_of(sym, struct symbol_name_rb_node, sym);
30279406cd7SArnaldo Carvalho de Melo 
30379406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
30479406cd7SArnaldo Carvalho de Melo 		parent = *p;
30579406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
30679406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
30779406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
30879406cd7SArnaldo Carvalho de Melo 		else
30979406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
31079406cd7SArnaldo Carvalho de Melo 	}
31179406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
31279406cd7SArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, self);
31379406cd7SArnaldo Carvalho de Melo }
31479406cd7SArnaldo Carvalho de Melo 
31579406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
31679406cd7SArnaldo Carvalho de Melo {
31779406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
31879406cd7SArnaldo Carvalho de Melo 
31979406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
32079406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
32179406cd7SArnaldo Carvalho de Melo 		symbols__insert_by_name(self, pos);
32279406cd7SArnaldo Carvalho de Melo 	}
32379406cd7SArnaldo Carvalho de Melo }
32479406cd7SArnaldo Carvalho de Melo 
32579406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
32679406cd7SArnaldo Carvalho de Melo {
32779406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
32879406cd7SArnaldo Carvalho de Melo 
32979406cd7SArnaldo Carvalho de Melo 	if (self == NULL)
33079406cd7SArnaldo Carvalho de Melo 		return NULL;
33179406cd7SArnaldo Carvalho de Melo 
33279406cd7SArnaldo Carvalho de Melo 	n = self->rb_node;
33379406cd7SArnaldo Carvalho de Melo 
33479406cd7SArnaldo Carvalho de Melo 	while (n) {
33579406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
33679406cd7SArnaldo Carvalho de Melo 		int cmp;
33779406cd7SArnaldo Carvalho de Melo 
33879406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
33979406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
34079406cd7SArnaldo Carvalho de Melo 
34179406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
34279406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
34379406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
34479406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
34579406cd7SArnaldo Carvalho de Melo 		else
34679406cd7SArnaldo Carvalho de Melo 			return &s->sym;
34779406cd7SArnaldo Carvalho de Melo 	}
34879406cd7SArnaldo Carvalho de Melo 
34979406cd7SArnaldo Carvalho de Melo 	return NULL;
35079406cd7SArnaldo Carvalho de Melo }
35179406cd7SArnaldo Carvalho de Melo 
35279406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self,
35379406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
354fcf1203aSArnaldo Carvalho de Melo {
3556a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
356fcf1203aSArnaldo Carvalho de Melo }
357fcf1203aSArnaldo Carvalho de Melo 
35879406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
35979406cd7SArnaldo Carvalho de Melo 					const char *name)
36079406cd7SArnaldo Carvalho de Melo {
36179406cd7SArnaldo Carvalho de Melo 	return symbols__find_by_name(&self->symbol_names[type], name);
36279406cd7SArnaldo Carvalho de Melo }
36379406cd7SArnaldo Carvalho de Melo 
36479406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type)
36579406cd7SArnaldo Carvalho de Melo {
36679406cd7SArnaldo Carvalho de Melo 	dso__set_sorted_by_name(self, type);
36779406cd7SArnaldo Carvalho de Melo 	return symbols__sort_by_name(&self->symbol_names[type],
36879406cd7SArnaldo Carvalho de Melo 				     &self->symbols[type]);
36979406cd7SArnaldo Carvalho de Melo }
37079406cd7SArnaldo Carvalho de Melo 
371ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf)
3728d06367fSArnaldo Carvalho de Melo {
3738d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
374ef12a141SArnaldo Carvalho de Melo 	const u8 *raw = self;
3758d06367fSArnaldo Carvalho de Melo 	int i;
3768d06367fSArnaldo Carvalho de Melo 
3778d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
3788d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
3798d06367fSArnaldo Carvalho de Melo 		++raw;
3808d06367fSArnaldo Carvalho de Melo 		bid += 2;
3818d06367fSArnaldo Carvalho de Melo 	}
3828d06367fSArnaldo Carvalho de Melo 
3838d06367fSArnaldo Carvalho de Melo 	return raw - self;
3848d06367fSArnaldo Carvalho de Melo }
3858d06367fSArnaldo Carvalho de Melo 
3869e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
38786470930SIngo Molnar {
3888d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
3898d06367fSArnaldo Carvalho de Melo 
3908d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
3919e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
3929e03eb2dSArnaldo Carvalho de Melo }
3939e03eb2dSArnaldo Carvalho de Melo 
39490f18e63SSrikar Dronamraju size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp)
39590f18e63SSrikar Dronamraju {
39690f18e63SSrikar Dronamraju 	size_t ret = 0;
39790f18e63SSrikar Dronamraju 	struct rb_node *nd;
39890f18e63SSrikar Dronamraju 	struct symbol_name_rb_node *pos;
39990f18e63SSrikar Dronamraju 
40090f18e63SSrikar Dronamraju 	for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) {
40190f18e63SSrikar Dronamraju 		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
40290f18e63SSrikar Dronamraju 		fprintf(fp, "%s\n", pos->sym.name);
40390f18e63SSrikar Dronamraju 	}
40490f18e63SSrikar Dronamraju 
40590f18e63SSrikar Dronamraju 	return ret;
40690f18e63SSrikar Dronamraju }
40790f18e63SSrikar Dronamraju 
40895011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
4099e03eb2dSArnaldo Carvalho de Melo {
4109e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
4119e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
4129e03eb2dSArnaldo Carvalho de Melo 
4133846df2eSArnaldo Carvalho de Melo 	if (self->short_name != self->long_name)
4143846df2eSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", self->long_name);
4153846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
4163846df2eSArnaldo Carvalho de Melo 		       self->loaded ? "" : "NOT ");
4179e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
4186a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
41995011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
42086470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
42186470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
42286470930SIngo Molnar 	}
42386470930SIngo Molnar 
42486470930SIngo Molnar 	return ret;
42586470930SIngo Molnar }
42686470930SIngo Molnar 
4279e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
4289e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
429682b335aSArnaldo Carvalho de Melo 						     char type, u64 start))
43086470930SIngo Molnar {
43186470930SIngo Molnar 	char *line = NULL;
43286470930SIngo Molnar 	size_t n;
433682b335aSArnaldo Carvalho de Melo 	int err = 0;
4349e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
43586470930SIngo Molnar 
43686470930SIngo Molnar 	if (file == NULL)
43786470930SIngo Molnar 		goto out_failure;
43886470930SIngo Molnar 
43986470930SIngo Molnar 	while (!feof(file)) {
4409cffa8d5SPaul Mackerras 		u64 start;
44186470930SIngo Molnar 		int line_len, len;
44286470930SIngo Molnar 		char symbol_type;
4432e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
44486470930SIngo Molnar 
44586470930SIngo Molnar 		line_len = getline(&line, &n, file);
446a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
44786470930SIngo Molnar 			break;
44886470930SIngo Molnar 
44986470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
45086470930SIngo Molnar 
45186470930SIngo Molnar 		len = hex2u64(line, &start);
45286470930SIngo Molnar 
45386470930SIngo Molnar 		len++;
45486470930SIngo Molnar 		if (len + 2 >= line_len)
45586470930SIngo Molnar 			continue;
45686470930SIngo Molnar 
45786470930SIngo Molnar 		symbol_type = toupper(line[len]);
458af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
459682b335aSArnaldo Carvalho de Melo 
460682b335aSArnaldo Carvalho de Melo 		err = process_symbol(arg, symbol_name, symbol_type, start);
461682b335aSArnaldo Carvalho de Melo 		if (err)
462682b335aSArnaldo Carvalho de Melo 			break;
463682b335aSArnaldo Carvalho de Melo 	}
464682b335aSArnaldo Carvalho de Melo 
465682b335aSArnaldo Carvalho de Melo 	free(line);
466682b335aSArnaldo Carvalho de Melo 	fclose(file);
467682b335aSArnaldo Carvalho de Melo 	return err;
468682b335aSArnaldo Carvalho de Melo 
469682b335aSArnaldo Carvalho de Melo out_failure:
470682b335aSArnaldo Carvalho de Melo 	return -1;
471682b335aSArnaldo Carvalho de Melo }
472682b335aSArnaldo Carvalho de Melo 
473682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
474682b335aSArnaldo Carvalho de Melo 	struct map *map;
475682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
476682b335aSArnaldo Carvalho de Melo };
477682b335aSArnaldo Carvalho de Melo 
478c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
479c408fedfSArnaldo Carvalho de Melo {
480c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
481c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
482c408fedfSArnaldo Carvalho de Melo 
483c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
484c408fedfSArnaldo Carvalho de Melo }
485c408fedfSArnaldo Carvalho de Melo 
486682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
487682b335aSArnaldo Carvalho de Melo 				       char type, u64 start)
488682b335aSArnaldo Carvalho de Melo {
489682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
490682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
491682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
492682b335aSArnaldo Carvalho de Melo 
493682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
494682b335aSArnaldo Carvalho de Melo 		return 0;
495682b335aSArnaldo Carvalho de Melo 
4962e538c4aSArnaldo Carvalho de Melo 	/*
4972e538c4aSArnaldo Carvalho de Melo 	 * Will fix up the end later, when we have all symbols sorted.
4982e538c4aSArnaldo Carvalho de Melo 	 */
499c408fedfSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
500af427bf5SArnaldo Carvalho de Melo 
5012e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
502682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
50382164161SArnaldo Carvalho de Melo 	/*
50482164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
5054e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
50682164161SArnaldo Carvalho de Melo 	 */
5074e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
508a1645ce1SZhang, Yanmin 
509682b335aSArnaldo Carvalho de Melo 	return 0;
5102e538c4aSArnaldo Carvalho de Melo }
5112e538c4aSArnaldo Carvalho de Melo 
512682b335aSArnaldo Carvalho de Melo /*
513682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
514682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
515682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
516682b335aSArnaldo Carvalho de Melo  */
5179e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename,
5189e201442SArnaldo Carvalho de Melo 				  struct map *map)
519682b335aSArnaldo Carvalho de Melo {
520682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = self, };
5219e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
5222e538c4aSArnaldo Carvalho de Melo }
5232e538c4aSArnaldo Carvalho de Melo 
5242e538c4aSArnaldo Carvalho de Melo /*
5252e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
5262e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
5272e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
5282e538c4aSArnaldo Carvalho de Melo  */
5299958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
5309de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
5312e538c4aSArnaldo Carvalho de Melo {
5329de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
53323346f21SArnaldo Carvalho de Melo 	struct machine *machine = kmaps->machine;
5344e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
5352e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
5368a953312SArnaldo Carvalho de Melo 	int count = 0, moved = 0;
5374e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
5384e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
5392e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
5402e538c4aSArnaldo Carvalho de Melo 
5412e538c4aSArnaldo Carvalho de Melo 	while (next) {
5422e538c4aSArnaldo Carvalho de Melo 		char *module;
5432e538c4aSArnaldo Carvalho de Melo 
5442e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
5452e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
5462e538c4aSArnaldo Carvalho de Melo 
5472e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
5482e538c4aSArnaldo Carvalho de Melo 		if (module) {
54975be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
5501de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
5511de8e245SArnaldo Carvalho de Melo 
5522e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
5532e538c4aSArnaldo Carvalho de Melo 
554b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
555a1645ce1SZhang, Yanmin 				if (curr_map != map &&
556a1645ce1SZhang, Yanmin 				    self->kernel == DSO_TYPE_GUEST_KERNEL &&
55723346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
558a1645ce1SZhang, Yanmin 					/*
559a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
560a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
561a1645ce1SZhang, Yanmin 					 * points to a module and all its
562a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
563a1645ce1SZhang, Yanmin 					 * loaded.
564a1645ce1SZhang, Yanmin 					 */
565a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
566a1645ce1SZhang, Yanmin 							curr_map->type);
567af427bf5SArnaldo Carvalho de Melo 				}
568b7cece76SArnaldo Carvalho de Melo 
569a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
570a1645ce1SZhang, Yanmin 							map->type, module);
571a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
5722f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
573a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
574a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
57523346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
576a1645ce1SZhang, Yanmin 					curr_map = map;
577a1645ce1SZhang, Yanmin 					goto discard_symbol;
578a1645ce1SZhang, Yanmin 				}
579a1645ce1SZhang, Yanmin 
580a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
58123346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
582b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
583af427bf5SArnaldo Carvalho de Melo 			}
58486470930SIngo Molnar 			/*
5852e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
5862e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
58786470930SIngo Molnar 			 */
5884e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
5894e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
5904e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
5912e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
5922e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
59386470930SIngo Molnar 
5948a953312SArnaldo Carvalho de Melo 			if (count == 0) {
5958a953312SArnaldo Carvalho de Melo 				curr_map = map;
5968a953312SArnaldo Carvalho de Melo 				goto filter_symbol;
5978a953312SArnaldo Carvalho de Melo 			}
5988a953312SArnaldo Carvalho de Melo 
599a1645ce1SZhang, Yanmin 			if (self->kernel == DSO_TYPE_GUEST_KERNEL)
600a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
601a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
602a1645ce1SZhang, Yanmin 					kernel_range++);
603a1645ce1SZhang, Yanmin 			else
604a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
605a1645ce1SZhang, Yanmin 					"[kernel].%d",
6062e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
60786470930SIngo Molnar 
60800a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
6092e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
6102e538c4aSArnaldo Carvalho de Melo 				return -1;
6112e538c4aSArnaldo Carvalho de Melo 
612a1645ce1SZhang, Yanmin 			dso->kernel = self->kernel;
613a1645ce1SZhang, Yanmin 
6144e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
61537fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
6162e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
6172e538c4aSArnaldo Carvalho de Melo 				return -1;
6182e538c4aSArnaldo Carvalho de Melo 			}
6192e538c4aSArnaldo Carvalho de Melo 
6204e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
6219de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
6222e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
6232e538c4aSArnaldo Carvalho de Melo 		}
6248a953312SArnaldo Carvalho de Melo filter_symbol:
6254e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
6261de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
62700a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
6282e538c4aSArnaldo Carvalho de Melo 		} else {
6294e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
6304e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
6314e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
6328a953312SArnaldo Carvalho de Melo 				++moved;
6338a953312SArnaldo Carvalho de Melo 			} else
6348a953312SArnaldo Carvalho de Melo 				++count;
6359974f496SMike Galbraith 		}
63686470930SIngo Molnar 	}
63786470930SIngo Molnar 
638a1645ce1SZhang, Yanmin 	if (curr_map != map &&
639a1645ce1SZhang, Yanmin 	    self->kernel == DSO_TYPE_GUEST_KERNEL &&
64023346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
641a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
642a1645ce1SZhang, Yanmin 	}
643a1645ce1SZhang, Yanmin 
6448a953312SArnaldo Carvalho de Melo 	return count + moved;
64586470930SIngo Molnar }
64686470930SIngo Molnar 
6479de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename,
6489de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
6492e538c4aSArnaldo Carvalho de Melo {
6509e201442SArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, filename, map) < 0)
6512e538c4aSArnaldo Carvalho de Melo 		return -1;
6522e538c4aSArnaldo Carvalho de Melo 
6534e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
654a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_GUEST_KERNEL)
655a1645ce1SZhang, Yanmin 		self->origin = DSO__ORIG_GUEST_KERNEL;
656a1645ce1SZhang, Yanmin 	else
6574e06255fSArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_KERNEL;
6582e538c4aSArnaldo Carvalho de Melo 
6599de89fe7SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, filter);
660af427bf5SArnaldo Carvalho de Melo }
661af427bf5SArnaldo Carvalho de Melo 
662439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
6636beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
66480d496beSPekka Enberg {
66580d496beSPekka Enberg 	char *line = NULL;
66680d496beSPekka Enberg 	size_t n;
66780d496beSPekka Enberg 	FILE *file;
66880d496beSPekka Enberg 	int nr_syms = 0;
66980d496beSPekka Enberg 
670439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
67180d496beSPekka Enberg 	if (file == NULL)
67280d496beSPekka Enberg 		goto out_failure;
67380d496beSPekka Enberg 
67480d496beSPekka Enberg 	while (!feof(file)) {
6759cffa8d5SPaul Mackerras 		u64 start, size;
67680d496beSPekka Enberg 		struct symbol *sym;
67780d496beSPekka Enberg 		int line_len, len;
67880d496beSPekka Enberg 
67980d496beSPekka Enberg 		line_len = getline(&line, &n, file);
68080d496beSPekka Enberg 		if (line_len < 0)
68180d496beSPekka Enberg 			break;
68280d496beSPekka Enberg 
68380d496beSPekka Enberg 		if (!line)
68480d496beSPekka Enberg 			goto out_failure;
68580d496beSPekka Enberg 
68680d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
68780d496beSPekka Enberg 
68880d496beSPekka Enberg 		len = hex2u64(line, &start);
68980d496beSPekka Enberg 
69080d496beSPekka Enberg 		len++;
69180d496beSPekka Enberg 		if (len + 2 >= line_len)
69280d496beSPekka Enberg 			continue;
69380d496beSPekka Enberg 
69480d496beSPekka Enberg 		len += hex2u64(line + len, &size);
69580d496beSPekka Enberg 
69680d496beSPekka Enberg 		len++;
69780d496beSPekka Enberg 		if (len + 2 >= line_len)
69880d496beSPekka Enberg 			continue;
69980d496beSPekka Enberg 
700c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
70180d496beSPekka Enberg 
70280d496beSPekka Enberg 		if (sym == NULL)
70380d496beSPekka Enberg 			goto out_delete_line;
70480d496beSPekka Enberg 
705439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
70600a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
70780d496beSPekka Enberg 		else {
7086a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
70980d496beSPekka Enberg 			nr_syms++;
71080d496beSPekka Enberg 		}
71180d496beSPekka Enberg 	}
71280d496beSPekka Enberg 
71380d496beSPekka Enberg 	free(line);
71480d496beSPekka Enberg 	fclose(file);
71580d496beSPekka Enberg 
71680d496beSPekka Enberg 	return nr_syms;
71780d496beSPekka Enberg 
71880d496beSPekka Enberg out_delete_line:
71980d496beSPekka Enberg 	free(line);
72080d496beSPekka Enberg out_failure:
72180d496beSPekka Enberg 	return -1;
72280d496beSPekka Enberg }
72380d496beSPekka Enberg 
72486470930SIngo Molnar /**
72586470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
72686470930SIngo Molnar  *
72786470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
72883a0944fSIngo Molnar  * @idx: uint32_t idx
72986470930SIngo Molnar  * @sym: GElf_Sym iterator
73086470930SIngo Molnar  */
73183a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
73283a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
73383a0944fSIngo Molnar 	     idx < nr_syms; \
73483a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
73586470930SIngo Molnar 
73686470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
73786470930SIngo Molnar {
73886470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
73986470930SIngo Molnar }
74086470930SIngo Molnar 
74186470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
74286470930SIngo Molnar {
74386470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
74486470930SIngo Molnar 	       sym->st_name != 0 &&
74581833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
74686470930SIngo Molnar }
74786470930SIngo Molnar 
748f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
749f1dfa0b1SArnaldo Carvalho de Melo {
750f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
751f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
752f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
753f1dfa0b1SArnaldo Carvalho de Melo }
754f1dfa0b1SArnaldo Carvalho de Melo 
7556cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
7566cfcc53eSMike Galbraith {
7576cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
7586cfcc53eSMike Galbraith 		sym->st_name != 0 &&
7596cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
7606cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
7616cfcc53eSMike Galbraith }
7626cfcc53eSMike Galbraith 
7636cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
7646cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7656cfcc53eSMike Galbraith {
7666cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
7676cfcc53eSMike Galbraith }
7686cfcc53eSMike Galbraith 
7696cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
7706cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7716cfcc53eSMike Galbraith {
7726cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
7736cfcc53eSMike Galbraith }
7746cfcc53eSMike Galbraith 
775f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
776f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
777f1dfa0b1SArnaldo Carvalho de Melo {
778f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
779f1dfa0b1SArnaldo Carvalho de Melo }
780f1dfa0b1SArnaldo Carvalho de Melo 
78186470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
78286470930SIngo Molnar 					const Elf_Data *symstrs)
78386470930SIngo Molnar {
78486470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
78586470930SIngo Molnar }
78686470930SIngo Molnar 
78786470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
78886470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
78983a0944fSIngo Molnar 				    size_t *idx)
79086470930SIngo Molnar {
79186470930SIngo Molnar 	Elf_Scn *sec = NULL;
79286470930SIngo Molnar 	size_t cnt = 1;
79386470930SIngo Molnar 
79486470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
79586470930SIngo Molnar 		char *str;
79686470930SIngo Molnar 
79786470930SIngo Molnar 		gelf_getshdr(sec, shp);
79886470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
79986470930SIngo Molnar 		if (!strcmp(name, str)) {
80083a0944fSIngo Molnar 			if (idx)
80183a0944fSIngo Molnar 				*idx = cnt;
80286470930SIngo Molnar 			break;
80386470930SIngo Molnar 		}
80486470930SIngo Molnar 		++cnt;
80586470930SIngo Molnar 	}
80686470930SIngo Molnar 
80786470930SIngo Molnar 	return sec;
80886470930SIngo Molnar }
80986470930SIngo Molnar 
81086470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
81186470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
81286470930SIngo Molnar 	     idx < nr_entries; \
81386470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
81486470930SIngo Molnar 
81586470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
81686470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
81786470930SIngo Molnar 	     idx < nr_entries; \
81886470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
81986470930SIngo Molnar 
820a25e46c4SArnaldo Carvalho de Melo /*
821a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
822a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
823a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
824a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
825a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
826a25e46c4SArnaldo Carvalho de Melo  */
82782164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
82882164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
82986470930SIngo Molnar {
83086470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
83186470930SIngo Molnar 	GElf_Sym sym;
8329cffa8d5SPaul Mackerras 	u64 plt_offset;
83386470930SIngo Molnar 	GElf_Shdr shdr_plt;
83486470930SIngo Molnar 	struct symbol *f;
835a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
83686470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
837a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
838a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
839a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
84086470930SIngo Molnar 	char sympltname[1024];
841a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
842a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
843*ec5761eaSDavid Ahern 	char name[PATH_MAX];
84486470930SIngo Molnar 
845*ec5761eaSDavid Ahern 	snprintf(name, sizeof(name), "%s%s",
846*ec5761eaSDavid Ahern 		 symbol_conf.symfs, self->long_name);
847*ec5761eaSDavid Ahern 	fd = open(name, O_RDONLY);
848a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
849a25e46c4SArnaldo Carvalho de Melo 		goto out;
850a25e46c4SArnaldo Carvalho de Melo 
85184087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
852a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
853a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
854a25e46c4SArnaldo Carvalho de Melo 
855a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
856a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
857a25e46c4SArnaldo Carvalho de Melo 
858a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
859a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
860a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
861a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
862a25e46c4SArnaldo Carvalho de Melo 
863a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
86486470930SIngo Molnar 					  ".rela.plt", NULL);
86586470930SIngo Molnar 	if (scn_plt_rel == NULL) {
866a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
86786470930SIngo Molnar 						  ".rel.plt", NULL);
86886470930SIngo Molnar 		if (scn_plt_rel == NULL)
869a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
87086470930SIngo Molnar 	}
87186470930SIngo Molnar 
872a25e46c4SArnaldo Carvalho de Melo 	err = -1;
87386470930SIngo Molnar 
874a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
875a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
876a25e46c4SArnaldo Carvalho de Melo 
877a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
878a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
87986470930SIngo Molnar 
88086470930SIngo Molnar 	/*
88183a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
88286470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
88386470930SIngo Molnar 	 */
88486470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
88586470930SIngo Molnar 	if (reldata == NULL)
886a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
88786470930SIngo Molnar 
88886470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
88986470930SIngo Molnar 	if (syms == NULL)
890a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
89186470930SIngo Molnar 
892a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
89386470930SIngo Molnar 	if (scn_symstrs == NULL)
894a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
89586470930SIngo Molnar 
89686470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
89786470930SIngo Molnar 	if (symstrs == NULL)
898a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
89986470930SIngo Molnar 
90086470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
90186470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
90286470930SIngo Molnar 
90386470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
90486470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
90586470930SIngo Molnar 
90686470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
90786470930SIngo Molnar 					   nr_rel_entries) {
90886470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
90986470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
91086470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
91186470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
91286470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
91386470930SIngo Molnar 
91486470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
915c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
91686470930SIngo Molnar 			if (!f)
917a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
91886470930SIngo Molnar 
91982164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
92082164161SArnaldo Carvalho de Melo 				symbol__delete(f);
92182164161SArnaldo Carvalho de Melo 			else {
9226a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
92386470930SIngo Molnar 				++nr;
92486470930SIngo Molnar 			}
92582164161SArnaldo Carvalho de Melo 		}
92686470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
92786470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
92886470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
92986470930SIngo Molnar 					  nr_rel_entries) {
93086470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
93186470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
93286470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
93386470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
93486470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
93586470930SIngo Molnar 
93686470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
937c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
93886470930SIngo Molnar 			if (!f)
939a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
94086470930SIngo Molnar 
94182164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
94282164161SArnaldo Carvalho de Melo 				symbol__delete(f);
94382164161SArnaldo Carvalho de Melo 			else {
9446a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
94586470930SIngo Molnar 				++nr;
94686470930SIngo Molnar 			}
94786470930SIngo Molnar 		}
94882164161SArnaldo Carvalho de Melo 	}
94986470930SIngo Molnar 
950a25e46c4SArnaldo Carvalho de Melo 	err = 0;
951a25e46c4SArnaldo Carvalho de Melo out_elf_end:
952a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
953a25e46c4SArnaldo Carvalho de Melo out_close:
954a25e46c4SArnaldo Carvalho de Melo 	close(fd);
955a25e46c4SArnaldo Carvalho de Melo 
956a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
95786470930SIngo Molnar 		return nr;
958a25e46c4SArnaldo Carvalho de Melo out:
959fe2197b8SArnaldo Carvalho de Melo 	pr_debug("%s: problems reading %s PLT info.\n",
960439d473bSArnaldo Carvalho de Melo 		 __func__, self->long_name);
961a25e46c4SArnaldo Carvalho de Melo 	return 0;
96286470930SIngo Molnar }
96386470930SIngo Molnar 
964d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
965d45868d3SArnaldo Carvalho de Melo {
966d45868d3SArnaldo Carvalho de Melo 	switch (type) {
967d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
968d45868d3SArnaldo Carvalho de Melo 		return elf_sym__is_function(self);
969f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
970f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sym__is_object(self);
971d45868d3SArnaldo Carvalho de Melo 	default:
972d45868d3SArnaldo Carvalho de Melo 		return false;
973d45868d3SArnaldo Carvalho de Melo 	}
974d45868d3SArnaldo Carvalho de Melo }
975d45868d3SArnaldo Carvalho de Melo 
976d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
977d45868d3SArnaldo Carvalho de Melo {
978d45868d3SArnaldo Carvalho de Melo 	switch (type) {
979d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
980d45868d3SArnaldo Carvalho de Melo 		return elf_sec__is_text(self, secstrs);
981f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
982f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sec__is_data(self, secstrs);
983d45868d3SArnaldo Carvalho de Melo 	default:
984d45868d3SArnaldo Carvalho de Melo 		return false;
985d45868d3SArnaldo Carvalho de Melo 	}
986d45868d3SArnaldo Carvalho de Melo }
987d45868d3SArnaldo Carvalho de Melo 
98870c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
98970c3856bSEric B Munson {
99070c3856bSEric B Munson 	Elf_Scn *sec = NULL;
99170c3856bSEric B Munson 	GElf_Shdr shdr;
99270c3856bSEric B Munson 	size_t cnt = 1;
99370c3856bSEric B Munson 
99470c3856bSEric B Munson 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
99570c3856bSEric B Munson 		gelf_getshdr(sec, &shdr);
99670c3856bSEric B Munson 
99770c3856bSEric B Munson 		if ((addr >= shdr.sh_addr) &&
99870c3856bSEric B Munson 		    (addr < (shdr.sh_addr + shdr.sh_size)))
99970c3856bSEric B Munson 			return cnt;
100070c3856bSEric B Munson 
100170c3856bSEric B Munson 		++cnt;
100270c3856bSEric B Munson 	}
100370c3856bSEric B Munson 
100470c3856bSEric B Munson 	return -1;
100570c3856bSEric B Munson }
100670c3856bSEric B Munson 
10079de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name,
10086da80ce8SDave Martin 			 int fd, symbol_filter_t filter, int kmodule,
10096da80ce8SDave Martin 			 int want_symtab)
101086470930SIngo Molnar {
10119de89fe7SArnaldo Carvalho de Melo 	struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
10122e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
10132e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
10146cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
101586470930SIngo Molnar 	uint32_t nr_syms;
101686470930SIngo Molnar 	int err = -1;
101783a0944fSIngo Molnar 	uint32_t idx;
101886470930SIngo Molnar 	GElf_Ehdr ehdr;
101970c3856bSEric B Munson 	GElf_Shdr shdr, opdshdr;
102070c3856bSEric B Munson 	Elf_Data *syms, *opddata = NULL;
102186470930SIngo Molnar 	GElf_Sym sym;
102270c3856bSEric B Munson 	Elf_Scn *sec, *sec_strndx, *opdsec;
102386470930SIngo Molnar 	Elf *elf;
1024439d473bSArnaldo Carvalho de Melo 	int nr = 0;
102570c3856bSEric B Munson 	size_t opdidx = 0;
102686470930SIngo Molnar 
102784087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
102886470930SIngo Molnar 	if (elf == NULL) {
10298b1389efSDave Martin 		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
103086470930SIngo Molnar 		goto out_close;
103186470930SIngo Molnar 	}
103286470930SIngo Molnar 
103386470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
10348b1389efSDave Martin 		pr_debug("%s: cannot get elf header.\n", __func__);
103586470930SIngo Molnar 		goto out_elf_end;
103686470930SIngo Molnar 	}
103786470930SIngo Molnar 
10386da80ce8SDave Martin 	/* Always reject images with a mismatched build-id: */
103921916c38SDave Martin 	if (self->has_build_id) {
104021916c38SDave Martin 		u8 build_id[BUILD_ID_SIZE];
104121916c38SDave Martin 
104221916c38SDave Martin 		if (elf_read_build_id(elf, build_id,
104321916c38SDave Martin 				      BUILD_ID_SIZE) != BUILD_ID_SIZE)
104421916c38SDave Martin 			goto out_elf_end;
104521916c38SDave Martin 
104621916c38SDave Martin 		if (!dso__build_id_equal(self, build_id))
104721916c38SDave Martin 			goto out_elf_end;
104821916c38SDave Martin 	}
104921916c38SDave Martin 
105086470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
105186470930SIngo Molnar 	if (sec == NULL) {
10526da80ce8SDave Martin 		if (want_symtab)
10536da80ce8SDave Martin 			goto out_elf_end;
10546da80ce8SDave Martin 
1055a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1056a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
105786470930SIngo Molnar 			goto out_elf_end;
105886470930SIngo Molnar 	}
105986470930SIngo Molnar 
106070c3856bSEric B Munson 	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
106170c3856bSEric B Munson 	if (opdsec)
106270c3856bSEric B Munson 		opddata = elf_rawdata(opdsec, NULL);
106370c3856bSEric B Munson 
106486470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
106586470930SIngo Molnar 	if (syms == NULL)
106686470930SIngo Molnar 		goto out_elf_end;
106786470930SIngo Molnar 
106886470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
106986470930SIngo Molnar 	if (sec == NULL)
107086470930SIngo Molnar 		goto out_elf_end;
107186470930SIngo Molnar 
107286470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
107386470930SIngo Molnar 	if (symstrs == NULL)
107486470930SIngo Molnar 		goto out_elf_end;
107586470930SIngo Molnar 
10766cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
10776cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
10786cfcc53eSMike Galbraith 		goto out_elf_end;
10796cfcc53eSMike Galbraith 
10806cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
10819b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
10826cfcc53eSMike Galbraith 		goto out_elf_end;
10836cfcc53eSMike Galbraith 
108486470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
108586470930SIngo Molnar 
1086e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
1087a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_USER) {
108830d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
108930d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
1090f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
109130d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
1092d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
1093d20ff6bdSMike Galbraith 
109483a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
109586470930SIngo Molnar 		struct symbol *f;
109656b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
10972e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
10986cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
10996cfcc53eSMike Galbraith 		const char *section_name;
110086470930SIngo Molnar 
11019de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
11029de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
11039de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
110456b03f3cSArnaldo Carvalho de Melo 
1105d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
110686470930SIngo Molnar 			continue;
110786470930SIngo Molnar 
1108696b97a5SDave Martin 		/* Reject ARM ELF "mapping symbols": these aren't unique and
1109696b97a5SDave Martin 		 * don't identify functions, so will confuse the profile
1110696b97a5SDave Martin 		 * output: */
1111696b97a5SDave Martin 		if (ehdr.e_machine == EM_ARM) {
1112696b97a5SDave Martin 			if (!strcmp(elf_name, "$a") ||
1113696b97a5SDave Martin 			    !strcmp(elf_name, "$d") ||
1114696b97a5SDave Martin 			    !strcmp(elf_name, "$t"))
1115696b97a5SDave Martin 				continue;
1116696b97a5SDave Martin 		}
1117696b97a5SDave Martin 
111870c3856bSEric B Munson 		if (opdsec && sym.st_shndx == opdidx) {
111970c3856bSEric B Munson 			u32 offset = sym.st_value - opdshdr.sh_addr;
112070c3856bSEric B Munson 			u64 *opd = opddata->d_buf + offset;
112170c3856bSEric B Munson 			sym.st_value = *opd;
112270c3856bSEric B Munson 			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
112370c3856bSEric B Munson 		}
112470c3856bSEric B Munson 
112586470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
112686470930SIngo Molnar 		if (!sec)
112786470930SIngo Molnar 			goto out_elf_end;
112886470930SIngo Molnar 
112986470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
11306cfcc53eSMike Galbraith 
1131d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
11326cfcc53eSMike Galbraith 			continue;
11336cfcc53eSMike Galbraith 
11346cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
113586470930SIngo Molnar 
1136a1645ce1SZhang, Yanmin 		if (self->kernel != DSO_TYPE_USER || kmodule) {
11372e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
11382e538c4aSArnaldo Carvalho de Melo 
11392e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1140b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1141b63be8d7SArnaldo Carvalho de Melo 				    self->short_name_len)) == 0)
11422e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
11432e538c4aSArnaldo Carvalho de Melo 
11442e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
11452e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
11462e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
11472e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1148af427bf5SArnaldo Carvalho de Melo 			}
1149af427bf5SArnaldo Carvalho de Melo 
11502e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
11512e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
11522e538c4aSArnaldo Carvalho de Melo 
11539de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
11542e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
11552e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
11562e538c4aSArnaldo Carvalho de Melo 
11572e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
11582e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
11592e538c4aSArnaldo Carvalho de Melo 
116000a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
11612e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
11622e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1163a1645ce1SZhang, Yanmin 				curr_dso->kernel = self->kernel;
11643610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
11656275ce2dSArnaldo Carvalho de Melo 						     map->type);
11662e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
11672e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
11682e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
11692e538c4aSArnaldo Carvalho de Melo 				}
1170ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1171ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1172b0a9ab62SArnaldo Carvalho de Melo 				curr_dso->origin = self->origin;
11739de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1174a1645ce1SZhang, Yanmin 				dsos__add(&self->node, curr_dso);
11756275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
11762e538c4aSArnaldo Carvalho de Melo 			} else
11772e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
11782e538c4aSArnaldo Carvalho de Melo 
11792e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
11802e538c4aSArnaldo Carvalho de Melo 		}
11812e538c4aSArnaldo Carvalho de Melo 
11822e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
118329a9f66dSArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#Lx "
118429a9f66dSArnaldo Carvalho de Melo 				  "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
118529a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
118629a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
118786470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1188af427bf5SArnaldo Carvalho de Melo 		}
118928ac909bSArnaldo Carvalho de Melo 		/*
119028ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
119128ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
119228ac909bSArnaldo Carvalho de Melo 		 * to it...
119328ac909bSArnaldo Carvalho de Melo 		 */
119483a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
119528ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
119683a0944fSIngo Molnar 			elf_name = demangled;
11972e538c4aSArnaldo Carvalho de Melo new_symbol:
1198c408fedfSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size,
1199c408fedfSArnaldo Carvalho de Melo 				GELF_ST_BIND(sym.st_info), elf_name);
120028ac909bSArnaldo Carvalho de Melo 		free(demangled);
120186470930SIngo Molnar 		if (!f)
120286470930SIngo Molnar 			goto out_elf_end;
120386470930SIngo Molnar 
12042e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
120500a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
120686470930SIngo Molnar 		else {
12076a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
120886470930SIngo Molnar 			nr++;
120986470930SIngo Molnar 		}
121086470930SIngo Molnar 	}
121186470930SIngo Molnar 
12122e538c4aSArnaldo Carvalho de Melo 	/*
12132e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
12142e538c4aSArnaldo Carvalho de Melo 	 */
12156275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
12166a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
12176275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
12186275ce2dSArnaldo Carvalho de Melo 			/*
12196275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
12206275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
12216275ce2dSArnaldo Carvalho de Melo 			 */
12226275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
12236275ce2dSArnaldo Carvalho de Melo 		}
12246275ce2dSArnaldo Carvalho de Melo 	}
122586470930SIngo Molnar 	err = nr;
122686470930SIngo Molnar out_elf_end:
122786470930SIngo Molnar 	elf_end(elf);
122886470930SIngo Molnar out_close:
122986470930SIngo Molnar 	return err;
123086470930SIngo Molnar }
123186470930SIngo Molnar 
123278075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
123378075caaSArnaldo Carvalho de Melo {
123478075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
123578075caaSArnaldo Carvalho de Melo }
123678075caaSArnaldo Carvalho de Melo 
1237a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
123857f395a7SFrederic Weisbecker {
1239e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
124057f395a7SFrederic Weisbecker 	struct dso *pos;
124157f395a7SFrederic Weisbecker 
12426122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
12436122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
12446122e4e4SArnaldo Carvalho de Melo 			continue;
1245f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
1246f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
1247f6e1467dSArnaldo Carvalho de Melo 			continue;
1248f6e1467dSArnaldo Carvalho de Melo 		}
1249e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1250e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1251e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1252e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
125357f395a7SFrederic Weisbecker 		}
12546122e4e4SArnaldo Carvalho de Melo 	}
125557f395a7SFrederic Weisbecker 
1256e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
125757f395a7SFrederic Weisbecker }
125857f395a7SFrederic Weisbecker 
1259fd7a346eSArnaldo Carvalho de Melo /*
1260fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1261fd7a346eSArnaldo Carvalho de Melo  */
1262fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1263fd7a346eSArnaldo Carvalho de Melo 
126421916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size)
12654d1e00a8SArnaldo Carvalho de Melo {
126621916c38SDave Martin 	int err = -1;
12674d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
12684d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1269fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
12704d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1271e57cfcdaSPekka Enberg 	Elf_Kind ek;
1272fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
12734d1e00a8SArnaldo Carvalho de Melo 
12742643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
12752643ce11SArnaldo Carvalho de Melo 		goto out;
12762643ce11SArnaldo Carvalho de Melo 
1277e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1278e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
127921916c38SDave Martin 		goto out;
1280e57cfcdaSPekka Enberg 
12814d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
12826beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
128321916c38SDave Martin 		goto out;
12844d1e00a8SArnaldo Carvalho de Melo 	}
12854d1e00a8SArnaldo Carvalho de Melo 
12862643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
12872643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1288fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1289fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1290fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
12914d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
129221916c38SDave Martin 			goto out;
1293fd7a346eSArnaldo Carvalho de Melo 	}
12944d1e00a8SArnaldo Carvalho de Melo 
1295fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1296fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
129721916c38SDave Martin 		goto out;
1298fd7a346eSArnaldo Carvalho de Melo 
1299fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1300fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1301fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1302fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1303fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1304fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1305fd7a346eSArnaldo Carvalho de Melo 
1306fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1307fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1308fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1309fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1310fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1311fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1312fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
13132643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1314fd7a346eSArnaldo Carvalho de Melo 				break;
1315fd7a346eSArnaldo Carvalho de Melo 			}
1316fd7a346eSArnaldo Carvalho de Melo 		}
1317fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1318fd7a346eSArnaldo Carvalho de Melo 	}
131921916c38SDave Martin 
132021916c38SDave Martin out:
132121916c38SDave Martin 	return err;
132221916c38SDave Martin }
132321916c38SDave Martin 
132421916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size)
132521916c38SDave Martin {
132621916c38SDave Martin 	int fd, err = -1;
132721916c38SDave Martin 	Elf *elf;
132821916c38SDave Martin 
132921916c38SDave Martin 	if (size < BUILD_ID_SIZE)
133021916c38SDave Martin 		goto out;
133121916c38SDave Martin 
133221916c38SDave Martin 	fd = open(filename, O_RDONLY);
133321916c38SDave Martin 	if (fd < 0)
133421916c38SDave Martin 		goto out;
133521916c38SDave Martin 
133621916c38SDave Martin 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
133721916c38SDave Martin 	if (elf == NULL) {
133821916c38SDave Martin 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
133921916c38SDave Martin 		goto out_close;
134021916c38SDave Martin 	}
134121916c38SDave Martin 
134221916c38SDave Martin 	err = elf_read_build_id(elf, bf, size);
134321916c38SDave Martin 
13442643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
13452643ce11SArnaldo Carvalho de Melo out_close:
13462643ce11SArnaldo Carvalho de Melo 	close(fd);
13472643ce11SArnaldo Carvalho de Melo out:
13482643ce11SArnaldo Carvalho de Melo 	return err;
13492643ce11SArnaldo Carvalho de Melo }
13502643ce11SArnaldo Carvalho de Melo 
1351f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1352f1617b40SArnaldo Carvalho de Melo {
1353f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1354f1617b40SArnaldo Carvalho de Melo 
1355f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1356f1617b40SArnaldo Carvalho de Melo 		goto out;
1357f1617b40SArnaldo Carvalho de Melo 
1358f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1359f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1360f1617b40SArnaldo Carvalho de Melo 		goto out;
1361f1617b40SArnaldo Carvalho de Melo 
1362f1617b40SArnaldo Carvalho de Melo 	while (1) {
1363f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1364f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1365f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1366f1617b40SArnaldo Carvalho de Melo 
1367f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1368f1617b40SArnaldo Carvalho de Melo 			break;
1369f1617b40SArnaldo Carvalho de Melo 
1370fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1371fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1372f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1373f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1374f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1375f1617b40SArnaldo Carvalho de Melo 				break;
1376f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1377f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1378f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1379f1617b40SArnaldo Carvalho de Melo 					err = 0;
1380f1617b40SArnaldo Carvalho de Melo 					break;
1381f1617b40SArnaldo Carvalho de Melo 				}
1382f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1383f1617b40SArnaldo Carvalho de Melo 				break;
1384f1617b40SArnaldo Carvalho de Melo 		} else {
1385f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1386f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1387f1617b40SArnaldo Carvalho de Melo 				break;
1388f1617b40SArnaldo Carvalho de Melo 		}
1389f1617b40SArnaldo Carvalho de Melo 	}
1390f1617b40SArnaldo Carvalho de Melo 	close(fd);
1391f1617b40SArnaldo Carvalho de Melo out:
1392f1617b40SArnaldo Carvalho de Melo 	return err;
1393f1617b40SArnaldo Carvalho de Melo }
1394f1617b40SArnaldo Carvalho de Melo 
139594cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
139694cb9e38SArnaldo Carvalho de Melo {
139794cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
139894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
139994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
14004cf40131SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILD_ID_CACHE] = 'B',
140194cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
140294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
140394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
140494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1405439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
1406a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KERNEL] =  'g',
1407a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KMODULE] =  'G',
140894cb9e38SArnaldo Carvalho de Melo 	};
140994cb9e38SArnaldo Carvalho de Melo 
141094cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
141194cb9e38SArnaldo Carvalho de Melo 		return '!';
141294cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
141394cb9e38SArnaldo Carvalho de Melo }
141494cb9e38SArnaldo Carvalho de Melo 
14159de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
141686470930SIngo Molnar {
14174d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1418c338aee8SArnaldo Carvalho de Melo 	char *name;
141986470930SIngo Molnar 	int ret = -1;
142086470930SIngo Molnar 	int fd;
142123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1422a1645ce1SZhang, Yanmin 	const char *root_dir;
14236da80ce8SDave Martin 	int want_symtab;
142486470930SIngo Molnar 
14253610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
142666bd8424SArnaldo Carvalho de Melo 
1427a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_KERNEL)
14289de89fe7SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, filter);
1429a1645ce1SZhang, Yanmin 	else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1430a1645ce1SZhang, Yanmin 		return dso__load_guest_kernel_sym(self, map, filter);
1431a1645ce1SZhang, Yanmin 
143223346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
143323346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1434a1645ce1SZhang, Yanmin 	else
143523346f21SArnaldo Carvalho de Melo 		machine = NULL;
1436c338aee8SArnaldo Carvalho de Melo 
1437c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
143886470930SIngo Molnar 	if (!name)
143986470930SIngo Molnar 		return -1;
144086470930SIngo Molnar 
144130d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1442f5812a7aSArnaldo Carvalho de Melo 
144394cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
14446beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
144594cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
144694cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
144794cb9e38SArnaldo Carvalho de Melo 		return ret;
144894cb9e38SArnaldo Carvalho de Melo 	}
144994cb9e38SArnaldo Carvalho de Melo 
14506da80ce8SDave Martin 	/* Iterate over candidate debug images.
14516da80ce8SDave Martin 	 * On the first pass, only load images if they have a full symtab.
14526da80ce8SDave Martin 	 * Failing that, do a second pass where we accept .dynsym also
14536da80ce8SDave Martin 	 */
14546da80ce8SDave Martin 	for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
14556da80ce8SDave Martin 	     self->origin != DSO__ORIG_NOT_FOUND;
14566da80ce8SDave Martin 	     self->origin++) {
145794cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
14586da80ce8SDave Martin 		case DSO__ORIG_BUILD_ID_CACHE:
1459*ec5761eaSDavid Ahern 			/* skip the locally configured cache if a symfs is given */
1460*ec5761eaSDavid Ahern 			if (symbol_conf.symfs[0] ||
1461*ec5761eaSDavid Ahern 			    (dso__build_id_filename(self, name, size) == NULL)) {
14626da80ce8SDave Martin 				continue;
1463*ec5761eaSDavid Ahern 			}
14646da80ce8SDave Martin 			break;
146594cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1466*ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s.debug",
1467*ec5761eaSDavid Ahern 				 symbol_conf.symfs, self->long_name);
146886470930SIngo Molnar 			break;
146994cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1470*ec5761eaSDavid Ahern 			snprintf(name, size, "%s/usr/lib/debug%s",
1471*ec5761eaSDavid Ahern 				 symbol_conf.symfs, self->long_name);
147286470930SIngo Molnar 			break;
14736da80ce8SDave Martin 		case DSO__ORIG_BUILDID: {
1474b36f19d5SArnaldo Carvalho de Melo 			char build_id_hex[BUILD_ID_SIZE * 2 + 1];
14756da80ce8SDave Martin 
14766da80ce8SDave Martin 			if (!self->has_build_id)
14776da80ce8SDave Martin 				continue;
14786da80ce8SDave Martin 
147921916c38SDave Martin 			build_id__sprintf(self->build_id,
148021916c38SDave Martin 					  sizeof(self->build_id),
1481d3379ab9SArnaldo Carvalho de Melo 					  build_id_hex);
14824d1e00a8SArnaldo Carvalho de Melo 			snprintf(name, size,
1483*ec5761eaSDavid Ahern 				 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1484*ec5761eaSDavid Ahern 				 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
14854d1e00a8SArnaldo Carvalho de Melo 			}
14866da80ce8SDave Martin 			break;
148794cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1488*ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s",
1489*ec5761eaSDavid Ahern 			     symbol_conf.symfs, self->long_name);
149086470930SIngo Molnar 			break;
1491a1645ce1SZhang, Yanmin 		case DSO__ORIG_GUEST_KMODULE:
149223346f21SArnaldo Carvalho de Melo 			if (map->groups && map->groups->machine)
149323346f21SArnaldo Carvalho de Melo 				root_dir = map->groups->machine->root_dir;
1494a1645ce1SZhang, Yanmin 			else
1495a1645ce1SZhang, Yanmin 				root_dir = "";
1496*ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1497*ec5761eaSDavid Ahern 				 root_dir, self->long_name);
1498*ec5761eaSDavid Ahern 			break;
1499*ec5761eaSDavid Ahern 
1500*ec5761eaSDavid Ahern 		case DSO__ORIG_KMODULE:
1501*ec5761eaSDavid Ahern 			snprintf(name, size, "%s%s", symbol_conf.symfs,
1502*ec5761eaSDavid Ahern 				 self->long_name);
1503a1645ce1SZhang, Yanmin 			break;
150486470930SIngo Molnar 
150586470930SIngo Molnar 		default:
15066da80ce8SDave Martin 			/*
15076da80ce8SDave Martin 			 * If we wanted a full symtab but no image had one,
15086da80ce8SDave Martin 			 * relax our requirements and repeat the search.
15096da80ce8SDave Martin 			 */
15106da80ce8SDave Martin 			if (want_symtab) {
15116da80ce8SDave Martin 				want_symtab = 0;
15126da80ce8SDave Martin 				self->origin = DSO__ORIG_BUILD_ID_CACHE;
15136da80ce8SDave Martin 			} else
15146da80ce8SDave Martin 				continue;
151586470930SIngo Molnar 		}
151686470930SIngo Molnar 
15176da80ce8SDave Martin 		/* Name is now the name of the next image to try */
15186da80ce8SDave Martin 		fd = open(name, O_RDONLY);
15196da80ce8SDave Martin 		if (fd < 0)
15206da80ce8SDave Martin 			continue;
15216da80ce8SDave Martin 
15226da80ce8SDave Martin 		ret = dso__load_sym(self, map, name, fd, filter, 0,
15236da80ce8SDave Martin 				    want_symtab);
152486470930SIngo Molnar 		close(fd);
152586470930SIngo Molnar 
152686470930SIngo Molnar 		/*
15276da80ce8SDave Martin 		 * Some people seem to have debuginfo files _WITHOUT_ debug
15286da80ce8SDave Martin 		 * info!?!?
152986470930SIngo Molnar 		 */
153086470930SIngo Molnar 		if (!ret)
15316da80ce8SDave Martin 			continue;
153286470930SIngo Molnar 
1533a25e46c4SArnaldo Carvalho de Melo 		if (ret > 0) {
153482164161SArnaldo Carvalho de Melo 			int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1535a25e46c4SArnaldo Carvalho de Melo 			if (nr_plt > 0)
1536a25e46c4SArnaldo Carvalho de Melo 				ret += nr_plt;
15376da80ce8SDave Martin 			break;
1538a25e46c4SArnaldo Carvalho de Melo 		}
15396da80ce8SDave Martin 	}
15406da80ce8SDave Martin 
154186470930SIngo Molnar 	free(name);
15421340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
15431340e6bbSArnaldo Carvalho de Melo 		return 0;
154486470930SIngo Molnar 	return ret;
154586470930SIngo Molnar }
154686470930SIngo Molnar 
154779406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self,
154879406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1549439d473bSArnaldo Carvalho de Melo {
1550439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1551439d473bSArnaldo Carvalho de Melo 
155279406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1553439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1554439d473bSArnaldo Carvalho de Melo 
1555b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1556439d473bSArnaldo Carvalho de Melo 			return map;
1557439d473bSArnaldo Carvalho de Melo 	}
1558439d473bSArnaldo Carvalho de Melo 
1559439d473bSArnaldo Carvalho de Melo 	return NULL;
1560439d473bSArnaldo Carvalho de Melo }
1561439d473bSArnaldo Carvalho de Melo 
1562a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self,
1563a1645ce1SZhang, Yanmin 				const char *root_dir)
1564b7cece76SArnaldo Carvalho de Melo {
1565b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1566b7cece76SArnaldo Carvalho de Melo 	/*
1567b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1568b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1569b7cece76SArnaldo Carvalho de Melo 	 */
1570b7cece76SArnaldo Carvalho de Melo 	const char *name = self->short_name + 1;
1571b7cece76SArnaldo Carvalho de Melo 
1572b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1573a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1574a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1575b7cece76SArnaldo Carvalho de Melo 
1576b7cece76SArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, self->build_id,
1577b7cece76SArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1578b7cece76SArnaldo Carvalho de Melo 		self->has_build_id = true;
1579b7cece76SArnaldo Carvalho de Melo 
1580b7cece76SArnaldo Carvalho de Melo 	return 0;
1581b7cece76SArnaldo Carvalho de Melo }
1582b7cece76SArnaldo Carvalho de Melo 
1583a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self,
1584a1645ce1SZhang, Yanmin 				const char *dir_name)
15856cfcc53eSMike Galbraith {
1586439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
15875aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
158874534341SGui Jianfeng 	int ret = 0;
15896cfcc53eSMike Galbraith 
1590439d473bSArnaldo Carvalho de Melo 	if (!dir) {
15915aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1592439d473bSArnaldo Carvalho de Melo 		return -1;
1593439d473bSArnaldo Carvalho de Melo 	}
15946cfcc53eSMike Galbraith 
1595439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1596439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1597a1645ce1SZhang, Yanmin 		struct stat st;
1598439d473bSArnaldo Carvalho de Melo 
1599a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
1600a1645ce1SZhang, Yanmin 		sprintf(path, "%s/%s", dir_name, dent->d_name);
1601a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1602a1645ce1SZhang, Yanmin 			continue;
1603a1645ce1SZhang, Yanmin 
1604a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1605439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1606439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1607439d473bSArnaldo Carvalho de Melo 				continue;
1608439d473bSArnaldo Carvalho de Melo 
1609439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
16105aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
161174534341SGui Jianfeng 			ret = map_groups__set_modules_path_dir(self, path);
161274534341SGui Jianfeng 			if (ret < 0)
161374534341SGui Jianfeng 				goto out;
1614439d473bSArnaldo Carvalho de Melo 		} else {
1615439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1616439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1617439d473bSArnaldo Carvalho de Melo 			struct map *map;
1618cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1619439d473bSArnaldo Carvalho de Melo 
1620439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1621439d473bSArnaldo Carvalho de Melo 				continue;
1622439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1623439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1624439d473bSArnaldo Carvalho de Melo 
1625a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
16269de89fe7SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1627439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1628439d473bSArnaldo Carvalho de Melo 				continue;
1629439d473bSArnaldo Carvalho de Melo 
1630439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
16315aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
1632439d473bSArnaldo Carvalho de Melo 
1633cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
163474534341SGui Jianfeng 			if (long_name == NULL) {
163574534341SGui Jianfeng 				ret = -1;
163674534341SGui Jianfeng 				goto out;
163774534341SGui Jianfeng 			}
1638cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
16396e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1640a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1641439d473bSArnaldo Carvalho de Melo 		}
1642439d473bSArnaldo Carvalho de Melo 	}
1643439d473bSArnaldo Carvalho de Melo 
164474534341SGui Jianfeng out:
1645439d473bSArnaldo Carvalho de Melo 	closedir(dir);
164674534341SGui Jianfeng 	return ret;
1647439d473bSArnaldo Carvalho de Melo }
1648439d473bSArnaldo Carvalho de Melo 
1649a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1650439d473bSArnaldo Carvalho de Melo {
1651a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1652a1645ce1SZhang, Yanmin 	FILE *file;
1653a1645ce1SZhang, Yanmin 	char *name, *tmp;
1654a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1655a1645ce1SZhang, Yanmin 
1656a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1657a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1658a1645ce1SZhang, Yanmin 	if (!file)
1659a1645ce1SZhang, Yanmin 		return NULL;
1660a1645ce1SZhang, Yanmin 
1661a1645ce1SZhang, Yanmin 	version[0] = '\0';
1662a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1663a1645ce1SZhang, Yanmin 	fclose(file);
1664a1645ce1SZhang, Yanmin 
1665a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1666a1645ce1SZhang, Yanmin 	if (!name)
1667a1645ce1SZhang, Yanmin 		return NULL;
1668a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1669a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1670a1645ce1SZhang, Yanmin 	if (tmp)
1671a1645ce1SZhang, Yanmin 		*tmp = '\0';
1672a1645ce1SZhang, Yanmin 
1673a1645ce1SZhang, Yanmin 	return strdup(name);
1674a1645ce1SZhang, Yanmin }
1675a1645ce1SZhang, Yanmin 
1676d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self)
1677a1645ce1SZhang, Yanmin {
1678a1645ce1SZhang, Yanmin 	char *version;
1679439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1680439d473bSArnaldo Carvalho de Melo 
1681d28c6223SArnaldo Carvalho de Melo 	version = get_kernel_version(self->root_dir);
1682a1645ce1SZhang, Yanmin 	if (!version)
1683439d473bSArnaldo Carvalho de Melo 		return -1;
1684439d473bSArnaldo Carvalho de Melo 
1685a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1686d28c6223SArnaldo Carvalho de Melo 		 self->root_dir, version);
1687a1645ce1SZhang, Yanmin 	free(version);
1688439d473bSArnaldo Carvalho de Melo 
1689d28c6223SArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
1690439d473bSArnaldo Carvalho de Melo }
16916cfcc53eSMike Galbraith 
16926cfcc53eSMike Galbraith /*
1693439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1694439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1695439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
16966cfcc53eSMike Galbraith  */
16973610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1698439d473bSArnaldo Carvalho de Melo {
16995aab621bSArnaldo Carvalho de Melo 	struct map *self = calloc(1, (sizeof(*self) +
17005aab621bSArnaldo Carvalho de Melo 				      (dso->kernel ? sizeof(struct kmap) : 0)));
1701439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1702439d473bSArnaldo Carvalho de Melo 		/*
1703afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1704439d473bSArnaldo Carvalho de Melo 		 */
17053610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1706439d473bSArnaldo Carvalho de Melo 	}
1707afb7b4f0SArnaldo Carvalho de Melo 
1708439d473bSArnaldo Carvalho de Melo 	return self;
1709439d473bSArnaldo Carvalho de Melo }
1710439d473bSArnaldo Carvalho de Melo 
1711d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start,
1712d28c6223SArnaldo Carvalho de Melo 				const char *filename)
1713b7cece76SArnaldo Carvalho de Melo {
1714b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1715d28c6223SArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
1716b7cece76SArnaldo Carvalho de Melo 
1717b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1718b7cece76SArnaldo Carvalho de Melo 		return NULL;
1719b7cece76SArnaldo Carvalho de Melo 
1720b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1721b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1722b7cece76SArnaldo Carvalho de Melo 		return NULL;
1723b7cece76SArnaldo Carvalho de Melo 
1724d28c6223SArnaldo Carvalho de Melo 	if (machine__is_host(self))
1725b7cece76SArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1726a1645ce1SZhang, Yanmin 	else
1727a1645ce1SZhang, Yanmin 		dso->origin = DSO__ORIG_GUEST_KMODULE;
1728d28c6223SArnaldo Carvalho de Melo 	map_groups__insert(&self->kmaps, map);
1729b7cece76SArnaldo Carvalho de Melo 	return map;
1730b7cece76SArnaldo Carvalho de Melo }
1731b7cece76SArnaldo Carvalho de Melo 
1732d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self)
1733439d473bSArnaldo Carvalho de Melo {
1734439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1735439d473bSArnaldo Carvalho de Melo 	size_t n;
1736a1645ce1SZhang, Yanmin 	FILE *file;
1737439d473bSArnaldo Carvalho de Melo 	struct map *map;
1738a1645ce1SZhang, Yanmin 	const char *modules;
1739a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1740439d473bSArnaldo Carvalho de Melo 
1741d28c6223SArnaldo Carvalho de Melo 	if (machine__is_default_guest(self))
1742a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
1743a1645ce1SZhang, Yanmin 	else {
1744d28c6223SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", self->root_dir);
1745a1645ce1SZhang, Yanmin 		modules = path;
1746a1645ce1SZhang, Yanmin 	}
1747a1645ce1SZhang, Yanmin 
1748a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
1749439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1750439d473bSArnaldo Carvalho de Melo 		return -1;
1751439d473bSArnaldo Carvalho de Melo 
1752439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1753439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1754439d473bSArnaldo Carvalho de Melo 		u64 start;
1755439d473bSArnaldo Carvalho de Melo 		char *sep;
1756439d473bSArnaldo Carvalho de Melo 		int line_len;
1757439d473bSArnaldo Carvalho de Melo 
1758439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1759439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
17606cfcc53eSMike Galbraith 			break;
17616cfcc53eSMike Galbraith 
1762439d473bSArnaldo Carvalho de Melo 		if (!line)
1763439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1764439d473bSArnaldo Carvalho de Melo 
1765439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1766439d473bSArnaldo Carvalho de Melo 
1767439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1768439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1769439d473bSArnaldo Carvalho de Melo 			continue;
1770439d473bSArnaldo Carvalho de Melo 
1771439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1772439d473bSArnaldo Carvalho de Melo 
1773439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1774439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1775439d473bSArnaldo Carvalho de Melo 			continue;
1776439d473bSArnaldo Carvalho de Melo 
1777439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1778439d473bSArnaldo Carvalho de Melo 
1779439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
1780d28c6223SArnaldo Carvalho de Melo 		map = machine__new_module(self, start, name);
1781b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1782439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1783d28c6223SArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, self->root_dir);
17846cfcc53eSMike Galbraith 	}
17856cfcc53eSMike Galbraith 
1786439d473bSArnaldo Carvalho de Melo 	free(line);
1787439d473bSArnaldo Carvalho de Melo 	fclose(file);
1788439d473bSArnaldo Carvalho de Melo 
1789d28c6223SArnaldo Carvalho de Melo 	return machine__set_modules_path(self);
1790439d473bSArnaldo Carvalho de Melo 
1791439d473bSArnaldo Carvalho de Melo out_delete_line:
1792439d473bSArnaldo Carvalho de Melo 	free(line);
1793439d473bSArnaldo Carvalho de Melo out_failure:
1794439d473bSArnaldo Carvalho de Melo 	return -1;
17956cfcc53eSMike Galbraith }
17966cfcc53eSMike Galbraith 
17979958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
17986beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
179986470930SIngo Molnar {
1800fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
1801*ec5761eaSDavid Ahern 	char symfs_vmlinux[PATH_MAX];
180286470930SIngo Molnar 
1803*ec5761eaSDavid Ahern 	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
1804*ec5761eaSDavid Ahern 		 symbol_conf.symfs, vmlinux);
1805*ec5761eaSDavid Ahern 	fd = open(symfs_vmlinux, O_RDONLY);
180686470930SIngo Molnar 	if (fd < 0)
180786470930SIngo Molnar 		return -1;
180886470930SIngo Molnar 
18093610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
1810*ec5761eaSDavid Ahern 	err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
181186470930SIngo Molnar 	close(fd);
181286470930SIngo Molnar 
18133846df2eSArnaldo Carvalho de Melo 	if (err > 0)
1814*ec5761eaSDavid Ahern 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
18153846df2eSArnaldo Carvalho de Melo 
181686470930SIngo Molnar 	return err;
181786470930SIngo Molnar }
181886470930SIngo Molnar 
1819a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map,
18209de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1821a19afe46SArnaldo Carvalho de Melo {
1822a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
18235ad90e4eSArnaldo Carvalho de Melo 	char *filename;
1824a19afe46SArnaldo Carvalho de Melo 
1825a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
18265ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
18275ad90e4eSArnaldo Carvalho de Melo 
18285ad90e4eSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(self, NULL, 0);
18295ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
18305ad90e4eSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, filename, filter);
18315ad90e4eSArnaldo Carvalho de Melo 		if (err > 0) {
18325ad90e4eSArnaldo Carvalho de Melo 			dso__set_long_name(self, filename);
18335ad90e4eSArnaldo Carvalho de Melo 			goto out;
18345ad90e4eSArnaldo Carvalho de Melo 		}
18355ad90e4eSArnaldo Carvalho de Melo 		free(filename);
18365ad90e4eSArnaldo Carvalho de Melo 	}
1837a19afe46SArnaldo Carvalho de Melo 
1838a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
18399de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1840a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1841a19afe46SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(vmlinux_path[i]));
1842a19afe46SArnaldo Carvalho de Melo 			break;
1843a19afe46SArnaldo Carvalho de Melo 		}
1844a19afe46SArnaldo Carvalho de Melo 	}
18455ad90e4eSArnaldo Carvalho de Melo out:
1846a19afe46SArnaldo Carvalho de Melo 	return err;
1847a19afe46SArnaldo Carvalho de Melo }
1848a19afe46SArnaldo Carvalho de Melo 
1849c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
18509de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
185186470930SIngo Molnar {
1852cc612d81SArnaldo Carvalho de Melo 	int err;
18539e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
18549e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1855dc8d6ab2SArnaldo Carvalho de Melo 	/*
1856b226a5a7SDavid Ahern 	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1857b226a5a7SDavid Ahern 	 * it and only it, reporting errors to the user if it cannot be used.
1858dc8d6ab2SArnaldo Carvalho de Melo 	 *
1859dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1860dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1861dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1862dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1863dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1864dc8d6ab2SArnaldo Carvalho de Melo 	 *
1865dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1866dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1867dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1868dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1869dc8d6ab2SArnaldo Carvalho de Melo 	 */
1870b226a5a7SDavid Ahern 	if (symbol_conf.kallsyms_name != NULL) {
1871b226a5a7SDavid Ahern 		kallsyms_filename = symbol_conf.kallsyms_name;
1872b226a5a7SDavid Ahern 		goto do_kallsyms;
1873b226a5a7SDavid Ahern 	}
1874b226a5a7SDavid Ahern 
1875dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
18769de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map,
1877dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1878e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
1879e7dadc00SArnaldo Carvalho de Melo 			dso__set_long_name(self,
1880e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
1881e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
1882e7dadc00SArnaldo Carvalho de Melo 		}
1883e7dadc00SArnaldo Carvalho de Melo 		return err;
1884dc8d6ab2SArnaldo Carvalho de Melo 	}
1885439d473bSArnaldo Carvalho de Melo 
1886cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
18879de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(self, map, filter);
1888a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1889cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1890cc612d81SArnaldo Carvalho de Melo 	}
1891cc612d81SArnaldo Carvalho de Melo 
1892*ec5761eaSDavid Ahern 	/* do not try local files if a symfs was given */
1893*ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
1894*ec5761eaSDavid Ahern 		return -1;
1895*ec5761eaSDavid Ahern 
1896b7cece76SArnaldo Carvalho de Melo 	/*
1897b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1898b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1899b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1900b7cece76SArnaldo Carvalho de Melo 	 */
1901b7cece76SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1902b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
19039e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1904b7cece76SArnaldo Carvalho de Melo 
1905b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
19068d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
19079e201442SArnaldo Carvalho de Melo 			if (dso__build_id_equal(self, kallsyms_build_id)) {
19089e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1909b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
19108d0591f6SArnaldo Carvalho de Melo 			}
19119e201442SArnaldo Carvalho de Melo 		}
1912dc8d6ab2SArnaldo Carvalho de Melo 		/*
1913dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1914dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1915dc8d6ab2SArnaldo Carvalho de Melo 		 */
19169e201442SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
19179e201442SArnaldo Carvalho de Melo 				  sbuild_id);
19189e201442SArnaldo Carvalho de Melo 
19199e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
19209e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
19213846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
19223846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
19238d0591f6SArnaldo Carvalho de Melo 			return -1;
19243846df2eSArnaldo Carvalho de Melo 		}
19258d0591f6SArnaldo Carvalho de Melo 
192619fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
192719fc2dedSArnaldo Carvalho de Melo 
1928dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
19293846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
19303846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
19319e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
1932dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
1933ef6ae724SArnaldo Carvalho de Melo 		}
1934dc8d6ab2SArnaldo Carvalho de Melo 	} else {
1935dc8d6ab2SArnaldo Carvalho de Melo 		/*
1936dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
1937dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
1938dc8d6ab2SArnaldo Carvalho de Melo 		 */
1939dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
1940dc8d6ab2SArnaldo Carvalho de Melo 	}
1941dc8d6ab2SArnaldo Carvalho de Melo 
1942dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
19439de89fe7SArnaldo Carvalho de Melo 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
19443846df2eSArnaldo Carvalho de Melo 	if (err > 0)
19453846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1946dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1947dc8d6ab2SArnaldo Carvalho de Melo 
1948439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1949cc612d81SArnaldo Carvalho de Melo out_fixup:
1950e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
1951dc8d6ab2SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup("[kernel.kallsyms]"));
19526a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
19536a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1954439d473bSArnaldo Carvalho de Melo 	}
195594cb9e38SArnaldo Carvalho de Melo 
195686470930SIngo Molnar 	return err;
195786470930SIngo Molnar }
195886470930SIngo Molnar 
1959a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1960a1645ce1SZhang, Yanmin 				symbol_filter_t filter)
1961a1645ce1SZhang, Yanmin {
1962a1645ce1SZhang, Yanmin 	int err;
1963a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
196423346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1965a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1966a1645ce1SZhang, Yanmin 
1967a1645ce1SZhang, Yanmin 	if (!map->groups) {
1968a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1969a1645ce1SZhang, Yanmin 		return -1;
1970a1645ce1SZhang, Yanmin 	}
197123346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1972a1645ce1SZhang, Yanmin 
197323346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1974a1645ce1SZhang, Yanmin 		/*
1975a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1976a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1977a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1978a1645ce1SZhang, Yanmin 		 */
1979a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1980a1645ce1SZhang, Yanmin 			err = dso__load_vmlinux(self, map,
1981a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
1982a1645ce1SZhang, Yanmin 			goto out_try_fixup;
1983a1645ce1SZhang, Yanmin 		}
1984a1645ce1SZhang, Yanmin 
1985a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1986a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1987a1645ce1SZhang, Yanmin 			return -1;
1988a1645ce1SZhang, Yanmin 	} else {
198923346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1990a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1991a1645ce1SZhang, Yanmin 	}
1992a1645ce1SZhang, Yanmin 
1993a1645ce1SZhang, Yanmin 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1994a1645ce1SZhang, Yanmin 	if (err > 0)
1995a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1996a1645ce1SZhang, Yanmin 
1997a1645ce1SZhang, Yanmin out_try_fixup:
1998a1645ce1SZhang, Yanmin 	if (err > 0) {
1999a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
200048ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
200123346f21SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(path));
2002a1645ce1SZhang, Yanmin 		}
2003a1645ce1SZhang, Yanmin 		map__fixup_start(map);
2004a1645ce1SZhang, Yanmin 		map__fixup_end(map);
2005a1645ce1SZhang, Yanmin 	}
2006a1645ce1SZhang, Yanmin 
2007a1645ce1SZhang, Yanmin 	return err;
2008a1645ce1SZhang, Yanmin }
2009cd84c2acSFrederic Weisbecker 
2010b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
2011cd84c2acSFrederic Weisbecker {
2012b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
2013cd84c2acSFrederic Weisbecker }
2014cd84c2acSFrederic Weisbecker 
2015b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
2016cd84c2acSFrederic Weisbecker {
2017cd84c2acSFrederic Weisbecker 	struct dso *pos;
2018cd84c2acSFrederic Weisbecker 
2019b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
2020cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
2021cd84c2acSFrederic Weisbecker 			return pos;
2022cd84c2acSFrederic Weisbecker 	return NULL;
2023cd84c2acSFrederic Weisbecker }
2024cd84c2acSFrederic Weisbecker 
2025a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
2026cd84c2acSFrederic Weisbecker {
2027a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
2028cd84c2acSFrederic Weisbecker 
2029e4204992SArnaldo Carvalho de Melo 	if (!dso) {
203000a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
2031cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
2032a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
2033cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
2034cfc10d3bSArnaldo Carvalho de Melo 		}
2035e4204992SArnaldo Carvalho de Melo 	}
2036cd84c2acSFrederic Weisbecker 
2037cd84c2acSFrederic Weisbecker 	return dso;
2038cd84c2acSFrederic Weisbecker }
2039cd84c2acSFrederic Weisbecker 
20401f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2041cd84c2acSFrederic Weisbecker {
2042cd84c2acSFrederic Weisbecker 	struct dso *pos;
2043cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2044cd84c2acSFrederic Weisbecker 
204595011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
204695011c60SArnaldo Carvalho de Melo 		int i;
204795011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
2048cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
2049cd84c2acSFrederic Weisbecker 	}
2050cd84c2acSFrederic Weisbecker 
2051cbf69680SArnaldo Carvalho de Melo 	return ret;
2052cbf69680SArnaldo Carvalho de Melo }
2053cbf69680SArnaldo Carvalho de Melo 
2054cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
2055b0da954aSArnaldo Carvalho de Melo {
2056a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2057cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2058a1645ce1SZhang, Yanmin 
2059cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
206023346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2061cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2062cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
2063a1645ce1SZhang, Yanmin 	}
2064cbf69680SArnaldo Carvalho de Melo 
2065cbf69680SArnaldo Carvalho de Melo 	return ret;
2066b0da954aSArnaldo Carvalho de Melo }
2067b0da954aSArnaldo Carvalho de Melo 
206888d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
206988d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
20709e03eb2dSArnaldo Carvalho de Melo {
20719e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
20729e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
20739e03eb2dSArnaldo Carvalho de Melo 
2074b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
207588d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
207688d3d9b7SArnaldo Carvalho de Melo 			continue;
20779e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
20789e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
20799e03eb2dSArnaldo Carvalho de Melo 	}
20809e03eb2dSArnaldo Carvalho de Melo 	return ret;
20819e03eb2dSArnaldo Carvalho de Melo }
20829e03eb2dSArnaldo Carvalho de Melo 
2083f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
2084f869097eSArnaldo Carvalho de Melo {
2085f869097eSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
2086f869097eSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
2087f869097eSArnaldo Carvalho de Melo }
2088f869097eSArnaldo Carvalho de Melo 
2089cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
2090b0da954aSArnaldo Carvalho de Melo {
2091a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2092a1645ce1SZhang, Yanmin 	size_t ret = 0;
2093a1645ce1SZhang, Yanmin 
2094cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
209523346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2096f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2097a1645ce1SZhang, Yanmin 	}
2098a1645ce1SZhang, Yanmin 	return ret;
2099b0da954aSArnaldo Carvalho de Melo }
2100b0da954aSArnaldo Carvalho de Melo 
2101fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name)
2102fd1d908cSArnaldo Carvalho de Melo {
2103fd1d908cSArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
2104fd1d908cSArnaldo Carvalho de Melo 
2105fd1d908cSArnaldo Carvalho de Melo 	if (self != NULL) {
2106b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, "[kernel]");
2107a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_KERNEL;
2108fd1d908cSArnaldo Carvalho de Melo 	}
2109fd1d908cSArnaldo Carvalho de Melo 
2110fd1d908cSArnaldo Carvalho de Melo 	return self;
2111fd1d908cSArnaldo Carvalho de Melo }
2112fd1d908cSArnaldo Carvalho de Melo 
211323346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine,
2114a1645ce1SZhang, Yanmin 					const char *name)
2115fd1d908cSArnaldo Carvalho de Melo {
211648ea8f54SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
211748ea8f54SArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
2118a1645ce1SZhang, Yanmin 
2119a1645ce1SZhang, Yanmin 	if (self != NULL) {
2120a1645ce1SZhang, Yanmin 		dso__set_short_name(self, "[guest.kernel]");
2121a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_GUEST_KERNEL;
2122a1645ce1SZhang, Yanmin 	}
2123a1645ce1SZhang, Yanmin 
2124a1645ce1SZhang, Yanmin 	return self;
2125a1645ce1SZhang, Yanmin }
2126a1645ce1SZhang, Yanmin 
212723346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
2128a1645ce1SZhang, Yanmin {
2129a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2130a1645ce1SZhang, Yanmin 
213123346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2132a1645ce1SZhang, Yanmin 		return;
213323346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2134a1645ce1SZhang, Yanmin 	if (sysfs__read_build_id(path, self->build_id,
2135fd1d908cSArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
2136fd1d908cSArnaldo Carvalho de Melo 		self->has_build_id = true;
2137fd1d908cSArnaldo Carvalho de Melo }
2138fd1d908cSArnaldo Carvalho de Melo 
21395c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self)
2140cd84c2acSFrederic Weisbecker {
2141a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
2142a1645ce1SZhang, Yanmin 	struct dso *kernel;
2143cd84c2acSFrederic Weisbecker 
21445c0541d5SArnaldo Carvalho de Melo 	if (machine__is_host(self)) {
2145a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2146a1645ce1SZhang, Yanmin 		kernel = dso__new_kernel(vmlinux_name);
2147a1645ce1SZhang, Yanmin 	} else {
21485c0541d5SArnaldo Carvalho de Melo 		if (machine__is_default_guest(self))
2149a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
21505c0541d5SArnaldo Carvalho de Melo 		kernel = dso__new_guest_kernel(self, vmlinux_name);
21518d92c02aSArnaldo Carvalho de Melo 	}
2152cd84c2acSFrederic Weisbecker 
2153a1645ce1SZhang, Yanmin 	if (kernel != NULL) {
21545c0541d5SArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, self);
21555c0541d5SArnaldo Carvalho de Melo 		dsos__add(&self->kernel_dsos, kernel);
2156a1645ce1SZhang, Yanmin 	}
2157f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2158f1dfa0b1SArnaldo Carvalho de Melo }
2159f1dfa0b1SArnaldo Carvalho de Melo 
2160d214afbdSMing Lei struct process_args {
2161d214afbdSMing Lei 	u64 start;
2162d214afbdSMing Lei };
2163d214afbdSMing Lei 
2164d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name,
2165d214afbdSMing Lei 			     char type __used, u64 start)
2166d214afbdSMing Lei {
2167d214afbdSMing Lei 	struct process_args *args = arg;
2168d214afbdSMing Lei 
2169d214afbdSMing Lei 	if (strchr(name, '['))
2170d214afbdSMing Lei 		return 0;
2171d214afbdSMing Lei 
2172d214afbdSMing Lei 	args->start = start;
2173d214afbdSMing Lei 	return 1;
2174d214afbdSMing Lei }
2175d214afbdSMing Lei 
2176d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */
2177d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine)
2178d214afbdSMing Lei {
2179d214afbdSMing Lei 	const char *filename;
2180d214afbdSMing Lei 	char path[PATH_MAX];
2181d214afbdSMing Lei 	struct process_args args;
2182d214afbdSMing Lei 
2183d214afbdSMing Lei 	if (machine__is_host(machine)) {
2184d214afbdSMing Lei 		filename = "/proc/kallsyms";
2185d214afbdSMing Lei 	} else {
2186d214afbdSMing Lei 		if (machine__is_default_guest(machine))
2187d214afbdSMing Lei 			filename = (char *)symbol_conf.default_guest_kallsyms;
2188d214afbdSMing Lei 		else {
2189d214afbdSMing Lei 			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2190d214afbdSMing Lei 			filename = path;
2191d214afbdSMing Lei 		}
2192d214afbdSMing Lei 	}
2193d214afbdSMing Lei 
2194d214afbdSMing Lei 	if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2195d214afbdSMing Lei 		return 0;
2196d214afbdSMing Lei 
2197d214afbdSMing Lei 	return args.start;
2198d214afbdSMing Lei }
2199d214afbdSMing Lei 
2200d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2201f1dfa0b1SArnaldo Carvalho de Melo {
2202de176489SArnaldo Carvalho de Melo 	enum map_type type;
2203d214afbdSMing Lei 	u64 start = machine__get_kernel_start_addr(self);
2204f1dfa0b1SArnaldo Carvalho de Melo 
2205de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
22069de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
22079de89fe7SArnaldo Carvalho de Melo 
2208d214afbdSMing Lei 		self->vmlinux_maps[type] = map__new2(start, kernel, type);
2209d28c6223SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2210f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2211f1dfa0b1SArnaldo Carvalho de Melo 
2212d28c6223SArnaldo Carvalho de Melo 		self->vmlinux_maps[type]->map_ip =
2213d28c6223SArnaldo Carvalho de Melo 			self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
22149de89fe7SArnaldo Carvalho de Melo 
2215d28c6223SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2216d28c6223SArnaldo Carvalho de Melo 		kmap->kmaps = &self->kmaps;
2217d28c6223SArnaldo Carvalho de Melo 		map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
2218f1dfa0b1SArnaldo Carvalho de Melo 	}
2219f1dfa0b1SArnaldo Carvalho de Melo 
2220f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
22212446042cSArnaldo Carvalho de Melo }
22222446042cSArnaldo Carvalho de Melo 
2223076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self)
2224076c6e45SArnaldo Carvalho de Melo {
2225076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
2226076c6e45SArnaldo Carvalho de Melo 
2227076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
2228076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
2229076c6e45SArnaldo Carvalho de Melo 
2230076c6e45SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2231076c6e45SArnaldo Carvalho de Melo 			continue;
2232076c6e45SArnaldo Carvalho de Melo 
2233076c6e45SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2234076c6e45SArnaldo Carvalho de Melo 		map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
2235076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
2236076c6e45SArnaldo Carvalho de Melo 			/*
2237076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
2238076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
2239076c6e45SArnaldo Carvalho de Melo 			 */
2240076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
2241076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
2242076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
2243076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
2244076c6e45SArnaldo Carvalho de Melo 			}
2245076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
2246076c6e45SArnaldo Carvalho de Melo 		}
2247076c6e45SArnaldo Carvalho de Melo 
2248076c6e45SArnaldo Carvalho de Melo 		map__delete(self->vmlinux_maps[type]);
2249076c6e45SArnaldo Carvalho de Melo 		self->vmlinux_maps[type] = NULL;
2250076c6e45SArnaldo Carvalho de Melo 	}
2251076c6e45SArnaldo Carvalho de Melo }
2252076c6e45SArnaldo Carvalho de Melo 
22535c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self)
22545c0541d5SArnaldo Carvalho de Melo {
22555c0541d5SArnaldo Carvalho de Melo 	struct dso *kernel = machine__create_kernel(self);
22565c0541d5SArnaldo Carvalho de Melo 
22575c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
22585c0541d5SArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(self, kernel) < 0)
22595c0541d5SArnaldo Carvalho de Melo 		return -1;
22605c0541d5SArnaldo Carvalho de Melo 
22615c0541d5SArnaldo Carvalho de Melo 	if (symbol_conf.use_modules && machine__create_modules(self) < 0)
22625c0541d5SArnaldo Carvalho de Melo 		pr_debug("Problems creating module maps, continuing anyway...\n");
22635c0541d5SArnaldo Carvalho de Melo 	/*
22645c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
22655c0541d5SArnaldo Carvalho de Melo 	 */
22665c0541d5SArnaldo Carvalho de Melo 	map_groups__fixup_end(&self->kmaps);
22675c0541d5SArnaldo Carvalho de Melo 	return 0;
22685c0541d5SArnaldo Carvalho de Melo }
22695c0541d5SArnaldo Carvalho de Melo 
2270cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
22712446042cSArnaldo Carvalho de Melo {
2272cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2273cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2274cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2275cc612d81SArnaldo Carvalho de Melo 	}
2276cc612d81SArnaldo Carvalho de Melo 
2277cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2278cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2279cc612d81SArnaldo Carvalho de Melo }
2280cc612d81SArnaldo Carvalho de Melo 
2281cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2282cc612d81SArnaldo Carvalho de Melo {
2283cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2284cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2285cc612d81SArnaldo Carvalho de Melo 
2286cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2287cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2288cc612d81SArnaldo Carvalho de Melo 		return -1;
2289cc612d81SArnaldo Carvalho de Melo 
2290cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2291cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2292cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2293cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2294cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2295cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2296cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2297cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2298*ec5761eaSDavid Ahern 
2299*ec5761eaSDavid Ahern 	/* only try running kernel version if no symfs was given */
2300*ec5761eaSDavid Ahern 	if (symbol_conf.symfs[0] != 0)
2301*ec5761eaSDavid Ahern 		return 0;
2302*ec5761eaSDavid Ahern 
2303*ec5761eaSDavid Ahern 	if (uname(&uts) < 0)
2304*ec5761eaSDavid Ahern 		return -1;
2305*ec5761eaSDavid Ahern 
2306cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2307cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2308cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2309cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2310cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2311cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2312cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2313cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2314cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2315cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2316cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2317cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2318cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2319cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2320cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2321cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2322cc612d81SArnaldo Carvalho de Melo 
2323cc612d81SArnaldo Carvalho de Melo 	return 0;
2324cc612d81SArnaldo Carvalho de Melo 
2325cc612d81SArnaldo Carvalho de Melo out_fail:
2326cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2327cc612d81SArnaldo Carvalho de Melo 	return -1;
2328cc612d81SArnaldo Carvalho de Melo }
2329cc612d81SArnaldo Carvalho de Melo 
23305ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp)
2331b0a9ab62SArnaldo Carvalho de Melo {
2332b0a9ab62SArnaldo Carvalho de Melo 	int i;
2333b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
23345ad90e4eSArnaldo Carvalho de Melo 	struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso;
23355ad90e4eSArnaldo Carvalho de Melo 
23365ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
23375ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
23385ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
23395ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
23405ad90e4eSArnaldo Carvalho de Melo 	}
2341b0a9ab62SArnaldo Carvalho de Melo 
2342b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
23435ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
23445ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
2345b0a9ab62SArnaldo Carvalho de Melo 
2346b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2347b0a9ab62SArnaldo Carvalho de Melo }
2348b0a9ab62SArnaldo Carvalho de Melo 
2349655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2350655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2351655000e7SArnaldo Carvalho de Melo {
2352655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2353655000e7SArnaldo Carvalho de Melo 		return 0;
2354655000e7SArnaldo Carvalho de Melo 
2355655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2356655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2357655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2358655000e7SArnaldo Carvalho de Melo 		return -1;
2359655000e7SArnaldo Carvalho de Melo 	}
2360655000e7SArnaldo Carvalho de Melo 	return 0;
2361655000e7SArnaldo Carvalho de Melo }
2362655000e7SArnaldo Carvalho de Melo 
236375be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2364cc612d81SArnaldo Carvalho de Melo {
2365*ec5761eaSDavid Ahern 	const char *symfs;
2366*ec5761eaSDavid Ahern 
236785e00b55SJovi Zhang 	if (symbol_conf.initialized)
236885e00b55SJovi Zhang 		return 0;
236985e00b55SJovi Zhang 
237095011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
237175be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
237275be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
237379406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2374b32d133aSArnaldo Carvalho de Melo 
237575be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2376cc612d81SArnaldo Carvalho de Melo 		return -1;
2377cc612d81SArnaldo Carvalho de Melo 
2378c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2379c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2380c410a338SArnaldo Carvalho de Melo 		return -1;
2381c410a338SArnaldo Carvalho de Melo 	}
2382c410a338SArnaldo Carvalho de Melo 
2383655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2384655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2385655000e7SArnaldo Carvalho de Melo 		return -1;
2386655000e7SArnaldo Carvalho de Melo 
2387655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2388655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2389655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2390655000e7SArnaldo Carvalho de Melo 
2391655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2392655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2393655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2394655000e7SArnaldo Carvalho de Melo 
2395*ec5761eaSDavid Ahern 	/*
2396*ec5761eaSDavid Ahern 	 * A path to symbols of "/" is identical to ""
2397*ec5761eaSDavid Ahern 	 * reset here for simplicity.
2398*ec5761eaSDavid Ahern 	 */
2399*ec5761eaSDavid Ahern 	symfs = realpath(symbol_conf.symfs, NULL);
2400*ec5761eaSDavid Ahern 	if (symfs == NULL)
2401*ec5761eaSDavid Ahern 		symfs = symbol_conf.symfs;
2402*ec5761eaSDavid Ahern 	if (strcmp(symfs, "/") == 0)
2403*ec5761eaSDavid Ahern 		symbol_conf.symfs = "";
2404*ec5761eaSDavid Ahern 	if (symfs != symbol_conf.symfs)
2405*ec5761eaSDavid Ahern 		free((void *)symfs);
2406*ec5761eaSDavid Ahern 
240785e00b55SJovi Zhang 	symbol_conf.initialized = true;
24084aa65636SArnaldo Carvalho de Melo 	return 0;
2409655000e7SArnaldo Carvalho de Melo 
2410655000e7SArnaldo Carvalho de Melo out_free_dso_list:
2411655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2412655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2413655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2414655000e7SArnaldo Carvalho de Melo 	return -1;
2415cc612d81SArnaldo Carvalho de Melo }
2416cc612d81SArnaldo Carvalho de Melo 
2417d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2418d65a458bSArnaldo Carvalho de Melo {
241985e00b55SJovi Zhang 	if (!symbol_conf.initialized)
242085e00b55SJovi Zhang 		return;
2421d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2422d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2423d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2424d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2425d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
242685e00b55SJovi Zhang 	symbol_conf.initialized = false;
2427d65a458bSArnaldo Carvalho de Melo }
2428d65a458bSArnaldo Carvalho de Melo 
2429d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
24304aa65636SArnaldo Carvalho de Melo {
2431d28c6223SArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(self, pid);
24329de89fe7SArnaldo Carvalho de Melo 
243323346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2434a1645ce1SZhang, Yanmin 		return -1;
24354aa65636SArnaldo Carvalho de Melo 
24365c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2437cd84c2acSFrederic Weisbecker }
24385aab621bSArnaldo Carvalho de Melo 
24395aab621bSArnaldo Carvalho de Melo static int hex(char ch)
24405aab621bSArnaldo Carvalho de Melo {
24415aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
24425aab621bSArnaldo Carvalho de Melo 		return ch - '0';
24435aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
24445aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
24455aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
24465aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
24475aab621bSArnaldo Carvalho de Melo 	return -1;
24485aab621bSArnaldo Carvalho de Melo }
24495aab621bSArnaldo Carvalho de Melo 
24505aab621bSArnaldo Carvalho de Melo /*
24515aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
24525aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
24535aab621bSArnaldo Carvalho de Melo  */
24545aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
24555aab621bSArnaldo Carvalho de Melo {
24565aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
24575aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
24585aab621bSArnaldo Carvalho de Melo 
24595aab621bSArnaldo Carvalho de Melo 	while (*p) {
24605aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
24615aab621bSArnaldo Carvalho de Melo 
24625aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
24635aab621bSArnaldo Carvalho de Melo 			break;
24645aab621bSArnaldo Carvalho de Melo 
24655aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
24665aab621bSArnaldo Carvalho de Melo 		p++;
24675aab621bSArnaldo Carvalho de Melo 	}
24685aab621bSArnaldo Carvalho de Melo 
24695aab621bSArnaldo Carvalho de Melo 	return p - ptr;
24705aab621bSArnaldo Carvalho de Melo }
24715aab621bSArnaldo Carvalho de Melo 
24725aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
24735aab621bSArnaldo Carvalho de Melo {
24745aab621bSArnaldo Carvalho de Melo 	char *p = s;
24755aab621bSArnaldo Carvalho de Melo 
24765aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
24775aab621bSArnaldo Carvalho de Melo 		*p++ = to;
24785aab621bSArnaldo Carvalho de Melo 
24795aab621bSArnaldo Carvalho de Melo 	return s;
24805aab621bSArnaldo Carvalho de Melo }
2481a1645ce1SZhang, Yanmin 
2482d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self)
2483a1645ce1SZhang, Yanmin {
2484a1645ce1SZhang, Yanmin 	int ret = 0;
2485a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2486a1645ce1SZhang, Yanmin 	int i, items = 0;
2487a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2488a1645ce1SZhang, Yanmin 	pid_t pid;
2489a1645ce1SZhang, Yanmin 
2490a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2491a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2492a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2493d28c6223SArnaldo Carvalho de Melo 		machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
2494a1645ce1SZhang, Yanmin 	}
2495a1645ce1SZhang, Yanmin 
2496a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2497a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2498a1645ce1SZhang, Yanmin 		if (items <= 0)
2499a1645ce1SZhang, Yanmin 			return -ENOENT;
2500a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2501a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2502a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2503a1645ce1SZhang, Yanmin 				continue;
2504a1645ce1SZhang, Yanmin 			}
2505a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2506a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2507a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2508a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2509a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2510a1645ce1SZhang, Yanmin 			if (ret) {
2511a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2512a1645ce1SZhang, Yanmin 				goto failure;
2513a1645ce1SZhang, Yanmin 			}
2514d28c6223SArnaldo Carvalho de Melo 			machines__create_kernel_maps(self, pid);
2515a1645ce1SZhang, Yanmin 		}
2516a1645ce1SZhang, Yanmin failure:
2517a1645ce1SZhang, Yanmin 		free(namelist);
2518a1645ce1SZhang, Yanmin 	}
2519a1645ce1SZhang, Yanmin 
2520a1645ce1SZhang, Yanmin 	return ret;
2521a1645ce1SZhang, Yanmin }
25225c0541d5SArnaldo Carvalho de Melo 
2523076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self)
2524076c6e45SArnaldo Carvalho de Melo {
2525076c6e45SArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
2526076c6e45SArnaldo Carvalho de Melo 
2527076c6e45SArnaldo Carvalho de Melo 	while (next) {
2528076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2529076c6e45SArnaldo Carvalho de Melo 
2530076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2531076c6e45SArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
2532076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2533076c6e45SArnaldo Carvalho de Melo 	}
2534076c6e45SArnaldo Carvalho de Melo }
2535076c6e45SArnaldo Carvalho de Melo 
25365c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename,
25375c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
25385c0541d5SArnaldo Carvalho de Melo {
25395c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
25405c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
25415c0541d5SArnaldo Carvalho de Melo 
25425c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
25435c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
25445c0541d5SArnaldo Carvalho de Melo 		/*
25455c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
25465c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
25475c0541d5SArnaldo Carvalho de Melo 		 * sections.
25485c0541d5SArnaldo Carvalho de Melo 		 */
25495c0541d5SArnaldo Carvalho de Melo 		__map_groups__fixup_end(&self->kmaps, type);
25505c0541d5SArnaldo Carvalho de Melo 	}
25515c0541d5SArnaldo Carvalho de Melo 
25525c0541d5SArnaldo Carvalho de Melo 	return ret;
25535c0541d5SArnaldo Carvalho de Melo }
25545c0541d5SArnaldo Carvalho de Melo 
25555c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type,
25565c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
25575c0541d5SArnaldo Carvalho de Melo {
25585c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
25595c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
25605c0541d5SArnaldo Carvalho de Melo 
25615c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
25625c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
25635c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
25645c0541d5SArnaldo Carvalho de Melo 	}
25655c0541d5SArnaldo Carvalho de Melo 
25665c0541d5SArnaldo Carvalho de Melo 	return ret;
25675c0541d5SArnaldo Carvalho de Melo }
2568