.. | .. |
---|
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 | |
---|