blob: 16d783d322b609094fb0b4a9405afc960480a7e6 [file] [log] [blame]
Frederic Weisbecker66e274f2009-08-12 11:07:25 +02001#include "symbol.h"
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -03002#include <errno.h>
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -02003#include <inttypes.h>
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -03004#include <limits.h>
Frederic Weisbecker66e274f2009-08-12 11:07:25 +02005#include <stdlib.h>
6#include <string.h>
7#include <stdio.h>
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08008#include <unistd.h>
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -03009#include "map.h"
David Ahern5cd95c22012-07-20 17:25:47 -060010#include "thread.h"
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020011
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -030012const char *map_type__name[MAP__NR_TYPES] = {
13 [MAP__FUNCTION] = "Functions",
14 [MAP__VARIABLE] = "Variables",
15};
16
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020017static inline int is_anon_memory(const char *filename)
18{
19 return strcmp(filename, "//anon") == 0;
20}
21
Jiri Olsa87ffef72011-08-24 15:18:34 +020022static inline int is_no_dso_memory(const char *filename)
23{
24 return !strcmp(filename, "[stack]") ||
25 !strcmp(filename, "[vdso]") ||
26 !strcmp(filename, "[heap]");
27}
28
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020029void map__init(struct map *self, enum map_type type,
30 u64 start, u64 end, u64 pgoff, struct dso *dso)
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020031{
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020032 self->type = type;
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020033 self->start = start;
34 self->end = end;
35 self->pgoff = pgoff;
36 self->dso = dso;
37 self->map_ip = map__map_ip;
38 self->unmap_ip = map__unmap_ip;
39 RB_CLEAR_NODE(&self->rb_node);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080040 self->groups = NULL;
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -030041 self->referenced = false;
Arnaldo Carvalho de Melo31d68e72012-03-27 12:55:57 -030042 self->erange_warned = false;
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020043}
44
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080045struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
46 u64 pgoff, u32 pid, char *filename,
Dave Martin361d1342010-07-27 16:40:02 +010047 enum map_type type)
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020048{
49 struct map *self = malloc(sizeof(*self));
50
51 if (self != NULL) {
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020052 char newfilename[PATH_MAX];
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020053 struct dso *dso;
Jiri Olsa87ffef72011-08-24 15:18:34 +020054 int anon, no_dso;
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020055
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020056 anon = is_anon_memory(filename);
Jiri Olsa87ffef72011-08-24 15:18:34 +020057 no_dso = is_no_dso_memory(filename);
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020058
59 if (anon) {
Arnaldo Carvalho de Melob177f632010-03-25 19:58:57 -030060 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020061 filename = newfilename;
62 }
63
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080064 dso = __dsos__findnew(dsos__list, filename);
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020065 if (dso == NULL)
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020066 goto out_delete;
67
Arnaldo Carvalho de Melob177f632010-03-25 19:58:57 -030068 map__init(self, type, start, start + len, pgoff, dso);
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020069
Jiri Olsa87ffef72011-08-24 15:18:34 +020070 if (anon || no_dso) {
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -020071 self->map_ip = self->unmap_ip = identity__map_ip;
Jiri Olsa87ffef72011-08-24 15:18:34 +020072
73 /*
74 * Set memory without DSO as loaded. All map__find_*
75 * functions still return NULL, and we avoid the
76 * unnecessary map__load warning.
77 */
78 if (no_dso)
79 dso__set_loaded(dso, self->type);
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -020080 }
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020081 }
82 return self;
83out_delete:
84 free(self);
85 return NULL;
86}
87
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020088void map__delete(struct map *self)
89{
90 free(self);
91}
92
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -020093void map__fixup_start(struct map *self)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020094{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -020095 struct rb_root *symbols = &self->dso->symbols[self->type];
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020096 struct rb_node *nd = rb_first(symbols);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020097 if (nd != NULL) {
98 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
99 self->start = sym->start;
100 }
101}
102
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200103void map__fixup_end(struct map *self)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200104{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200105 struct rb_root *symbols = &self->dso->symbols[self->type];
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200106 struct rb_node *nd = rb_last(symbols);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200107 if (nd != NULL) {
108 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
109 self->end = sym->end;
110 }
111}
112
Arnaldo Carvalho de Melod70a5402009-10-30 16:28:25 -0200113#define DSO__DELETED "(deleted)"
114
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200115int map__load(struct map *self, symbol_filter_t filter)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200116{
117 const char *name = self->dso->long_name;
Masami Hiramatsua1281682009-12-15 10:32:33 -0500118 int nr;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200119
Masami Hiramatsua1281682009-12-15 10:32:33 -0500120 if (dso__loaded(self->dso, self->type))
121 return 0;
122
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200123 nr = dso__load(self->dso, self, filter);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200124 if (nr < 0) {
125 if (self->dso->has_build_id) {
126 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
127
128 build_id__sprintf(self->dso->build_id,
129 sizeof(self->dso->build_id),
130 sbuild_id);
131 pr_warning("%s with build id %s not found",
132 name, sbuild_id);
133 } else
134 pr_warning("Failed to open %s", name);
135
136 pr_warning(", continuing without symbols\n");
137 return -1;
138 } else if (nr == 0) {
139 const size_t len = strlen(name);
140 const size_t real_len = len - sizeof(DSO__DELETED);
141
142 if (len > sizeof(DSO__DELETED) &&
143 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
David Aherne77b15b2011-10-18 18:44:45 -0600144 pr_warning("%.*s was updated (is prelink enabled?). "
145 "Restart the long running apps that use it!\n",
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200146 (int)real_len, name);
147 } else {
148 pr_warning("no symbols found in %s, maybe install "
149 "a debug package?\n", name);
150 }
151
152 return -1;
153 }
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200154 /*
155 * Only applies to the kernel, as its symtabs aren't relative like the
156 * module ones.
157 */
158 if (self->dso->kernel)
159 map__reloc_vmlinux(self);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200160
161 return 0;
162}
163
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200164struct symbol *map__find_symbol(struct map *self, u64 addr,
165 symbol_filter_t filter)
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200166{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200167 if (map__load(self, filter) < 0)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200168 return NULL;
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200169
Arnaldo Carvalho de Meloea08d8c2009-12-11 18:56:39 -0200170 return dso__find_symbol(self->dso, self->type, addr);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200171}
172
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200173struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
174 symbol_filter_t filter)
175{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200176 if (map__load(self, filter) < 0)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200177 return NULL;
178
179 if (!dso__sorted_by_name(self->dso, self->type))
180 dso__sort_by_name(self->dso, self->type);
181
182 return dso__find_symbol_by_name(self->dso, self->type, name);
183}
184
Frederic Weisbecker66e274f2009-08-12 11:07:25 +0200185struct map *map__clone(struct map *self)
186{
187 struct map *map = malloc(sizeof(*self));
188
189 if (!map)
190 return NULL;
191
192 memcpy(map, self, sizeof(*self));
193
194 return map;
195}
196
197int map__overlap(struct map *l, struct map *r)
198{
199 if (l->start > r->start) {
200 struct map *t = l;
201 l = r;
202 r = t;
203 }
204
205 if (l->end > r->start)
206 return 1;
207
208 return 0;
209}
210
211size_t map__fprintf(struct map *self, FILE *fp)
212{
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200213 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
Frederic Weisbecker66e274f2009-08-12 11:07:25 +0200214 self->start, self->end, self->pgoff, self->dso->name);
215}
Kirill Smelkov7a2b6202010-02-03 16:52:07 -0200216
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900217size_t map__fprintf_dsoname(struct map *map, FILE *fp)
218{
219 const char *dsoname;
220
Akihiro Nagai0bc8d202012-01-30 13:43:20 +0900221 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
222 if (symbol_conf.show_kernel_path && map->dso->long_name)
223 dsoname = map->dso->long_name;
224 else if (map->dso->name)
225 dsoname = map->dso->name;
226 } else
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900227 dsoname = "[unknown]";
228
229 return fprintf(fp, "%s", dsoname);
230}
231
Kirill Smelkov7a2b6202010-02-03 16:52:07 -0200232/*
233 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
234 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
235 */
236u64 map__rip_2objdump(struct map *map, u64 rip)
237{
238 u64 addr = map->dso->adjust_symbols ?
239 map->unmap_ip(map, rip) : /* RIP -> IP */
240 rip;
241 return addr;
242}
Kirill Smelkovee11b902010-02-07 11:46:15 -0200243
244u64 map__objdump_2ip(struct map *map, u64 addr)
245{
246 u64 ip = map->dso->adjust_symbols ?
247 addr :
248 map->unmap_ip(map, addr); /* RIP -> IP */
249 return ip;
250}
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300251
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300252void map_groups__init(struct map_groups *mg)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300253{
254 int i;
255 for (i = 0; i < MAP__NR_TYPES; ++i) {
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300256 mg->maps[i] = RB_ROOT;
257 INIT_LIST_HEAD(&mg->removed_maps[i]);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300258 }
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300259 mg->machine = NULL;
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300260}
261
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300262static void maps__delete(struct rb_root *maps)
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300263{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300264 struct rb_node *next = rb_first(maps);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300265
266 while (next) {
267 struct map *pos = rb_entry(next, struct map, rb_node);
268
269 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300270 rb_erase(&pos->rb_node, maps);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300271 map__delete(pos);
272 }
273}
274
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300275static void maps__delete_removed(struct list_head *maps)
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300276{
277 struct map *pos, *n;
278
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300279 list_for_each_entry_safe(pos, n, maps, node) {
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300280 list_del(&pos->node);
281 map__delete(pos);
282 }
283}
284
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300285void map_groups__exit(struct map_groups *mg)
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300286{
287 int i;
288
289 for (i = 0; i < MAP__NR_TYPES; ++i) {
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300290 maps__delete(&mg->maps[i]);
291 maps__delete_removed(&mg->removed_maps[i]);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300292 }
293}
294
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300295void map_groups__flush(struct map_groups *mg)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300296{
297 int type;
298
299 for (type = 0; type < MAP__NR_TYPES; type++) {
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300300 struct rb_root *root = &mg->maps[type];
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300301 struct rb_node *next = rb_first(root);
302
303 while (next) {
304 struct map *pos = rb_entry(next, struct map, rb_node);
305 next = rb_next(&pos->rb_node);
306 rb_erase(&pos->rb_node, root);
307 /*
308 * We may have references to this map, for
309 * instance in some hist_entry instances, so
310 * just move them to a separate list.
311 */
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300312 list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300313 }
314 }
315}
316
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300317struct symbol *map_groups__find_symbol(struct map_groups *mg,
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300318 enum map_type type, u64 addr,
Arnaldo Carvalho de Melo7e5e1b12010-03-26 12:30:40 -0300319 struct map **mapp,
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300320 symbol_filter_t filter)
321{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300322 struct map *map = map_groups__find(mg, type, addr);
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300323
Arnaldo Carvalho de Melo7e5e1b12010-03-26 12:30:40 -0300324 if (map != NULL) {
325 if (mapp != NULL)
326 *mapp = map;
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300327 return map__find_symbol(map, map->map_ip(map, addr), filter);
Arnaldo Carvalho de Melo7e5e1b12010-03-26 12:30:40 -0300328 }
329
330 return NULL;
331}
332
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300333struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
Arnaldo Carvalho de Melo7e5e1b12010-03-26 12:30:40 -0300334 enum map_type type,
335 const char *name,
336 struct map **mapp,
337 symbol_filter_t filter)
338{
339 struct rb_node *nd;
340
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300341 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo7e5e1b12010-03-26 12:30:40 -0300342 struct map *pos = rb_entry(nd, struct map, rb_node);
343 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
344
345 if (sym == NULL)
346 continue;
347 if (mapp != NULL)
348 *mapp = pos;
349 return sym;
350 }
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300351
352 return NULL;
353}
354
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300355size_t __map_groups__fprintf_maps(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300356 enum map_type type, int verbose, FILE *fp)
357{
358 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
359 struct rb_node *nd;
360
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300361 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300362 struct map *pos = rb_entry(nd, struct map, rb_node);
363 printed += fprintf(fp, "Map:");
364 printed += map__fprintf(pos, fp);
365 if (verbose > 2) {
366 printed += dso__fprintf(pos->dso, type, fp);
367 printed += fprintf(fp, "--\n");
368 }
369 }
370
371 return printed;
372}
373
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300374size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300375{
376 size_t printed = 0, i;
377 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300378 printed += __map_groups__fprintf_maps(mg, i, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300379 return printed;
380}
381
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300382static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300383 enum map_type type,
384 int verbose, FILE *fp)
385{
386 struct map *pos;
387 size_t printed = 0;
388
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300389 list_for_each_entry(pos, &mg->removed_maps[type], node) {
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300390 printed += fprintf(fp, "Map:");
391 printed += map__fprintf(pos, fp);
392 if (verbose > 1) {
393 printed += dso__fprintf(pos->dso, type, fp);
394 printed += fprintf(fp, "--\n");
395 }
396 }
397 return printed;
398}
399
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300400static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300401 int verbose, FILE *fp)
402{
403 size_t printed = 0, i;
404 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300405 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300406 return printed;
407}
408
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300409size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300410{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300411 size_t printed = map_groups__fprintf_maps(mg, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300412 printed += fprintf(fp, "Removed maps:\n");
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300413 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300414}
415
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300416int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300417 int verbose, FILE *fp)
418{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300419 struct rb_root *root = &mg->maps[map->type];
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300420 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300421 int err = 0;
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300422
423 while (next) {
424 struct map *pos = rb_entry(next, struct map, rb_node);
425 next = rb_next(&pos->rb_node);
426
427 if (!map__overlap(pos, map))
428 continue;
429
430 if (verbose >= 2) {
431 fputs("overlapping maps:\n", fp);
432 map__fprintf(map, fp);
433 map__fprintf(pos, fp);
434 }
435
436 rb_erase(&pos->rb_node, root);
437 /*
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300438 * Now check if we need to create new maps for areas not
439 * overlapped by the new map:
440 */
441 if (map->start > pos->start) {
442 struct map *before = map__clone(pos);
443
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300444 if (before == NULL) {
445 err = -ENOMEM;
446 goto move_map;
447 }
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300448
449 before->end = map->start - 1;
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300450 map_groups__insert(mg, before);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300451 if (verbose >= 2)
452 map__fprintf(before, fp);
453 }
454
455 if (map->end < pos->end) {
456 struct map *after = map__clone(pos);
457
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300458 if (after == NULL) {
459 err = -ENOMEM;
460 goto move_map;
461 }
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300462
463 after->start = map->end + 1;
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300464 map_groups__insert(mg, after);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300465 if (verbose >= 2)
466 map__fprintf(after, fp);
467 }
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300468move_map:
469 /*
470 * If we have references, just move them to a separate list.
471 */
472 if (pos->referenced)
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300473 list_add_tail(&pos->node, &mg->removed_maps[map->type]);
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300474 else
475 map__delete(pos);
476
477 if (err)
478 return err;
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300479 }
480
481 return 0;
482}
483
484/*
485 * XXX This should not really _copy_ te maps, but refcount them.
486 */
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300487int map_groups__clone(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300488 struct map_groups *parent, enum map_type type)
489{
490 struct rb_node *nd;
491 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
492 struct map *map = rb_entry(nd, struct map, rb_node);
493 struct map *new = map__clone(map);
494 if (new == NULL)
495 return -ENOMEM;
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300496 map_groups__insert(mg, new);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300497 }
498 return 0;
499}
500
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300501static u64 map__reloc_map_ip(struct map *map, u64 ip)
502{
503 return ip + (s64)map->pgoff;
504}
505
506static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
507{
508 return ip - (s64)map->pgoff;
509}
510
511void map__reloc_vmlinux(struct map *self)
512{
513 struct kmap *kmap = map__kmap(self);
514 s64 reloc;
515
516 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
517 return;
518
519 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
520 kmap->ref_reloc_sym->addr);
521
522 if (!reloc)
523 return;
524
525 self->map_ip = map__reloc_map_ip;
526 self->unmap_ip = map__reloc_unmap_ip;
527 self->pgoff = reloc;
528}
529
530void maps__insert(struct rb_root *maps, struct map *map)
531{
532 struct rb_node **p = &maps->rb_node;
533 struct rb_node *parent = NULL;
534 const u64 ip = map->start;
535 struct map *m;
536
537 while (*p != NULL) {
538 parent = *p;
539 m = rb_entry(parent, struct map, rb_node);
540 if (ip < m->start)
541 p = &(*p)->rb_left;
542 else
543 p = &(*p)->rb_right;
544 }
545
546 rb_link_node(&map->rb_node, parent, p);
547 rb_insert_color(&map->rb_node, maps);
548}
549
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -0300550void maps__remove(struct rb_root *self, struct map *map)
551{
552 rb_erase(&map->rb_node, self);
553}
554
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300555struct map *maps__find(struct rb_root *maps, u64 ip)
556{
557 struct rb_node **p = &maps->rb_node;
558 struct rb_node *parent = NULL;
559 struct map *m;
560
561 while (*p != NULL) {
562 parent = *p;
563 m = rb_entry(parent, struct map, rb_node);
564 if (ip < m->start)
565 p = &(*p)->rb_left;
566 else if (ip > m->end)
567 p = &(*p)->rb_right;
568 else
569 return m;
570 }
571
572 return NULL;
573}
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800574
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300575int machine__init(struct machine *self, const char *root_dir, pid_t pid)
576{
577 map_groups__init(&self->kmaps);
578 RB_CLEAR_NODE(&self->rb_node);
579 INIT_LIST_HEAD(&self->user_dsos);
580 INIT_LIST_HEAD(&self->kernel_dsos);
581
Arnaldo Carvalho de Melob424eba2011-11-09 13:24:25 -0200582 self->threads = RB_ROOT;
583 INIT_LIST_HEAD(&self->dead_threads);
584 self->last_match = NULL;
585
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300586 self->kmaps.machine = self;
587 self->pid = pid;
588 self->root_dir = strdup(root_dir);
David Ahern5cd95c22012-07-20 17:25:47 -0600589 if (self->root_dir == NULL)
590 return -ENOMEM;
591
592 if (pid != HOST_KERNEL_ID) {
593 struct thread *thread = machine__findnew_thread(self, pid);
594 char comm[64];
595
596 if (thread == NULL)
597 return -ENOMEM;
598
599 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
600 thread__set_comm(thread, comm);
601 }
602
603 return 0;
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300604}
605
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300606static void dsos__delete(struct list_head *self)
607{
608 struct dso *pos, *n;
609
610 list_for_each_entry_safe(pos, n, self, node) {
611 list_del(&pos->node);
612 dso__delete(pos);
613 }
614}
615
616void machine__exit(struct machine *self)
617{
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300618 map_groups__exit(&self->kmaps);
619 dsos__delete(&self->user_dsos);
620 dsos__delete(&self->kernel_dsos);
621 free(self->root_dir);
622 self->root_dir = NULL;
623}
624
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -0300625void machine__delete(struct machine *self)
626{
627 machine__exit(self);
628 free(self);
629}
630
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300631struct machine *machines__add(struct rb_root *self, pid_t pid,
632 const char *root_dir)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800633{
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300634 struct rb_node **p = &self->rb_node;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800635 struct rb_node *parent = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300636 struct machine *pos, *machine = malloc(sizeof(*machine));
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800637
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300638 if (!machine)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800639 return NULL;
640
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300641 if (machine__init(machine, root_dir, pid) != 0) {
642 free(machine);
643 return NULL;
644 }
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800645
646 while (*p != NULL) {
647 parent = *p;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300648 pos = rb_entry(parent, struct machine, rb_node);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800649 if (pid < pos->pid)
650 p = &(*p)->rb_left;
651 else
652 p = &(*p)->rb_right;
653 }
654
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300655 rb_link_node(&machine->rb_node, parent, p);
656 rb_insert_color(&machine->rb_node, self);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800657
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300658 return machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800659}
660
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300661struct machine *machines__find(struct rb_root *self, pid_t pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800662{
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300663 struct rb_node **p = &self->rb_node;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800664 struct rb_node *parent = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300665 struct machine *machine;
666 struct machine *default_machine = NULL;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800667
668 while (*p != NULL) {
669 parent = *p;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300670 machine = rb_entry(parent, struct machine, rb_node);
671 if (pid < machine->pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800672 p = &(*p)->rb_left;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300673 else if (pid > machine->pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800674 p = &(*p)->rb_right;
675 else
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300676 return machine;
677 if (!machine->pid)
678 default_machine = machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800679 }
680
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300681 return default_machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800682}
683
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300684struct machine *machines__findnew(struct rb_root *self, pid_t pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800685{
686 char path[PATH_MAX];
David Ahern7ed97ad2012-07-02 09:12:57 -0600687 const char *root_dir = "";
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300688 struct machine *machine = machines__find(self, pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800689
David Ahern7ed97ad2012-07-02 09:12:57 -0600690 if (machine && (machine->pid == pid))
691 goto out;
692
693 if ((pid != HOST_KERNEL_ID) &&
694 (pid != DEFAULT_GUEST_KERNEL_ID) &&
695 (symbol_conf.guestmount)) {
696 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
697 if (access(path, R_OK)) {
698 pr_err("Can't access file %s\n", path);
699 machine = NULL;
700 goto out;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800701 }
David Ahern7ed97ad2012-07-02 09:12:57 -0600702 root_dir = path;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800703 }
704
David Ahern7ed97ad2012-07-02 09:12:57 -0600705 machine = machines__add(self, pid, root_dir);
706
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800707out:
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300708 return machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800709}
710
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300711void machines__process(struct rb_root *self, machine__process_t process, void *data)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800712{
713 struct rb_node *nd;
714
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300715 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
716 struct machine *pos = rb_entry(nd, struct machine, rb_node);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800717 process(pos, data);
718 }
719}
720
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300721char *machine__mmap_name(struct machine *self, char *bf, size_t size)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800722{
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300723 if (machine__is_host(self))
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300724 snprintf(bf, size, "[%s]", "kernel.kallsyms");
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300725 else if (machine__is_default_guest(self))
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300726 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800727 else
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300728 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800729
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300730 return bf;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800731}
David Ahernadb5d2a2012-07-20 17:25:49 -0600732
733void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
734{
735 struct rb_node *node;
736 struct machine *machine;
737
738 for (node = rb_first(machines); node; node = rb_next(node)) {
739 machine = rb_entry(node, struct machine, rb_node);
740 machine->id_hdr_size = id_hdr_size;
741 }
742
743 return;
744}