| .. | .. |
|---|
| 9 | 9 | #include <stdio.h> |
|---|
| 10 | 10 | #include <unistd.h> |
|---|
| 11 | 11 | #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ |
|---|
| 12 | +#include "dso.h" |
|---|
| 12 | 13 | #include "map.h" |
|---|
| 14 | +#include "map_symbol.h" |
|---|
| 13 | 15 | #include "thread.h" |
|---|
| 14 | 16 | #include "vdso.h" |
|---|
| 15 | 17 | #include "build-id.h" |
|---|
| 16 | | -#include "util.h" |
|---|
| 17 | 18 | #include "debug.h" |
|---|
| 18 | 19 | #include "machine.h" |
|---|
| 19 | 20 | #include <linux/string.h> |
|---|
| 21 | +#include <linux/zalloc.h> |
|---|
| 20 | 22 | #include "srcline.h" |
|---|
| 21 | 23 | #include "namespaces.h" |
|---|
| 22 | 24 | #include "unwind.h" |
|---|
| 25 | +#include "srccode.h" |
|---|
| 26 | +#include "ui/ui.h" |
|---|
| 23 | 27 | |
|---|
| 24 | 28 | static void __maps__insert(struct maps *maps, struct map *map); |
|---|
| 25 | 29 | |
|---|
| 26 | | -static inline int is_anon_memory(const char *filename, u32 flags) |
|---|
| 27 | | -{ |
|---|
| 28 | | - return flags & MAP_HUGETLB || |
|---|
| 29 | | - !strcmp(filename, "//anon") || |
|---|
| 30 | | - !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) || |
|---|
| 31 | | - !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1); |
|---|
| 32 | | -} |
|---|
| 33 | | - |
|---|
| 34 | | -static inline int is_no_dso_memory(const char *filename) |
|---|
| 35 | | -{ |
|---|
| 36 | | - return !strncmp(filename, "[stack", 6) || |
|---|
| 37 | | - !strncmp(filename, "/SYSV",5) || |
|---|
| 38 | | - !strcmp(filename, "[heap]"); |
|---|
| 39 | | -} |
|---|
| 40 | | - |
|---|
| 41 | 30 | static inline int is_android_lib(const char *filename) |
|---|
| 42 | 31 | { |
|---|
| 43 | | - return !strncmp(filename, "/data/app-lib", 13) || |
|---|
| 44 | | - !strncmp(filename, "/system/lib", 11); |
|---|
| 32 | + return strstarts(filename, "/data/app-lib/") || |
|---|
| 33 | + strstarts(filename, "/system/lib/"); |
|---|
| 45 | 34 | } |
|---|
| 46 | 35 | |
|---|
| 47 | 36 | static inline bool replace_android_lib(const char *filename, char *newfilename) |
|---|
| .. | .. |
|---|
| 61 | 50 | |
|---|
| 62 | 51 | app_abi_length = strlen(app_abi); |
|---|
| 63 | 52 | |
|---|
| 64 | | - if (!strncmp(filename, "/data/app-lib", 13)) { |
|---|
| 53 | + if (strstarts(filename, "/data/app-lib/")) { |
|---|
| 65 | 54 | char *apk_path; |
|---|
| 66 | 55 | |
|---|
| 67 | 56 | if (!app_abi_length) |
|---|
| .. | .. |
|---|
| 85 | 74 | return true; |
|---|
| 86 | 75 | } |
|---|
| 87 | 76 | |
|---|
| 88 | | - if (!strncmp(filename, "/system/lib/", 12)) { |
|---|
| 77 | + if (strstarts(filename, "/system/lib/")) { |
|---|
| 89 | 78 | char *ndk, *app; |
|---|
| 90 | 79 | const char *arch; |
|---|
| 91 | 80 | int ndk_length, app_length; |
|---|
| .. | .. |
|---|
| 134 | 123 | map->map_ip = map__map_ip; |
|---|
| 135 | 124 | map->unmap_ip = map__unmap_ip; |
|---|
| 136 | 125 | RB_CLEAR_NODE(&map->rb_node); |
|---|
| 137 | | - map->groups = NULL; |
|---|
| 138 | 126 | map->erange_warned = false; |
|---|
| 139 | 127 | refcount_set(&map->refcnt, 1); |
|---|
| 140 | 128 | } |
|---|
| 141 | 129 | |
|---|
| 142 | 130 | struct map *map__new(struct machine *machine, u64 start, u64 len, |
|---|
| 143 | | - u64 pgoff, u32 d_maj, u32 d_min, u64 ino, |
|---|
| 144 | | - u64 ino_gen, u32 prot, u32 flags, char *filename, |
|---|
| 131 | + u64 pgoff, struct dso_id *id, |
|---|
| 132 | + u32 prot, u32 flags, char *filename, |
|---|
| 145 | 133 | struct thread *thread) |
|---|
| 146 | 134 | { |
|---|
| 147 | 135 | struct map *map = malloc(sizeof(*map)); |
|---|
| .. | .. |
|---|
| 154 | 142 | int anon, no_dso, vdso, android; |
|---|
| 155 | 143 | |
|---|
| 156 | 144 | android = is_android_lib(filename); |
|---|
| 157 | | - anon = is_anon_memory(filename, flags); |
|---|
| 145 | + anon = is_anon_memory(filename) || flags & MAP_HUGETLB; |
|---|
| 158 | 146 | vdso = is_vdso_map(filename); |
|---|
| 159 | 147 | no_dso = is_no_dso_memory(filename); |
|---|
| 160 | | - |
|---|
| 161 | | - map->maj = d_maj; |
|---|
| 162 | | - map->min = d_min; |
|---|
| 163 | | - map->ino = ino; |
|---|
| 164 | | - map->ino_generation = ino_gen; |
|---|
| 165 | 148 | map->prot = prot; |
|---|
| 166 | 149 | map->flags = flags; |
|---|
| 167 | 150 | nsi = nsinfo__get(thread->nsinfo); |
|---|
| .. | .. |
|---|
| 191 | 174 | pgoff = 0; |
|---|
| 192 | 175 | dso = machine__findnew_vdso(machine, thread); |
|---|
| 193 | 176 | } else |
|---|
| 194 | | - dso = machine__findnew_dso(machine, filename); |
|---|
| 177 | + dso = machine__findnew_dso_id(machine, filename, id); |
|---|
| 195 | 178 | |
|---|
| 196 | 179 | if (dso == NULL) |
|---|
| 197 | 180 | goto out_delete; |
|---|
| .. | .. |
|---|
| 238 | 221 | return map; |
|---|
| 239 | 222 | } |
|---|
| 240 | 223 | |
|---|
| 241 | | -/* |
|---|
| 242 | | - * Use this and __map__is_kmodule() for map instances that are in |
|---|
| 243 | | - * machine->kmaps, and thus have map->groups->machine all properly set, to |
|---|
| 244 | | - * disambiguate between the kernel and modules. |
|---|
| 245 | | - * |
|---|
| 246 | | - * When the need arises, introduce map__is_{kernel,kmodule)() that |
|---|
| 247 | | - * checks (map->groups != NULL && map->groups->machine != NULL && |
|---|
| 248 | | - * map->dso->kernel) before calling __map__is_{kernel,kmodule}()) |
|---|
| 249 | | - */ |
|---|
| 250 | 224 | bool __map__is_kernel(const struct map *map) |
|---|
| 251 | 225 | { |
|---|
| 252 | | - return machine__kernel_map(map->groups->machine) == map; |
|---|
| 226 | + if (!map->dso->kernel) |
|---|
| 227 | + return false; |
|---|
| 228 | + return machine__kernel_map(map__kmaps((struct map *)map)->machine) == map; |
|---|
| 253 | 229 | } |
|---|
| 254 | 230 | |
|---|
| 255 | 231 | bool __map__is_extra_kernel_map(const struct map *map) |
|---|
| .. | .. |
|---|
| 259 | 235 | return kmap && kmap->name[0]; |
|---|
| 260 | 236 | } |
|---|
| 261 | 237 | |
|---|
| 238 | +bool __map__is_bpf_prog(const struct map *map) |
|---|
| 239 | +{ |
|---|
| 240 | + const char *name; |
|---|
| 241 | + |
|---|
| 242 | + if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) |
|---|
| 243 | + return true; |
|---|
| 244 | + |
|---|
| 245 | + /* |
|---|
| 246 | + * If PERF_RECORD_BPF_EVENT is not included, the dso will not have |
|---|
| 247 | + * type of DSO_BINARY_TYPE__BPF_PROG_INFO. In such cases, we can |
|---|
| 248 | + * guess the type based on name. |
|---|
| 249 | + */ |
|---|
| 250 | + name = map->dso->short_name; |
|---|
| 251 | + return name && (strstr(name, "bpf_prog_") == name); |
|---|
| 252 | +} |
|---|
| 253 | + |
|---|
| 254 | +bool __map__is_bpf_image(const struct map *map) |
|---|
| 255 | +{ |
|---|
| 256 | + const char *name; |
|---|
| 257 | + |
|---|
| 258 | + if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) |
|---|
| 259 | + return true; |
|---|
| 260 | + |
|---|
| 261 | + /* |
|---|
| 262 | + * If PERF_RECORD_KSYMBOL is not included, the dso will not have |
|---|
| 263 | + * type of DSO_BINARY_TYPE__BPF_IMAGE. In such cases, we can |
|---|
| 264 | + * guess the type based on name. |
|---|
| 265 | + */ |
|---|
| 266 | + name = map->dso->short_name; |
|---|
| 267 | + return name && is_bpf_image(name); |
|---|
| 268 | +} |
|---|
| 269 | + |
|---|
| 270 | +bool __map__is_ool(const struct map *map) |
|---|
| 271 | +{ |
|---|
| 272 | + return map->dso && map->dso->binary_type == DSO_BINARY_TYPE__OOL; |
|---|
| 273 | +} |
|---|
| 274 | + |
|---|
| 262 | 275 | bool map__has_symbols(const struct map *map) |
|---|
| 263 | 276 | { |
|---|
| 264 | 277 | return dso__has_symbols(map->dso); |
|---|
| .. | .. |
|---|
| 266 | 279 | |
|---|
| 267 | 280 | static void map__exit(struct map *map) |
|---|
| 268 | 281 | { |
|---|
| 269 | | - BUG_ON(!RB_EMPTY_NODE(&map->rb_node)); |
|---|
| 282 | + BUG_ON(refcount_read(&map->refcnt) != 0); |
|---|
| 270 | 283 | dso__zput(map->dso); |
|---|
| 271 | 284 | } |
|---|
| 272 | 285 | |
|---|
| .. | .. |
|---|
| 284 | 297 | |
|---|
| 285 | 298 | void map__fixup_start(struct map *map) |
|---|
| 286 | 299 | { |
|---|
| 287 | | - struct rb_root *symbols = &map->dso->symbols; |
|---|
| 288 | | - struct rb_node *nd = rb_first(symbols); |
|---|
| 300 | + struct rb_root_cached *symbols = &map->dso->symbols; |
|---|
| 301 | + struct rb_node *nd = rb_first_cached(symbols); |
|---|
| 289 | 302 | if (nd != NULL) { |
|---|
| 290 | 303 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); |
|---|
| 291 | 304 | map->start = sym->start; |
|---|
| .. | .. |
|---|
| 294 | 307 | |
|---|
| 295 | 308 | void map__fixup_end(struct map *map) |
|---|
| 296 | 309 | { |
|---|
| 297 | | - struct rb_root *symbols = &map->dso->symbols; |
|---|
| 298 | | - struct rb_node *nd = rb_last(symbols); |
|---|
| 310 | + struct rb_root_cached *symbols = &map->dso->symbols; |
|---|
| 311 | + struct rb_node *nd = rb_last(&symbols->rb_root); |
|---|
| 299 | 312 | if (nd != NULL) { |
|---|
| 300 | 313 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); |
|---|
| 301 | 314 | map->end = sym->end; |
|---|
| .. | .. |
|---|
| 317 | 330 | if (map->dso->has_build_id) { |
|---|
| 318 | 331 | char sbuild_id[SBUILD_ID_SIZE]; |
|---|
| 319 | 332 | |
|---|
| 320 | | - build_id__sprintf(map->dso->build_id, |
|---|
| 321 | | - sizeof(map->dso->build_id), |
|---|
| 322 | | - sbuild_id); |
|---|
| 323 | | - pr_warning("%s with build id %s not found", |
|---|
| 324 | | - name, sbuild_id); |
|---|
| 333 | + build_id__sprintf(&map->dso->bid, sbuild_id); |
|---|
| 334 | + pr_debug("%s with build id %s not found", name, sbuild_id); |
|---|
| 325 | 335 | } else |
|---|
| 326 | | - pr_warning("Failed to open %s", name); |
|---|
| 336 | + pr_debug("Failed to open %s", name); |
|---|
| 327 | 337 | |
|---|
| 328 | | - pr_warning(", continuing without symbols\n"); |
|---|
| 338 | + pr_debug(", continuing without symbols\n"); |
|---|
| 329 | 339 | return -1; |
|---|
| 330 | 340 | } else if (nr == 0) { |
|---|
| 331 | 341 | #ifdef HAVE_LIBELF_SUPPORT |
|---|
| .. | .. |
|---|
| 334 | 344 | |
|---|
| 335 | 345 | if (len > sizeof(DSO__DELETED) && |
|---|
| 336 | 346 | strcmp(name + real_len + 1, DSO__DELETED) == 0) { |
|---|
| 337 | | - pr_warning("%.*s was updated (is prelink enabled?). " |
|---|
| 347 | + pr_debug("%.*s was updated (is prelink enabled?). " |
|---|
| 338 | 348 | "Restart the long running apps that use it!\n", |
|---|
| 339 | 349 | (int)real_len, name); |
|---|
| 340 | 350 | } else { |
|---|
| 341 | | - pr_warning("no symbols found in %s, maybe install " |
|---|
| 342 | | - "a debug package?\n", name); |
|---|
| 351 | + pr_debug("no symbols found in %s, maybe install a debug package?\n", name); |
|---|
| 343 | 352 | } |
|---|
| 344 | 353 | #endif |
|---|
| 345 | 354 | return -1; |
|---|
| .. | .. |
|---|
| 369 | 378 | |
|---|
| 370 | 379 | struct map *map__clone(struct map *from) |
|---|
| 371 | 380 | { |
|---|
| 372 | | - struct map *map = memdup(from, sizeof(*map)); |
|---|
| 381 | + size_t size = sizeof(struct map); |
|---|
| 382 | + struct map *map; |
|---|
| 373 | 383 | |
|---|
| 384 | + if (from->dso && from->dso->kernel) |
|---|
| 385 | + size += sizeof(struct kmap); |
|---|
| 386 | + |
|---|
| 387 | + map = memdup(from, size); |
|---|
| 374 | 388 | if (map != NULL) { |
|---|
| 375 | 389 | refcount_set(&map->refcnt, 1); |
|---|
| 376 | 390 | RB_CLEAR_NODE(&map->rb_node); |
|---|
| 377 | 391 | dso__get(map->dso); |
|---|
| 378 | | - map->groups = NULL; |
|---|
| 379 | 392 | } |
|---|
| 380 | 393 | |
|---|
| 381 | 394 | return map; |
|---|
| .. | .. |
|---|
| 389 | 402 | |
|---|
| 390 | 403 | size_t map__fprintf_dsoname(struct map *map, FILE *fp) |
|---|
| 391 | 404 | { |
|---|
| 405 | + char buf[symbol_conf.pad_output_len_dso + 1]; |
|---|
| 392 | 406 | const char *dsoname = "[unknown]"; |
|---|
| 393 | 407 | |
|---|
| 394 | 408 | if (map && map->dso) { |
|---|
| .. | .. |
|---|
| 396 | 410 | dsoname = map->dso->long_name; |
|---|
| 397 | 411 | else |
|---|
| 398 | 412 | dsoname = map->dso->name; |
|---|
| 413 | + } |
|---|
| 414 | + |
|---|
| 415 | + if (symbol_conf.pad_output_len_dso) { |
|---|
| 416 | + scnprintf_pad(buf, symbol_conf.pad_output_len_dso, "%s", dsoname); |
|---|
| 417 | + dsoname = buf; |
|---|
| 399 | 418 | } |
|---|
| 400 | 419 | |
|---|
| 401 | 420 | return fprintf(fp, "%s", dsoname); |
|---|
| .. | .. |
|---|
| 415 | 434 | |
|---|
| 416 | 435 | if (map && map->dso) { |
|---|
| 417 | 436 | char *srcline = map__srcline(map, addr, NULL); |
|---|
| 418 | | - if (srcline != SRCLINE_UNKNOWN) |
|---|
| 437 | + if (strncmp(srcline, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) |
|---|
| 419 | 438 | ret = fprintf(fp, "%s%s", prefix, srcline); |
|---|
| 420 | 439 | free_srcline(srcline); |
|---|
| 421 | 440 | } |
|---|
| 422 | 441 | return ret; |
|---|
| 442 | +} |
|---|
| 443 | + |
|---|
| 444 | +void srccode_state_free(struct srccode_state *state) |
|---|
| 445 | +{ |
|---|
| 446 | + zfree(&state->srcfile); |
|---|
| 447 | + state->line = 0; |
|---|
| 423 | 448 | } |
|---|
| 424 | 449 | |
|---|
| 425 | 450 | /** |
|---|
| .. | .. |
|---|
| 459 | 484 | * kernel modules also have DSO_TYPE_USER in dso->kernel, |
|---|
| 460 | 485 | * but all kernel modules are ET_REL, so won't get here. |
|---|
| 461 | 486 | */ |
|---|
| 462 | | - if (map->dso->kernel == DSO_TYPE_USER) |
|---|
| 487 | + if (map->dso->kernel == DSO_SPACE__USER) |
|---|
| 463 | 488 | return rip + map->dso->text_offset; |
|---|
| 464 | 489 | |
|---|
| 465 | 490 | return map->unmap_ip(map, rip) - map->reloc; |
|---|
| .. | .. |
|---|
| 489 | 514 | * kernel modules also have DSO_TYPE_USER in dso->kernel, |
|---|
| 490 | 515 | * but all kernel modules are ET_REL, so won't get here. |
|---|
| 491 | 516 | */ |
|---|
| 492 | | - if (map->dso->kernel == DSO_TYPE_USER) |
|---|
| 517 | + if (map->dso->kernel == DSO_SPACE__USER) |
|---|
| 493 | 518 | return map->unmap_ip(map, ip - map->dso->text_offset); |
|---|
| 494 | 519 | |
|---|
| 495 | 520 | return ip + map->reloc; |
|---|
| 496 | 521 | } |
|---|
| 497 | 522 | |
|---|
| 498 | | -static void maps__init(struct maps *maps) |
|---|
| 523 | +void maps__init(struct maps *maps, struct machine *machine) |
|---|
| 499 | 524 | { |
|---|
| 500 | 525 | maps->entries = RB_ROOT; |
|---|
| 501 | 526 | init_rwsem(&maps->lock); |
|---|
| 527 | + maps->machine = machine; |
|---|
| 528 | + maps->last_search_by_name = NULL; |
|---|
| 529 | + maps->nr_maps = 0; |
|---|
| 530 | + maps->maps_by_name = NULL; |
|---|
| 531 | + refcount_set(&maps->refcnt, 1); |
|---|
| 502 | 532 | } |
|---|
| 503 | 533 | |
|---|
| 504 | | -void map_groups__init(struct map_groups *mg, struct machine *machine) |
|---|
| 534 | +static void __maps__free_maps_by_name(struct maps *maps) |
|---|
| 505 | 535 | { |
|---|
| 506 | | - maps__init(&mg->maps); |
|---|
| 507 | | - mg->machine = machine; |
|---|
| 508 | | - refcount_set(&mg->refcnt, 1); |
|---|
| 536 | + /* |
|---|
| 537 | + * Free everything to try to do it from the rbtree in the next search |
|---|
| 538 | + */ |
|---|
| 539 | + zfree(&maps->maps_by_name); |
|---|
| 540 | + maps->nr_maps_allocated = 0; |
|---|
| 541 | +} |
|---|
| 542 | + |
|---|
| 543 | +void maps__insert(struct maps *maps, struct map *map) |
|---|
| 544 | +{ |
|---|
| 545 | + down_write(&maps->lock); |
|---|
| 546 | + __maps__insert(maps, map); |
|---|
| 547 | + ++maps->nr_maps; |
|---|
| 548 | + |
|---|
| 549 | + if (map->dso && map->dso->kernel) { |
|---|
| 550 | + struct kmap *kmap = map__kmap(map); |
|---|
| 551 | + |
|---|
| 552 | + if (kmap) |
|---|
| 553 | + kmap->kmaps = maps; |
|---|
| 554 | + else |
|---|
| 555 | + pr_err("Internal error: kernel dso with non kernel map\n"); |
|---|
| 556 | + } |
|---|
| 557 | + |
|---|
| 558 | + |
|---|
| 559 | + /* |
|---|
| 560 | + * If we already performed some search by name, then we need to add the just |
|---|
| 561 | + * inserted map and resort. |
|---|
| 562 | + */ |
|---|
| 563 | + if (maps->maps_by_name) { |
|---|
| 564 | + if (maps->nr_maps > maps->nr_maps_allocated) { |
|---|
| 565 | + int nr_allocate = maps->nr_maps * 2; |
|---|
| 566 | + struct map **maps_by_name = realloc(maps->maps_by_name, nr_allocate * sizeof(map)); |
|---|
| 567 | + |
|---|
| 568 | + if (maps_by_name == NULL) { |
|---|
| 569 | + __maps__free_maps_by_name(maps); |
|---|
| 570 | + up_write(&maps->lock); |
|---|
| 571 | + return; |
|---|
| 572 | + } |
|---|
| 573 | + |
|---|
| 574 | + maps->maps_by_name = maps_by_name; |
|---|
| 575 | + maps->nr_maps_allocated = nr_allocate; |
|---|
| 576 | + } |
|---|
| 577 | + maps->maps_by_name[maps->nr_maps - 1] = map; |
|---|
| 578 | + __maps__sort_by_name(maps); |
|---|
| 579 | + } |
|---|
| 580 | + up_write(&maps->lock); |
|---|
| 581 | +} |
|---|
| 582 | + |
|---|
| 583 | +static void __maps__remove(struct maps *maps, struct map *map) |
|---|
| 584 | +{ |
|---|
| 585 | + rb_erase_init(&map->rb_node, &maps->entries); |
|---|
| 586 | + map__put(map); |
|---|
| 587 | +} |
|---|
| 588 | + |
|---|
| 589 | +void maps__remove(struct maps *maps, struct map *map) |
|---|
| 590 | +{ |
|---|
| 591 | + down_write(&maps->lock); |
|---|
| 592 | + if (maps->last_search_by_name == map) |
|---|
| 593 | + maps->last_search_by_name = NULL; |
|---|
| 594 | + |
|---|
| 595 | + __maps__remove(maps, map); |
|---|
| 596 | + --maps->nr_maps; |
|---|
| 597 | + if (maps->maps_by_name) |
|---|
| 598 | + __maps__free_maps_by_name(maps); |
|---|
| 599 | + up_write(&maps->lock); |
|---|
| 509 | 600 | } |
|---|
| 510 | 601 | |
|---|
| 511 | 602 | static void __maps__purge(struct maps *maps) |
|---|
| 512 | 603 | { |
|---|
| 513 | | - struct rb_root *root = &maps->entries; |
|---|
| 514 | | - struct rb_node *next = rb_first(root); |
|---|
| 604 | + struct map *pos, *next; |
|---|
| 515 | 605 | |
|---|
| 516 | | - while (next) { |
|---|
| 517 | | - struct map *pos = rb_entry(next, struct map, rb_node); |
|---|
| 518 | | - |
|---|
| 519 | | - next = rb_next(&pos->rb_node); |
|---|
| 520 | | - rb_erase_init(&pos->rb_node, root); |
|---|
| 606 | + maps__for_each_entry_safe(maps, pos, next) { |
|---|
| 607 | + rb_erase_init(&pos->rb_node, &maps->entries); |
|---|
| 521 | 608 | map__put(pos); |
|---|
| 522 | 609 | } |
|---|
| 523 | 610 | } |
|---|
| 524 | 611 | |
|---|
| 525 | | -static void maps__exit(struct maps *maps) |
|---|
| 612 | +void maps__exit(struct maps *maps) |
|---|
| 526 | 613 | { |
|---|
| 527 | 614 | down_write(&maps->lock); |
|---|
| 528 | 615 | __maps__purge(maps); |
|---|
| 529 | 616 | up_write(&maps->lock); |
|---|
| 530 | 617 | } |
|---|
| 531 | 618 | |
|---|
| 532 | | -void map_groups__exit(struct map_groups *mg) |
|---|
| 619 | +bool maps__empty(struct maps *maps) |
|---|
| 533 | 620 | { |
|---|
| 534 | | - maps__exit(&mg->maps); |
|---|
| 621 | + return !maps__first(maps); |
|---|
| 535 | 622 | } |
|---|
| 536 | 623 | |
|---|
| 537 | | -bool map_groups__empty(struct map_groups *mg) |
|---|
| 624 | +struct maps *maps__new(struct machine *machine) |
|---|
| 538 | 625 | { |
|---|
| 539 | | - return !maps__first(&mg->maps); |
|---|
| 626 | + struct maps *maps = zalloc(sizeof(*maps)); |
|---|
| 627 | + |
|---|
| 628 | + if (maps != NULL) |
|---|
| 629 | + maps__init(maps, machine); |
|---|
| 630 | + |
|---|
| 631 | + return maps; |
|---|
| 540 | 632 | } |
|---|
| 541 | 633 | |
|---|
| 542 | | -struct map_groups *map_groups__new(struct machine *machine) |
|---|
| 634 | +void maps__delete(struct maps *maps) |
|---|
| 543 | 635 | { |
|---|
| 544 | | - struct map_groups *mg = malloc(sizeof(*mg)); |
|---|
| 545 | | - |
|---|
| 546 | | - if (mg != NULL) |
|---|
| 547 | | - map_groups__init(mg, machine); |
|---|
| 548 | | - |
|---|
| 549 | | - return mg; |
|---|
| 636 | + maps__exit(maps); |
|---|
| 637 | + unwind__finish_access(maps); |
|---|
| 638 | + free(maps); |
|---|
| 550 | 639 | } |
|---|
| 551 | 640 | |
|---|
| 552 | | -void map_groups__delete(struct map_groups *mg) |
|---|
| 641 | +void maps__put(struct maps *maps) |
|---|
| 553 | 642 | { |
|---|
| 554 | | - map_groups__exit(mg); |
|---|
| 555 | | - free(mg); |
|---|
| 643 | + if (maps && refcount_dec_and_test(&maps->refcnt)) |
|---|
| 644 | + maps__delete(maps); |
|---|
| 556 | 645 | } |
|---|
| 557 | 646 | |
|---|
| 558 | | -void map_groups__put(struct map_groups *mg) |
|---|
| 647 | +struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) |
|---|
| 559 | 648 | { |
|---|
| 560 | | - if (mg && refcount_dec_and_test(&mg->refcnt)) |
|---|
| 561 | | - map_groups__delete(mg); |
|---|
| 562 | | -} |
|---|
| 563 | | - |
|---|
| 564 | | -struct symbol *map_groups__find_symbol(struct map_groups *mg, |
|---|
| 565 | | - u64 addr, struct map **mapp) |
|---|
| 566 | | -{ |
|---|
| 567 | | - struct map *map = map_groups__find(mg, addr); |
|---|
| 649 | + struct map *map = maps__find(maps, addr); |
|---|
| 568 | 650 | |
|---|
| 569 | 651 | /* Ensure map is loaded before using map->map_ip */ |
|---|
| 570 | 652 | if (map != NULL && map__load(map) >= 0) { |
|---|
| .. | .. |
|---|
| 583 | 665 | return ip >= map->start && ip < map->end; |
|---|
| 584 | 666 | } |
|---|
| 585 | 667 | |
|---|
| 586 | | -struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, |
|---|
| 587 | | - struct map **mapp) |
|---|
| 668 | +struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp) |
|---|
| 588 | 669 | { |
|---|
| 589 | 670 | struct symbol *sym; |
|---|
| 590 | | - struct rb_node *nd; |
|---|
| 671 | + struct map *pos; |
|---|
| 591 | 672 | |
|---|
| 592 | 673 | down_read(&maps->lock); |
|---|
| 593 | 674 | |
|---|
| 594 | | - for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) { |
|---|
| 595 | | - struct map *pos = rb_entry(nd, struct map, rb_node); |
|---|
| 596 | | - |
|---|
| 675 | + maps__for_each_entry(maps, pos) { |
|---|
| 597 | 676 | sym = map__find_symbol_by_name(pos, name); |
|---|
| 598 | 677 | |
|---|
| 599 | 678 | if (sym == NULL) |
|---|
| .. | .. |
|---|
| 613 | 692 | return sym; |
|---|
| 614 | 693 | } |
|---|
| 615 | 694 | |
|---|
| 616 | | -struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, |
|---|
| 617 | | - const char *name, |
|---|
| 618 | | - struct map **mapp) |
|---|
| 695 | +int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) |
|---|
| 619 | 696 | { |
|---|
| 620 | | - return maps__find_symbol_by_name(&mg->maps, name, mapp); |
|---|
| 621 | | -} |
|---|
| 622 | | - |
|---|
| 623 | | -int map_groups__find_ams(struct addr_map_symbol *ams) |
|---|
| 624 | | -{ |
|---|
| 625 | | - if (ams->addr < ams->map->start || ams->addr >= ams->map->end) { |
|---|
| 626 | | - if (ams->map->groups == NULL) |
|---|
| 697 | + if (ams->addr < ams->ms.map->start || ams->addr >= ams->ms.map->end) { |
|---|
| 698 | + if (maps == NULL) |
|---|
| 627 | 699 | return -1; |
|---|
| 628 | | - ams->map = map_groups__find(ams->map->groups, ams->addr); |
|---|
| 629 | | - if (ams->map == NULL) |
|---|
| 700 | + ams->ms.map = maps__find(maps, ams->addr); |
|---|
| 701 | + if (ams->ms.map == NULL) |
|---|
| 630 | 702 | return -1; |
|---|
| 631 | 703 | } |
|---|
| 632 | 704 | |
|---|
| 633 | | - ams->al_addr = ams->map->map_ip(ams->map, ams->addr); |
|---|
| 634 | | - ams->sym = map__find_symbol(ams->map, ams->al_addr); |
|---|
| 705 | + ams->al_addr = ams->ms.map->map_ip(ams->ms.map, ams->addr); |
|---|
| 706 | + ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr); |
|---|
| 635 | 707 | |
|---|
| 636 | | - return ams->sym ? 0 : -1; |
|---|
| 708 | + return ams->ms.sym ? 0 : -1; |
|---|
| 637 | 709 | } |
|---|
| 638 | 710 | |
|---|
| 639 | | -static size_t maps__fprintf(struct maps *maps, FILE *fp) |
|---|
| 711 | +size_t maps__fprintf(struct maps *maps, FILE *fp) |
|---|
| 640 | 712 | { |
|---|
| 641 | 713 | size_t printed = 0; |
|---|
| 642 | | - struct rb_node *nd; |
|---|
| 714 | + struct map *pos; |
|---|
| 643 | 715 | |
|---|
| 644 | 716 | down_read(&maps->lock); |
|---|
| 645 | 717 | |
|---|
| 646 | | - for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) { |
|---|
| 647 | | - struct map *pos = rb_entry(nd, struct map, rb_node); |
|---|
| 718 | + maps__for_each_entry(maps, pos) { |
|---|
| 648 | 719 | printed += fprintf(fp, "Map:"); |
|---|
| 649 | 720 | printed += map__fprintf(pos, fp); |
|---|
| 650 | 721 | if (verbose > 2) { |
|---|
| .. | .. |
|---|
| 658 | 729 | return printed; |
|---|
| 659 | 730 | } |
|---|
| 660 | 731 | |
|---|
| 661 | | -size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) |
|---|
| 662 | | -{ |
|---|
| 663 | | - return maps__fprintf(&mg->maps, fp); |
|---|
| 664 | | -} |
|---|
| 665 | | - |
|---|
| 666 | | -static void __map_groups__insert(struct map_groups *mg, struct map *map) |
|---|
| 667 | | -{ |
|---|
| 668 | | - __maps__insert(&mg->maps, map); |
|---|
| 669 | | - map->groups = mg; |
|---|
| 670 | | -} |
|---|
| 671 | | - |
|---|
| 672 | | -static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) |
|---|
| 732 | +int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) |
|---|
| 673 | 733 | { |
|---|
| 674 | 734 | struct rb_root *root; |
|---|
| 675 | 735 | struct rb_node *next, *first; |
|---|
| .. | .. |
|---|
| 712 | 772 | if (verbose >= 2) { |
|---|
| 713 | 773 | |
|---|
| 714 | 774 | if (use_browser) { |
|---|
| 715 | | - pr_warning("overlapping maps in %s " |
|---|
| 716 | | - "(disable tui for more info)\n", |
|---|
| 775 | + pr_debug("overlapping maps in %s (disable tui for more info)\n", |
|---|
| 717 | 776 | map->dso->name); |
|---|
| 718 | 777 | } else { |
|---|
| 719 | 778 | fputs("overlapping maps:\n", fp); |
|---|
| .. | .. |
|---|
| 736 | 795 | } |
|---|
| 737 | 796 | |
|---|
| 738 | 797 | before->end = map->start; |
|---|
| 739 | | - __map_groups__insert(pos->groups, before); |
|---|
| 798 | + __maps__insert(maps, before); |
|---|
| 740 | 799 | if (verbose >= 2 && !use_browser) |
|---|
| 741 | 800 | map__fprintf(before, fp); |
|---|
| 742 | 801 | map__put(before); |
|---|
| .. | .. |
|---|
| 753 | 812 | after->start = map->end; |
|---|
| 754 | 813 | after->pgoff += map->end - pos->start; |
|---|
| 755 | 814 | assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end)); |
|---|
| 756 | | - __map_groups__insert(pos->groups, after); |
|---|
| 815 | + __maps__insert(maps, after); |
|---|
| 757 | 816 | if (verbose >= 2 && !use_browser) |
|---|
| 758 | 817 | map__fprintf(after, fp); |
|---|
| 759 | 818 | map__put(after); |
|---|
| .. | .. |
|---|
| 771 | 830 | return err; |
|---|
| 772 | 831 | } |
|---|
| 773 | 832 | |
|---|
| 774 | | -int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, |
|---|
| 775 | | - FILE *fp) |
|---|
| 776 | | -{ |
|---|
| 777 | | - return maps__fixup_overlappings(&mg->maps, map, fp); |
|---|
| 778 | | -} |
|---|
| 779 | | - |
|---|
| 780 | 833 | /* |
|---|
| 781 | 834 | * XXX This should not really _copy_ te maps, but refcount them. |
|---|
| 782 | 835 | */ |
|---|
| 783 | | -int map_groups__clone(struct thread *thread, struct map_groups *parent) |
|---|
| 836 | +int maps__clone(struct thread *thread, struct maps *parent) |
|---|
| 784 | 837 | { |
|---|
| 785 | | - struct map_groups *mg = thread->mg; |
|---|
| 786 | | - int err = -ENOMEM; |
|---|
| 838 | + struct maps *maps = thread->maps; |
|---|
| 839 | + int err; |
|---|
| 787 | 840 | struct map *map; |
|---|
| 788 | | - struct maps *maps = &parent->maps; |
|---|
| 789 | 841 | |
|---|
| 790 | | - down_read(&maps->lock); |
|---|
| 842 | + down_read(&parent->lock); |
|---|
| 791 | 843 | |
|---|
| 792 | | - for (map = maps__first(maps); map; map = map__next(map)) { |
|---|
| 844 | + maps__for_each_entry(parent, map) { |
|---|
| 793 | 845 | struct map *new = map__clone(map); |
|---|
| 794 | | - if (new == NULL) |
|---|
| 795 | | - goto out_unlock; |
|---|
| 796 | 846 | |
|---|
| 797 | | - err = unwind__prepare_access(thread, new, NULL); |
|---|
| 847 | + if (new == NULL) { |
|---|
| 848 | + err = -ENOMEM; |
|---|
| 849 | + goto out_unlock; |
|---|
| 850 | + } |
|---|
| 851 | + |
|---|
| 852 | + err = unwind__prepare_access(maps, new, NULL); |
|---|
| 798 | 853 | if (err) |
|---|
| 799 | 854 | goto out_unlock; |
|---|
| 800 | 855 | |
|---|
| 801 | | - map_groups__insert(mg, new); |
|---|
| 856 | + maps__insert(maps, new); |
|---|
| 802 | 857 | map__put(new); |
|---|
| 803 | 858 | } |
|---|
| 804 | 859 | |
|---|
| 805 | 860 | err = 0; |
|---|
| 806 | 861 | out_unlock: |
|---|
| 807 | | - up_read(&maps->lock); |
|---|
| 862 | + up_read(&parent->lock); |
|---|
| 808 | 863 | return err; |
|---|
| 809 | 864 | } |
|---|
| 810 | 865 | |
|---|
| .. | .. |
|---|
| 829 | 884 | map__get(map); |
|---|
| 830 | 885 | } |
|---|
| 831 | 886 | |
|---|
| 832 | | -void maps__insert(struct maps *maps, struct map *map) |
|---|
| 833 | | -{ |
|---|
| 834 | | - down_write(&maps->lock); |
|---|
| 835 | | - __maps__insert(maps, map); |
|---|
| 836 | | - up_write(&maps->lock); |
|---|
| 837 | | -} |
|---|
| 838 | | - |
|---|
| 839 | | -static void __maps__remove(struct maps *maps, struct map *map) |
|---|
| 840 | | -{ |
|---|
| 841 | | - rb_erase_init(&map->rb_node, &maps->entries); |
|---|
| 842 | | - map__put(map); |
|---|
| 843 | | -} |
|---|
| 844 | | - |
|---|
| 845 | | -void maps__remove(struct maps *maps, struct map *map) |
|---|
| 846 | | -{ |
|---|
| 847 | | - down_write(&maps->lock); |
|---|
| 848 | | - __maps__remove(maps, map); |
|---|
| 849 | | - up_write(&maps->lock); |
|---|
| 850 | | -} |
|---|
| 851 | | - |
|---|
| 852 | 887 | struct map *maps__find(struct maps *maps, u64 ip) |
|---|
| 853 | 888 | { |
|---|
| 854 | | - struct rb_node **p, *parent = NULL; |
|---|
| 889 | + struct rb_node *p; |
|---|
| 855 | 890 | struct map *m; |
|---|
| 856 | 891 | |
|---|
| 857 | 892 | down_read(&maps->lock); |
|---|
| 858 | 893 | |
|---|
| 859 | | - p = &maps->entries.rb_node; |
|---|
| 860 | | - while (*p != NULL) { |
|---|
| 861 | | - parent = *p; |
|---|
| 862 | | - m = rb_entry(parent, struct map, rb_node); |
|---|
| 894 | + p = maps->entries.rb_node; |
|---|
| 895 | + while (p != NULL) { |
|---|
| 896 | + m = rb_entry(p, struct map, rb_node); |
|---|
| 863 | 897 | if (ip < m->start) |
|---|
| 864 | | - p = &(*p)->rb_left; |
|---|
| 898 | + p = p->rb_left; |
|---|
| 865 | 899 | else if (ip >= m->end) |
|---|
| 866 | | - p = &(*p)->rb_right; |
|---|
| 900 | + p = p->rb_right; |
|---|
| 867 | 901 | else |
|---|
| 868 | 902 | goto out; |
|---|
| 869 | 903 | } |
|---|
| .. | .. |
|---|
| 883 | 917 | return NULL; |
|---|
| 884 | 918 | } |
|---|
| 885 | 919 | |
|---|
| 886 | | -struct map *map__next(struct map *map) |
|---|
| 920 | +static struct map *__map__next(struct map *map) |
|---|
| 887 | 921 | { |
|---|
| 888 | 922 | struct rb_node *next = rb_next(&map->rb_node); |
|---|
| 889 | 923 | |
|---|
| 890 | 924 | if (next) |
|---|
| 891 | 925 | return rb_entry(next, struct map, rb_node); |
|---|
| 892 | 926 | return NULL; |
|---|
| 927 | +} |
|---|
| 928 | + |
|---|
| 929 | +struct map *map__next(struct map *map) |
|---|
| 930 | +{ |
|---|
| 931 | + return map ? __map__next(map) : NULL; |
|---|
| 893 | 932 | } |
|---|
| 894 | 933 | |
|---|
| 895 | 934 | struct kmap *__map__kmap(struct map *map) |
|---|
| .. | .. |
|---|
| 908 | 947 | return kmap; |
|---|
| 909 | 948 | } |
|---|
| 910 | 949 | |
|---|
| 911 | | -struct map_groups *map__kmaps(struct map *map) |
|---|
| 950 | +struct maps *map__kmaps(struct map *map) |
|---|
| 912 | 951 | { |
|---|
| 913 | 952 | struct kmap *kmap = map__kmap(map); |
|---|
| 914 | 953 | |
|---|