xref: /openbmc/linux/tools/perf/util/map.c (revision a128168d)
166e274f3SFrederic Weisbecker #include "event.h"
266e274f3SFrederic Weisbecker #include "symbol.h"
366e274f3SFrederic Weisbecker #include <stdlib.h>
466e274f3SFrederic Weisbecker #include <string.h>
566e274f3SFrederic Weisbecker #include <stdio.h>
6e4204992SArnaldo Carvalho de Melo #include "debug.h"
766e274f3SFrederic Weisbecker 
866e274f3SFrederic Weisbecker static inline int is_anon_memory(const char *filename)
966e274f3SFrederic Weisbecker {
1066e274f3SFrederic Weisbecker 	return strcmp(filename, "//anon") == 0;
1166e274f3SFrederic Weisbecker }
1266e274f3SFrederic Weisbecker 
1366e274f3SFrederic Weisbecker static int strcommon(const char *pathname, char *cwd, int cwdlen)
1466e274f3SFrederic Weisbecker {
1566e274f3SFrederic Weisbecker 	int n = 0;
1666e274f3SFrederic Weisbecker 
1766e274f3SFrederic Weisbecker 	while (n < cwdlen && pathname[n] == cwd[n])
1866e274f3SFrederic Weisbecker 		++n;
1966e274f3SFrederic Weisbecker 
2066e274f3SFrederic Weisbecker 	return n;
2166e274f3SFrederic Weisbecker }
2266e274f3SFrederic Weisbecker 
233610583cSArnaldo Carvalho de Melo void map__init(struct map *self, enum map_type type,
243610583cSArnaldo Carvalho de Melo 	       u64 start, u64 end, u64 pgoff, struct dso *dso)
25afb7b4f0SArnaldo Carvalho de Melo {
263610583cSArnaldo Carvalho de Melo 	self->type     = type;
27afb7b4f0SArnaldo Carvalho de Melo 	self->start    = start;
28afb7b4f0SArnaldo Carvalho de Melo 	self->end      = end;
29afb7b4f0SArnaldo Carvalho de Melo 	self->pgoff    = pgoff;
30afb7b4f0SArnaldo Carvalho de Melo 	self->dso      = dso;
31afb7b4f0SArnaldo Carvalho de Melo 	self->map_ip   = map__map_ip;
32afb7b4f0SArnaldo Carvalho de Melo 	self->unmap_ip = map__unmap_ip;
33afb7b4f0SArnaldo Carvalho de Melo 	RB_CLEAR_NODE(&self->rb_node);
34afb7b4f0SArnaldo Carvalho de Melo }
35afb7b4f0SArnaldo Carvalho de Melo 
363610583cSArnaldo Carvalho de Melo struct map *map__new(struct mmap_event *event, enum map_type type,
373610583cSArnaldo Carvalho de Melo 		     char *cwd, int cwdlen)
3866e274f3SFrederic Weisbecker {
3966e274f3SFrederic Weisbecker 	struct map *self = malloc(sizeof(*self));
4066e274f3SFrederic Weisbecker 
4166e274f3SFrederic Weisbecker 	if (self != NULL) {
4266e274f3SFrederic Weisbecker 		const char *filename = event->filename;
4366e274f3SFrederic Weisbecker 		char newfilename[PATH_MAX];
44afb7b4f0SArnaldo Carvalho de Melo 		struct dso *dso;
4566e274f3SFrederic Weisbecker 		int anon;
4666e274f3SFrederic Weisbecker 
4766e274f3SFrederic Weisbecker 		if (cwd) {
4866e274f3SFrederic Weisbecker 			int n = strcommon(filename, cwd, cwdlen);
4966e274f3SFrederic Weisbecker 
5066e274f3SFrederic Weisbecker 			if (n == cwdlen) {
5166e274f3SFrederic Weisbecker 				snprintf(newfilename, sizeof(newfilename),
5266e274f3SFrederic Weisbecker 					 ".%s", filename + n);
5366e274f3SFrederic Weisbecker 				filename = newfilename;
5466e274f3SFrederic Weisbecker 			}
5566e274f3SFrederic Weisbecker 		}
5666e274f3SFrederic Weisbecker 
5766e274f3SFrederic Weisbecker 		anon = is_anon_memory(filename);
5866e274f3SFrederic Weisbecker 
5966e274f3SFrederic Weisbecker 		if (anon) {
6066e274f3SFrederic Weisbecker 			snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
6166e274f3SFrederic Weisbecker 			filename = newfilename;
6266e274f3SFrederic Weisbecker 		}
6366e274f3SFrederic Weisbecker 
6400a192b3SArnaldo Carvalho de Melo 		dso = dsos__findnew(filename);
65afb7b4f0SArnaldo Carvalho de Melo 		if (dso == NULL)
6666e274f3SFrederic Weisbecker 			goto out_delete;
6766e274f3SFrederic Weisbecker 
683610583cSArnaldo Carvalho de Melo 		map__init(self, type, event->start, event->start + event->len,
69afb7b4f0SArnaldo Carvalho de Melo 			  event->pgoff, dso);
70afb7b4f0SArnaldo Carvalho de Melo 
7166e274f3SFrederic Weisbecker 		if (self->dso == vdso || anon)
72ed52ce2eSArnaldo Carvalho de Melo 			self->map_ip = self->unmap_ip = identity__map_ip;
7366e274f3SFrederic Weisbecker 	}
7466e274f3SFrederic Weisbecker 	return self;
7566e274f3SFrederic Weisbecker out_delete:
7666e274f3SFrederic Weisbecker 	free(self);
7766e274f3SFrederic Weisbecker 	return NULL;
7866e274f3SFrederic Weisbecker }
7966e274f3SFrederic Weisbecker 
80c338aee8SArnaldo Carvalho de Melo void map__delete(struct map *self)
81c338aee8SArnaldo Carvalho de Melo {
82c338aee8SArnaldo Carvalho de Melo 	free(self);
83c338aee8SArnaldo Carvalho de Melo }
84c338aee8SArnaldo Carvalho de Melo 
856a4694a4SArnaldo Carvalho de Melo void map__fixup_start(struct map *self)
86c338aee8SArnaldo Carvalho de Melo {
876a4694a4SArnaldo Carvalho de Melo 	struct rb_root *symbols = &self->dso->symbols[self->type];
88fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_first(symbols);
89c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
90c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
91c338aee8SArnaldo Carvalho de Melo 		self->start = sym->start;
92c338aee8SArnaldo Carvalho de Melo 	}
93c338aee8SArnaldo Carvalho de Melo }
94c338aee8SArnaldo Carvalho de Melo 
956a4694a4SArnaldo Carvalho de Melo void map__fixup_end(struct map *self)
96c338aee8SArnaldo Carvalho de Melo {
976a4694a4SArnaldo Carvalho de Melo 	struct rb_root *symbols = &self->dso->symbols[self->type];
98fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_last(symbols);
99c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
100c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
101c338aee8SArnaldo Carvalho de Melo 		self->end = sym->end;
102c338aee8SArnaldo Carvalho de Melo 	}
103c338aee8SArnaldo Carvalho de Melo }
104c338aee8SArnaldo Carvalho de Melo 
105d70a5402SArnaldo Carvalho de Melo #define DSO__DELETED "(deleted)"
106d70a5402SArnaldo Carvalho de Melo 
107a128168dSMasami Hiramatsu int map__load(struct map *self, struct perf_session *session,
1084aa65636SArnaldo Carvalho de Melo 	      symbol_filter_t filter)
10966bd8424SArnaldo Carvalho de Melo {
11079406cd7SArnaldo Carvalho de Melo 	const char *name = self->dso->long_name;
111a128168dSMasami Hiramatsu 	int nr;
11266bd8424SArnaldo Carvalho de Melo 
113a128168dSMasami Hiramatsu 	if (dso__loaded(self->dso, self->type))
114a128168dSMasami Hiramatsu 		return 0;
115a128168dSMasami Hiramatsu 
116a128168dSMasami Hiramatsu 	nr = dso__load(self->dso, self, session, filter);
11766bd8424SArnaldo Carvalho de Melo 	if (nr < 0) {
1188d06367fSArnaldo Carvalho de Melo 		if (self->dso->has_build_id) {
1198d06367fSArnaldo Carvalho de Melo 			char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1208d06367fSArnaldo Carvalho de Melo 
1218d06367fSArnaldo Carvalho de Melo 			build_id__sprintf(self->dso->build_id,
1228d06367fSArnaldo Carvalho de Melo 					  sizeof(self->dso->build_id),
1238d06367fSArnaldo Carvalho de Melo 					  sbuild_id);
1248d06367fSArnaldo Carvalho de Melo 			pr_warning("%s with build id %s not found",
12579406cd7SArnaldo Carvalho de Melo 				   name, sbuild_id);
1268d06367fSArnaldo Carvalho de Melo 		} else
12779406cd7SArnaldo Carvalho de Melo 			pr_warning("Failed to open %s", name);
12879406cd7SArnaldo Carvalho de Melo 
1298d06367fSArnaldo Carvalho de Melo 		pr_warning(", continuing without symbols\n");
13079406cd7SArnaldo Carvalho de Melo 		return -1;
13166bd8424SArnaldo Carvalho de Melo 	} else if (nr == 0) {
132d70a5402SArnaldo Carvalho de Melo 		const size_t len = strlen(name);
133d70a5402SArnaldo Carvalho de Melo 		const size_t real_len = len - sizeof(DSO__DELETED);
134d70a5402SArnaldo Carvalho de Melo 
135d70a5402SArnaldo Carvalho de Melo 		if (len > sizeof(DSO__DELETED) &&
136900b20d5SIngo Molnar 		    strcmp(name + real_len + 1, DSO__DELETED) == 0) {
13779406cd7SArnaldo Carvalho de Melo 			pr_warning("%.*s was updated, restart the long "
13879406cd7SArnaldo Carvalho de Melo 				   "running apps that use it!\n",
139900b20d5SIngo Molnar 				   (int)real_len, name);
140900b20d5SIngo Molnar 		} else {
14179406cd7SArnaldo Carvalho de Melo 			pr_warning("no symbols found in %s, maybe install "
14279406cd7SArnaldo Carvalho de Melo 				   "a debug package?\n", name);
14366bd8424SArnaldo Carvalho de Melo 		}
14466bd8424SArnaldo Carvalho de Melo 
14579406cd7SArnaldo Carvalho de Melo 		return -1;
14679406cd7SArnaldo Carvalho de Melo 	}
14779406cd7SArnaldo Carvalho de Melo 
14879406cd7SArnaldo Carvalho de Melo 	return 0;
14979406cd7SArnaldo Carvalho de Melo }
15079406cd7SArnaldo Carvalho de Melo 
1514aa65636SArnaldo Carvalho de Melo struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
1524aa65636SArnaldo Carvalho de Melo 				u64 addr, symbol_filter_t filter)
15379406cd7SArnaldo Carvalho de Melo {
154a128168dSMasami Hiramatsu 	if (map__load(self, session, filter) < 0)
15579406cd7SArnaldo Carvalho de Melo 		return NULL;
15679406cd7SArnaldo Carvalho de Melo 
157ea08d8cbSArnaldo Carvalho de Melo 	return dso__find_symbol(self->dso, self->type, addr);
15866bd8424SArnaldo Carvalho de Melo }
15966bd8424SArnaldo Carvalho de Melo 
16079406cd7SArnaldo Carvalho de Melo struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
1614aa65636SArnaldo Carvalho de Melo 					struct perf_session *session,
16279406cd7SArnaldo Carvalho de Melo 					symbol_filter_t filter)
16379406cd7SArnaldo Carvalho de Melo {
164a128168dSMasami Hiramatsu 	if (map__load(self, session, filter) < 0)
16579406cd7SArnaldo Carvalho de Melo 		return NULL;
16679406cd7SArnaldo Carvalho de Melo 
16779406cd7SArnaldo Carvalho de Melo 	if (!dso__sorted_by_name(self->dso, self->type))
16879406cd7SArnaldo Carvalho de Melo 		dso__sort_by_name(self->dso, self->type);
16979406cd7SArnaldo Carvalho de Melo 
17079406cd7SArnaldo Carvalho de Melo 	return dso__find_symbol_by_name(self->dso, self->type, name);
17179406cd7SArnaldo Carvalho de Melo }
17279406cd7SArnaldo Carvalho de Melo 
17366e274f3SFrederic Weisbecker struct map *map__clone(struct map *self)
17466e274f3SFrederic Weisbecker {
17566e274f3SFrederic Weisbecker 	struct map *map = malloc(sizeof(*self));
17666e274f3SFrederic Weisbecker 
17766e274f3SFrederic Weisbecker 	if (!map)
17866e274f3SFrederic Weisbecker 		return NULL;
17966e274f3SFrederic Weisbecker 
18066e274f3SFrederic Weisbecker 	memcpy(map, self, sizeof(*self));
18166e274f3SFrederic Weisbecker 
18266e274f3SFrederic Weisbecker 	return map;
18366e274f3SFrederic Weisbecker }
18466e274f3SFrederic Weisbecker 
18566e274f3SFrederic Weisbecker int map__overlap(struct map *l, struct map *r)
18666e274f3SFrederic Weisbecker {
18766e274f3SFrederic Weisbecker 	if (l->start > r->start) {
18866e274f3SFrederic Weisbecker 		struct map *t = l;
18966e274f3SFrederic Weisbecker 		l = r;
19066e274f3SFrederic Weisbecker 		r = t;
19166e274f3SFrederic Weisbecker 	}
19266e274f3SFrederic Weisbecker 
19366e274f3SFrederic Weisbecker 	if (l->end > r->start)
19466e274f3SFrederic Weisbecker 		return 1;
19566e274f3SFrederic Weisbecker 
19666e274f3SFrederic Weisbecker 	return 0;
19766e274f3SFrederic Weisbecker }
19866e274f3SFrederic Weisbecker 
19966e274f3SFrederic Weisbecker size_t map__fprintf(struct map *self, FILE *fp)
20066e274f3SFrederic Weisbecker {
20166e274f3SFrederic Weisbecker 	return fprintf(fp, " %Lx-%Lx %Lx %s\n",
20266e274f3SFrederic Weisbecker 		       self->start, self->end, self->pgoff, self->dso->name);
20366e274f3SFrederic Weisbecker }
204