blob: 287cb3452b4b2a5809d36443fb60be704d8923e0 [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"
David Ahernc80c3c22012-07-20 17:25:51 -060011#include "strlist.h"
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020012
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -030013const char *map_type__name[MAP__NR_TYPES] = {
14 [MAP__FUNCTION] = "Functions",
15 [MAP__VARIABLE] = "Variables",
16};
17
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020018static inline int is_anon_memory(const char *filename)
19{
20 return strcmp(filename, "//anon") == 0;
21}
22
Jiri Olsa87ffef72011-08-24 15:18:34 +020023static inline int is_no_dso_memory(const char *filename)
24{
25 return !strcmp(filename, "[stack]") ||
26 !strcmp(filename, "[vdso]") ||
27 !strcmp(filename, "[heap]");
28}
29
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020030void map__init(struct map *self, enum map_type type,
31 u64 start, u64 end, u64 pgoff, struct dso *dso)
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020032{
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020033 self->type = type;
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020034 self->start = start;
35 self->end = end;
36 self->pgoff = pgoff;
37 self->dso = dso;
38 self->map_ip = map__map_ip;
39 self->unmap_ip = map__unmap_ip;
40 RB_CLEAR_NODE(&self->rb_node);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080041 self->groups = NULL;
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -030042 self->referenced = false;
Arnaldo Carvalho de Melo31d68e72012-03-27 12:55:57 -030043 self->erange_warned = false;
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020044}
45
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080046struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
47 u64 pgoff, u32 pid, char *filename,
Dave Martin361d1342010-07-27 16:40:02 +010048 enum map_type type)
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020049{
50 struct map *self = malloc(sizeof(*self));
51
52 if (self != NULL) {
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020053 char newfilename[PATH_MAX];
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020054 struct dso *dso;
Jiri Olsa87ffef72011-08-24 15:18:34 +020055 int anon, no_dso;
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020056
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020057 anon = is_anon_memory(filename);
Jiri Olsa87ffef72011-08-24 15:18:34 +020058 no_dso = is_no_dso_memory(filename);
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020059
60 if (anon) {
Arnaldo Carvalho de Melob177f632010-03-25 19:58:57 -030061 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020062 filename = newfilename;
63 }
64
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080065 dso = __dsos__findnew(dsos__list, filename);
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020066 if (dso == NULL)
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020067 goto out_delete;
68
Arnaldo Carvalho de Melob177f632010-03-25 19:58:57 -030069 map__init(self, type, start, start + len, pgoff, dso);
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020070
Jiri Olsa87ffef72011-08-24 15:18:34 +020071 if (anon || no_dso) {
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -020072 self->map_ip = self->unmap_ip = identity__map_ip;
Jiri Olsa87ffef72011-08-24 15:18:34 +020073
74 /*
75 * Set memory without DSO as loaded. All map__find_*
76 * functions still return NULL, and we avoid the
77 * unnecessary map__load warning.
78 */
79 if (no_dso)
80 dso__set_loaded(dso, self->type);
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -020081 }
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020082 }
83 return self;
84out_delete:
85 free(self);
86 return NULL;
87}
88
Namhyung Kime5a18452012-08-06 13:41:20 +090089/*
90 * Constructor variant for modules (where we know from /proc/modules where
91 * they are loaded) and for vmlinux, where only after we load all the
92 * symbols we'll know where it starts and ends.
93 */
94struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
95{
96 struct map *map = calloc(1, (sizeof(*map) +
97 (dso->kernel ? sizeof(struct kmap) : 0)));
98 if (map != NULL) {
99 /*
100 * ->end will be filled after we load all the symbols
101 */
102 map__init(map, type, start, 0, 0, dso);
103 }
104
105 return map;
106}
107
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200108void map__delete(struct map *self)
109{
110 free(self);
111}
112
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200113void map__fixup_start(struct map *self)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200114{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200115 struct rb_root *symbols = &self->dso->symbols[self->type];
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200116 struct rb_node *nd = rb_first(symbols);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200117 if (nd != NULL) {
118 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
119 self->start = sym->start;
120 }
121}
122
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200123void map__fixup_end(struct map *self)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200124{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200125 struct rb_root *symbols = &self->dso->symbols[self->type];
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200126 struct rb_node *nd = rb_last(symbols);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200127 if (nd != NULL) {
128 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
129 self->end = sym->end;
130 }
131}
132
Arnaldo Carvalho de Melod70a5402009-10-30 16:28:25 -0200133#define DSO__DELETED "(deleted)"
134
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200135int map__load(struct map *self, symbol_filter_t filter)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200136{
137 const char *name = self->dso->long_name;
Masami Hiramatsua1281682009-12-15 10:32:33 -0500138 int nr;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200139
Masami Hiramatsua1281682009-12-15 10:32:33 -0500140 if (dso__loaded(self->dso, self->type))
141 return 0;
142
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200143 nr = dso__load(self->dso, self, filter);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200144 if (nr < 0) {
145 if (self->dso->has_build_id) {
146 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
147
148 build_id__sprintf(self->dso->build_id,
149 sizeof(self->dso->build_id),
150 sbuild_id);
151 pr_warning("%s with build id %s not found",
152 name, sbuild_id);
153 } else
154 pr_warning("Failed to open %s", name);
155
156 pr_warning(", continuing without symbols\n");
157 return -1;
158 } else if (nr == 0) {
Namhyung Kim393be2e2012-08-06 13:41:21 +0900159#ifndef NO_LIBELF_SUPPORT
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200160 const size_t len = strlen(name);
161 const size_t real_len = len - sizeof(DSO__DELETED);
162
163 if (len > sizeof(DSO__DELETED) &&
164 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
David Aherne77b15b2011-10-18 18:44:45 -0600165 pr_warning("%.*s was updated (is prelink enabled?). "
166 "Restart the long running apps that use it!\n",
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200167 (int)real_len, name);
168 } else {
169 pr_warning("no symbols found in %s, maybe install "
170 "a debug package?\n", name);
171 }
Namhyung Kim393be2e2012-08-06 13:41:21 +0900172#endif
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200173 return -1;
174 }
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200175 /*
176 * Only applies to the kernel, as its symtabs aren't relative like the
177 * module ones.
178 */
179 if (self->dso->kernel)
180 map__reloc_vmlinux(self);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200181
182 return 0;
183}
184
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200185struct symbol *map__find_symbol(struct map *self, u64 addr,
186 symbol_filter_t filter)
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200187{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200188 if (map__load(self, filter) < 0)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200189 return NULL;
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200190
Arnaldo Carvalho de Meloea08d8c2009-12-11 18:56:39 -0200191 return dso__find_symbol(self->dso, self->type, addr);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200192}
193
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200194struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
195 symbol_filter_t filter)
196{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200197 if (map__load(self, filter) < 0)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200198 return NULL;
199
200 if (!dso__sorted_by_name(self->dso, self->type))
201 dso__sort_by_name(self->dso, self->type);
202
203 return dso__find_symbol_by_name(self->dso, self->type, name);
204}
205
Frederic Weisbecker66e274f2009-08-12 11:07:25 +0200206struct map *map__clone(struct map *self)
207{
208 struct map *map = malloc(sizeof(*self));
209
210 if (!map)
211 return NULL;
212
213 memcpy(map, self, sizeof(*self));
214
215 return map;
216}
217
218int map__overlap(struct map *l, struct map *r)
219{
220 if (l->start > r->start) {
221 struct map *t = l;
222 l = r;
223 r = t;
224 }
225
226 if (l->end > r->start)
227 return 1;
228
229 return 0;
230}
231
232size_t map__fprintf(struct map *self, FILE *fp)
233{
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200234 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
Frederic Weisbecker66e274f2009-08-12 11:07:25 +0200235 self->start, self->end, self->pgoff, self->dso->name);
236}
Kirill Smelkov7a2b6202010-02-03 16:52:07 -0200237
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900238size_t map__fprintf_dsoname(struct map *map, FILE *fp)
239{
240 const char *dsoname;
241
Akihiro Nagai0bc8d202012-01-30 13:43:20 +0900242 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
243 if (symbol_conf.show_kernel_path && map->dso->long_name)
244 dsoname = map->dso->long_name;
245 else if (map->dso->name)
246 dsoname = map->dso->name;
247 } else
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900248 dsoname = "[unknown]";
249
250 return fprintf(fp, "%s", dsoname);
251}
252
Kirill Smelkov7a2b6202010-02-03 16:52:07 -0200253/*
254 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
255 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
256 */
257u64 map__rip_2objdump(struct map *map, u64 rip)
258{
259 u64 addr = map->dso->adjust_symbols ?
260 map->unmap_ip(map, rip) : /* RIP -> IP */
261 rip;
262 return addr;
263}
Kirill Smelkovee11b902010-02-07 11:46:15 -0200264
265u64 map__objdump_2ip(struct map *map, u64 addr)
266{
267 u64 ip = map->dso->adjust_symbols ?
268 addr :
269 map->unmap_ip(map, addr); /* RIP -> IP */
270 return ip;
271}
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300272
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300273void map_groups__init(struct map_groups *mg)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300274{
275 int i;
276 for (i = 0; i < MAP__NR_TYPES; ++i) {
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300277 mg->maps[i] = RB_ROOT;
278 INIT_LIST_HEAD(&mg->removed_maps[i]);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300279 }
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300280 mg->machine = NULL;
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300281}
282
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300283static void maps__delete(struct rb_root *maps)
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300284{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300285 struct rb_node *next = rb_first(maps);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300286
287 while (next) {
288 struct map *pos = rb_entry(next, struct map, rb_node);
289
290 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300291 rb_erase(&pos->rb_node, maps);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300292 map__delete(pos);
293 }
294}
295
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300296static void maps__delete_removed(struct list_head *maps)
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300297{
298 struct map *pos, *n;
299
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300300 list_for_each_entry_safe(pos, n, maps, node) {
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300301 list_del(&pos->node);
302 map__delete(pos);
303 }
304}
305
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300306void map_groups__exit(struct map_groups *mg)
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300307{
308 int i;
309
310 for (i = 0; i < MAP__NR_TYPES; ++i) {
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300311 maps__delete(&mg->maps[i]);
312 maps__delete_removed(&mg->removed_maps[i]);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -0300313 }
314}
315
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300316void map_groups__flush(struct map_groups *mg)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300317{
318 int type;
319
320 for (type = 0; type < MAP__NR_TYPES; type++) {
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300321 struct rb_root *root = &mg->maps[type];
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300322 struct rb_node *next = rb_first(root);
323
324 while (next) {
325 struct map *pos = rb_entry(next, struct map, rb_node);
326 next = rb_next(&pos->rb_node);
327 rb_erase(&pos->rb_node, root);
328 /*
329 * We may have references to this map, for
330 * instance in some hist_entry instances, so
331 * just move them to a separate list.
332 */
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300333 list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300334 }
335 }
336}
337
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300338struct symbol *map_groups__find_symbol(struct map_groups *mg,
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300339 enum map_type type, u64 addr,
Arnaldo Carvalho de Melo7e5e1b142010-03-26 12:30:40 -0300340 struct map **mapp,
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300341 symbol_filter_t filter)
342{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300343 struct map *map = map_groups__find(mg, type, addr);
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300344
Arnaldo Carvalho de Melo7e5e1b142010-03-26 12:30:40 -0300345 if (map != NULL) {
346 if (mapp != NULL)
347 *mapp = map;
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300348 return map__find_symbol(map, map->map_ip(map, addr), filter);
Arnaldo Carvalho de Melo7e5e1b142010-03-26 12:30:40 -0300349 }
350
351 return NULL;
352}
353
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300354struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
Arnaldo Carvalho de Melo7e5e1b142010-03-26 12:30:40 -0300355 enum map_type type,
356 const char *name,
357 struct map **mapp,
358 symbol_filter_t filter)
359{
360 struct rb_node *nd;
361
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300362 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo7e5e1b142010-03-26 12:30:40 -0300363 struct map *pos = rb_entry(nd, struct map, rb_node);
364 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
365
366 if (sym == NULL)
367 continue;
368 if (mapp != NULL)
369 *mapp = pos;
370 return sym;
371 }
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300372
373 return NULL;
374}
375
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300376size_t __map_groups__fprintf_maps(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300377 enum map_type type, int verbose, FILE *fp)
378{
379 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
380 struct rb_node *nd;
381
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300382 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300383 struct map *pos = rb_entry(nd, struct map, rb_node);
384 printed += fprintf(fp, "Map:");
385 printed += map__fprintf(pos, fp);
386 if (verbose > 2) {
387 printed += dso__fprintf(pos->dso, type, fp);
388 printed += fprintf(fp, "--\n");
389 }
390 }
391
392 return printed;
393}
394
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300395size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300396{
397 size_t printed = 0, i;
398 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300399 printed += __map_groups__fprintf_maps(mg, i, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300400 return printed;
401}
402
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300403static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300404 enum map_type type,
405 int verbose, FILE *fp)
406{
407 struct map *pos;
408 size_t printed = 0;
409
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300410 list_for_each_entry(pos, &mg->removed_maps[type], node) {
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300411 printed += fprintf(fp, "Map:");
412 printed += map__fprintf(pos, fp);
413 if (verbose > 1) {
414 printed += dso__fprintf(pos->dso, type, fp);
415 printed += fprintf(fp, "--\n");
416 }
417 }
418 return printed;
419}
420
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300421static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300422 int verbose, FILE *fp)
423{
424 size_t printed = 0, i;
425 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300426 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300427 return printed;
428}
429
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300430size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp)
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300431{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300432 size_t printed = map_groups__fprintf_maps(mg, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300433 printed += fprintf(fp, "Removed maps:\n");
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300434 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300435}
436
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300437int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300438 int verbose, FILE *fp)
439{
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300440 struct rb_root *root = &mg->maps[map->type];
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300441 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300442 int err = 0;
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300443
444 while (next) {
445 struct map *pos = rb_entry(next, struct map, rb_node);
446 next = rb_next(&pos->rb_node);
447
448 if (!map__overlap(pos, map))
449 continue;
450
451 if (verbose >= 2) {
452 fputs("overlapping maps:\n", fp);
453 map__fprintf(map, fp);
454 map__fprintf(pos, fp);
455 }
456
457 rb_erase(&pos->rb_node, root);
458 /*
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300459 * Now check if we need to create new maps for areas not
460 * overlapped by the new map:
461 */
462 if (map->start > pos->start) {
463 struct map *before = map__clone(pos);
464
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300465 if (before == NULL) {
466 err = -ENOMEM;
467 goto move_map;
468 }
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300469
470 before->end = map->start - 1;
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300471 map_groups__insert(mg, before);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300472 if (verbose >= 2)
473 map__fprintf(before, fp);
474 }
475
476 if (map->end < pos->end) {
477 struct map *after = map__clone(pos);
478
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300479 if (after == NULL) {
480 err = -ENOMEM;
481 goto move_map;
482 }
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300483
484 after->start = map->end + 1;
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300485 map_groups__insert(mg, after);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300486 if (verbose >= 2)
487 map__fprintf(after, fp);
488 }
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300489move_map:
490 /*
491 * If we have references, just move them to a separate list.
492 */
493 if (pos->referenced)
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300494 list_add_tail(&pos->node, &mg->removed_maps[map->type]);
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300495 else
496 map__delete(pos);
497
498 if (err)
499 return err;
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300500 }
501
502 return 0;
503}
504
505/*
506 * XXX This should not really _copy_ te maps, but refcount them.
507 */
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300508int map_groups__clone(struct map_groups *mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300509 struct map_groups *parent, enum map_type type)
510{
511 struct rb_node *nd;
512 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
513 struct map *map = rb_entry(nd, struct map, rb_node);
514 struct map *new = map__clone(map);
515 if (new == NULL)
516 return -ENOMEM;
Arnaldo Carvalho de Melo98dfd552011-08-23 14:31:30 -0300517 map_groups__insert(mg, new);
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300518 }
519 return 0;
520}
521
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300522static u64 map__reloc_map_ip(struct map *map, u64 ip)
523{
524 return ip + (s64)map->pgoff;
525}
526
527static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
528{
529 return ip - (s64)map->pgoff;
530}
531
532void map__reloc_vmlinux(struct map *self)
533{
534 struct kmap *kmap = map__kmap(self);
535 s64 reloc;
536
537 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
538 return;
539
540 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
541 kmap->ref_reloc_sym->addr);
542
543 if (!reloc)
544 return;
545
546 self->map_ip = map__reloc_map_ip;
547 self->unmap_ip = map__reloc_unmap_ip;
548 self->pgoff = reloc;
549}
550
551void maps__insert(struct rb_root *maps, struct map *map)
552{
553 struct rb_node **p = &maps->rb_node;
554 struct rb_node *parent = NULL;
555 const u64 ip = map->start;
556 struct map *m;
557
558 while (*p != NULL) {
559 parent = *p;
560 m = rb_entry(parent, struct map, rb_node);
561 if (ip < m->start)
562 p = &(*p)->rb_left;
563 else
564 p = &(*p)->rb_right;
565 }
566
567 rb_link_node(&map->rb_node, parent, p);
568 rb_insert_color(&map->rb_node, maps);
569}
570
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -0300571void maps__remove(struct rb_root *self, struct map *map)
572{
573 rb_erase(&map->rb_node, self);
574}
575
Arnaldo Carvalho de Melo4b8cf842010-03-25 19:58:58 -0300576struct map *maps__find(struct rb_root *maps, u64 ip)
577{
578 struct rb_node **p = &maps->rb_node;
579 struct rb_node *parent = NULL;
580 struct map *m;
581
582 while (*p != NULL) {
583 parent = *p;
584 m = rb_entry(parent, struct map, rb_node);
585 if (ip < m->start)
586 p = &(*p)->rb_left;
587 else if (ip > m->end)
588 p = &(*p)->rb_right;
589 else
590 return m;
591 }
592
593 return NULL;
594}
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800595
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300596int machine__init(struct machine *self, const char *root_dir, pid_t pid)
597{
598 map_groups__init(&self->kmaps);
599 RB_CLEAR_NODE(&self->rb_node);
600 INIT_LIST_HEAD(&self->user_dsos);
601 INIT_LIST_HEAD(&self->kernel_dsos);
602
Arnaldo Carvalho de Melob424eba2011-11-09 13:24:25 -0200603 self->threads = RB_ROOT;
604 INIT_LIST_HEAD(&self->dead_threads);
605 self->last_match = NULL;
606
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300607 self->kmaps.machine = self;
608 self->pid = pid;
609 self->root_dir = strdup(root_dir);
David Ahern5cd95c22012-07-20 17:25:47 -0600610 if (self->root_dir == NULL)
611 return -ENOMEM;
612
613 if (pid != HOST_KERNEL_ID) {
614 struct thread *thread = machine__findnew_thread(self, pid);
615 char comm[64];
616
617 if (thread == NULL)
618 return -ENOMEM;
619
620 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
621 thread__set_comm(thread, comm);
622 }
623
624 return 0;
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300625}
626
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300627static void dsos__delete(struct list_head *self)
628{
629 struct dso *pos, *n;
630
631 list_for_each_entry_safe(pos, n, self, node) {
632 list_del(&pos->node);
633 dso__delete(pos);
634 }
635}
636
637void machine__exit(struct machine *self)
638{
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300639 map_groups__exit(&self->kmaps);
640 dsos__delete(&self->user_dsos);
641 dsos__delete(&self->kernel_dsos);
642 free(self->root_dir);
643 self->root_dir = NULL;
644}
645
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -0300646void machine__delete(struct machine *self)
647{
648 machine__exit(self);
649 free(self);
650}
651
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300652struct machine *machines__add(struct rb_root *self, pid_t pid,
653 const char *root_dir)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800654{
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300655 struct rb_node **p = &self->rb_node;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800656 struct rb_node *parent = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300657 struct machine *pos, *machine = malloc(sizeof(*machine));
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800658
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300659 if (!machine)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800660 return NULL;
661
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300662 if (machine__init(machine, root_dir, pid) != 0) {
663 free(machine);
664 return NULL;
665 }
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800666
667 while (*p != NULL) {
668 parent = *p;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300669 pos = rb_entry(parent, struct machine, rb_node);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800670 if (pid < pos->pid)
671 p = &(*p)->rb_left;
672 else
673 p = &(*p)->rb_right;
674 }
675
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300676 rb_link_node(&machine->rb_node, parent, p);
677 rb_insert_color(&machine->rb_node, self);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800678
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300679 return machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800680}
681
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300682struct machine *machines__find(struct rb_root *self, pid_t pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800683{
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300684 struct rb_node **p = &self->rb_node;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800685 struct rb_node *parent = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300686 struct machine *machine;
687 struct machine *default_machine = NULL;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800688
689 while (*p != NULL) {
690 parent = *p;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300691 machine = rb_entry(parent, struct machine, rb_node);
692 if (pid < machine->pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800693 p = &(*p)->rb_left;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300694 else if (pid > machine->pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800695 p = &(*p)->rb_right;
696 else
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300697 return machine;
698 if (!machine->pid)
699 default_machine = machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800700 }
701
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300702 return default_machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800703}
704
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300705struct machine *machines__findnew(struct rb_root *self, pid_t pid)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800706{
707 char path[PATH_MAX];
David Ahern7ed97ad2012-07-02 09:12:57 -0600708 const char *root_dir = "";
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300709 struct machine *machine = machines__find(self, pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800710
David Ahern7ed97ad2012-07-02 09:12:57 -0600711 if (machine && (machine->pid == pid))
712 goto out;
713
714 if ((pid != HOST_KERNEL_ID) &&
715 (pid != DEFAULT_GUEST_KERNEL_ID) &&
716 (symbol_conf.guestmount)) {
717 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
718 if (access(path, R_OK)) {
David Ahernc80c3c22012-07-20 17:25:51 -0600719 static struct strlist *seen;
720
721 if (!seen)
722 seen = strlist__new(true, NULL);
723
724 if (!strlist__has_entry(seen, path)) {
725 pr_err("Can't access file %s\n", path);
726 strlist__add(seen, path);
727 }
David Ahern7ed97ad2012-07-02 09:12:57 -0600728 machine = NULL;
729 goto out;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800730 }
David Ahern7ed97ad2012-07-02 09:12:57 -0600731 root_dir = path;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800732 }
733
David Ahern7ed97ad2012-07-02 09:12:57 -0600734 machine = machines__add(self, pid, root_dir);
735
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800736out:
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300737 return machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800738}
739
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300740void machines__process(struct rb_root *self, machine__process_t process, void *data)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800741{
742 struct rb_node *nd;
743
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300744 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
745 struct machine *pos = rb_entry(nd, struct machine, rb_node);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800746 process(pos, data);
747 }
748}
749
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300750char *machine__mmap_name(struct machine *self, char *bf, size_t size)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800751{
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300752 if (machine__is_host(self))
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300753 snprintf(bf, size, "[%s]", "kernel.kallsyms");
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300754 else if (machine__is_default_guest(self))
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300755 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800756 else
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300757 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800758
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -0300759 return bf;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800760}
David Ahernadb5d2a2012-07-20 17:25:49 -0600761
762void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
763{
764 struct rb_node *node;
765 struct machine *machine;
766
767 for (node = rb_first(machines); node; node = rb_next(node)) {
768 machine = rb_entry(node, struct machine, rb_node);
769 machine->id_hdr_size = id_hdr_size;
770 }
771
772 return;
773}