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> 9fbef103fSArnaldo Carvalho de Melo #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 104b8cf846SArnaldo Carvalho de Melo #include "map.h" 115cd95c2dSDavid Ahern #include "thread.h" 12c80c3c26SDavid Ahern #include "strlist.h" 137dbf4dcfSJiri Olsa #include "vdso.h" 14ebb296c2SJiri Olsa #include "build-id.h" 15cc8fae1dSAdrian Hunter #include "util.h" 16acebd408SJiri Olsa #include "debug.h" 172a03068cSAdrian Hunter #include "machine.h" 188e16017dSArnaldo Carvalho de Melo #include <linux/string.h> 196c502584SJiri Olsa #include "unwind.h" 2066e274f3SFrederic Weisbecker 216a2ffcddSArnaldo Carvalho de Melo static void __maps__insert(struct maps *maps, struct map *map); 226a2ffcddSArnaldo Carvalho de Melo 233846df2eSArnaldo Carvalho de Melo const char *map_type__name[MAP__NR_TYPES] = { 243846df2eSArnaldo Carvalho de Melo [MAP__FUNCTION] = "Functions", 253846df2eSArnaldo Carvalho de Melo [MAP__VARIABLE] = "Variables", 263846df2eSArnaldo Carvalho de Melo }; 273846df2eSArnaldo Carvalho de Melo 280ac3348eSWang Nan static inline int is_anon_memory(const char *filename, u32 flags) 2966e274f3SFrederic Weisbecker { 30fbef103fSArnaldo Carvalho de Melo return flags & MAP_HUGETLB || 310ac3348eSWang Nan !strcmp(filename, "//anon") || 32b2be5451SYannick Brosseau !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) || 33b2be5451SYannick Brosseau !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1); 3466e274f3SFrederic Weisbecker } 3566e274f3SFrederic Weisbecker 3687ffef79SJiri Olsa static inline int is_no_dso_memory(const char *filename) 3787ffef79SJiri Olsa { 381e82574dSNamhyung Kim return !strncmp(filename, "[stack", 6) || 39700be564SDon Zickus !strncmp(filename, "/SYSV",5) || 4087ffef79SJiri Olsa !strcmp(filename, "[heap]"); 4187ffef79SJiri Olsa } 4287ffef79SJiri Olsa 43eca81836SMichael Lentine static inline int is_android_lib(const char *filename) 44eca81836SMichael Lentine { 45eca81836SMichael Lentine return !strncmp(filename, "/data/app-lib", 13) || 46eca81836SMichael Lentine !strncmp(filename, "/system/lib", 11); 47eca81836SMichael Lentine } 48eca81836SMichael Lentine 49eca81836SMichael Lentine static inline bool replace_android_lib(const char *filename, char *newfilename) 50eca81836SMichael Lentine { 51eca81836SMichael Lentine const char *libname; 52eca81836SMichael Lentine char *app_abi; 53eca81836SMichael Lentine size_t app_abi_length, new_length; 54eca81836SMichael Lentine size_t lib_length = 0; 55eca81836SMichael Lentine 56eca81836SMichael Lentine libname = strrchr(filename, '/'); 57eca81836SMichael Lentine if (libname) 58eca81836SMichael Lentine lib_length = strlen(libname); 59eca81836SMichael Lentine 60eca81836SMichael Lentine app_abi = getenv("APP_ABI"); 61eca81836SMichael Lentine if (!app_abi) 62eca81836SMichael Lentine return false; 63eca81836SMichael Lentine 64eca81836SMichael Lentine app_abi_length = strlen(app_abi); 65eca81836SMichael Lentine 66eca81836SMichael Lentine if (!strncmp(filename, "/data/app-lib", 13)) { 67eca81836SMichael Lentine char *apk_path; 68eca81836SMichael Lentine 69eca81836SMichael Lentine if (!app_abi_length) 70eca81836SMichael Lentine return false; 71eca81836SMichael Lentine 72eca81836SMichael Lentine new_length = 7 + app_abi_length + lib_length; 73eca81836SMichael Lentine 74eca81836SMichael Lentine apk_path = getenv("APK_PATH"); 75eca81836SMichael Lentine if (apk_path) { 76eca81836SMichael Lentine new_length += strlen(apk_path) + 1; 77eca81836SMichael Lentine if (new_length > PATH_MAX) 78eca81836SMichael Lentine return false; 79eca81836SMichael Lentine snprintf(newfilename, new_length, 80eca81836SMichael Lentine "%s/libs/%s/%s", apk_path, app_abi, libname); 81eca81836SMichael Lentine } else { 82eca81836SMichael Lentine if (new_length > PATH_MAX) 83eca81836SMichael Lentine return false; 84eca81836SMichael Lentine snprintf(newfilename, new_length, 85eca81836SMichael Lentine "libs/%s/%s", app_abi, libname); 86eca81836SMichael Lentine } 87eca81836SMichael Lentine return true; 88eca81836SMichael Lentine } 89eca81836SMichael Lentine 90eca81836SMichael Lentine if (!strncmp(filename, "/system/lib/", 11)) { 91eca81836SMichael Lentine char *ndk, *app; 92eca81836SMichael Lentine const char *arch; 93eca81836SMichael Lentine size_t ndk_length; 94eca81836SMichael Lentine size_t app_length; 95eca81836SMichael Lentine 96eca81836SMichael Lentine ndk = getenv("NDK_ROOT"); 97eca81836SMichael Lentine app = getenv("APP_PLATFORM"); 98eca81836SMichael Lentine 99eca81836SMichael Lentine if (!(ndk && app)) 100eca81836SMichael Lentine return false; 101eca81836SMichael Lentine 102eca81836SMichael Lentine ndk_length = strlen(ndk); 103eca81836SMichael Lentine app_length = strlen(app); 104eca81836SMichael Lentine 105eca81836SMichael Lentine if (!(ndk_length && app_length && app_abi_length)) 106eca81836SMichael Lentine return false; 107eca81836SMichael Lentine 108eca81836SMichael Lentine arch = !strncmp(app_abi, "arm", 3) ? "arm" : 109eca81836SMichael Lentine !strncmp(app_abi, "mips", 4) ? "mips" : 110eca81836SMichael Lentine !strncmp(app_abi, "x86", 3) ? "x86" : NULL; 111eca81836SMichael Lentine 112eca81836SMichael Lentine if (!arch) 113eca81836SMichael Lentine return false; 114eca81836SMichael Lentine 115eca81836SMichael Lentine new_length = 27 + ndk_length + 116eca81836SMichael Lentine app_length + lib_length 117eca81836SMichael Lentine + strlen(arch); 118eca81836SMichael Lentine 119eca81836SMichael Lentine if (new_length > PATH_MAX) 120eca81836SMichael Lentine return false; 121eca81836SMichael Lentine snprintf(newfilename, new_length, 122eca81836SMichael Lentine "%s/platforms/%s/arch-%s/usr/lib/%s", 123eca81836SMichael Lentine ndk, app, arch, libname); 124eca81836SMichael Lentine 125eca81836SMichael Lentine return true; 126eca81836SMichael Lentine } 127eca81836SMichael Lentine return false; 128eca81836SMichael Lentine } 129eca81836SMichael Lentine 130237a7e04SArnaldo Carvalho de Melo void map__init(struct map *map, enum map_type type, 1313610583cSArnaldo Carvalho de Melo u64 start, u64 end, u64 pgoff, struct dso *dso) 132afb7b4f0SArnaldo Carvalho de Melo { 133237a7e04SArnaldo Carvalho de Melo map->type = type; 134237a7e04SArnaldo Carvalho de Melo map->start = start; 135237a7e04SArnaldo Carvalho de Melo map->end = end; 136237a7e04SArnaldo Carvalho de Melo map->pgoff = pgoff; 1379176753dSAdrian Hunter map->reloc = 0; 138d3a7c489SArnaldo Carvalho de Melo map->dso = dso__get(dso); 139237a7e04SArnaldo Carvalho de Melo map->map_ip = map__map_ip; 140237a7e04SArnaldo Carvalho de Melo map->unmap_ip = map__unmap_ip; 141237a7e04SArnaldo Carvalho de Melo RB_CLEAR_NODE(&map->rb_node); 142237a7e04SArnaldo Carvalho de Melo map->groups = NULL; 143237a7e04SArnaldo Carvalho de Melo map->erange_warned = false; 14484c2cafaSArnaldo Carvalho de Melo atomic_set(&map->refcnt, 1); 145afb7b4f0SArnaldo Carvalho de Melo } 146afb7b4f0SArnaldo Carvalho de Melo 1472a03068cSAdrian Hunter struct map *map__new(struct machine *machine, u64 start, u64 len, 1485c5e854bSStephane Eranian u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 1497ef80703SDon Zickus u64 ino_gen, u32 prot, u32 flags, char *filename, 1505835eddaSAdrian Hunter enum map_type type, struct thread *thread) 15166e274f3SFrederic Weisbecker { 152237a7e04SArnaldo Carvalho de Melo struct map *map = malloc(sizeof(*map)); 15366e274f3SFrederic Weisbecker 154237a7e04SArnaldo Carvalho de Melo if (map != NULL) { 15566e274f3SFrederic Weisbecker char newfilename[PATH_MAX]; 156afb7b4f0SArnaldo Carvalho de Melo struct dso *dso; 157eca81836SMichael Lentine int anon, no_dso, vdso, android; 15866e274f3SFrederic Weisbecker 159eca81836SMichael Lentine android = is_android_lib(filename); 1600ac3348eSWang Nan anon = is_anon_memory(filename, flags); 1617dbf4dcfSJiri Olsa vdso = is_vdso_map(filename); 16287ffef79SJiri Olsa no_dso = is_no_dso_memory(filename); 16366e274f3SFrederic Weisbecker 1645c5e854bSStephane Eranian map->maj = d_maj; 1655c5e854bSStephane Eranian map->min = d_min; 1665c5e854bSStephane Eranian map->ino = ino; 1675c5e854bSStephane Eranian map->ino_generation = ino_gen; 1687ef80703SDon Zickus map->prot = prot; 1697ef80703SDon Zickus map->flags = flags; 1705c5e854bSStephane Eranian 171578c03c8SNamhyung Kim if ((anon || no_dso) && type == MAP__FUNCTION) { 172b177f63fSArnaldo Carvalho de Melo snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 17366e274f3SFrederic Weisbecker filename = newfilename; 17466e274f3SFrederic Weisbecker } 17566e274f3SFrederic Weisbecker 176eca81836SMichael Lentine if (android) { 177eca81836SMichael Lentine if (replace_android_lib(filename, newfilename)) 178eca81836SMichael Lentine filename = newfilename; 179eca81836SMichael Lentine } 180eca81836SMichael Lentine 1817dbf4dcfSJiri Olsa if (vdso) { 1827dbf4dcfSJiri Olsa pgoff = 0; 1839a4388c7SArnaldo Carvalho de Melo dso = machine__findnew_vdso(machine, thread); 1847dbf4dcfSJiri Olsa } else 185aa7cc2aeSArnaldo Carvalho de Melo dso = machine__findnew_dso(machine, filename); 1867dbf4dcfSJiri Olsa 187afb7b4f0SArnaldo Carvalho de Melo if (dso == NULL) 18866e274f3SFrederic Weisbecker goto out_delete; 18966e274f3SFrederic Weisbecker 190237a7e04SArnaldo Carvalho de Melo map__init(map, type, start, start + len, pgoff, dso); 191afb7b4f0SArnaldo Carvalho de Melo 19287ffef79SJiri Olsa if (anon || no_dso) { 193237a7e04SArnaldo Carvalho de Melo map->map_ip = map->unmap_ip = identity__map_ip; 19487ffef79SJiri Olsa 19587ffef79SJiri Olsa /* 19687ffef79SJiri Olsa * Set memory without DSO as loaded. All map__find_* 19787ffef79SJiri Olsa * functions still return NULL, and we avoid the 19887ffef79SJiri Olsa * unnecessary map__load warning. 19987ffef79SJiri Olsa */ 200578c03c8SNamhyung Kim if (type != MAP__FUNCTION) 201237a7e04SArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 2028d92c02aSArnaldo Carvalho de Melo } 203d3a7c489SArnaldo Carvalho de Melo dso__put(dso); 20466e274f3SFrederic Weisbecker } 205237a7e04SArnaldo Carvalho de Melo return map; 20666e274f3SFrederic Weisbecker out_delete: 207237a7e04SArnaldo Carvalho de Melo free(map); 20866e274f3SFrederic Weisbecker return NULL; 20966e274f3SFrederic Weisbecker } 21066e274f3SFrederic Weisbecker 211e5a1845fSNamhyung Kim /* 212e5a1845fSNamhyung Kim * Constructor variant for modules (where we know from /proc/modules where 213e5a1845fSNamhyung Kim * they are loaded) and for vmlinux, where only after we load all the 214e5a1845fSNamhyung Kim * symbols we'll know where it starts and ends. 215e5a1845fSNamhyung Kim */ 216e5a1845fSNamhyung Kim struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 217e5a1845fSNamhyung Kim { 218e5a1845fSNamhyung Kim struct map *map = calloc(1, (sizeof(*map) + 219e5a1845fSNamhyung Kim (dso->kernel ? sizeof(struct kmap) : 0))); 220e5a1845fSNamhyung Kim if (map != NULL) { 221e5a1845fSNamhyung Kim /* 222e5a1845fSNamhyung Kim * ->end will be filled after we load all the symbols 223e5a1845fSNamhyung Kim */ 224e5a1845fSNamhyung Kim map__init(map, type, start, 0, 0, dso); 225e5a1845fSNamhyung Kim } 226e5a1845fSNamhyung Kim 227e5a1845fSNamhyung Kim return map; 228e5a1845fSNamhyung Kim } 229e5a1845fSNamhyung Kim 230e6ce7126SArnaldo Carvalho de Melo /* 231e6ce7126SArnaldo Carvalho de Melo * Use this and __map__is_kmodule() for map instances that are in 232e6ce7126SArnaldo Carvalho de Melo * machine->kmaps, and thus have map->groups->machine all properly set, to 233e6ce7126SArnaldo Carvalho de Melo * disambiguate between the kernel and modules. 234e6ce7126SArnaldo Carvalho de Melo * 235e6ce7126SArnaldo Carvalho de Melo * When the need arises, introduce map__is_{kernel,kmodule)() that 236e6ce7126SArnaldo Carvalho de Melo * checks (map->groups != NULL && map->groups->machine != NULL && 237e6ce7126SArnaldo Carvalho de Melo * map->dso->kernel) before calling __map__is_{kernel,kmodule}()) 238e6ce7126SArnaldo Carvalho de Melo */ 239e6ce7126SArnaldo Carvalho de Melo bool __map__is_kernel(const struct map *map) 240e6ce7126SArnaldo Carvalho de Melo { 241a5e813c6SArnaldo Carvalho de Melo return __machine__kernel_map(map->groups->machine, map->type) == map; 242e6ce7126SArnaldo Carvalho de Melo } 243e6ce7126SArnaldo Carvalho de Melo 244d3a7c489SArnaldo Carvalho de Melo static void map__exit(struct map *map) 245c338aee8SArnaldo Carvalho de Melo { 246facf3f06SArnaldo Carvalho de Melo BUG_ON(!RB_EMPTY_NODE(&map->rb_node)); 247d3a7c489SArnaldo Carvalho de Melo dso__zput(map->dso); 248d3a7c489SArnaldo Carvalho de Melo } 249d3a7c489SArnaldo Carvalho de Melo 250d3a7c489SArnaldo Carvalho de Melo void map__delete(struct map *map) 251d3a7c489SArnaldo Carvalho de Melo { 252d3a7c489SArnaldo Carvalho de Melo map__exit(map); 253237a7e04SArnaldo Carvalho de Melo free(map); 254c338aee8SArnaldo Carvalho de Melo } 255c338aee8SArnaldo Carvalho de Melo 25684c2cafaSArnaldo Carvalho de Melo void map__put(struct map *map) 25784c2cafaSArnaldo Carvalho de Melo { 25884c2cafaSArnaldo Carvalho de Melo if (map && atomic_dec_and_test(&map->refcnt)) 25984c2cafaSArnaldo Carvalho de Melo map__delete(map); 26084c2cafaSArnaldo Carvalho de Melo } 26184c2cafaSArnaldo Carvalho de Melo 262237a7e04SArnaldo Carvalho de Melo void map__fixup_start(struct map *map) 263c338aee8SArnaldo Carvalho de Melo { 264237a7e04SArnaldo Carvalho de Melo struct rb_root *symbols = &map->dso->symbols[map->type]; 265fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd = rb_first(symbols); 266c338aee8SArnaldo Carvalho de Melo if (nd != NULL) { 267c338aee8SArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 268237a7e04SArnaldo Carvalho de Melo map->start = sym->start; 269c338aee8SArnaldo Carvalho de Melo } 270c338aee8SArnaldo Carvalho de Melo } 271c338aee8SArnaldo Carvalho de Melo 272237a7e04SArnaldo Carvalho de Melo void map__fixup_end(struct map *map) 273c338aee8SArnaldo Carvalho de Melo { 274237a7e04SArnaldo Carvalho de Melo struct rb_root *symbols = &map->dso->symbols[map->type]; 275fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd = rb_last(symbols); 276c338aee8SArnaldo Carvalho de Melo if (nd != NULL) { 277c338aee8SArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 278237a7e04SArnaldo Carvalho de Melo map->end = sym->end; 279c338aee8SArnaldo Carvalho de Melo } 280c338aee8SArnaldo Carvalho de Melo } 281c338aee8SArnaldo Carvalho de Melo 282d70a5402SArnaldo Carvalho de Melo #define DSO__DELETED "(deleted)" 283d70a5402SArnaldo Carvalho de Melo 284be39db9fSArnaldo Carvalho de Melo int map__load(struct map *map) 28566bd8424SArnaldo Carvalho de Melo { 286237a7e04SArnaldo Carvalho de Melo const char *name = map->dso->long_name; 287a128168dSMasami Hiramatsu int nr; 28866bd8424SArnaldo Carvalho de Melo 289237a7e04SArnaldo Carvalho de Melo if (dso__loaded(map->dso, map->type)) 290a128168dSMasami Hiramatsu return 0; 291a128168dSMasami Hiramatsu 292be39db9fSArnaldo Carvalho de Melo nr = dso__load(map->dso, map); 29366bd8424SArnaldo Carvalho de Melo if (nr < 0) { 294237a7e04SArnaldo Carvalho de Melo if (map->dso->has_build_id) { 295b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 2968d06367fSArnaldo Carvalho de Melo 297237a7e04SArnaldo Carvalho de Melo build_id__sprintf(map->dso->build_id, 298237a7e04SArnaldo Carvalho de Melo sizeof(map->dso->build_id), 2998d06367fSArnaldo Carvalho de Melo sbuild_id); 3008d06367fSArnaldo Carvalho de Melo pr_warning("%s with build id %s not found", 30179406cd7SArnaldo Carvalho de Melo name, sbuild_id); 3028d06367fSArnaldo Carvalho de Melo } else 30379406cd7SArnaldo Carvalho de Melo pr_warning("Failed to open %s", name); 30479406cd7SArnaldo Carvalho de Melo 3058d06367fSArnaldo Carvalho de Melo pr_warning(", continuing without symbols\n"); 30679406cd7SArnaldo Carvalho de Melo return -1; 30766bd8424SArnaldo Carvalho de Melo } else if (nr == 0) { 30889fe808aSIngo Molnar #ifdef HAVE_LIBELF_SUPPORT 309d70a5402SArnaldo Carvalho de Melo const size_t len = strlen(name); 310d70a5402SArnaldo Carvalho de Melo const size_t real_len = len - sizeof(DSO__DELETED); 311d70a5402SArnaldo Carvalho de Melo 312d70a5402SArnaldo Carvalho de Melo if (len > sizeof(DSO__DELETED) && 313900b20d5SIngo Molnar strcmp(name + real_len + 1, DSO__DELETED) == 0) { 314e77b15bdSDavid Ahern pr_warning("%.*s was updated (is prelink enabled?). " 315e77b15bdSDavid Ahern "Restart the long running apps that use it!\n", 316900b20d5SIngo Molnar (int)real_len, name); 317900b20d5SIngo Molnar } else { 31879406cd7SArnaldo Carvalho de Melo pr_warning("no symbols found in %s, maybe install " 31979406cd7SArnaldo Carvalho de Melo "a debug package?\n", name); 32066bd8424SArnaldo Carvalho de Melo } 321393be2e3SNamhyung Kim #endif 32279406cd7SArnaldo Carvalho de Melo return -1; 32379406cd7SArnaldo Carvalho de Melo } 32479406cd7SArnaldo Carvalho de Melo 32579406cd7SArnaldo Carvalho de Melo return 0; 32679406cd7SArnaldo Carvalho de Melo } 32779406cd7SArnaldo Carvalho de Melo 328031b84c4SNaveen N. Rao int __weak arch__compare_symbol_names(const char *namea, const char *nameb) 329031b84c4SNaveen N. Rao { 330031b84c4SNaveen N. Rao return strcmp(namea, nameb); 331031b84c4SNaveen N. Rao } 332031b84c4SNaveen N. Rao 333be39db9fSArnaldo Carvalho de Melo struct symbol *map__find_symbol(struct map *map, u64 addr) 33479406cd7SArnaldo Carvalho de Melo { 335be39db9fSArnaldo Carvalho de Melo if (map__load(map) < 0) 33679406cd7SArnaldo Carvalho de Melo return NULL; 33779406cd7SArnaldo Carvalho de Melo 338237a7e04SArnaldo Carvalho de Melo return dso__find_symbol(map->dso, map->type, addr); 33966bd8424SArnaldo Carvalho de Melo } 34066bd8424SArnaldo Carvalho de Melo 341be39db9fSArnaldo Carvalho de Melo struct symbol *map__find_symbol_by_name(struct map *map, const char *name) 34279406cd7SArnaldo Carvalho de Melo { 343be39db9fSArnaldo Carvalho de Melo if (map__load(map) < 0) 34479406cd7SArnaldo Carvalho de Melo return NULL; 34579406cd7SArnaldo Carvalho de Melo 346237a7e04SArnaldo Carvalho de Melo if (!dso__sorted_by_name(map->dso, map->type)) 347237a7e04SArnaldo Carvalho de Melo dso__sort_by_name(map->dso, map->type); 34879406cd7SArnaldo Carvalho de Melo 349237a7e04SArnaldo Carvalho de Melo return dso__find_symbol_by_name(map->dso, map->type, name); 35079406cd7SArnaldo Carvalho de Melo } 35179406cd7SArnaldo Carvalho de Melo 35266671d00SArnaldo Carvalho de Melo struct map *map__clone(struct map *from) 35366e274f3SFrederic Weisbecker { 35466671d00SArnaldo Carvalho de Melo struct map *map = memdup(from, sizeof(*map)); 35566671d00SArnaldo Carvalho de Melo 35666671d00SArnaldo Carvalho de Melo if (map != NULL) { 35766671d00SArnaldo Carvalho de Melo atomic_set(&map->refcnt, 1); 35866671d00SArnaldo Carvalho de Melo RB_CLEAR_NODE(&map->rb_node); 35966671d00SArnaldo Carvalho de Melo dso__get(map->dso); 36066671d00SArnaldo Carvalho de Melo map->groups = NULL; 36166671d00SArnaldo Carvalho de Melo } 36266671d00SArnaldo Carvalho de Melo 36366671d00SArnaldo Carvalho de Melo return map; 36466e274f3SFrederic Weisbecker } 36566e274f3SFrederic Weisbecker 36666e274f3SFrederic Weisbecker int map__overlap(struct map *l, struct map *r) 36766e274f3SFrederic Weisbecker { 36866e274f3SFrederic Weisbecker if (l->start > r->start) { 36966e274f3SFrederic Weisbecker struct map *t = l; 37066e274f3SFrederic Weisbecker l = r; 37166e274f3SFrederic Weisbecker r = t; 37266e274f3SFrederic Weisbecker } 37366e274f3SFrederic Weisbecker 37466e274f3SFrederic Weisbecker if (l->end > r->start) 37566e274f3SFrederic Weisbecker return 1; 37666e274f3SFrederic Weisbecker 37766e274f3SFrederic Weisbecker return 0; 37866e274f3SFrederic Weisbecker } 37966e274f3SFrederic Weisbecker 380237a7e04SArnaldo Carvalho de Melo size_t map__fprintf(struct map *map, FILE *fp) 38166e274f3SFrederic Weisbecker { 3829486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 383237a7e04SArnaldo Carvalho de Melo map->start, map->end, map->pgoff, map->dso->name); 38466e274f3SFrederic Weisbecker } 3857a2b6209SKirill Smelkov 386547a92e0SAkihiro Nagai size_t map__fprintf_dsoname(struct map *map, FILE *fp) 387547a92e0SAkihiro Nagai { 3888f28f19aSFeng Tang const char *dsoname = "[unknown]"; 389547a92e0SAkihiro Nagai 3905eae7d84SArnaldo Carvalho de Melo if (map && map->dso) { 3910bc8d205SAkihiro Nagai if (symbol_conf.show_kernel_path && map->dso->long_name) 3920bc8d205SAkihiro Nagai dsoname = map->dso->long_name; 3935eae7d84SArnaldo Carvalho de Melo else 394547a92e0SAkihiro Nagai dsoname = map->dso->name; 3958f28f19aSFeng Tang } 396547a92e0SAkihiro Nagai 397547a92e0SAkihiro Nagai return fprintf(fp, "%s", dsoname); 398547a92e0SAkihiro Nagai } 399547a92e0SAkihiro Nagai 400cc8fae1dSAdrian Hunter int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, 401cc8fae1dSAdrian Hunter FILE *fp) 402cc8fae1dSAdrian Hunter { 403cc8fae1dSAdrian Hunter char *srcline; 404cc8fae1dSAdrian Hunter int ret = 0; 405cc8fae1dSAdrian Hunter 406cc8fae1dSAdrian Hunter if (map && map->dso) { 407cc8fae1dSAdrian Hunter srcline = get_srcline(map->dso, 40885c116a6SAndi Kleen map__rip_2objdump(map, addr), NULL, true); 409cc8fae1dSAdrian Hunter if (srcline != SRCLINE_UNKNOWN) 410cc8fae1dSAdrian Hunter ret = fprintf(fp, "%s%s", prefix, srcline); 411cc8fae1dSAdrian Hunter free_srcline(srcline); 412cc8fae1dSAdrian Hunter } 413cc8fae1dSAdrian Hunter return ret; 414cc8fae1dSAdrian Hunter } 415cc8fae1dSAdrian Hunter 4161d5077bdSAdrian Hunter /** 4171d5077bdSAdrian Hunter * map__rip_2objdump - convert symbol start address to objdump address. 4181d5077bdSAdrian Hunter * @map: memory map 4191d5077bdSAdrian Hunter * @rip: symbol start address 4201d5077bdSAdrian Hunter * 4217a2b6209SKirill Smelkov * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 4220131c4ecSAdrian Hunter * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is 4230131c4ecSAdrian Hunter * relative to section start. 4241d5077bdSAdrian Hunter * 4251d5077bdSAdrian Hunter * Return: Address suitable for passing to "objdump --start-address=" 4267a2b6209SKirill Smelkov */ 4277a2b6209SKirill Smelkov u64 map__rip_2objdump(struct map *map, u64 rip) 4287a2b6209SKirill Smelkov { 4290131c4ecSAdrian Hunter if (!map->dso->adjust_symbols) 4300131c4ecSAdrian Hunter return rip; 4310131c4ecSAdrian Hunter 4320131c4ecSAdrian Hunter if (map->dso->rel) 4330131c4ecSAdrian Hunter return rip - map->pgoff; 4340131c4ecSAdrian Hunter 435a58f7033SWang Nan /* 436a58f7033SWang Nan * kernel modules also have DSO_TYPE_USER in dso->kernel, 437a58f7033SWang Nan * but all kernel modules are ET_REL, so won't get here. 438a58f7033SWang Nan */ 439a58f7033SWang Nan if (map->dso->kernel == DSO_TYPE_USER) 440a58f7033SWang Nan return rip + map->dso->text_offset; 441a58f7033SWang Nan 4429176753dSAdrian Hunter return map->unmap_ip(map, rip) - map->reloc; 4437a2b6209SKirill Smelkov } 444ee11b90bSKirill Smelkov 4451d5077bdSAdrian Hunter /** 4461d5077bdSAdrian Hunter * map__objdump_2mem - convert objdump address to a memory address. 4471d5077bdSAdrian Hunter * @map: memory map 4481d5077bdSAdrian Hunter * @ip: objdump address 4491d5077bdSAdrian Hunter * 4501d5077bdSAdrian Hunter * Closely related to map__rip_2objdump(), this function takes an address from 4511d5077bdSAdrian Hunter * objdump and converts it to a memory address. Note this assumes that @map 4521d5077bdSAdrian Hunter * contains the address. To be sure the result is valid, check it forwards 4531d5077bdSAdrian Hunter * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip 4541d5077bdSAdrian Hunter * 4551d5077bdSAdrian Hunter * Return: Memory address. 4561d5077bdSAdrian Hunter */ 4571d5077bdSAdrian Hunter u64 map__objdump_2mem(struct map *map, u64 ip) 4581d5077bdSAdrian Hunter { 4591d5077bdSAdrian Hunter if (!map->dso->adjust_symbols) 4601d5077bdSAdrian Hunter return map->unmap_ip(map, ip); 4611d5077bdSAdrian Hunter 4621d5077bdSAdrian Hunter if (map->dso->rel) 4631d5077bdSAdrian Hunter return map->unmap_ip(map, ip + map->pgoff); 4641d5077bdSAdrian Hunter 465a58f7033SWang Nan /* 466a58f7033SWang Nan * kernel modules also have DSO_TYPE_USER in dso->kernel, 467a58f7033SWang Nan * but all kernel modules are ET_REL, so won't get here. 468a58f7033SWang Nan */ 469a58f7033SWang Nan if (map->dso->kernel == DSO_TYPE_USER) 470a58f7033SWang Nan return map->unmap_ip(map, ip - map->dso->text_offset); 471a58f7033SWang Nan 4729176753dSAdrian Hunter return ip + map->reloc; 4731d5077bdSAdrian Hunter } 4741d5077bdSAdrian Hunter 4751eee78aeSArnaldo Carvalho de Melo static void maps__init(struct maps *maps) 4761eee78aeSArnaldo Carvalho de Melo { 4771eee78aeSArnaldo Carvalho de Melo maps->entries = RB_ROOT; 4786a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_init(&maps->lock, NULL); 4791eee78aeSArnaldo Carvalho de Melo } 4801eee78aeSArnaldo Carvalho de Melo 48111246c70SArnaldo Carvalho de Melo void map_groups__init(struct map_groups *mg, struct machine *machine) 482c6e718ffSArnaldo Carvalho de Melo { 483c6e718ffSArnaldo Carvalho de Melo int i; 484c6e718ffSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) { 4851eee78aeSArnaldo Carvalho de Melo maps__init(&mg->maps[i]); 486c6e718ffSArnaldo Carvalho de Melo } 48711246c70SArnaldo Carvalho de Melo mg->machine = machine; 488848cbd25SArnaldo Carvalho de Melo atomic_set(&mg->refcnt, 1); 489c6e718ffSArnaldo Carvalho de Melo } 490c6e718ffSArnaldo Carvalho de Melo 4916a2ffcddSArnaldo Carvalho de Melo static void __maps__purge(struct maps *maps) 492591765fdSArnaldo Carvalho de Melo { 4931eee78aeSArnaldo Carvalho de Melo struct rb_root *root = &maps->entries; 4941eee78aeSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 495591765fdSArnaldo Carvalho de Melo 496591765fdSArnaldo Carvalho de Melo while (next) { 497591765fdSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 498591765fdSArnaldo Carvalho de Melo 499591765fdSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 500facf3f06SArnaldo Carvalho de Melo rb_erase_init(&pos->rb_node, root); 50184c2cafaSArnaldo Carvalho de Melo map__put(pos); 502591765fdSArnaldo Carvalho de Melo } 503591765fdSArnaldo Carvalho de Melo } 504591765fdSArnaldo Carvalho de Melo 5051eee78aeSArnaldo Carvalho de Melo static void maps__exit(struct maps *maps) 5061eee78aeSArnaldo Carvalho de Melo { 5076a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_wrlock(&maps->lock); 5086a2ffcddSArnaldo Carvalho de Melo __maps__purge(maps); 5096a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 5101eee78aeSArnaldo Carvalho de Melo } 5111eee78aeSArnaldo Carvalho de Melo 51298dfd55dSArnaldo Carvalho de Melo void map_groups__exit(struct map_groups *mg) 513591765fdSArnaldo Carvalho de Melo { 514591765fdSArnaldo Carvalho de Melo int i; 515591765fdSArnaldo Carvalho de Melo 5161eee78aeSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 5171eee78aeSArnaldo Carvalho de Melo maps__exit(&mg->maps[i]); 518591765fdSArnaldo Carvalho de Melo } 519591765fdSArnaldo Carvalho de Melo 52029ce3612SAdrian Hunter bool map_groups__empty(struct map_groups *mg) 52129ce3612SAdrian Hunter { 52229ce3612SAdrian Hunter int i; 52329ce3612SAdrian Hunter 52429ce3612SAdrian Hunter for (i = 0; i < MAP__NR_TYPES; ++i) { 52529ce3612SAdrian Hunter if (maps__first(&mg->maps[i])) 52629ce3612SAdrian Hunter return false; 52729ce3612SAdrian Hunter } 52829ce3612SAdrian Hunter 52929ce3612SAdrian Hunter return true; 53029ce3612SAdrian Hunter } 53129ce3612SAdrian Hunter 53211246c70SArnaldo Carvalho de Melo struct map_groups *map_groups__new(struct machine *machine) 53393d5731dSArnaldo Carvalho de Melo { 53493d5731dSArnaldo Carvalho de Melo struct map_groups *mg = malloc(sizeof(*mg)); 53593d5731dSArnaldo Carvalho de Melo 53693d5731dSArnaldo Carvalho de Melo if (mg != NULL) 53711246c70SArnaldo Carvalho de Melo map_groups__init(mg, machine); 53893d5731dSArnaldo Carvalho de Melo 53993d5731dSArnaldo Carvalho de Melo return mg; 54093d5731dSArnaldo Carvalho de Melo } 54193d5731dSArnaldo Carvalho de Melo 54293d5731dSArnaldo Carvalho de Melo void map_groups__delete(struct map_groups *mg) 54393d5731dSArnaldo Carvalho de Melo { 54493d5731dSArnaldo Carvalho de Melo map_groups__exit(mg); 54593d5731dSArnaldo Carvalho de Melo free(mg); 54693d5731dSArnaldo Carvalho de Melo } 54793d5731dSArnaldo Carvalho de Melo 548a26ca671SArnaldo Carvalho de Melo void map_groups__put(struct map_groups *mg) 549a26ca671SArnaldo Carvalho de Melo { 550848cbd25SArnaldo Carvalho de Melo if (mg && atomic_dec_and_test(&mg->refcnt)) 551a26ca671SArnaldo Carvalho de Melo map_groups__delete(mg); 552a26ca671SArnaldo Carvalho de Melo } 553a26ca671SArnaldo Carvalho de Melo 55498dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol(struct map_groups *mg, 5554b8cf846SArnaldo Carvalho de Melo enum map_type type, u64 addr, 556be39db9fSArnaldo Carvalho de Melo struct map **mapp) 5574b8cf846SArnaldo Carvalho de Melo { 55898dfd55dSArnaldo Carvalho de Melo struct map *map = map_groups__find(mg, type, addr); 5594b8cf846SArnaldo Carvalho de Melo 5604afc81cdSMasami Hiramatsu /* Ensure map is loaded before using map->map_ip */ 561be39db9fSArnaldo Carvalho de Melo if (map != NULL && map__load(map) >= 0) { 5627e5e1b14SArnaldo Carvalho de Melo if (mapp != NULL) 5637e5e1b14SArnaldo Carvalho de Melo *mapp = map; 564be39db9fSArnaldo Carvalho de Melo return map__find_symbol(map, map->map_ip(map, addr)); 5657e5e1b14SArnaldo Carvalho de Melo } 5667e5e1b14SArnaldo Carvalho de Melo 5677e5e1b14SArnaldo Carvalho de Melo return NULL; 5687e5e1b14SArnaldo Carvalho de Melo } 5697e5e1b14SArnaldo Carvalho de Melo 570b7f9ff56SArnaldo Carvalho de Melo struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, 571be39db9fSArnaldo Carvalho de Melo struct map **mapp) 5727e5e1b14SArnaldo Carvalho de Melo { 5736a2ffcddSArnaldo Carvalho de Melo struct symbol *sym; 5747e5e1b14SArnaldo Carvalho de Melo struct rb_node *nd; 5757e5e1b14SArnaldo Carvalho de Melo 5766a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_rdlock(&maps->lock); 5776a2ffcddSArnaldo Carvalho de Melo 5786a2ffcddSArnaldo Carvalho de Melo for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) { 5797e5e1b14SArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 5806a2ffcddSArnaldo Carvalho de Melo 581be39db9fSArnaldo Carvalho de Melo sym = map__find_symbol_by_name(pos, name); 5827e5e1b14SArnaldo Carvalho de Melo 5837e5e1b14SArnaldo Carvalho de Melo if (sym == NULL) 5847e5e1b14SArnaldo Carvalho de Melo continue; 5857e5e1b14SArnaldo Carvalho de Melo if (mapp != NULL) 5867e5e1b14SArnaldo Carvalho de Melo *mapp = pos; 5876a2ffcddSArnaldo Carvalho de Melo goto out; 5887e5e1b14SArnaldo Carvalho de Melo } 5894b8cf846SArnaldo Carvalho de Melo 5906a2ffcddSArnaldo Carvalho de Melo sym = NULL; 5916a2ffcddSArnaldo Carvalho de Melo out: 5926a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 5936a2ffcddSArnaldo Carvalho de Melo return sym; 5944b8cf846SArnaldo Carvalho de Melo } 5954b8cf846SArnaldo Carvalho de Melo 596b7f9ff56SArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, 597b7f9ff56SArnaldo Carvalho de Melo enum map_type type, 598b7f9ff56SArnaldo Carvalho de Melo const char *name, 599be39db9fSArnaldo Carvalho de Melo struct map **mapp) 600b7f9ff56SArnaldo Carvalho de Melo { 601be39db9fSArnaldo Carvalho de Melo struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp); 602b7f9ff56SArnaldo Carvalho de Melo 603b7f9ff56SArnaldo Carvalho de Melo return sym; 604b7f9ff56SArnaldo Carvalho de Melo } 605b7f9ff56SArnaldo Carvalho de Melo 606be39db9fSArnaldo Carvalho de Melo int map_groups__find_ams(struct addr_map_symbol *ams) 6074e987712SArnaldo Carvalho de Melo { 60877faf4d0SStephane Eranian if (ams->addr < ams->map->start || ams->addr >= ams->map->end) { 6094e987712SArnaldo Carvalho de Melo if (ams->map->groups == NULL) 6104e987712SArnaldo Carvalho de Melo return -1; 6114e987712SArnaldo Carvalho de Melo ams->map = map_groups__find(ams->map->groups, ams->map->type, 6124e987712SArnaldo Carvalho de Melo ams->addr); 6134e987712SArnaldo Carvalho de Melo if (ams->map == NULL) 6144e987712SArnaldo Carvalho de Melo return -1; 6154e987712SArnaldo Carvalho de Melo } 6164e987712SArnaldo Carvalho de Melo 6174e987712SArnaldo Carvalho de Melo ams->al_addr = ams->map->map_ip(ams->map, ams->addr); 618be39db9fSArnaldo Carvalho de Melo ams->sym = map__find_symbol(ams->map, ams->al_addr); 6194e987712SArnaldo Carvalho de Melo 6204e987712SArnaldo Carvalho de Melo return ams->sym ? 0 : -1; 6214e987712SArnaldo Carvalho de Melo } 6224e987712SArnaldo Carvalho de Melo 6236a2ffcddSArnaldo Carvalho de Melo static size_t maps__fprintf(struct maps *maps, FILE *fp) 624c6e718ffSArnaldo Carvalho de Melo { 6256a2ffcddSArnaldo Carvalho de Melo size_t printed = 0; 626c6e718ffSArnaldo Carvalho de Melo struct rb_node *nd; 627c6e718ffSArnaldo Carvalho de Melo 6286a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_rdlock(&maps->lock); 6296a2ffcddSArnaldo Carvalho de Melo 6306a2ffcddSArnaldo Carvalho de Melo for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) { 631c6e718ffSArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 632c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 633c6e718ffSArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 634c6e718ffSArnaldo Carvalho de Melo if (verbose > 2) { 6356a2ffcddSArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, pos->type, fp); 636c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 637c6e718ffSArnaldo Carvalho de Melo } 638c6e718ffSArnaldo Carvalho de Melo } 639c6e718ffSArnaldo Carvalho de Melo 6406a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 6416a2ffcddSArnaldo Carvalho de Melo 642c6e718ffSArnaldo Carvalho de Melo return printed; 643c6e718ffSArnaldo Carvalho de Melo } 644c6e718ffSArnaldo Carvalho de Melo 6456a2ffcddSArnaldo Carvalho de Melo size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, 6466a2ffcddSArnaldo Carvalho de Melo FILE *fp) 6476a2ffcddSArnaldo Carvalho de Melo { 6486a2ffcddSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 6496a2ffcddSArnaldo Carvalho de Melo return printed += maps__fprintf(&mg->maps[type], fp); 6506a2ffcddSArnaldo Carvalho de Melo } 6516a2ffcddSArnaldo Carvalho de Melo 6525c24b67aSArnaldo Carvalho de Melo size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) 653c6e718ffSArnaldo Carvalho de Melo { 654c6e718ffSArnaldo Carvalho de Melo size_t printed = 0, i; 655c6e718ffSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 656acebd408SJiri Olsa printed += __map_groups__fprintf_maps(mg, i, fp); 657c6e718ffSArnaldo Carvalho de Melo return printed; 658c6e718ffSArnaldo Carvalho de Melo } 659c6e718ffSArnaldo Carvalho de Melo 660cb8382e0SJiri Olsa static void __map_groups__insert(struct map_groups *mg, struct map *map) 661cb8382e0SJiri Olsa { 662cb8382e0SJiri Olsa __maps__insert(&mg->maps[map->type], map); 663cb8382e0SJiri Olsa map->groups = mg; 664cb8382e0SJiri Olsa } 665cb8382e0SJiri Olsa 6666a2ffcddSArnaldo Carvalho de Melo static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) 667c6e718ffSArnaldo Carvalho de Melo { 6686a2ffcddSArnaldo Carvalho de Melo struct rb_root *root; 6696a2ffcddSArnaldo Carvalho de Melo struct rb_node *next; 6700a1eae39SArnaldo Carvalho de Melo int err = 0; 671c6e718ffSArnaldo Carvalho de Melo 6726a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_wrlock(&maps->lock); 6736a2ffcddSArnaldo Carvalho de Melo 6746a2ffcddSArnaldo Carvalho de Melo root = &maps->entries; 6756a2ffcddSArnaldo Carvalho de Melo next = rb_first(root); 6766a2ffcddSArnaldo Carvalho de Melo 677c6e718ffSArnaldo Carvalho de Melo while (next) { 678c6e718ffSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 679c6e718ffSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 680c6e718ffSArnaldo Carvalho de Melo 681c6e718ffSArnaldo Carvalho de Melo if (!map__overlap(pos, map)) 682c6e718ffSArnaldo Carvalho de Melo continue; 683c6e718ffSArnaldo Carvalho de Melo 684c6e718ffSArnaldo Carvalho de Melo if (verbose >= 2) { 68521e8c810SAlexis Berlemont 68621e8c810SAlexis Berlemont if (use_browser) { 68721e8c810SAlexis Berlemont pr_warning("overlapping maps in %s " 68821e8c810SAlexis Berlemont "(disable tui for more info)\n", 68921e8c810SAlexis Berlemont map->dso->name); 69021e8c810SAlexis Berlemont } else { 691c6e718ffSArnaldo Carvalho de Melo fputs("overlapping maps:\n", fp); 692c6e718ffSArnaldo Carvalho de Melo map__fprintf(map, fp); 693c6e718ffSArnaldo Carvalho de Melo map__fprintf(pos, fp); 694c6e718ffSArnaldo Carvalho de Melo } 69521e8c810SAlexis Berlemont } 696c6e718ffSArnaldo Carvalho de Melo 697facf3f06SArnaldo Carvalho de Melo rb_erase_init(&pos->rb_node, root); 698c6e718ffSArnaldo Carvalho de Melo /* 699c6e718ffSArnaldo Carvalho de Melo * Now check if we need to create new maps for areas not 700c6e718ffSArnaldo Carvalho de Melo * overlapped by the new map: 701c6e718ffSArnaldo Carvalho de Melo */ 702c6e718ffSArnaldo Carvalho de Melo if (map->start > pos->start) { 703c6e718ffSArnaldo Carvalho de Melo struct map *before = map__clone(pos); 704c6e718ffSArnaldo Carvalho de Melo 7050a1eae39SArnaldo Carvalho de Melo if (before == NULL) { 7060a1eae39SArnaldo Carvalho de Melo err = -ENOMEM; 70784c2cafaSArnaldo Carvalho de Melo goto put_map; 7080a1eae39SArnaldo Carvalho de Melo } 709c6e718ffSArnaldo Carvalho de Melo 71077faf4d0SStephane Eranian before->end = map->start; 711cb8382e0SJiri Olsa __map_groups__insert(pos->groups, before); 71221e8c810SAlexis Berlemont if (verbose >= 2 && !use_browser) 713c6e718ffSArnaldo Carvalho de Melo map__fprintf(before, fp); 714d91130e9SMasami Hiramatsu map__put(before); 715c6e718ffSArnaldo Carvalho de Melo } 716c6e718ffSArnaldo Carvalho de Melo 717c6e718ffSArnaldo Carvalho de Melo if (map->end < pos->end) { 718c6e718ffSArnaldo Carvalho de Melo struct map *after = map__clone(pos); 719c6e718ffSArnaldo Carvalho de Melo 7200a1eae39SArnaldo Carvalho de Melo if (after == NULL) { 7210a1eae39SArnaldo Carvalho de Melo err = -ENOMEM; 72284c2cafaSArnaldo Carvalho de Melo goto put_map; 7230a1eae39SArnaldo Carvalho de Melo } 724c6e718ffSArnaldo Carvalho de Melo 72577faf4d0SStephane Eranian after->start = map->end; 726cb8382e0SJiri Olsa __map_groups__insert(pos->groups, after); 72721e8c810SAlexis Berlemont if (verbose >= 2 && !use_browser) 728c6e718ffSArnaldo Carvalho de Melo map__fprintf(after, fp); 729d91130e9SMasami Hiramatsu map__put(after); 730c6e718ffSArnaldo Carvalho de Melo } 73184c2cafaSArnaldo Carvalho de Melo put_map: 73284c2cafaSArnaldo Carvalho de Melo map__put(pos); 7330a1eae39SArnaldo Carvalho de Melo 7340a1eae39SArnaldo Carvalho de Melo if (err) 7356a2ffcddSArnaldo Carvalho de Melo goto out; 7366a2ffcddSArnaldo Carvalho de Melo } 7376a2ffcddSArnaldo Carvalho de Melo 7386a2ffcddSArnaldo Carvalho de Melo err = 0; 7396a2ffcddSArnaldo Carvalho de Melo out: 7406a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 7410a1eae39SArnaldo Carvalho de Melo return err; 742c6e718ffSArnaldo Carvalho de Melo } 743c6e718ffSArnaldo Carvalho de Melo 7446a2ffcddSArnaldo Carvalho de Melo int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 7456a2ffcddSArnaldo Carvalho de Melo FILE *fp) 7466a2ffcddSArnaldo Carvalho de Melo { 7476a2ffcddSArnaldo Carvalho de Melo return maps__fixup_overlappings(&mg->maps[map->type], map, fp); 748c6e718ffSArnaldo Carvalho de Melo } 749c6e718ffSArnaldo Carvalho de Melo 750c6e718ffSArnaldo Carvalho de Melo /* 751c6e718ffSArnaldo Carvalho de Melo * XXX This should not really _copy_ te maps, but refcount them. 752c6e718ffSArnaldo Carvalho de Melo */ 7536c502584SJiri Olsa int map_groups__clone(struct thread *thread, 754c6e718ffSArnaldo Carvalho de Melo struct map_groups *parent, enum map_type type) 755c6e718ffSArnaldo Carvalho de Melo { 7566c502584SJiri Olsa struct map_groups *mg = thread->mg; 7576a2ffcddSArnaldo Carvalho de Melo int err = -ENOMEM; 7584bb7123dSArnaldo Carvalho de Melo struct map *map; 7591eee78aeSArnaldo Carvalho de Melo struct maps *maps = &parent->maps[type]; 7604bb7123dSArnaldo Carvalho de Melo 7616a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_rdlock(&maps->lock); 7626a2ffcddSArnaldo Carvalho de Melo 7634bb7123dSArnaldo Carvalho de Melo for (map = maps__first(maps); map; map = map__next(map)) { 764c6e718ffSArnaldo Carvalho de Melo struct map *new = map__clone(map); 765c6e718ffSArnaldo Carvalho de Melo if (new == NULL) 7666a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 7676c502584SJiri Olsa 7686c502584SJiri Olsa err = unwind__prepare_access(thread, new, NULL); 7696c502584SJiri Olsa if (err) 7706c502584SJiri Olsa goto out_unlock; 7716c502584SJiri Olsa 77298dfd55dSArnaldo Carvalho de Melo map_groups__insert(mg, new); 773bae32b50SMasami Hiramatsu map__put(new); 774c6e718ffSArnaldo Carvalho de Melo } 7756a2ffcddSArnaldo Carvalho de Melo 7766a2ffcddSArnaldo Carvalho de Melo err = 0; 7776a2ffcddSArnaldo Carvalho de Melo out_unlock: 7786a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 7796a2ffcddSArnaldo Carvalho de Melo return err; 780c6e718ffSArnaldo Carvalho de Melo } 781c6e718ffSArnaldo Carvalho de Melo 7826a2ffcddSArnaldo Carvalho de Melo static void __maps__insert(struct maps *maps, struct map *map) 7834b8cf846SArnaldo Carvalho de Melo { 7841eee78aeSArnaldo Carvalho de Melo struct rb_node **p = &maps->entries.rb_node; 7854b8cf846SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 7864b8cf846SArnaldo Carvalho de Melo const u64 ip = map->start; 7874b8cf846SArnaldo Carvalho de Melo struct map *m; 7884b8cf846SArnaldo Carvalho de Melo 7894b8cf846SArnaldo Carvalho de Melo while (*p != NULL) { 7904b8cf846SArnaldo Carvalho de Melo parent = *p; 7914b8cf846SArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 7924b8cf846SArnaldo Carvalho de Melo if (ip < m->start) 7934b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_left; 7944b8cf846SArnaldo Carvalho de Melo else 7954b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_right; 7964b8cf846SArnaldo Carvalho de Melo } 7974b8cf846SArnaldo Carvalho de Melo 7984b8cf846SArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 7991eee78aeSArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, &maps->entries); 80084c2cafaSArnaldo Carvalho de Melo map__get(map); 8014b8cf846SArnaldo Carvalho de Melo } 8024b8cf846SArnaldo Carvalho de Melo 8036a2ffcddSArnaldo Carvalho de Melo void maps__insert(struct maps *maps, struct map *map) 8046a2ffcddSArnaldo Carvalho de Melo { 8056a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_wrlock(&maps->lock); 8066a2ffcddSArnaldo Carvalho de Melo __maps__insert(maps, map); 8076a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 8086a2ffcddSArnaldo Carvalho de Melo } 8096a2ffcddSArnaldo Carvalho de Melo 8106a2ffcddSArnaldo Carvalho de Melo static void __maps__remove(struct maps *maps, struct map *map) 811076c6e45SArnaldo Carvalho de Melo { 812facf3f06SArnaldo Carvalho de Melo rb_erase_init(&map->rb_node, &maps->entries); 81384c2cafaSArnaldo Carvalho de Melo map__put(map); 814076c6e45SArnaldo Carvalho de Melo } 815076c6e45SArnaldo Carvalho de Melo 8166a2ffcddSArnaldo Carvalho de Melo void maps__remove(struct maps *maps, struct map *map) 8176a2ffcddSArnaldo Carvalho de Melo { 8186a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_wrlock(&maps->lock); 8196a2ffcddSArnaldo Carvalho de Melo __maps__remove(maps, map); 8206a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 8216a2ffcddSArnaldo Carvalho de Melo } 8226a2ffcddSArnaldo Carvalho de Melo 8231eee78aeSArnaldo Carvalho de Melo struct map *maps__find(struct maps *maps, u64 ip) 8244b8cf846SArnaldo Carvalho de Melo { 8256a2ffcddSArnaldo Carvalho de Melo struct rb_node **p, *parent = NULL; 8264b8cf846SArnaldo Carvalho de Melo struct map *m; 8274b8cf846SArnaldo Carvalho de Melo 8286a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_rdlock(&maps->lock); 8296a2ffcddSArnaldo Carvalho de Melo 8306a2ffcddSArnaldo Carvalho de Melo p = &maps->entries.rb_node; 8314b8cf846SArnaldo Carvalho de Melo while (*p != NULL) { 8324b8cf846SArnaldo Carvalho de Melo parent = *p; 8334b8cf846SArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 8344b8cf846SArnaldo Carvalho de Melo if (ip < m->start) 8354b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_left; 8364955ea22SNamhyung Kim else if (ip >= m->end) 8374b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_right; 8384b8cf846SArnaldo Carvalho de Melo else 8396a2ffcddSArnaldo Carvalho de Melo goto out; 8404b8cf846SArnaldo Carvalho de Melo } 8414b8cf846SArnaldo Carvalho de Melo 8426a2ffcddSArnaldo Carvalho de Melo m = NULL; 8436a2ffcddSArnaldo Carvalho de Melo out: 8446a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 8456a2ffcddSArnaldo Carvalho de Melo return m; 8464b8cf846SArnaldo Carvalho de Melo } 8478e0cf965SAdrian Hunter 8481eee78aeSArnaldo Carvalho de Melo struct map *maps__first(struct maps *maps) 8498e0cf965SAdrian Hunter { 8501eee78aeSArnaldo Carvalho de Melo struct rb_node *first = rb_first(&maps->entries); 8518e0cf965SAdrian Hunter 8528e0cf965SAdrian Hunter if (first) 8538e0cf965SAdrian Hunter return rb_entry(first, struct map, rb_node); 8548e0cf965SAdrian Hunter return NULL; 8558e0cf965SAdrian Hunter } 8568e0cf965SAdrian Hunter 8574d4dee9aSArnaldo Carvalho de Melo struct map *map__next(struct map *map) 8588e0cf965SAdrian Hunter { 8598e0cf965SAdrian Hunter struct rb_node *next = rb_next(&map->rb_node); 8608e0cf965SAdrian Hunter 8618e0cf965SAdrian Hunter if (next) 8628e0cf965SAdrian Hunter return rb_entry(next, struct map, rb_node); 8638e0cf965SAdrian Hunter return NULL; 8648e0cf965SAdrian Hunter } 865ba92732eSWang Nan 866ba92732eSWang Nan struct kmap *map__kmap(struct map *map) 867ba92732eSWang Nan { 868ba92732eSWang Nan if (!map->dso || !map->dso->kernel) { 869ba92732eSWang Nan pr_err("Internal error: map__kmap with a non-kernel map\n"); 870ba92732eSWang Nan return NULL; 871ba92732eSWang Nan } 872ba92732eSWang Nan return (struct kmap *)(map + 1); 873ba92732eSWang Nan } 874ba92732eSWang Nan 875ba92732eSWang Nan struct map_groups *map__kmaps(struct map *map) 876ba92732eSWang Nan { 877ba92732eSWang Nan struct kmap *kmap = map__kmap(map); 878ba92732eSWang Nan 879ba92732eSWang Nan if (!kmap || !kmap->kmaps) { 880ba92732eSWang Nan pr_err("Internal error: map__kmaps with a non-kernel map\n"); 881ba92732eSWang Nan return NULL; 882ba92732eSWang Nan } 883ba92732eSWang Nan return kmap->kmaps; 884ba92732eSWang Nan } 885