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