xref: /openbmc/linux/tools/perf/util/map.c (revision 89fe808a)
166e274f3SFrederic Weisbecker #include "symbol.h"
2c6e718ffSArnaldo Carvalho de Melo #include <errno.h>
39486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
44b8cf846SArnaldo Carvalho de Melo #include <limits.h>
566e274f3SFrederic Weisbecker #include <stdlib.h>
666e274f3SFrederic Weisbecker #include <string.h>
766e274f3SFrederic Weisbecker #include <stdio.h>
8a1645ce1SZhang, Yanmin #include <unistd.h>
94b8cf846SArnaldo Carvalho de Melo #include "map.h"
105cd95c2dSDavid Ahern #include "thread.h"
11c80c3c26SDavid Ahern #include "strlist.h"
127dbf4dcfSJiri Olsa #include "vdso.h"
13ebb296c2SJiri Olsa #include "build-id.h"
148e16017dSArnaldo Carvalho de Melo #include <linux/string.h>
1566e274f3SFrederic Weisbecker 
163846df2eSArnaldo Carvalho de Melo const char *map_type__name[MAP__NR_TYPES] = {
173846df2eSArnaldo Carvalho de Melo 	[MAP__FUNCTION] = "Functions",
183846df2eSArnaldo Carvalho de Melo 	[MAP__VARIABLE] = "Variables",
193846df2eSArnaldo Carvalho de Melo };
203846df2eSArnaldo Carvalho de Melo 
2166e274f3SFrederic Weisbecker static inline int is_anon_memory(const char *filename)
2266e274f3SFrederic Weisbecker {
23d0528b5dSJoshua Zhu 	return !strcmp(filename, "//anon") ||
2489365e6cSAndi Kleen 	       !strcmp(filename, "/dev/zero (deleted)") ||
25d0528b5dSJoshua Zhu 	       !strcmp(filename, "/anon_hugepage (deleted)");
2666e274f3SFrederic Weisbecker }
2766e274f3SFrederic Weisbecker 
2887ffef79SJiri Olsa static inline int is_no_dso_memory(const char *filename)
2987ffef79SJiri Olsa {
301e82574dSNamhyung Kim 	return !strncmp(filename, "[stack", 6) ||
3187ffef79SJiri Olsa 	       !strcmp(filename, "[heap]");
3287ffef79SJiri Olsa }
3387ffef79SJiri Olsa 
34237a7e04SArnaldo Carvalho de Melo void map__init(struct map *map, enum map_type type,
353610583cSArnaldo Carvalho de Melo 	       u64 start, u64 end, u64 pgoff, struct dso *dso)
36afb7b4f0SArnaldo Carvalho de Melo {
37237a7e04SArnaldo Carvalho de Melo 	map->type     = type;
38237a7e04SArnaldo Carvalho de Melo 	map->start    = start;
39237a7e04SArnaldo Carvalho de Melo 	map->end      = end;
40237a7e04SArnaldo Carvalho de Melo 	map->pgoff    = pgoff;
41237a7e04SArnaldo Carvalho de Melo 	map->dso      = dso;
42237a7e04SArnaldo Carvalho de Melo 	map->map_ip   = map__map_ip;
43237a7e04SArnaldo Carvalho de Melo 	map->unmap_ip = map__unmap_ip;
44237a7e04SArnaldo Carvalho de Melo 	RB_CLEAR_NODE(&map->rb_node);
45237a7e04SArnaldo Carvalho de Melo 	map->groups   = NULL;
46237a7e04SArnaldo Carvalho de Melo 	map->referenced = false;
47237a7e04SArnaldo Carvalho de Melo 	map->erange_warned = false;
48afb7b4f0SArnaldo Carvalho de Melo }
49afb7b4f0SArnaldo Carvalho de Melo 
50a1645ce1SZhang, Yanmin struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
515c5e854bSStephane Eranian 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
525c5e854bSStephane Eranian 		     u64 ino_gen, char *filename,
53361d1346SDave Martin 		     enum map_type type)
5466e274f3SFrederic Weisbecker {
55237a7e04SArnaldo Carvalho de Melo 	struct map *map = malloc(sizeof(*map));
5666e274f3SFrederic Weisbecker 
57237a7e04SArnaldo Carvalho de Melo 	if (map != NULL) {
5866e274f3SFrederic Weisbecker 		char newfilename[PATH_MAX];
59afb7b4f0SArnaldo Carvalho de Melo 		struct dso *dso;
607dbf4dcfSJiri Olsa 		int anon, no_dso, vdso;
6166e274f3SFrederic Weisbecker 
6266e274f3SFrederic Weisbecker 		anon = is_anon_memory(filename);
637dbf4dcfSJiri Olsa 		vdso = is_vdso_map(filename);
6487ffef79SJiri Olsa 		no_dso = is_no_dso_memory(filename);
6566e274f3SFrederic Weisbecker 
665c5e854bSStephane Eranian 		map->maj = d_maj;
675c5e854bSStephane Eranian 		map->min = d_min;
685c5e854bSStephane Eranian 		map->ino = ino;
695c5e854bSStephane Eranian 		map->ino_generation = ino_gen;
705c5e854bSStephane Eranian 
7166e274f3SFrederic Weisbecker 		if (anon) {
72b177f63fSArnaldo Carvalho de Melo 			snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
7366e274f3SFrederic Weisbecker 			filename = newfilename;
7466e274f3SFrederic Weisbecker 		}
7566e274f3SFrederic Weisbecker 
767dbf4dcfSJiri Olsa 		if (vdso) {
777dbf4dcfSJiri Olsa 			pgoff = 0;
787dbf4dcfSJiri Olsa 			dso = vdso__dso_findnew(dsos__list);
797dbf4dcfSJiri Olsa 		} else
80a1645ce1SZhang, Yanmin 			dso = __dsos__findnew(dsos__list, filename);
817dbf4dcfSJiri Olsa 
82afb7b4f0SArnaldo Carvalho de Melo 		if (dso == NULL)
8366e274f3SFrederic Weisbecker 			goto out_delete;
8466e274f3SFrederic Weisbecker 
85237a7e04SArnaldo Carvalho de Melo 		map__init(map, type, start, start + len, pgoff, dso);
86afb7b4f0SArnaldo Carvalho de Melo 
8787ffef79SJiri Olsa 		if (anon || no_dso) {
88237a7e04SArnaldo Carvalho de Melo 			map->map_ip = map->unmap_ip = identity__map_ip;
8987ffef79SJiri Olsa 
9087ffef79SJiri Olsa 			/*
9187ffef79SJiri Olsa 			 * Set memory without DSO as loaded. All map__find_*
9287ffef79SJiri Olsa 			 * functions still return NULL, and we avoid the
9387ffef79SJiri Olsa 			 * unnecessary map__load warning.
9487ffef79SJiri Olsa 			 */
9587ffef79SJiri Olsa 			if (no_dso)
96237a7e04SArnaldo Carvalho de Melo 				dso__set_loaded(dso, map->type);
978d92c02aSArnaldo Carvalho de Melo 		}
9866e274f3SFrederic Weisbecker 	}
99237a7e04SArnaldo Carvalho de Melo 	return map;
10066e274f3SFrederic Weisbecker out_delete:
101237a7e04SArnaldo Carvalho de Melo 	free(map);
10266e274f3SFrederic Weisbecker 	return NULL;
10366e274f3SFrederic Weisbecker }
10466e274f3SFrederic Weisbecker 
105e5a1845fSNamhyung Kim /*
106e5a1845fSNamhyung Kim  * Constructor variant for modules (where we know from /proc/modules where
107e5a1845fSNamhyung Kim  * they are loaded) and for vmlinux, where only after we load all the
108e5a1845fSNamhyung Kim  * symbols we'll know where it starts and ends.
109e5a1845fSNamhyung Kim  */
110e5a1845fSNamhyung Kim struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
111e5a1845fSNamhyung Kim {
112e5a1845fSNamhyung Kim 	struct map *map = calloc(1, (sizeof(*map) +
113e5a1845fSNamhyung Kim 				     (dso->kernel ? sizeof(struct kmap) : 0)));
114e5a1845fSNamhyung Kim 	if (map != NULL) {
115e5a1845fSNamhyung Kim 		/*
116e5a1845fSNamhyung Kim 		 * ->end will be filled after we load all the symbols
117e5a1845fSNamhyung Kim 		 */
118e5a1845fSNamhyung Kim 		map__init(map, type, start, 0, 0, dso);
119e5a1845fSNamhyung Kim 	}
120e5a1845fSNamhyung Kim 
121e5a1845fSNamhyung Kim 	return map;
122e5a1845fSNamhyung Kim }
123e5a1845fSNamhyung Kim 
124237a7e04SArnaldo Carvalho de Melo void map__delete(struct map *map)
125c338aee8SArnaldo Carvalho de Melo {
126237a7e04SArnaldo Carvalho de Melo 	free(map);
127c338aee8SArnaldo Carvalho de Melo }
128c338aee8SArnaldo Carvalho de Melo 
129237a7e04SArnaldo Carvalho de Melo void map__fixup_start(struct map *map)
130c338aee8SArnaldo Carvalho de Melo {
131237a7e04SArnaldo Carvalho de Melo 	struct rb_root *symbols = &map->dso->symbols[map->type];
132fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_first(symbols);
133c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
134c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
135237a7e04SArnaldo Carvalho de Melo 		map->start = sym->start;
136c338aee8SArnaldo Carvalho de Melo 	}
137c338aee8SArnaldo Carvalho de Melo }
138c338aee8SArnaldo Carvalho de Melo 
139237a7e04SArnaldo Carvalho de Melo void map__fixup_end(struct map *map)
140c338aee8SArnaldo Carvalho de Melo {
141237a7e04SArnaldo Carvalho de Melo 	struct rb_root *symbols = &map->dso->symbols[map->type];
142fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_last(symbols);
143c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
144c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
145237a7e04SArnaldo Carvalho de Melo 		map->end = sym->end;
146c338aee8SArnaldo Carvalho de Melo 	}
147c338aee8SArnaldo Carvalho de Melo }
148c338aee8SArnaldo Carvalho de Melo 
149d70a5402SArnaldo Carvalho de Melo #define DSO__DELETED "(deleted)"
150d70a5402SArnaldo Carvalho de Melo 
151237a7e04SArnaldo Carvalho de Melo int map__load(struct map *map, symbol_filter_t filter)
15266bd8424SArnaldo Carvalho de Melo {
153237a7e04SArnaldo Carvalho de Melo 	const char *name = map->dso->long_name;
154a128168dSMasami Hiramatsu 	int nr;
15566bd8424SArnaldo Carvalho de Melo 
156237a7e04SArnaldo Carvalho de Melo 	if (dso__loaded(map->dso, map->type))
157a128168dSMasami Hiramatsu 		return 0;
158a128168dSMasami Hiramatsu 
159237a7e04SArnaldo Carvalho de Melo 	nr = dso__load(map->dso, map, filter);
16066bd8424SArnaldo Carvalho de Melo 	if (nr < 0) {
161237a7e04SArnaldo Carvalho de Melo 		if (map->dso->has_build_id) {
1628d06367fSArnaldo Carvalho de Melo 			char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1638d06367fSArnaldo Carvalho de Melo 
164237a7e04SArnaldo Carvalho de Melo 			build_id__sprintf(map->dso->build_id,
165237a7e04SArnaldo Carvalho de Melo 					  sizeof(map->dso->build_id),
1668d06367fSArnaldo Carvalho de Melo 					  sbuild_id);
1678d06367fSArnaldo Carvalho de Melo 			pr_warning("%s with build id %s not found",
16879406cd7SArnaldo Carvalho de Melo 				   name, sbuild_id);
1698d06367fSArnaldo Carvalho de Melo 		} else
17079406cd7SArnaldo Carvalho de Melo 			pr_warning("Failed to open %s", name);
17179406cd7SArnaldo Carvalho de Melo 
1728d06367fSArnaldo Carvalho de Melo 		pr_warning(", continuing without symbols\n");
17379406cd7SArnaldo Carvalho de Melo 		return -1;
17466bd8424SArnaldo Carvalho de Melo 	} else if (nr == 0) {
17589fe808aSIngo Molnar #ifdef HAVE_LIBELF_SUPPORT
176d70a5402SArnaldo Carvalho de Melo 		const size_t len = strlen(name);
177d70a5402SArnaldo Carvalho de Melo 		const size_t real_len = len - sizeof(DSO__DELETED);
178d70a5402SArnaldo Carvalho de Melo 
179d70a5402SArnaldo Carvalho de Melo 		if (len > sizeof(DSO__DELETED) &&
180900b20d5SIngo Molnar 		    strcmp(name + real_len + 1, DSO__DELETED) == 0) {
181e77b15bdSDavid Ahern 			pr_warning("%.*s was updated (is prelink enabled?). "
182e77b15bdSDavid Ahern 				"Restart the long running apps that use it!\n",
183900b20d5SIngo Molnar 				   (int)real_len, name);
184900b20d5SIngo Molnar 		} else {
18579406cd7SArnaldo Carvalho de Melo 			pr_warning("no symbols found in %s, maybe install "
18679406cd7SArnaldo Carvalho de Melo 				   "a debug package?\n", name);
18766bd8424SArnaldo Carvalho de Melo 		}
188393be2e3SNamhyung Kim #endif
18979406cd7SArnaldo Carvalho de Melo 		return -1;
19079406cd7SArnaldo Carvalho de Melo 	}
19179406cd7SArnaldo Carvalho de Melo 
19279406cd7SArnaldo Carvalho de Melo 	return 0;
19379406cd7SArnaldo Carvalho de Melo }
19479406cd7SArnaldo Carvalho de Melo 
195237a7e04SArnaldo Carvalho de Melo struct symbol *map__find_symbol(struct map *map, u64 addr,
1969de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
19779406cd7SArnaldo Carvalho de Melo {
198237a7e04SArnaldo Carvalho de Melo 	if (map__load(map, filter) < 0)
19979406cd7SArnaldo Carvalho de Melo 		return NULL;
20079406cd7SArnaldo Carvalho de Melo 
201237a7e04SArnaldo Carvalho de Melo 	return dso__find_symbol(map->dso, map->type, addr);
20266bd8424SArnaldo Carvalho de Melo }
20366bd8424SArnaldo Carvalho de Melo 
204237a7e04SArnaldo Carvalho de Melo struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
20579406cd7SArnaldo Carvalho de Melo 					symbol_filter_t filter)
20679406cd7SArnaldo Carvalho de Melo {
207237a7e04SArnaldo Carvalho de Melo 	if (map__load(map, filter) < 0)
20879406cd7SArnaldo Carvalho de Melo 		return NULL;
20979406cd7SArnaldo Carvalho de Melo 
210237a7e04SArnaldo Carvalho de Melo 	if (!dso__sorted_by_name(map->dso, map->type))
211237a7e04SArnaldo Carvalho de Melo 		dso__sort_by_name(map->dso, map->type);
21279406cd7SArnaldo Carvalho de Melo 
213237a7e04SArnaldo Carvalho de Melo 	return dso__find_symbol_by_name(map->dso, map->type, name);
21479406cd7SArnaldo Carvalho de Melo }
21579406cd7SArnaldo Carvalho de Melo 
216237a7e04SArnaldo Carvalho de Melo struct map *map__clone(struct map *map)
21766e274f3SFrederic Weisbecker {
2188e16017dSArnaldo Carvalho de Melo 	return memdup(map, sizeof(*map));
21966e274f3SFrederic Weisbecker }
22066e274f3SFrederic Weisbecker 
22166e274f3SFrederic Weisbecker int map__overlap(struct map *l, struct map *r)
22266e274f3SFrederic Weisbecker {
22366e274f3SFrederic Weisbecker 	if (l->start > r->start) {
22466e274f3SFrederic Weisbecker 		struct map *t = l;
22566e274f3SFrederic Weisbecker 		l = r;
22666e274f3SFrederic Weisbecker 		r = t;
22766e274f3SFrederic Weisbecker 	}
22866e274f3SFrederic Weisbecker 
22966e274f3SFrederic Weisbecker 	if (l->end > r->start)
23066e274f3SFrederic Weisbecker 		return 1;
23166e274f3SFrederic Weisbecker 
23266e274f3SFrederic Weisbecker 	return 0;
23366e274f3SFrederic Weisbecker }
23466e274f3SFrederic Weisbecker 
235237a7e04SArnaldo Carvalho de Melo size_t map__fprintf(struct map *map, FILE *fp)
23666e274f3SFrederic Weisbecker {
2379486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
238237a7e04SArnaldo Carvalho de Melo 		       map->start, map->end, map->pgoff, map->dso->name);
23966e274f3SFrederic Weisbecker }
2407a2b6209SKirill Smelkov 
241547a92e0SAkihiro Nagai size_t map__fprintf_dsoname(struct map *map, FILE *fp)
242547a92e0SAkihiro Nagai {
2438f28f19aSFeng Tang 	const char *dsoname = "[unknown]";
244547a92e0SAkihiro Nagai 
2450bc8d205SAkihiro Nagai 	if (map && map->dso && (map->dso->name || map->dso->long_name)) {
2460bc8d205SAkihiro Nagai 		if (symbol_conf.show_kernel_path && map->dso->long_name)
2470bc8d205SAkihiro Nagai 			dsoname = map->dso->long_name;
2480bc8d205SAkihiro Nagai 		else if (map->dso->name)
249547a92e0SAkihiro Nagai 			dsoname = map->dso->name;
2508f28f19aSFeng Tang 	}
251547a92e0SAkihiro Nagai 
252547a92e0SAkihiro Nagai 	return fprintf(fp, "%s", dsoname);
253547a92e0SAkihiro Nagai }
254547a92e0SAkihiro Nagai 
2557a2b6209SKirill Smelkov /*
2567a2b6209SKirill Smelkov  * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
2570131c4ecSAdrian Hunter  * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
2580131c4ecSAdrian Hunter  * relative to section start.
2597a2b6209SKirill Smelkov  */
2607a2b6209SKirill Smelkov u64 map__rip_2objdump(struct map *map, u64 rip)
2617a2b6209SKirill Smelkov {
2620131c4ecSAdrian Hunter 	if (!map->dso->adjust_symbols)
2630131c4ecSAdrian Hunter 		return rip;
2640131c4ecSAdrian Hunter 
2650131c4ecSAdrian Hunter 	if (map->dso->rel)
2660131c4ecSAdrian Hunter 		return rip - map->pgoff;
2670131c4ecSAdrian Hunter 
2680131c4ecSAdrian Hunter 	return map->unmap_ip(map, rip);
2697a2b6209SKirill Smelkov }
270ee11b90bSKirill Smelkov 
27198dfd55dSArnaldo Carvalho de Melo void map_groups__init(struct map_groups *mg)
272c6e718ffSArnaldo Carvalho de Melo {
273c6e718ffSArnaldo Carvalho de Melo 	int i;
274c6e718ffSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i) {
27598dfd55dSArnaldo Carvalho de Melo 		mg->maps[i] = RB_ROOT;
27698dfd55dSArnaldo Carvalho de Melo 		INIT_LIST_HEAD(&mg->removed_maps[i]);
277c6e718ffSArnaldo Carvalho de Melo 	}
27898dfd55dSArnaldo Carvalho de Melo 	mg->machine = NULL;
279c6e718ffSArnaldo Carvalho de Melo }
280c6e718ffSArnaldo Carvalho de Melo 
28198dfd55dSArnaldo Carvalho de Melo static void maps__delete(struct rb_root *maps)
282591765fdSArnaldo Carvalho de Melo {
28398dfd55dSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(maps);
284591765fdSArnaldo Carvalho de Melo 
285591765fdSArnaldo Carvalho de Melo 	while (next) {
286591765fdSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(next, struct map, rb_node);
287591765fdSArnaldo Carvalho de Melo 
288591765fdSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
28998dfd55dSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, maps);
290591765fdSArnaldo Carvalho de Melo 		map__delete(pos);
291591765fdSArnaldo Carvalho de Melo 	}
292591765fdSArnaldo Carvalho de Melo }
293591765fdSArnaldo Carvalho de Melo 
29498dfd55dSArnaldo Carvalho de Melo static void maps__delete_removed(struct list_head *maps)
295591765fdSArnaldo Carvalho de Melo {
296591765fdSArnaldo Carvalho de Melo 	struct map *pos, *n;
297591765fdSArnaldo Carvalho de Melo 
29898dfd55dSArnaldo Carvalho de Melo 	list_for_each_entry_safe(pos, n, maps, node) {
299591765fdSArnaldo Carvalho de Melo 		list_del(&pos->node);
300591765fdSArnaldo Carvalho de Melo 		map__delete(pos);
301591765fdSArnaldo Carvalho de Melo 	}
302591765fdSArnaldo Carvalho de Melo }
303591765fdSArnaldo Carvalho de Melo 
30498dfd55dSArnaldo Carvalho de Melo void map_groups__exit(struct map_groups *mg)
305591765fdSArnaldo Carvalho de Melo {
306591765fdSArnaldo Carvalho de Melo 	int i;
307591765fdSArnaldo Carvalho de Melo 
308591765fdSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i) {
30998dfd55dSArnaldo Carvalho de Melo 		maps__delete(&mg->maps[i]);
31098dfd55dSArnaldo Carvalho de Melo 		maps__delete_removed(&mg->removed_maps[i]);
311591765fdSArnaldo Carvalho de Melo 	}
312591765fdSArnaldo Carvalho de Melo }
313591765fdSArnaldo Carvalho de Melo 
31498dfd55dSArnaldo Carvalho de Melo void map_groups__flush(struct map_groups *mg)
315c6e718ffSArnaldo Carvalho de Melo {
316c6e718ffSArnaldo Carvalho de Melo 	int type;
317c6e718ffSArnaldo Carvalho de Melo 
318c6e718ffSArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; type++) {
31998dfd55dSArnaldo Carvalho de Melo 		struct rb_root *root = &mg->maps[type];
320c6e718ffSArnaldo Carvalho de Melo 		struct rb_node *next = rb_first(root);
321c6e718ffSArnaldo Carvalho de Melo 
322c6e718ffSArnaldo Carvalho de Melo 		while (next) {
323c6e718ffSArnaldo Carvalho de Melo 			struct map *pos = rb_entry(next, struct map, rb_node);
324c6e718ffSArnaldo Carvalho de Melo 			next = rb_next(&pos->rb_node);
325c6e718ffSArnaldo Carvalho de Melo 			rb_erase(&pos->rb_node, root);
326c6e718ffSArnaldo Carvalho de Melo 			/*
327c6e718ffSArnaldo Carvalho de Melo 			 * We may have references to this map, for
328c6e718ffSArnaldo Carvalho de Melo 			 * instance in some hist_entry instances, so
329c6e718ffSArnaldo Carvalho de Melo 			 * just move them to a separate list.
330c6e718ffSArnaldo Carvalho de Melo 			 */
33198dfd55dSArnaldo Carvalho de Melo 			list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
332c6e718ffSArnaldo Carvalho de Melo 		}
333c6e718ffSArnaldo Carvalho de Melo 	}
334c6e718ffSArnaldo Carvalho de Melo }
335c6e718ffSArnaldo Carvalho de Melo 
33698dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol(struct map_groups *mg,
3374b8cf846SArnaldo Carvalho de Melo 				       enum map_type type, u64 addr,
3387e5e1b14SArnaldo Carvalho de Melo 				       struct map **mapp,
3394b8cf846SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
3404b8cf846SArnaldo Carvalho de Melo {
34198dfd55dSArnaldo Carvalho de Melo 	struct map *map = map_groups__find(mg, type, addr);
3424b8cf846SArnaldo Carvalho de Melo 
3437e5e1b14SArnaldo Carvalho de Melo 	if (map != NULL) {
3447e5e1b14SArnaldo Carvalho de Melo 		if (mapp != NULL)
3457e5e1b14SArnaldo Carvalho de Melo 			*mapp = map;
3464b8cf846SArnaldo Carvalho de Melo 		return map__find_symbol(map, map->map_ip(map, addr), filter);
3477e5e1b14SArnaldo Carvalho de Melo 	}
3487e5e1b14SArnaldo Carvalho de Melo 
3497e5e1b14SArnaldo Carvalho de Melo 	return NULL;
3507e5e1b14SArnaldo Carvalho de Melo }
3517e5e1b14SArnaldo Carvalho de Melo 
35298dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
3537e5e1b14SArnaldo Carvalho de Melo 					       enum map_type type,
3547e5e1b14SArnaldo Carvalho de Melo 					       const char *name,
3557e5e1b14SArnaldo Carvalho de Melo 					       struct map **mapp,
3567e5e1b14SArnaldo Carvalho de Melo 					       symbol_filter_t filter)
3577e5e1b14SArnaldo Carvalho de Melo {
3587e5e1b14SArnaldo Carvalho de Melo 	struct rb_node *nd;
3597e5e1b14SArnaldo Carvalho de Melo 
36098dfd55dSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
3617e5e1b14SArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
3627e5e1b14SArnaldo Carvalho de Melo 		struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
3637e5e1b14SArnaldo Carvalho de Melo 
3647e5e1b14SArnaldo Carvalho de Melo 		if (sym == NULL)
3657e5e1b14SArnaldo Carvalho de Melo 			continue;
3667e5e1b14SArnaldo Carvalho de Melo 		if (mapp != NULL)
3677e5e1b14SArnaldo Carvalho de Melo 			*mapp = pos;
3687e5e1b14SArnaldo Carvalho de Melo 		return sym;
3697e5e1b14SArnaldo Carvalho de Melo 	}
3704b8cf846SArnaldo Carvalho de Melo 
3714b8cf846SArnaldo Carvalho de Melo 	return NULL;
3724b8cf846SArnaldo Carvalho de Melo }
3734b8cf846SArnaldo Carvalho de Melo 
37498dfd55dSArnaldo Carvalho de Melo size_t __map_groups__fprintf_maps(struct map_groups *mg,
375c6e718ffSArnaldo Carvalho de Melo 				  enum map_type type, int verbose, FILE *fp)
376c6e718ffSArnaldo Carvalho de Melo {
377c6e718ffSArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
378c6e718ffSArnaldo Carvalho de Melo 	struct rb_node *nd;
379c6e718ffSArnaldo Carvalho de Melo 
38098dfd55dSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
381c6e718ffSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
382c6e718ffSArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
383c6e718ffSArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
384c6e718ffSArnaldo Carvalho de Melo 		if (verbose > 2) {
385c6e718ffSArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, type, fp);
386c6e718ffSArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
387c6e718ffSArnaldo Carvalho de Melo 		}
388c6e718ffSArnaldo Carvalho de Melo 	}
389c6e718ffSArnaldo Carvalho de Melo 
390c6e718ffSArnaldo Carvalho de Melo 	return printed;
391c6e718ffSArnaldo Carvalho de Melo }
392c6e718ffSArnaldo Carvalho de Melo 
39398dfd55dSArnaldo Carvalho de Melo size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp)
394c6e718ffSArnaldo Carvalho de Melo {
395c6e718ffSArnaldo Carvalho de Melo 	size_t printed = 0, i;
396c6e718ffSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
39798dfd55dSArnaldo Carvalho de Melo 		printed += __map_groups__fprintf_maps(mg, i, verbose, fp);
398c6e718ffSArnaldo Carvalho de Melo 	return printed;
399c6e718ffSArnaldo Carvalho de Melo }
400c6e718ffSArnaldo Carvalho de Melo 
40198dfd55dSArnaldo Carvalho de Melo static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
402c6e718ffSArnaldo Carvalho de Melo 						 enum map_type type,
403c6e718ffSArnaldo Carvalho de Melo 						 int verbose, FILE *fp)
404c6e718ffSArnaldo Carvalho de Melo {
405c6e718ffSArnaldo Carvalho de Melo 	struct map *pos;
406c6e718ffSArnaldo Carvalho de Melo 	size_t printed = 0;
407c6e718ffSArnaldo Carvalho de Melo 
40898dfd55dSArnaldo Carvalho de Melo 	list_for_each_entry(pos, &mg->removed_maps[type], node) {
409c6e718ffSArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
410c6e718ffSArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
411c6e718ffSArnaldo Carvalho de Melo 		if (verbose > 1) {
412c6e718ffSArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, type, fp);
413c6e718ffSArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
414c6e718ffSArnaldo Carvalho de Melo 		}
415c6e718ffSArnaldo Carvalho de Melo 	}
416c6e718ffSArnaldo Carvalho de Melo 	return printed;
417c6e718ffSArnaldo Carvalho de Melo }
418c6e718ffSArnaldo Carvalho de Melo 
41998dfd55dSArnaldo Carvalho de Melo static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
420c6e718ffSArnaldo Carvalho de Melo 					       int verbose, FILE *fp)
421c6e718ffSArnaldo Carvalho de Melo {
422c6e718ffSArnaldo Carvalho de Melo 	size_t printed = 0, i;
423c6e718ffSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
42498dfd55dSArnaldo Carvalho de Melo 		printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp);
425c6e718ffSArnaldo Carvalho de Melo 	return printed;
426c6e718ffSArnaldo Carvalho de Melo }
427c6e718ffSArnaldo Carvalho de Melo 
42898dfd55dSArnaldo Carvalho de Melo size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp)
429c6e718ffSArnaldo Carvalho de Melo {
43098dfd55dSArnaldo Carvalho de Melo 	size_t printed = map_groups__fprintf_maps(mg, verbose, fp);
431c6e718ffSArnaldo Carvalho de Melo 	printed += fprintf(fp, "Removed maps:\n");
43298dfd55dSArnaldo Carvalho de Melo 	return printed + map_groups__fprintf_removed_maps(mg, verbose, fp);
433c6e718ffSArnaldo Carvalho de Melo }
434c6e718ffSArnaldo Carvalho de Melo 
43598dfd55dSArnaldo Carvalho de Melo int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
436c6e718ffSArnaldo Carvalho de Melo 				   int verbose, FILE *fp)
437c6e718ffSArnaldo Carvalho de Melo {
43898dfd55dSArnaldo Carvalho de Melo 	struct rb_root *root = &mg->maps[map->type];
439c6e718ffSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
4400a1eae39SArnaldo Carvalho de Melo 	int err = 0;
441c6e718ffSArnaldo Carvalho de Melo 
442c6e718ffSArnaldo Carvalho de Melo 	while (next) {
443c6e718ffSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(next, struct map, rb_node);
444c6e718ffSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
445c6e718ffSArnaldo Carvalho de Melo 
446c6e718ffSArnaldo Carvalho de Melo 		if (!map__overlap(pos, map))
447c6e718ffSArnaldo Carvalho de Melo 			continue;
448c6e718ffSArnaldo Carvalho de Melo 
449c6e718ffSArnaldo Carvalho de Melo 		if (verbose >= 2) {
450c6e718ffSArnaldo Carvalho de Melo 			fputs("overlapping maps:\n", fp);
451c6e718ffSArnaldo Carvalho de Melo 			map__fprintf(map, fp);
452c6e718ffSArnaldo Carvalho de Melo 			map__fprintf(pos, fp);
453c6e718ffSArnaldo Carvalho de Melo 		}
454c6e718ffSArnaldo Carvalho de Melo 
455c6e718ffSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, root);
456c6e718ffSArnaldo Carvalho de Melo 		/*
457c6e718ffSArnaldo Carvalho de Melo 		 * Now check if we need to create new maps for areas not
458c6e718ffSArnaldo Carvalho de Melo 		 * overlapped by the new map:
459c6e718ffSArnaldo Carvalho de Melo 		 */
460c6e718ffSArnaldo Carvalho de Melo 		if (map->start > pos->start) {
461c6e718ffSArnaldo Carvalho de Melo 			struct map *before = map__clone(pos);
462c6e718ffSArnaldo Carvalho de Melo 
4630a1eae39SArnaldo Carvalho de Melo 			if (before == NULL) {
4640a1eae39SArnaldo Carvalho de Melo 				err = -ENOMEM;
4650a1eae39SArnaldo Carvalho de Melo 				goto move_map;
4660a1eae39SArnaldo Carvalho de Melo 			}
467c6e718ffSArnaldo Carvalho de Melo 
468c6e718ffSArnaldo Carvalho de Melo 			before->end = map->start - 1;
46998dfd55dSArnaldo Carvalho de Melo 			map_groups__insert(mg, before);
470c6e718ffSArnaldo Carvalho de Melo 			if (verbose >= 2)
471c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(before, fp);
472c6e718ffSArnaldo Carvalho de Melo 		}
473c6e718ffSArnaldo Carvalho de Melo 
474c6e718ffSArnaldo Carvalho de Melo 		if (map->end < pos->end) {
475c6e718ffSArnaldo Carvalho de Melo 			struct map *after = map__clone(pos);
476c6e718ffSArnaldo Carvalho de Melo 
4770a1eae39SArnaldo Carvalho de Melo 			if (after == NULL) {
4780a1eae39SArnaldo Carvalho de Melo 				err = -ENOMEM;
4790a1eae39SArnaldo Carvalho de Melo 				goto move_map;
4800a1eae39SArnaldo Carvalho de Melo 			}
481c6e718ffSArnaldo Carvalho de Melo 
482c6e718ffSArnaldo Carvalho de Melo 			after->start = map->end + 1;
48398dfd55dSArnaldo Carvalho de Melo 			map_groups__insert(mg, after);
484c6e718ffSArnaldo Carvalho de Melo 			if (verbose >= 2)
485c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(after, fp);
486c6e718ffSArnaldo Carvalho de Melo 		}
4870a1eae39SArnaldo Carvalho de Melo move_map:
4880a1eae39SArnaldo Carvalho de Melo 		/*
4890a1eae39SArnaldo Carvalho de Melo 		 * If we have references, just move them to a separate list.
4900a1eae39SArnaldo Carvalho de Melo 		 */
4910a1eae39SArnaldo Carvalho de Melo 		if (pos->referenced)
49298dfd55dSArnaldo Carvalho de Melo 			list_add_tail(&pos->node, &mg->removed_maps[map->type]);
4930a1eae39SArnaldo Carvalho de Melo 		else
4940a1eae39SArnaldo Carvalho de Melo 			map__delete(pos);
4950a1eae39SArnaldo Carvalho de Melo 
4960a1eae39SArnaldo Carvalho de Melo 		if (err)
4970a1eae39SArnaldo Carvalho de Melo 			return err;
498c6e718ffSArnaldo Carvalho de Melo 	}
499c6e718ffSArnaldo Carvalho de Melo 
500c6e718ffSArnaldo Carvalho de Melo 	return 0;
501c6e718ffSArnaldo Carvalho de Melo }
502c6e718ffSArnaldo Carvalho de Melo 
503c6e718ffSArnaldo Carvalho de Melo /*
504c6e718ffSArnaldo Carvalho de Melo  * XXX This should not really _copy_ te maps, but refcount them.
505c6e718ffSArnaldo Carvalho de Melo  */
50698dfd55dSArnaldo Carvalho de Melo int map_groups__clone(struct map_groups *mg,
507c6e718ffSArnaldo Carvalho de Melo 		      struct map_groups *parent, enum map_type type)
508c6e718ffSArnaldo Carvalho de Melo {
509c6e718ffSArnaldo Carvalho de Melo 	struct rb_node *nd;
510c6e718ffSArnaldo Carvalho de Melo 	for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
511c6e718ffSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
512c6e718ffSArnaldo Carvalho de Melo 		struct map *new = map__clone(map);
513c6e718ffSArnaldo Carvalho de Melo 		if (new == NULL)
514c6e718ffSArnaldo Carvalho de Melo 			return -ENOMEM;
51598dfd55dSArnaldo Carvalho de Melo 		map_groups__insert(mg, new);
516c6e718ffSArnaldo Carvalho de Melo 	}
517c6e718ffSArnaldo Carvalho de Melo 	return 0;
518c6e718ffSArnaldo Carvalho de Melo }
519c6e718ffSArnaldo Carvalho de Melo 
5204b8cf846SArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map)
5214b8cf846SArnaldo Carvalho de Melo {
5224b8cf846SArnaldo Carvalho de Melo 	struct rb_node **p = &maps->rb_node;
5234b8cf846SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
5244b8cf846SArnaldo Carvalho de Melo 	const u64 ip = map->start;
5254b8cf846SArnaldo Carvalho de Melo 	struct map *m;
5264b8cf846SArnaldo Carvalho de Melo 
5274b8cf846SArnaldo Carvalho de Melo 	while (*p != NULL) {
5284b8cf846SArnaldo Carvalho de Melo 		parent = *p;
5294b8cf846SArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
5304b8cf846SArnaldo Carvalho de Melo 		if (ip < m->start)
5314b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
5324b8cf846SArnaldo Carvalho de Melo 		else
5334b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
5344b8cf846SArnaldo Carvalho de Melo 	}
5354b8cf846SArnaldo Carvalho de Melo 
5364b8cf846SArnaldo Carvalho de Melo 	rb_link_node(&map->rb_node, parent, p);
5374b8cf846SArnaldo Carvalho de Melo 	rb_insert_color(&map->rb_node, maps);
5384b8cf846SArnaldo Carvalho de Melo }
5394b8cf846SArnaldo Carvalho de Melo 
540237a7e04SArnaldo Carvalho de Melo void maps__remove(struct rb_root *maps, struct map *map)
541076c6e45SArnaldo Carvalho de Melo {
542237a7e04SArnaldo Carvalho de Melo 	rb_erase(&map->rb_node, maps);
543076c6e45SArnaldo Carvalho de Melo }
544076c6e45SArnaldo Carvalho de Melo 
5454b8cf846SArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip)
5464b8cf846SArnaldo Carvalho de Melo {
5474b8cf846SArnaldo Carvalho de Melo 	struct rb_node **p = &maps->rb_node;
5484b8cf846SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
5494b8cf846SArnaldo Carvalho de Melo 	struct map *m;
5504b8cf846SArnaldo Carvalho de Melo 
5514b8cf846SArnaldo Carvalho de Melo 	while (*p != NULL) {
5524b8cf846SArnaldo Carvalho de Melo 		parent = *p;
5534b8cf846SArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
5544b8cf846SArnaldo Carvalho de Melo 		if (ip < m->start)
5554b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
5564b8cf846SArnaldo Carvalho de Melo 		else if (ip > m->end)
5574b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
5584b8cf846SArnaldo Carvalho de Melo 		else
5594b8cf846SArnaldo Carvalho de Melo 			return m;
5604b8cf846SArnaldo Carvalho de Melo 	}
5614b8cf846SArnaldo Carvalho de Melo 
5624b8cf846SArnaldo Carvalho de Melo 	return NULL;
5634b8cf846SArnaldo Carvalho de Melo }
5648e0cf965SAdrian Hunter 
5658e0cf965SAdrian Hunter struct map *maps__first(struct rb_root *maps)
5668e0cf965SAdrian Hunter {
5678e0cf965SAdrian Hunter 	struct rb_node *first = rb_first(maps);
5688e0cf965SAdrian Hunter 
5698e0cf965SAdrian Hunter 	if (first)
5708e0cf965SAdrian Hunter 		return rb_entry(first, struct map, rb_node);
5718e0cf965SAdrian Hunter 	return NULL;
5728e0cf965SAdrian Hunter }
5738e0cf965SAdrian Hunter 
5748e0cf965SAdrian Hunter struct map *maps__next(struct map *map)
5758e0cf965SAdrian Hunter {
5768e0cf965SAdrian Hunter 	struct rb_node *next = rb_next(&map->rb_node);
5778e0cf965SAdrian Hunter 
5788e0cf965SAdrian Hunter 	if (next)
5798e0cf965SAdrian Hunter 		return rb_entry(next, struct map, rb_node);
5808e0cf965SAdrian Hunter 	return NULL;
5818e0cf965SAdrian Hunter }
582