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" 14cc8fae1dSAdrian Hunter #include "util.h" 15acebd408SJiri Olsa #include "debug.h" 162a03068cSAdrian Hunter #include "machine.h" 178e16017dSArnaldo Carvalho de Melo #include <linux/string.h> 1866e274f3SFrederic Weisbecker 193846df2eSArnaldo Carvalho de Melo const char *map_type__name[MAP__NR_TYPES] = { 203846df2eSArnaldo Carvalho de Melo [MAP__FUNCTION] = "Functions", 213846df2eSArnaldo Carvalho de Melo [MAP__VARIABLE] = "Variables", 223846df2eSArnaldo Carvalho de Melo }; 233846df2eSArnaldo Carvalho de Melo 2466e274f3SFrederic Weisbecker static inline int is_anon_memory(const char *filename) 2566e274f3SFrederic Weisbecker { 26d0528b5dSJoshua Zhu return !strcmp(filename, "//anon") || 2789365e6cSAndi Kleen !strcmp(filename, "/dev/zero (deleted)") || 28d0528b5dSJoshua Zhu !strcmp(filename, "/anon_hugepage (deleted)"); 2966e274f3SFrederic Weisbecker } 3066e274f3SFrederic Weisbecker 3187ffef79SJiri Olsa static inline int is_no_dso_memory(const char *filename) 3287ffef79SJiri Olsa { 331e82574dSNamhyung Kim return !strncmp(filename, "[stack", 6) || 34700be564SDon Zickus !strncmp(filename, "/SYSV",5) || 3587ffef79SJiri Olsa !strcmp(filename, "[heap]"); 3687ffef79SJiri Olsa } 3787ffef79SJiri Olsa 38eca81836SMichael Lentine static inline int is_android_lib(const char *filename) 39eca81836SMichael Lentine { 40eca81836SMichael Lentine return !strncmp(filename, "/data/app-lib", 13) || 41eca81836SMichael Lentine !strncmp(filename, "/system/lib", 11); 42eca81836SMichael Lentine } 43eca81836SMichael Lentine 44eca81836SMichael Lentine static inline bool replace_android_lib(const char *filename, char *newfilename) 45eca81836SMichael Lentine { 46eca81836SMichael Lentine const char *libname; 47eca81836SMichael Lentine char *app_abi; 48eca81836SMichael Lentine size_t app_abi_length, new_length; 49eca81836SMichael Lentine size_t lib_length = 0; 50eca81836SMichael Lentine 51eca81836SMichael Lentine libname = strrchr(filename, '/'); 52eca81836SMichael Lentine if (libname) 53eca81836SMichael Lentine lib_length = strlen(libname); 54eca81836SMichael Lentine 55eca81836SMichael Lentine app_abi = getenv("APP_ABI"); 56eca81836SMichael Lentine if (!app_abi) 57eca81836SMichael Lentine return false; 58eca81836SMichael Lentine 59eca81836SMichael Lentine app_abi_length = strlen(app_abi); 60eca81836SMichael Lentine 61eca81836SMichael Lentine if (!strncmp(filename, "/data/app-lib", 13)) { 62eca81836SMichael Lentine char *apk_path; 63eca81836SMichael Lentine 64eca81836SMichael Lentine if (!app_abi_length) 65eca81836SMichael Lentine return false; 66eca81836SMichael Lentine 67eca81836SMichael Lentine new_length = 7 + app_abi_length + lib_length; 68eca81836SMichael Lentine 69eca81836SMichael Lentine apk_path = getenv("APK_PATH"); 70eca81836SMichael Lentine if (apk_path) { 71eca81836SMichael Lentine new_length += strlen(apk_path) + 1; 72eca81836SMichael Lentine if (new_length > PATH_MAX) 73eca81836SMichael Lentine return false; 74eca81836SMichael Lentine snprintf(newfilename, new_length, 75eca81836SMichael Lentine "%s/libs/%s/%s", apk_path, app_abi, libname); 76eca81836SMichael Lentine } else { 77eca81836SMichael Lentine if (new_length > PATH_MAX) 78eca81836SMichael Lentine return false; 79eca81836SMichael Lentine snprintf(newfilename, new_length, 80eca81836SMichael Lentine "libs/%s/%s", app_abi, libname); 81eca81836SMichael Lentine } 82eca81836SMichael Lentine return true; 83eca81836SMichael Lentine } 84eca81836SMichael Lentine 85eca81836SMichael Lentine if (!strncmp(filename, "/system/lib/", 11)) { 86eca81836SMichael Lentine char *ndk, *app; 87eca81836SMichael Lentine const char *arch; 88eca81836SMichael Lentine size_t ndk_length; 89eca81836SMichael Lentine size_t app_length; 90eca81836SMichael Lentine 91eca81836SMichael Lentine ndk = getenv("NDK_ROOT"); 92eca81836SMichael Lentine app = getenv("APP_PLATFORM"); 93eca81836SMichael Lentine 94eca81836SMichael Lentine if (!(ndk && app)) 95eca81836SMichael Lentine return false; 96eca81836SMichael Lentine 97eca81836SMichael Lentine ndk_length = strlen(ndk); 98eca81836SMichael Lentine app_length = strlen(app); 99eca81836SMichael Lentine 100eca81836SMichael Lentine if (!(ndk_length && app_length && app_abi_length)) 101eca81836SMichael Lentine return false; 102eca81836SMichael Lentine 103eca81836SMichael Lentine arch = !strncmp(app_abi, "arm", 3) ? "arm" : 104eca81836SMichael Lentine !strncmp(app_abi, "mips", 4) ? "mips" : 105eca81836SMichael Lentine !strncmp(app_abi, "x86", 3) ? "x86" : NULL; 106eca81836SMichael Lentine 107eca81836SMichael Lentine if (!arch) 108eca81836SMichael Lentine return false; 109eca81836SMichael Lentine 110eca81836SMichael Lentine new_length = 27 + ndk_length + 111eca81836SMichael Lentine app_length + lib_length 112eca81836SMichael Lentine + strlen(arch); 113eca81836SMichael Lentine 114eca81836SMichael Lentine if (new_length > PATH_MAX) 115eca81836SMichael Lentine return false; 116eca81836SMichael Lentine snprintf(newfilename, new_length, 117eca81836SMichael Lentine "%s/platforms/%s/arch-%s/usr/lib/%s", 118eca81836SMichael Lentine ndk, app, arch, libname); 119eca81836SMichael Lentine 120eca81836SMichael Lentine return true; 121eca81836SMichael Lentine } 122eca81836SMichael Lentine return false; 123eca81836SMichael Lentine } 124eca81836SMichael Lentine 125237a7e04SArnaldo Carvalho de Melo void map__init(struct map *map, enum map_type type, 1263610583cSArnaldo Carvalho de Melo u64 start, u64 end, u64 pgoff, struct dso *dso) 127afb7b4f0SArnaldo Carvalho de Melo { 128237a7e04SArnaldo Carvalho de Melo map->type = type; 129237a7e04SArnaldo Carvalho de Melo map->start = start; 130237a7e04SArnaldo Carvalho de Melo map->end = end; 131237a7e04SArnaldo Carvalho de Melo map->pgoff = pgoff; 1329176753dSAdrian Hunter map->reloc = 0; 133237a7e04SArnaldo Carvalho de Melo map->dso = dso; 134237a7e04SArnaldo Carvalho de Melo map->map_ip = map__map_ip; 135237a7e04SArnaldo Carvalho de Melo map->unmap_ip = map__unmap_ip; 136237a7e04SArnaldo Carvalho de Melo RB_CLEAR_NODE(&map->rb_node); 137237a7e04SArnaldo Carvalho de Melo map->groups = NULL; 138237a7e04SArnaldo Carvalho de Melo map->referenced = false; 139237a7e04SArnaldo Carvalho de Melo map->erange_warned = false; 140afb7b4f0SArnaldo Carvalho de Melo } 141afb7b4f0SArnaldo Carvalho de Melo 1422a03068cSAdrian Hunter struct map *map__new(struct machine *machine, u64 start, u64 len, 1435c5e854bSStephane Eranian u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 1447ef80703SDon Zickus u64 ino_gen, u32 prot, u32 flags, char *filename, 1455835eddaSAdrian Hunter enum map_type type, struct thread *thread) 14666e274f3SFrederic Weisbecker { 147237a7e04SArnaldo Carvalho de Melo struct map *map = malloc(sizeof(*map)); 14866e274f3SFrederic Weisbecker 149237a7e04SArnaldo Carvalho de Melo if (map != NULL) { 15066e274f3SFrederic Weisbecker char newfilename[PATH_MAX]; 151afb7b4f0SArnaldo Carvalho de Melo struct dso *dso; 152eca81836SMichael Lentine int anon, no_dso, vdso, android; 15366e274f3SFrederic Weisbecker 154eca81836SMichael Lentine android = is_android_lib(filename); 15566e274f3SFrederic Weisbecker anon = is_anon_memory(filename); 1567dbf4dcfSJiri Olsa vdso = is_vdso_map(filename); 15787ffef79SJiri Olsa no_dso = is_no_dso_memory(filename); 15866e274f3SFrederic Weisbecker 1595c5e854bSStephane Eranian map->maj = d_maj; 1605c5e854bSStephane Eranian map->min = d_min; 1615c5e854bSStephane Eranian map->ino = ino; 1625c5e854bSStephane Eranian map->ino_generation = ino_gen; 1637ef80703SDon Zickus map->prot = prot; 1647ef80703SDon Zickus map->flags = flags; 1655c5e854bSStephane Eranian 166578c03c8SNamhyung Kim if ((anon || no_dso) && type == MAP__FUNCTION) { 167b177f63fSArnaldo Carvalho de Melo snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 16866e274f3SFrederic Weisbecker filename = newfilename; 16966e274f3SFrederic Weisbecker } 17066e274f3SFrederic Weisbecker 171eca81836SMichael Lentine if (android) { 172eca81836SMichael Lentine if (replace_android_lib(filename, newfilename)) 173eca81836SMichael Lentine filename = newfilename; 174eca81836SMichael Lentine } 175eca81836SMichael Lentine 1767dbf4dcfSJiri Olsa if (vdso) { 1777dbf4dcfSJiri Olsa pgoff = 0; 1785835eddaSAdrian Hunter dso = vdso__dso_findnew(machine, thread); 1797dbf4dcfSJiri Olsa } else 1802a03068cSAdrian Hunter dso = __dsos__findnew(&machine->user_dsos, filename); 1817dbf4dcfSJiri Olsa 182afb7b4f0SArnaldo Carvalho de Melo if (dso == NULL) 18366e274f3SFrederic Weisbecker goto out_delete; 18466e274f3SFrederic Weisbecker 185237a7e04SArnaldo Carvalho de Melo map__init(map, type, start, start + len, pgoff, dso); 186afb7b4f0SArnaldo Carvalho de Melo 18787ffef79SJiri Olsa if (anon || no_dso) { 188237a7e04SArnaldo Carvalho de Melo map->map_ip = map->unmap_ip = identity__map_ip; 18987ffef79SJiri Olsa 19087ffef79SJiri Olsa /* 19187ffef79SJiri Olsa * Set memory without DSO as loaded. All map__find_* 19287ffef79SJiri Olsa * functions still return NULL, and we avoid the 19387ffef79SJiri Olsa * unnecessary map__load warning. 19487ffef79SJiri Olsa */ 195578c03c8SNamhyung Kim if (type != MAP__FUNCTION) 196237a7e04SArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 1978d92c02aSArnaldo Carvalho de Melo } 19866e274f3SFrederic Weisbecker } 199237a7e04SArnaldo Carvalho de Melo return map; 20066e274f3SFrederic Weisbecker out_delete: 201237a7e04SArnaldo Carvalho de Melo free(map); 20266e274f3SFrederic Weisbecker return NULL; 20366e274f3SFrederic Weisbecker } 20466e274f3SFrederic Weisbecker 205e5a1845fSNamhyung Kim /* 206e5a1845fSNamhyung Kim * Constructor variant for modules (where we know from /proc/modules where 207e5a1845fSNamhyung Kim * they are loaded) and for vmlinux, where only after we load all the 208e5a1845fSNamhyung Kim * symbols we'll know where it starts and ends. 209e5a1845fSNamhyung Kim */ 210e5a1845fSNamhyung Kim struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 211e5a1845fSNamhyung Kim { 212e5a1845fSNamhyung Kim struct map *map = calloc(1, (sizeof(*map) + 213e5a1845fSNamhyung Kim (dso->kernel ? sizeof(struct kmap) : 0))); 214e5a1845fSNamhyung Kim if (map != NULL) { 215e5a1845fSNamhyung Kim /* 216e5a1845fSNamhyung Kim * ->end will be filled after we load all the symbols 217e5a1845fSNamhyung Kim */ 218e5a1845fSNamhyung Kim map__init(map, type, start, 0, 0, dso); 219e5a1845fSNamhyung Kim } 220e5a1845fSNamhyung Kim 221e5a1845fSNamhyung Kim return map; 222e5a1845fSNamhyung Kim } 223e5a1845fSNamhyung Kim 224237a7e04SArnaldo Carvalho de Melo void map__delete(struct map *map) 225c338aee8SArnaldo Carvalho de Melo { 226237a7e04SArnaldo Carvalho de Melo free(map); 227c338aee8SArnaldo Carvalho de Melo } 228c338aee8SArnaldo Carvalho de Melo 229237a7e04SArnaldo Carvalho de Melo void map__fixup_start(struct map *map) 230c338aee8SArnaldo Carvalho de Melo { 231237a7e04SArnaldo Carvalho de Melo struct rb_root *symbols = &map->dso->symbols[map->type]; 232fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd = rb_first(symbols); 233c338aee8SArnaldo Carvalho de Melo if (nd != NULL) { 234c338aee8SArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 235237a7e04SArnaldo Carvalho de Melo map->start = sym->start; 236c338aee8SArnaldo Carvalho de Melo } 237c338aee8SArnaldo Carvalho de Melo } 238c338aee8SArnaldo Carvalho de Melo 239237a7e04SArnaldo Carvalho de Melo void map__fixup_end(struct map *map) 240c338aee8SArnaldo Carvalho de Melo { 241237a7e04SArnaldo Carvalho de Melo struct rb_root *symbols = &map->dso->symbols[map->type]; 242fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd = rb_last(symbols); 243c338aee8SArnaldo Carvalho de Melo if (nd != NULL) { 244c338aee8SArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 245237a7e04SArnaldo Carvalho de Melo map->end = sym->end; 246c338aee8SArnaldo Carvalho de Melo } 247c338aee8SArnaldo Carvalho de Melo } 248c338aee8SArnaldo Carvalho de Melo 249d70a5402SArnaldo Carvalho de Melo #define DSO__DELETED "(deleted)" 250d70a5402SArnaldo Carvalho de Melo 251237a7e04SArnaldo Carvalho de Melo int map__load(struct map *map, symbol_filter_t filter) 25266bd8424SArnaldo Carvalho de Melo { 253237a7e04SArnaldo Carvalho de Melo const char *name = map->dso->long_name; 254a128168dSMasami Hiramatsu int nr; 25566bd8424SArnaldo Carvalho de Melo 256237a7e04SArnaldo Carvalho de Melo if (dso__loaded(map->dso, map->type)) 257a128168dSMasami Hiramatsu return 0; 258a128168dSMasami Hiramatsu 259237a7e04SArnaldo Carvalho de Melo nr = dso__load(map->dso, map, filter); 26066bd8424SArnaldo Carvalho de Melo if (nr < 0) { 261237a7e04SArnaldo Carvalho de Melo if (map->dso->has_build_id) { 2628d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2638d06367fSArnaldo Carvalho de Melo 264237a7e04SArnaldo Carvalho de Melo build_id__sprintf(map->dso->build_id, 265237a7e04SArnaldo Carvalho de Melo sizeof(map->dso->build_id), 2668d06367fSArnaldo Carvalho de Melo sbuild_id); 2678d06367fSArnaldo Carvalho de Melo pr_warning("%s with build id %s not found", 26879406cd7SArnaldo Carvalho de Melo name, sbuild_id); 2698d06367fSArnaldo Carvalho de Melo } else 27079406cd7SArnaldo Carvalho de Melo pr_warning("Failed to open %s", name); 27179406cd7SArnaldo Carvalho de Melo 2728d06367fSArnaldo Carvalho de Melo pr_warning(", continuing without symbols\n"); 27379406cd7SArnaldo Carvalho de Melo return -1; 27466bd8424SArnaldo Carvalho de Melo } else if (nr == 0) { 27589fe808aSIngo Molnar #ifdef HAVE_LIBELF_SUPPORT 276d70a5402SArnaldo Carvalho de Melo const size_t len = strlen(name); 277d70a5402SArnaldo Carvalho de Melo const size_t real_len = len - sizeof(DSO__DELETED); 278d70a5402SArnaldo Carvalho de Melo 279d70a5402SArnaldo Carvalho de Melo if (len > sizeof(DSO__DELETED) && 280900b20d5SIngo Molnar strcmp(name + real_len + 1, DSO__DELETED) == 0) { 281e77b15bdSDavid Ahern pr_warning("%.*s was updated (is prelink enabled?). " 282e77b15bdSDavid Ahern "Restart the long running apps that use it!\n", 283900b20d5SIngo Molnar (int)real_len, name); 284900b20d5SIngo Molnar } else { 28579406cd7SArnaldo Carvalho de Melo pr_warning("no symbols found in %s, maybe install " 28679406cd7SArnaldo Carvalho de Melo "a debug package?\n", name); 28766bd8424SArnaldo Carvalho de Melo } 288393be2e3SNamhyung Kim #endif 28979406cd7SArnaldo Carvalho de Melo return -1; 29079406cd7SArnaldo Carvalho de Melo } 29179406cd7SArnaldo Carvalho de Melo 29279406cd7SArnaldo Carvalho de Melo return 0; 29379406cd7SArnaldo Carvalho de Melo } 29479406cd7SArnaldo Carvalho de Melo 295237a7e04SArnaldo Carvalho de Melo struct symbol *map__find_symbol(struct map *map, u64 addr, 2969de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 29779406cd7SArnaldo Carvalho de Melo { 298237a7e04SArnaldo Carvalho de Melo if (map__load(map, filter) < 0) 29979406cd7SArnaldo Carvalho de Melo return NULL; 30079406cd7SArnaldo Carvalho de Melo 301237a7e04SArnaldo Carvalho de Melo return dso__find_symbol(map->dso, map->type, addr); 30266bd8424SArnaldo Carvalho de Melo } 30366bd8424SArnaldo Carvalho de Melo 304237a7e04SArnaldo Carvalho de Melo struct symbol *map__find_symbol_by_name(struct map *map, const char *name, 30579406cd7SArnaldo Carvalho de Melo symbol_filter_t filter) 30679406cd7SArnaldo Carvalho de Melo { 307237a7e04SArnaldo Carvalho de Melo if (map__load(map, filter) < 0) 30879406cd7SArnaldo Carvalho de Melo return NULL; 30979406cd7SArnaldo Carvalho de Melo 310237a7e04SArnaldo Carvalho de Melo if (!dso__sorted_by_name(map->dso, map->type)) 311237a7e04SArnaldo Carvalho de Melo dso__sort_by_name(map->dso, map->type); 31279406cd7SArnaldo Carvalho de Melo 313237a7e04SArnaldo Carvalho de Melo return dso__find_symbol_by_name(map->dso, map->type, name); 31479406cd7SArnaldo Carvalho de Melo } 31579406cd7SArnaldo Carvalho de Melo 316237a7e04SArnaldo Carvalho de Melo struct map *map__clone(struct map *map) 31766e274f3SFrederic Weisbecker { 3188e16017dSArnaldo Carvalho de Melo return memdup(map, sizeof(*map)); 31966e274f3SFrederic Weisbecker } 32066e274f3SFrederic Weisbecker 32166e274f3SFrederic Weisbecker int map__overlap(struct map *l, struct map *r) 32266e274f3SFrederic Weisbecker { 32366e274f3SFrederic Weisbecker if (l->start > r->start) { 32466e274f3SFrederic Weisbecker struct map *t = l; 32566e274f3SFrederic Weisbecker l = r; 32666e274f3SFrederic Weisbecker r = t; 32766e274f3SFrederic Weisbecker } 32866e274f3SFrederic Weisbecker 32966e274f3SFrederic Weisbecker if (l->end > r->start) 33066e274f3SFrederic Weisbecker return 1; 33166e274f3SFrederic Weisbecker 33266e274f3SFrederic Weisbecker return 0; 33366e274f3SFrederic Weisbecker } 33466e274f3SFrederic Weisbecker 335237a7e04SArnaldo Carvalho de Melo size_t map__fprintf(struct map *map, FILE *fp) 33666e274f3SFrederic Weisbecker { 3379486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 338237a7e04SArnaldo Carvalho de Melo map->start, map->end, map->pgoff, map->dso->name); 33966e274f3SFrederic Weisbecker } 3407a2b6209SKirill Smelkov 341547a92e0SAkihiro Nagai size_t map__fprintf_dsoname(struct map *map, FILE *fp) 342547a92e0SAkihiro Nagai { 3438f28f19aSFeng Tang const char *dsoname = "[unknown]"; 344547a92e0SAkihiro Nagai 3450bc8d205SAkihiro Nagai if (map && map->dso && (map->dso->name || map->dso->long_name)) { 3460bc8d205SAkihiro Nagai if (symbol_conf.show_kernel_path && map->dso->long_name) 3470bc8d205SAkihiro Nagai dsoname = map->dso->long_name; 3480bc8d205SAkihiro Nagai else if (map->dso->name) 349547a92e0SAkihiro Nagai dsoname = map->dso->name; 3508f28f19aSFeng Tang } 351547a92e0SAkihiro Nagai 352547a92e0SAkihiro Nagai return fprintf(fp, "%s", dsoname); 353547a92e0SAkihiro Nagai } 354547a92e0SAkihiro Nagai 355cc8fae1dSAdrian Hunter int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, 356cc8fae1dSAdrian Hunter FILE *fp) 357cc8fae1dSAdrian Hunter { 358cc8fae1dSAdrian Hunter char *srcline; 359cc8fae1dSAdrian Hunter int ret = 0; 360cc8fae1dSAdrian Hunter 361cc8fae1dSAdrian Hunter if (map && map->dso) { 362cc8fae1dSAdrian Hunter srcline = get_srcline(map->dso, 36385c116a6SAndi Kleen map__rip_2objdump(map, addr), NULL, true); 364cc8fae1dSAdrian Hunter if (srcline != SRCLINE_UNKNOWN) 365cc8fae1dSAdrian Hunter ret = fprintf(fp, "%s%s", prefix, srcline); 366cc8fae1dSAdrian Hunter free_srcline(srcline); 367cc8fae1dSAdrian Hunter } 368cc8fae1dSAdrian Hunter return ret; 369cc8fae1dSAdrian Hunter } 370cc8fae1dSAdrian Hunter 3711d5077bdSAdrian Hunter /** 3721d5077bdSAdrian Hunter * map__rip_2objdump - convert symbol start address to objdump address. 3731d5077bdSAdrian Hunter * @map: memory map 3741d5077bdSAdrian Hunter * @rip: symbol start address 3751d5077bdSAdrian Hunter * 3767a2b6209SKirill Smelkov * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 3770131c4ecSAdrian Hunter * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is 3780131c4ecSAdrian Hunter * relative to section start. 3791d5077bdSAdrian Hunter * 3801d5077bdSAdrian Hunter * Return: Address suitable for passing to "objdump --start-address=" 3817a2b6209SKirill Smelkov */ 3827a2b6209SKirill Smelkov u64 map__rip_2objdump(struct map *map, u64 rip) 3837a2b6209SKirill Smelkov { 3840131c4ecSAdrian Hunter if (!map->dso->adjust_symbols) 3850131c4ecSAdrian Hunter return rip; 3860131c4ecSAdrian Hunter 3870131c4ecSAdrian Hunter if (map->dso->rel) 3880131c4ecSAdrian Hunter return rip - map->pgoff; 3890131c4ecSAdrian Hunter 3909176753dSAdrian Hunter return map->unmap_ip(map, rip) - map->reloc; 3917a2b6209SKirill Smelkov } 392ee11b90bSKirill Smelkov 3931d5077bdSAdrian Hunter /** 3941d5077bdSAdrian Hunter * map__objdump_2mem - convert objdump address to a memory address. 3951d5077bdSAdrian Hunter * @map: memory map 3961d5077bdSAdrian Hunter * @ip: objdump address 3971d5077bdSAdrian Hunter * 3981d5077bdSAdrian Hunter * Closely related to map__rip_2objdump(), this function takes an address from 3991d5077bdSAdrian Hunter * objdump and converts it to a memory address. Note this assumes that @map 4001d5077bdSAdrian Hunter * contains the address. To be sure the result is valid, check it forwards 4011d5077bdSAdrian Hunter * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip 4021d5077bdSAdrian Hunter * 4031d5077bdSAdrian Hunter * Return: Memory address. 4041d5077bdSAdrian Hunter */ 4051d5077bdSAdrian Hunter u64 map__objdump_2mem(struct map *map, u64 ip) 4061d5077bdSAdrian Hunter { 4071d5077bdSAdrian Hunter if (!map->dso->adjust_symbols) 4081d5077bdSAdrian Hunter return map->unmap_ip(map, ip); 4091d5077bdSAdrian Hunter 4101d5077bdSAdrian Hunter if (map->dso->rel) 4111d5077bdSAdrian Hunter return map->unmap_ip(map, ip + map->pgoff); 4121d5077bdSAdrian Hunter 4139176753dSAdrian Hunter return ip + map->reloc; 4141d5077bdSAdrian Hunter } 4151d5077bdSAdrian Hunter 41611246c70SArnaldo Carvalho de Melo void map_groups__init(struct map_groups *mg, struct machine *machine) 417c6e718ffSArnaldo Carvalho de Melo { 418c6e718ffSArnaldo Carvalho de Melo int i; 419c6e718ffSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) { 42098dfd55dSArnaldo Carvalho de Melo mg->maps[i] = RB_ROOT; 42198dfd55dSArnaldo Carvalho de Melo INIT_LIST_HEAD(&mg->removed_maps[i]); 422c6e718ffSArnaldo Carvalho de Melo } 42311246c70SArnaldo Carvalho de Melo mg->machine = machine; 424a26ca671SArnaldo Carvalho de Melo mg->refcnt = 1; 425c6e718ffSArnaldo Carvalho de Melo } 426c6e718ffSArnaldo Carvalho de Melo 42798dfd55dSArnaldo Carvalho de Melo static void maps__delete(struct rb_root *maps) 428591765fdSArnaldo Carvalho de Melo { 42998dfd55dSArnaldo Carvalho de Melo struct rb_node *next = rb_first(maps); 430591765fdSArnaldo Carvalho de Melo 431591765fdSArnaldo Carvalho de Melo while (next) { 432591765fdSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 433591765fdSArnaldo Carvalho de Melo 434591765fdSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 43598dfd55dSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, maps); 436591765fdSArnaldo Carvalho de Melo map__delete(pos); 437591765fdSArnaldo Carvalho de Melo } 438591765fdSArnaldo Carvalho de Melo } 439591765fdSArnaldo Carvalho de Melo 44098dfd55dSArnaldo Carvalho de Melo static void maps__delete_removed(struct list_head *maps) 441591765fdSArnaldo Carvalho de Melo { 442591765fdSArnaldo Carvalho de Melo struct map *pos, *n; 443591765fdSArnaldo Carvalho de Melo 44498dfd55dSArnaldo Carvalho de Melo list_for_each_entry_safe(pos, n, maps, node) { 445591765fdSArnaldo Carvalho de Melo list_del(&pos->node); 446591765fdSArnaldo Carvalho de Melo map__delete(pos); 447591765fdSArnaldo Carvalho de Melo } 448591765fdSArnaldo Carvalho de Melo } 449591765fdSArnaldo Carvalho de Melo 45098dfd55dSArnaldo Carvalho de Melo void map_groups__exit(struct map_groups *mg) 451591765fdSArnaldo Carvalho de Melo { 452591765fdSArnaldo Carvalho de Melo int i; 453591765fdSArnaldo Carvalho de Melo 454591765fdSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) { 45598dfd55dSArnaldo Carvalho de Melo maps__delete(&mg->maps[i]); 45698dfd55dSArnaldo Carvalho de Melo maps__delete_removed(&mg->removed_maps[i]); 457591765fdSArnaldo Carvalho de Melo } 458591765fdSArnaldo Carvalho de Melo } 459591765fdSArnaldo Carvalho de Melo 46029ce3612SAdrian Hunter bool map_groups__empty(struct map_groups *mg) 46129ce3612SAdrian Hunter { 46229ce3612SAdrian Hunter int i; 46329ce3612SAdrian Hunter 46429ce3612SAdrian Hunter for (i = 0; i < MAP__NR_TYPES; ++i) { 46529ce3612SAdrian Hunter if (maps__first(&mg->maps[i])) 46629ce3612SAdrian Hunter return false; 46729ce3612SAdrian Hunter if (!list_empty(&mg->removed_maps[i])) 46829ce3612SAdrian Hunter return false; 46929ce3612SAdrian Hunter } 47029ce3612SAdrian Hunter 47129ce3612SAdrian Hunter return true; 47229ce3612SAdrian Hunter } 47329ce3612SAdrian Hunter 47411246c70SArnaldo Carvalho de Melo struct map_groups *map_groups__new(struct machine *machine) 47593d5731dSArnaldo Carvalho de Melo { 47693d5731dSArnaldo Carvalho de Melo struct map_groups *mg = malloc(sizeof(*mg)); 47793d5731dSArnaldo Carvalho de Melo 47893d5731dSArnaldo Carvalho de Melo if (mg != NULL) 47911246c70SArnaldo Carvalho de Melo map_groups__init(mg, machine); 48093d5731dSArnaldo Carvalho de Melo 48193d5731dSArnaldo Carvalho de Melo return mg; 48293d5731dSArnaldo Carvalho de Melo } 48393d5731dSArnaldo Carvalho de Melo 48493d5731dSArnaldo Carvalho de Melo void map_groups__delete(struct map_groups *mg) 48593d5731dSArnaldo Carvalho de Melo { 48693d5731dSArnaldo Carvalho de Melo map_groups__exit(mg); 48793d5731dSArnaldo Carvalho de Melo free(mg); 48893d5731dSArnaldo Carvalho de Melo } 48993d5731dSArnaldo Carvalho de Melo 490a26ca671SArnaldo Carvalho de Melo void map_groups__put(struct map_groups *mg) 491a26ca671SArnaldo Carvalho de Melo { 492a26ca671SArnaldo Carvalho de Melo if (--mg->refcnt == 0) 493a26ca671SArnaldo Carvalho de Melo map_groups__delete(mg); 494a26ca671SArnaldo Carvalho de Melo } 495a26ca671SArnaldo Carvalho de Melo 49698dfd55dSArnaldo Carvalho de Melo void map_groups__flush(struct map_groups *mg) 497c6e718ffSArnaldo Carvalho de Melo { 498c6e718ffSArnaldo Carvalho de Melo int type; 499c6e718ffSArnaldo Carvalho de Melo 500c6e718ffSArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; type++) { 50198dfd55dSArnaldo Carvalho de Melo struct rb_root *root = &mg->maps[type]; 502c6e718ffSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 503c6e718ffSArnaldo Carvalho de Melo 504c6e718ffSArnaldo Carvalho de Melo while (next) { 505c6e718ffSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 506c6e718ffSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 507c6e718ffSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 508c6e718ffSArnaldo Carvalho de Melo /* 509c6e718ffSArnaldo Carvalho de Melo * We may have references to this map, for 510c6e718ffSArnaldo Carvalho de Melo * instance in some hist_entry instances, so 511c6e718ffSArnaldo Carvalho de Melo * just move them to a separate list. 512c6e718ffSArnaldo Carvalho de Melo */ 51398dfd55dSArnaldo Carvalho de Melo list_add_tail(&pos->node, &mg->removed_maps[pos->type]); 514c6e718ffSArnaldo Carvalho de Melo } 515c6e718ffSArnaldo Carvalho de Melo } 516c6e718ffSArnaldo Carvalho de Melo } 517c6e718ffSArnaldo Carvalho de Melo 51898dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol(struct map_groups *mg, 5194b8cf846SArnaldo Carvalho de Melo enum map_type type, u64 addr, 5207e5e1b14SArnaldo Carvalho de Melo struct map **mapp, 5214b8cf846SArnaldo Carvalho de Melo symbol_filter_t filter) 5224b8cf846SArnaldo Carvalho de Melo { 52398dfd55dSArnaldo Carvalho de Melo struct map *map = map_groups__find(mg, type, addr); 5244b8cf846SArnaldo Carvalho de Melo 5254afc81cdSMasami Hiramatsu /* Ensure map is loaded before using map->map_ip */ 5264afc81cdSMasami Hiramatsu if (map != NULL && map__load(map, filter) >= 0) { 5277e5e1b14SArnaldo Carvalho de Melo if (mapp != NULL) 5287e5e1b14SArnaldo Carvalho de Melo *mapp = map; 5294b8cf846SArnaldo Carvalho de Melo return map__find_symbol(map, map->map_ip(map, addr), filter); 5307e5e1b14SArnaldo Carvalho de Melo } 5317e5e1b14SArnaldo Carvalho de Melo 5327e5e1b14SArnaldo Carvalho de Melo return NULL; 5337e5e1b14SArnaldo Carvalho de Melo } 5347e5e1b14SArnaldo Carvalho de Melo 53598dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, 5367e5e1b14SArnaldo Carvalho de Melo enum map_type type, 5377e5e1b14SArnaldo Carvalho de Melo const char *name, 5387e5e1b14SArnaldo Carvalho de Melo struct map **mapp, 5397e5e1b14SArnaldo Carvalho de Melo symbol_filter_t filter) 5407e5e1b14SArnaldo Carvalho de Melo { 5417e5e1b14SArnaldo Carvalho de Melo struct rb_node *nd; 5427e5e1b14SArnaldo Carvalho de Melo 54398dfd55dSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 5447e5e1b14SArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 5457e5e1b14SArnaldo Carvalho de Melo struct symbol *sym = map__find_symbol_by_name(pos, name, filter); 5467e5e1b14SArnaldo Carvalho de Melo 5477e5e1b14SArnaldo Carvalho de Melo if (sym == NULL) 5487e5e1b14SArnaldo Carvalho de Melo continue; 5497e5e1b14SArnaldo Carvalho de Melo if (mapp != NULL) 5507e5e1b14SArnaldo Carvalho de Melo *mapp = pos; 5517e5e1b14SArnaldo Carvalho de Melo return sym; 5527e5e1b14SArnaldo Carvalho de Melo } 5534b8cf846SArnaldo Carvalho de Melo 5544b8cf846SArnaldo Carvalho de Melo return NULL; 5554b8cf846SArnaldo Carvalho de Melo } 5564b8cf846SArnaldo Carvalho de Melo 5574e987712SArnaldo Carvalho de Melo int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) 5584e987712SArnaldo Carvalho de Melo { 55977faf4d0SStephane Eranian if (ams->addr < ams->map->start || ams->addr >= ams->map->end) { 5604e987712SArnaldo Carvalho de Melo if (ams->map->groups == NULL) 5614e987712SArnaldo Carvalho de Melo return -1; 5624e987712SArnaldo Carvalho de Melo ams->map = map_groups__find(ams->map->groups, ams->map->type, 5634e987712SArnaldo Carvalho de Melo ams->addr); 5644e987712SArnaldo Carvalho de Melo if (ams->map == NULL) 5654e987712SArnaldo Carvalho de Melo return -1; 5664e987712SArnaldo Carvalho de Melo } 5674e987712SArnaldo Carvalho de Melo 5684e987712SArnaldo Carvalho de Melo ams->al_addr = ams->map->map_ip(ams->map, ams->addr); 5694e987712SArnaldo Carvalho de Melo ams->sym = map__find_symbol(ams->map, ams->al_addr, filter); 5704e987712SArnaldo Carvalho de Melo 5714e987712SArnaldo Carvalho de Melo return ams->sym ? 0 : -1; 5724e987712SArnaldo Carvalho de Melo } 5734e987712SArnaldo Carvalho de Melo 574acebd408SJiri Olsa size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, 575acebd408SJiri Olsa FILE *fp) 576c6e718ffSArnaldo Carvalho de Melo { 577c6e718ffSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 578c6e718ffSArnaldo Carvalho de Melo struct rb_node *nd; 579c6e718ffSArnaldo Carvalho de Melo 58098dfd55dSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 581c6e718ffSArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 582c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 583c6e718ffSArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 584c6e718ffSArnaldo Carvalho de Melo if (verbose > 2) { 585c6e718ffSArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, type, fp); 586c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 587c6e718ffSArnaldo Carvalho de Melo } 588c6e718ffSArnaldo Carvalho de Melo } 589c6e718ffSArnaldo Carvalho de Melo 590c6e718ffSArnaldo Carvalho de Melo return printed; 591c6e718ffSArnaldo Carvalho de Melo } 592c6e718ffSArnaldo Carvalho de Melo 593acebd408SJiri Olsa static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) 594c6e718ffSArnaldo Carvalho de Melo { 595c6e718ffSArnaldo Carvalho de Melo size_t printed = 0, i; 596c6e718ffSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 597acebd408SJiri Olsa printed += __map_groups__fprintf_maps(mg, i, fp); 598c6e718ffSArnaldo Carvalho de Melo return printed; 599c6e718ffSArnaldo Carvalho de Melo } 600c6e718ffSArnaldo Carvalho de Melo 60198dfd55dSArnaldo Carvalho de Melo static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, 602acebd408SJiri Olsa enum map_type type, FILE *fp) 603c6e718ffSArnaldo Carvalho de Melo { 604c6e718ffSArnaldo Carvalho de Melo struct map *pos; 605c6e718ffSArnaldo Carvalho de Melo size_t printed = 0; 606c6e718ffSArnaldo Carvalho de Melo 60798dfd55dSArnaldo Carvalho de Melo list_for_each_entry(pos, &mg->removed_maps[type], node) { 608c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 609c6e718ffSArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 610c6e718ffSArnaldo Carvalho de Melo if (verbose > 1) { 611c6e718ffSArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, type, fp); 612c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 613c6e718ffSArnaldo Carvalho de Melo } 614c6e718ffSArnaldo Carvalho de Melo } 615c6e718ffSArnaldo Carvalho de Melo return printed; 616c6e718ffSArnaldo Carvalho de Melo } 617c6e718ffSArnaldo Carvalho de Melo 61898dfd55dSArnaldo Carvalho de Melo static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, 619acebd408SJiri Olsa FILE *fp) 620c6e718ffSArnaldo Carvalho de Melo { 621c6e718ffSArnaldo Carvalho de Melo size_t printed = 0, i; 622c6e718ffSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 623acebd408SJiri Olsa printed += __map_groups__fprintf_removed_maps(mg, i, fp); 624c6e718ffSArnaldo Carvalho de Melo return printed; 625c6e718ffSArnaldo Carvalho de Melo } 626c6e718ffSArnaldo Carvalho de Melo 627acebd408SJiri Olsa size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) 628c6e718ffSArnaldo Carvalho de Melo { 629acebd408SJiri Olsa size_t printed = map_groups__fprintf_maps(mg, fp); 630c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "Removed maps:\n"); 631acebd408SJiri Olsa return printed + map_groups__fprintf_removed_maps(mg, fp); 632c6e718ffSArnaldo Carvalho de Melo } 633c6e718ffSArnaldo Carvalho de Melo 63498dfd55dSArnaldo Carvalho de Melo int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 635acebd408SJiri Olsa FILE *fp) 636c6e718ffSArnaldo Carvalho de Melo { 63798dfd55dSArnaldo Carvalho de Melo struct rb_root *root = &mg->maps[map->type]; 638c6e718ffSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 6390a1eae39SArnaldo Carvalho de Melo int err = 0; 640c6e718ffSArnaldo Carvalho de Melo 641c6e718ffSArnaldo Carvalho de Melo while (next) { 642c6e718ffSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 643c6e718ffSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 644c6e718ffSArnaldo Carvalho de Melo 645c6e718ffSArnaldo Carvalho de Melo if (!map__overlap(pos, map)) 646c6e718ffSArnaldo Carvalho de Melo continue; 647c6e718ffSArnaldo Carvalho de Melo 648c6e718ffSArnaldo Carvalho de Melo if (verbose >= 2) { 649c6e718ffSArnaldo Carvalho de Melo fputs("overlapping maps:\n", fp); 650c6e718ffSArnaldo Carvalho de Melo map__fprintf(map, fp); 651c6e718ffSArnaldo Carvalho de Melo map__fprintf(pos, fp); 652c6e718ffSArnaldo Carvalho de Melo } 653c6e718ffSArnaldo Carvalho de Melo 654c6e718ffSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 655c6e718ffSArnaldo Carvalho de Melo /* 656c6e718ffSArnaldo Carvalho de Melo * Now check if we need to create new maps for areas not 657c6e718ffSArnaldo Carvalho de Melo * overlapped by the new map: 658c6e718ffSArnaldo Carvalho de Melo */ 659c6e718ffSArnaldo Carvalho de Melo if (map->start > pos->start) { 660c6e718ffSArnaldo Carvalho de Melo struct map *before = map__clone(pos); 661c6e718ffSArnaldo Carvalho de Melo 6620a1eae39SArnaldo Carvalho de Melo if (before == NULL) { 6630a1eae39SArnaldo Carvalho de Melo err = -ENOMEM; 6640a1eae39SArnaldo Carvalho de Melo goto move_map; 6650a1eae39SArnaldo Carvalho de Melo } 666c6e718ffSArnaldo Carvalho de Melo 66777faf4d0SStephane Eranian before->end = map->start; 66898dfd55dSArnaldo Carvalho de Melo map_groups__insert(mg, before); 669c6e718ffSArnaldo Carvalho de Melo if (verbose >= 2) 670c6e718ffSArnaldo Carvalho de Melo map__fprintf(before, fp); 671c6e718ffSArnaldo Carvalho de Melo } 672c6e718ffSArnaldo Carvalho de Melo 673c6e718ffSArnaldo Carvalho de Melo if (map->end < pos->end) { 674c6e718ffSArnaldo Carvalho de Melo struct map *after = map__clone(pos); 675c6e718ffSArnaldo Carvalho de Melo 6760a1eae39SArnaldo Carvalho de Melo if (after == NULL) { 6770a1eae39SArnaldo Carvalho de Melo err = -ENOMEM; 6780a1eae39SArnaldo Carvalho de Melo goto move_map; 6790a1eae39SArnaldo Carvalho de Melo } 680c6e718ffSArnaldo Carvalho de Melo 68177faf4d0SStephane Eranian after->start = map->end; 68298dfd55dSArnaldo Carvalho de Melo map_groups__insert(mg, after); 683c6e718ffSArnaldo Carvalho de Melo if (verbose >= 2) 684c6e718ffSArnaldo Carvalho de Melo map__fprintf(after, fp); 685c6e718ffSArnaldo Carvalho de Melo } 6860a1eae39SArnaldo Carvalho de Melo move_map: 6870a1eae39SArnaldo Carvalho de Melo /* 6880a1eae39SArnaldo Carvalho de Melo * If we have references, just move them to a separate list. 6890a1eae39SArnaldo Carvalho de Melo */ 6900a1eae39SArnaldo Carvalho de Melo if (pos->referenced) 69198dfd55dSArnaldo Carvalho de Melo list_add_tail(&pos->node, &mg->removed_maps[map->type]); 6920a1eae39SArnaldo Carvalho de Melo else 6930a1eae39SArnaldo Carvalho de Melo map__delete(pos); 6940a1eae39SArnaldo Carvalho de Melo 6950a1eae39SArnaldo Carvalho de Melo if (err) 6960a1eae39SArnaldo Carvalho de Melo return err; 697c6e718ffSArnaldo Carvalho de Melo } 698c6e718ffSArnaldo Carvalho de Melo 699c6e718ffSArnaldo Carvalho de Melo return 0; 700c6e718ffSArnaldo Carvalho de Melo } 701c6e718ffSArnaldo Carvalho de Melo 702c6e718ffSArnaldo Carvalho de Melo /* 703c6e718ffSArnaldo Carvalho de Melo * XXX This should not really _copy_ te maps, but refcount them. 704c6e718ffSArnaldo Carvalho de Melo */ 70598dfd55dSArnaldo Carvalho de Melo int map_groups__clone(struct map_groups *mg, 706c6e718ffSArnaldo Carvalho de Melo struct map_groups *parent, enum map_type type) 707c6e718ffSArnaldo Carvalho de Melo { 708c6e718ffSArnaldo Carvalho de Melo struct rb_node *nd; 709c6e718ffSArnaldo Carvalho de Melo for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { 710c6e718ffSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 711c6e718ffSArnaldo Carvalho de Melo struct map *new = map__clone(map); 712c6e718ffSArnaldo Carvalho de Melo if (new == NULL) 713c6e718ffSArnaldo Carvalho de Melo return -ENOMEM; 71498dfd55dSArnaldo Carvalho de Melo map_groups__insert(mg, new); 715c6e718ffSArnaldo Carvalho de Melo } 716c6e718ffSArnaldo Carvalho de Melo return 0; 717c6e718ffSArnaldo Carvalho de Melo } 718c6e718ffSArnaldo Carvalho de Melo 7194b8cf846SArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map) 7204b8cf846SArnaldo Carvalho de Melo { 7214b8cf846SArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 7224b8cf846SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 7234b8cf846SArnaldo Carvalho de Melo const u64 ip = map->start; 7244b8cf846SArnaldo Carvalho de Melo struct map *m; 7254b8cf846SArnaldo Carvalho de Melo 7264b8cf846SArnaldo Carvalho de Melo while (*p != NULL) { 7274b8cf846SArnaldo Carvalho de Melo parent = *p; 7284b8cf846SArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 7294b8cf846SArnaldo Carvalho de Melo if (ip < m->start) 7304b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_left; 7314b8cf846SArnaldo Carvalho de Melo else 7324b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_right; 7334b8cf846SArnaldo Carvalho de Melo } 7344b8cf846SArnaldo Carvalho de Melo 7354b8cf846SArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 7364b8cf846SArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, maps); 7374b8cf846SArnaldo Carvalho de Melo } 7384b8cf846SArnaldo Carvalho de Melo 739237a7e04SArnaldo Carvalho de Melo void maps__remove(struct rb_root *maps, struct map *map) 740076c6e45SArnaldo Carvalho de Melo { 741237a7e04SArnaldo Carvalho de Melo rb_erase(&map->rb_node, maps); 742076c6e45SArnaldo Carvalho de Melo } 743076c6e45SArnaldo Carvalho de Melo 7444b8cf846SArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip) 7454b8cf846SArnaldo Carvalho de Melo { 7464b8cf846SArnaldo Carvalho de Melo struct rb_node **p = &maps->rb_node; 7474b8cf846SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 7484b8cf846SArnaldo Carvalho de Melo struct map *m; 7494b8cf846SArnaldo Carvalho de Melo 7504b8cf846SArnaldo Carvalho de Melo while (*p != NULL) { 7514b8cf846SArnaldo Carvalho de Melo parent = *p; 7524b8cf846SArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 7534b8cf846SArnaldo Carvalho de Melo if (ip < m->start) 7544b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_left; 7554955ea22SNamhyung Kim else if (ip >= m->end) 7564b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_right; 7574b8cf846SArnaldo Carvalho de Melo else 7584b8cf846SArnaldo Carvalho de Melo return m; 7594b8cf846SArnaldo Carvalho de Melo } 7604b8cf846SArnaldo Carvalho de Melo 7614b8cf846SArnaldo Carvalho de Melo return NULL; 7624b8cf846SArnaldo Carvalho de Melo } 7638e0cf965SAdrian Hunter 7648e0cf965SAdrian Hunter struct map *maps__first(struct rb_root *maps) 7658e0cf965SAdrian Hunter { 7668e0cf965SAdrian Hunter struct rb_node *first = rb_first(maps); 7678e0cf965SAdrian Hunter 7688e0cf965SAdrian Hunter if (first) 7698e0cf965SAdrian Hunter return rb_entry(first, struct map, rb_node); 7708e0cf965SAdrian Hunter return NULL; 7718e0cf965SAdrian Hunter } 7728e0cf965SAdrian Hunter 7738e0cf965SAdrian Hunter struct map *maps__next(struct map *map) 7748e0cf965SAdrian Hunter { 7758e0cf965SAdrian Hunter struct rb_node *next = rb_next(&map->rb_node); 7768e0cf965SAdrian Hunter 7778e0cf965SAdrian Hunter if (next) 7788e0cf965SAdrian Hunter return rb_entry(next, struct map, rb_node); 7798e0cf965SAdrian Hunter return NULL; 7808e0cf965SAdrian Hunter } 781ba92732eSWang Nan 782ba92732eSWang Nan struct kmap *map__kmap(struct map *map) 783ba92732eSWang Nan { 784ba92732eSWang Nan if (!map->dso || !map->dso->kernel) { 785ba92732eSWang Nan pr_err("Internal error: map__kmap with a non-kernel map\n"); 786ba92732eSWang Nan return NULL; 787ba92732eSWang Nan } 788ba92732eSWang Nan return (struct kmap *)(map + 1); 789ba92732eSWang Nan } 790ba92732eSWang Nan 791ba92732eSWang Nan struct map_groups *map__kmaps(struct map *map) 792ba92732eSWang Nan { 793ba92732eSWang Nan struct kmap *kmap = map__kmap(map); 794ba92732eSWang Nan 795ba92732eSWang Nan if (!kmap || !kmap->kmaps) { 796ba92732eSWang Nan pr_err("Internal error: map__kmaps with a non-kernel map\n"); 797ba92732eSWang Nan return NULL; 798ba92732eSWang Nan } 799ba92732eSWang Nan return kmap->kmaps; 800ba92732eSWang Nan } 801