xref: /linux/tools/perf/util/map.c (revision a33f32244d8550da8b4a26e277ce07d5c6d158b5)
1 #include "event.h"
2 #include "symbol.h"
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include "debug.h"
7 
8 const char *map_type__name[MAP__NR_TYPES] = {
9 	[MAP__FUNCTION] = "Functions",
10 	[MAP__VARIABLE] = "Variables",
11 };
12 
13 static inline int is_anon_memory(const char *filename)
14 {
15 	return strcmp(filename, "//anon") == 0;
16 }
17 
18 static int strcommon(const char *pathname, char *cwd, int cwdlen)
19 {
20 	int n = 0;
21 
22 	while (n < cwdlen && pathname[n] == cwd[n])
23 		++n;
24 
25 	return n;
26 }
27 
28 void map__init(struct map *self, enum map_type type,
29 	       u64 start, u64 end, u64 pgoff, struct dso *dso)
30 {
31 	self->type     = type;
32 	self->start    = start;
33 	self->end      = end;
34 	self->pgoff    = pgoff;
35 	self->dso      = dso;
36 	self->map_ip   = map__map_ip;
37 	self->unmap_ip = map__unmap_ip;
38 	RB_CLEAR_NODE(&self->rb_node);
39 }
40 
41 struct map *map__new(struct mmap_event *event, enum map_type type,
42 		     char *cwd, int cwdlen)
43 {
44 	struct map *self = malloc(sizeof(*self));
45 
46 	if (self != NULL) {
47 		const char *filename = event->filename;
48 		char newfilename[PATH_MAX];
49 		struct dso *dso;
50 		int anon;
51 
52 		if (cwd) {
53 			int n = strcommon(filename, cwd, cwdlen);
54 
55 			if (n == cwdlen) {
56 				snprintf(newfilename, sizeof(newfilename),
57 					 ".%s", filename + n);
58 				filename = newfilename;
59 			}
60 		}
61 
62 		anon = is_anon_memory(filename);
63 
64 		if (anon) {
65 			snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
66 			filename = newfilename;
67 		}
68 
69 		dso = dsos__findnew(filename);
70 		if (dso == NULL)
71 			goto out_delete;
72 
73 		map__init(self, type, event->start, event->start + event->len,
74 			  event->pgoff, dso);
75 
76 		if (anon) {
77 set_identity:
78 			self->map_ip = self->unmap_ip = identity__map_ip;
79 		} else if (strcmp(filename, "[vdso]") == 0) {
80 			dso__set_loaded(dso, self->type);
81 			goto set_identity;
82 		}
83 	}
84 	return self;
85 out_delete:
86 	free(self);
87 	return NULL;
88 }
89 
90 void map__delete(struct map *self)
91 {
92 	free(self);
93 }
94 
95 void map__fixup_start(struct map *self)
96 {
97 	struct rb_root *symbols = &self->dso->symbols[self->type];
98 	struct rb_node *nd = rb_first(symbols);
99 	if (nd != NULL) {
100 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
101 		self->start = sym->start;
102 	}
103 }
104 
105 void map__fixup_end(struct map *self)
106 {
107 	struct rb_root *symbols = &self->dso->symbols[self->type];
108 	struct rb_node *nd = rb_last(symbols);
109 	if (nd != NULL) {
110 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
111 		self->end = sym->end;
112 	}
113 }
114 
115 #define DSO__DELETED "(deleted)"
116 
117 int map__load(struct map *self, symbol_filter_t filter)
118 {
119 	const char *name = self->dso->long_name;
120 	int nr;
121 
122 	if (dso__loaded(self->dso, self->type))
123 		return 0;
124 
125 	nr = dso__load(self->dso, self, filter);
126 	if (nr < 0) {
127 		if (self->dso->has_build_id) {
128 			char sbuild_id[BUILD_ID_SIZE * 2 + 1];
129 
130 			build_id__sprintf(self->dso->build_id,
131 					  sizeof(self->dso->build_id),
132 					  sbuild_id);
133 			pr_warning("%s with build id %s not found",
134 				   name, sbuild_id);
135 		} else
136 			pr_warning("Failed to open %s", name);
137 
138 		pr_warning(", continuing without symbols\n");
139 		return -1;
140 	} else if (nr == 0) {
141 		const size_t len = strlen(name);
142 		const size_t real_len = len - sizeof(DSO__DELETED);
143 
144 		if (len > sizeof(DSO__DELETED) &&
145 		    strcmp(name + real_len + 1, DSO__DELETED) == 0) {
146 			pr_warning("%.*s was updated, restart the long "
147 				   "running apps that use it!\n",
148 				   (int)real_len, name);
149 		} else {
150 			pr_warning("no symbols found in %s, maybe install "
151 				   "a debug package?\n", name);
152 		}
153 
154 		return -1;
155 	}
156 	/*
157 	 * Only applies to the kernel, as its symtabs aren't relative like the
158 	 * module ones.
159 	 */
160 	if (self->dso->kernel)
161 		map__reloc_vmlinux(self);
162 
163 	return 0;
164 }
165 
166 struct symbol *map__find_symbol(struct map *self, u64 addr,
167 				symbol_filter_t filter)
168 {
169 	if (map__load(self, filter) < 0)
170 		return NULL;
171 
172 	return dso__find_symbol(self->dso, self->type, addr);
173 }
174 
175 struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
176 					symbol_filter_t filter)
177 {
178 	if (map__load(self, filter) < 0)
179 		return NULL;
180 
181 	if (!dso__sorted_by_name(self->dso, self->type))
182 		dso__sort_by_name(self->dso, self->type);
183 
184 	return dso__find_symbol_by_name(self->dso, self->type, name);
185 }
186 
187 struct map *map__clone(struct map *self)
188 {
189 	struct map *map = malloc(sizeof(*self));
190 
191 	if (!map)
192 		return NULL;
193 
194 	memcpy(map, self, sizeof(*self));
195 
196 	return map;
197 }
198 
199 int map__overlap(struct map *l, struct map *r)
200 {
201 	if (l->start > r->start) {
202 		struct map *t = l;
203 		l = r;
204 		r = t;
205 	}
206 
207 	if (l->end > r->start)
208 		return 1;
209 
210 	return 0;
211 }
212 
213 size_t map__fprintf(struct map *self, FILE *fp)
214 {
215 	return fprintf(fp, " %Lx-%Lx %Lx %s\n",
216 		       self->start, self->end, self->pgoff, self->dso->name);
217 }
218 
219 /*
220  * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
221  * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
222  */
223 u64 map__rip_2objdump(struct map *map, u64 rip)
224 {
225 	u64 addr = map->dso->adjust_symbols ?
226 			map->unmap_ip(map, rip) :	/* RIP -> IP */
227 			rip;
228 	return addr;
229 }
230 
231 u64 map__objdump_2ip(struct map *map, u64 addr)
232 {
233 	u64 ip = map->dso->adjust_symbols ?
234 			addr :
235 			map->unmap_ip(map, addr);	/* RIP -> IP */
236 	return ip;
237 }
238