Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf dso: Move build_id to dso_id

The dso_id previously contained the major, minor, inode and inode
generation information from a mmap2 event - the inode generation would
be zero when reading from /proc/pid/maps. The build_id was in the
dso. With build ID mmap2 events these fields wouldn't be initialized
which would largely mean the special empty case where any dso would
match for equality. This isn't desirable as if a dso is replaced we
want the comparison to yield a difference.

To support detecting the difference between DSOs based on build_id,
move the build_id out of the DSO and into the dso_id. The dso_id is
also stored in the DSO so nothing is lost. Capture in the dso_id what
parts have been initialized and rename dso_id__inject to
dso_id__improve_id so that it is clear the dso_id is being improved
upon with additional information. With the build_id in the dso_id, use
memcmp to compare for equality.

Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250724163302.596743-7-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
d9f2ecbc eee4b661

+197 -155
+1 -1
tools/perf/builtin-buildid-list.c
··· 31 31 32 32 memset(bid_buf, 0, sizeof(bid_buf)); 33 33 if (dso__has_build_id(dso)) 34 - build_id__snprintf(dso__bid_const(dso), bid_buf, sizeof(bid_buf)); 34 + build_id__snprintf(dso__bid(dso), bid_buf, sizeof(bid_buf)); 35 35 printf("%s %16" PRIx64 " %16" PRIx64, bid_buf, map__start(map), map__end(map)); 36 36 if (dso_long_name != NULL) 37 37 printf(" %s", dso_long_name);
+21 -15
tools/perf/builtin-inject.c
··· 587 587 struct perf_sample *sample, 588 588 struct machine *machine) 589 589 { 590 - struct dso_id id; 591 - struct dso_id *dso_id = NULL; 590 + struct dso_id id = dso_id_empty; 592 591 593 - if (!(event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)) { 592 + if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) { 593 + build_id__init(&id.build_id, event->mmap2.build_id, event->mmap2.build_id_size); 594 + } else { 594 595 id.maj = event->mmap2.maj; 595 596 id.min = event->mmap2.min; 596 597 id.ino = event->mmap2.ino; 597 598 id.ino_generation = event->mmap2.ino_generation; 598 - dso_id = &id; 599 + id.mmap2_valid = true; 600 + id.mmap2_ino_generation_valid = true; 599 601 } 600 602 601 603 return perf_event__repipe_common_mmap( ··· 605 603 event->mmap2.pid, event->mmap2.tid, 606 604 event->mmap2.start, event->mmap2.len, event->mmap2.pgoff, 607 605 event->mmap2.flags, event->mmap2.prot, 608 - event->mmap2.filename, dso_id, 606 + event->mmap2.filename, &id, 609 607 perf_event__process_mmap2); 610 608 } 611 609 ··· 673 671 static int dso__read_build_id(struct dso *dso) 674 672 { 675 673 struct nscookie nsc; 674 + struct build_id bid = { .size = 0, }; 676 675 677 676 if (dso__has_build_id(dso)) 678 677 return 0; 679 678 680 679 mutex_lock(dso__lock(dso)); 681 680 nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 682 - if (filename__read_build_id(dso__long_name(dso), dso__bid(dso)) > 0) 683 - dso__set_has_build_id(dso); 681 + if (filename__read_build_id(dso__long_name(dso), &bid) > 0) 682 + dso__set_build_id(dso, &bid); 684 683 else if (dso__nsinfo(dso)) { 685 684 char *new_name = dso__filename_with_chroot(dso, dso__long_name(dso)); 686 685 687 - if (new_name && filename__read_build_id(new_name, dso__bid(dso)) > 0) 688 - dso__set_has_build_id(dso); 686 + if (new_name && filename__read_build_id(new_name, &bid) > 0) 687 + dso__set_build_id(dso, &bid); 689 688 free(new_name); 690 689 } 691 690 nsinfo__mountns_exit(&nsc); ··· 735 732 struct dso *dso) 736 733 { 737 734 struct str_node *pos; 738 - int bid_len; 739 735 740 736 strlist__for_each_entry(pos, inject->known_build_ids) { 737 + struct build_id bid; 741 738 const char *build_id, *dso_name; 739 + size_t bid_len; 742 740 743 741 build_id = skip_spaces(pos->s); 744 742 dso_name = strchr(build_id, ' '); 745 743 bid_len = dso_name - pos->s; 744 + if (bid_len > sizeof(bid.data)) 745 + bid_len = sizeof(bid.data); 746 746 dso_name = skip_spaces(dso_name); 747 747 if (strcmp(dso__long_name(dso), dso_name)) 748 748 continue; 749 - for (int ix = 0; 2 * ix + 1 < bid_len; ++ix) { 750 - dso__bid(dso)->data[ix] = (hex(build_id[2 * ix]) << 4 | 751 - hex(build_id[2 * ix + 1])); 749 + for (size_t ix = 0; 2 * ix + 1 < bid_len; ++ix) { 750 + bid.data[ix] = (hex(build_id[2 * ix]) << 4 | 751 + hex(build_id[2 * ix + 1])); 752 752 } 753 - dso__bid(dso)->size = bid_len / 2; 754 - dso__set_has_build_id(dso); 753 + bid.size = bid_len / 2; 754 + dso__set_build_id(dso, &bid); 755 755 return true; 756 756 } 757 757 return false;
+9 -2
tools/perf/builtin-report.c
··· 861 861 struct maps__fprintf_task_args *args = data; 862 862 const struct dso *dso = map__dso(map); 863 863 u32 prot = map__prot(map); 864 + const struct dso_id *dso_id = dso__id_const(dso); 864 865 int ret; 866 + char buf[SBUILD_ID_SIZE]; 867 + 868 + if (dso_id->mmap2_valid) 869 + snprintf(buf, sizeof(buf), "%" PRIu64, dso_id->ino); 870 + else 871 + build_id__snprintf(&dso_id->build_id, buf, sizeof(buf)); 865 872 866 873 ret = fprintf(args->fp, 867 - "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", 874 + "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %s %s\n", 868 875 args->indent, "", map__start(map), map__end(map), 869 876 prot & PROT_READ ? 'r' : '-', 870 877 prot & PROT_WRITE ? 'w' : '-', 871 878 prot & PROT_EXEC ? 'x' : '-', 872 879 map__flags(map) ? 's' : 'p', 873 880 map__pgoff(map), 874 - dso__id_const(dso)->ino, dso__name(dso)); 881 + buf, dso__name(dso)); 875 882 876 883 if (ret < 0) 877 884 return ret;
+1 -1
tools/perf/include/perf/perf_dlfilter.h
··· 87 87 __u8 is_64_bit; /* Only valid if dso is not NULL */ 88 88 __u8 is_kernel_ip; /* True if in kernel space */ 89 89 __u32 buildid_size; 90 - __u8 *buildid; 90 + const __u8 *buildid; 91 91 /* Below members are only populated by resolve_ip() */ 92 92 __u8 filtered; /* True if this sample event will be filtered out */ 93 93 const char *comm;
+2 -2
tools/perf/tests/symbols.c
··· 96 96 dso__put(dso); 97 97 98 98 /* Create a dummy map at 0x100000 */ 99 - *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, NULL, 100 - PROT_EXEC, 0, NULL, filename, ti->thread); 99 + *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, &dso_id_empty, 100 + PROT_EXEC, /*flags=*/0, filename, ti->thread); 101 101 if (!*map_p) { 102 102 pr_debug("Failed to create map!"); 103 103 return TEST_FAIL;
+2 -2
tools/perf/util/build-id.c
··· 251 251 if (!dso__has_build_id(dso)) 252 252 return NULL; 253 253 254 - build_id__snprintf(dso__bid_const(dso), sbuild_id, sizeof(sbuild_id)); 254 + build_id__snprintf(dso__bid(dso), sbuild_id, sizeof(sbuild_id)); 255 255 linkname = build_id_cache__linkname(sbuild_id, NULL, 0); 256 256 if (!linkname) 257 257 return NULL; ··· 334 334 } 335 335 336 336 in_kernel = dso__kernel(dso) || is_kernel_module(name, PERF_RECORD_MISC_CPUMODE_UNKNOWN); 337 - return write_buildid(name, name_len, dso__bid(dso), args->machine->pid, 337 + return write_buildid(name, name_len, &dso__id(dso)->build_id, args->machine->pid, 338 338 in_kernel ? args->kmisc : args->umisc, args->fd); 339 339 } 340 340
+60 -49
tools/perf/util/dso.c
··· 217 217 break; 218 218 } 219 219 220 - build_id__snprintf(dso__bid_const(dso), build_id_hex, sizeof(build_id_hex)); 220 + build_id__snprintf(dso__bid(dso), build_id_hex, sizeof(build_id_hex)); 221 221 len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/"); 222 222 snprintf(filename + len, size - len, "%.2s/%s.debug", 223 223 build_id_hex, build_id_hex + 2); ··· 1382 1382 1383 1383 static int __dso_id__cmp(const struct dso_id *a, const struct dso_id *b) 1384 1384 { 1385 - if (a->maj > b->maj) return -1; 1386 - if (a->maj < b->maj) return 1; 1385 + if (a->mmap2_valid && b->mmap2_valid) { 1386 + if (a->maj > b->maj) return -1; 1387 + if (a->maj < b->maj) return 1; 1387 1388 1388 - if (a->min > b->min) return -1; 1389 - if (a->min < b->min) return 1; 1389 + if (a->min > b->min) return -1; 1390 + if (a->min < b->min) return 1; 1390 1391 1391 - if (a->ino > b->ino) return -1; 1392 - if (a->ino < b->ino) return 1; 1393 - 1394 - /* 1395 - * Synthesized MMAP events have zero ino_generation, avoid comparing 1396 - * them with MMAP events with actual ino_generation. 1397 - * 1398 - * I found it harmful because the mismatch resulted in a new 1399 - * dso that did not have a build ID whereas the original dso did have a 1400 - * build ID. The build ID was essential because the object was not found 1401 - * otherwise. - Adrian 1402 - */ 1403 - if (a->ino_generation && b->ino_generation) { 1392 + if (a->ino > b->ino) return -1; 1393 + if (a->ino < b->ino) return 1; 1394 + } 1395 + if (a->mmap2_ino_generation_valid && b->mmap2_ino_generation_valid) { 1404 1396 if (a->ino_generation > b->ino_generation) return -1; 1405 1397 if (a->ino_generation < b->ino_generation) return 1; 1406 1398 } 1407 - 1399 + if (build_id__is_defined(&a->build_id) && build_id__is_defined(&b->build_id)) { 1400 + if (a->build_id.size != b->build_id.size) 1401 + return a->build_id.size < b->build_id.size ? -1 : 1; 1402 + return memcmp(a->build_id.data, b->build_id.data, a->build_id.size); 1403 + } 1408 1404 return 0; 1409 1405 } 1410 1406 1411 - bool dso_id__empty(const struct dso_id *id) 1412 - { 1413 - if (!id) 1414 - return true; 1407 + const struct dso_id dso_id_empty = { 1408 + { 1409 + .maj = 0, 1410 + .min = 0, 1411 + .ino = 0, 1412 + .ino_generation = 0, 1413 + }, 1414 + .mmap2_valid = false, 1415 + .mmap2_ino_generation_valid = false, 1416 + { 1417 + .size = 0, 1418 + } 1419 + }; 1415 1420 1416 - return !id->maj && !id->min && !id->ino && !id->ino_generation; 1417 - } 1418 - 1419 - void __dso__inject_id(struct dso *dso, const struct dso_id *id) 1421 + void __dso__improve_id(struct dso *dso, const struct dso_id *id) 1420 1422 { 1421 1423 struct dsos *dsos = dso__dsos(dso); 1422 1424 struct dso_id *dso_id = dso__id(dso); 1425 + bool changed = false; 1423 1426 1424 1427 /* dsos write lock held by caller. */ 1425 1428 1426 - dso_id->maj = id->maj; 1427 - dso_id->min = id->min; 1428 - dso_id->ino = id->ino; 1429 - dso_id->ino_generation = id->ino_generation; 1430 - 1431 - if (dsos) 1429 + if (id->mmap2_valid && !dso_id->mmap2_valid) { 1430 + dso_id->maj = id->maj; 1431 + dso_id->min = id->min; 1432 + dso_id->ino = id->ino; 1433 + dso_id->mmap2_valid = true; 1434 + changed = true; 1435 + } 1436 + if (id->mmap2_ino_generation_valid && !dso_id->mmap2_ino_generation_valid) { 1437 + dso_id->ino_generation = id->ino_generation; 1438 + dso_id->mmap2_ino_generation_valid = true; 1439 + changed = true; 1440 + } 1441 + if (build_id__is_defined(&id->build_id) && !build_id__is_defined(&dso_id->build_id)) { 1442 + dso_id->build_id = id->build_id; 1443 + changed = true; 1444 + } 1445 + if (changed && dsos) 1432 1446 dsos->sorted = false; 1433 1447 } 1434 1448 1435 1449 int dso_id__cmp(const struct dso_id *a, const struct dso_id *b) 1436 1450 { 1437 - /* 1438 - * The second is always dso->id, so zeroes if not set, assume passing 1439 - * NULL for a means a zeroed id 1440 - */ 1441 - if (dso_id__empty(a) || dso_id__empty(b)) 1451 + if (a == &dso_id_empty || b == &dso_id_empty) { 1452 + /* There is no valid data to compare so the comparison always returns identical. */ 1442 1453 return 0; 1454 + } 1443 1455 1444 1456 return __dso_id__cmp(a, b); 1445 1457 } ··· 1552 1540 dso->loaded = 0; 1553 1541 dso->rel = 0; 1554 1542 dso->sorted_by_name = 0; 1555 - dso->has_build_id = 0; 1556 1543 dso->has_srcline = 1; 1557 1544 dso->a2l_fails = 1; 1558 1545 dso->kernel = DSO_SPACE__USER; ··· 1660 1649 return 0; 1661 1650 } 1662 1651 1663 - void dso__set_build_id(struct dso *dso, struct build_id *bid) 1652 + void dso__set_build_id(struct dso *dso, const struct build_id *bid) 1664 1653 { 1665 - RC_CHK_ACCESS(dso)->bid = *bid; 1666 - RC_CHK_ACCESS(dso)->has_build_id = 1; 1654 + dso__id(dso)->build_id = *bid; 1667 1655 } 1668 1656 1669 - bool dso__build_id_equal(const struct dso *dso, struct build_id *bid) 1657 + bool dso__build_id_equal(const struct dso *dso, const struct build_id *bid) 1670 1658 { 1671 - const struct build_id *dso_bid = dso__bid_const(dso); 1659 + const struct build_id *dso_bid = dso__bid(dso); 1672 1660 1673 1661 if (dso_bid->size > bid->size && dso_bid->size == BUILD_ID_SIZE) { 1674 1662 /* ··· 1686 1676 void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) 1687 1677 { 1688 1678 char path[PATH_MAX]; 1679 + struct build_id bid = { .size = 0, }; 1689 1680 1690 1681 if (machine__is_default_guest(machine)) 1691 1682 return; 1692 1683 sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 1693 - if (sysfs__read_build_id(path, dso__bid(dso)) == 0) 1694 - dso__set_has_build_id(dso); 1684 + sysfs__read_build_id(path, &bid); 1685 + dso__set_build_id(dso, &bid); 1695 1686 } 1696 1687 1697 1688 int dso__kernel_module_get_build_id(struct dso *dso, 1698 1689 const char *root_dir) 1699 1690 { 1700 1691 char filename[PATH_MAX]; 1692 + struct build_id bid = { .size = 0, }; 1701 1693 /* 1702 1694 * kernel module short names are of the form "[module]" and 1703 1695 * we need just "module" here. ··· 1710 1698 "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1711 1699 root_dir, (int)strlen(name) - 1, name); 1712 1700 1713 - if (sysfs__read_build_id(filename, dso__bid(dso)) == 0) 1714 - dso__set_has_build_id(dso); 1715 - 1701 + sysfs__read_build_id(filename, &bid); 1702 + dso__set_build_id(dso, &bid); 1716 1703 return 0; 1717 1704 } 1718 1705
+41 -34
tools/perf/util/dso.h
··· 185 185 #define DSO__DATA_CACHE_SIZE 4096 186 186 #define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1) 187 187 188 - /* 189 - * Data about backing storage DSO, comes from PERF_RECORD_MMAP2 meta events 188 + /** 189 + * struct dso_id 190 + * 191 + * Data about backing storage DSO, comes from PERF_RECORD_MMAP2 meta events, 192 + * reading from /proc/pid/maps or synthesis of build_ids from DSOs. Possibly 193 + * incomplete at any particular use. 190 194 */ 191 195 struct dso_id { 192 - u32 maj; 193 - u32 min; 194 - u64 ino; 195 - u64 ino_generation; 196 + /* Data related to the mmap2 event or read from /proc/pid/maps. */ 197 + struct { 198 + u32 maj; 199 + u32 min; 200 + u64 ino; 201 + u64 ino_generation; 202 + }; 203 + /** @mmap2_valid: Are the maj, min and ino fields valid? */ 204 + bool mmap2_valid; 205 + /** 206 + * @mmap2_ino_generation_valid: Is the ino_generation valid? Generally 207 + * false for /proc/pid/maps mmap event. 208 + */ 209 + bool mmap2_ino_generation_valid; 210 + /** 211 + * @build_id: A possibly populated build_id. build_id__is_defined checks 212 + * whether it is populated. 213 + */ 214 + struct build_id build_id; 196 215 }; 197 216 198 217 struct dso_cache { ··· 262 243 u64 addr; 263 244 struct symbol *symbol; 264 245 } last_find_result; 265 - struct build_id bid; 266 246 u64 text_offset; 267 247 u64 text_end; 268 248 const char *short_name; ··· 294 276 enum dso_swap_type needs_swap:2; 295 277 bool is_kmod:1; 296 278 u8 adjust_symbols:1; 297 - u8 has_build_id:1; 298 279 u8 header_build_id:1; 299 280 u8 has_srcline:1; 300 281 u8 hit:1; ··· 309 292 }; 310 293 311 294 extern struct mutex _dso__data_open_lock; 295 + extern const struct dso_id dso_id_empty; 296 + 297 + int dso_id__cmp(const struct dso_id *a, const struct dso_id *b); 312 298 313 299 /* dso__for_each_symbol - iterate over the symbols of given type 314 300 * ··· 382 362 RC_CHK_ACCESS(dso)->auxtrace_cache = cache; 383 363 } 384 364 385 - static inline struct build_id *dso__bid(struct dso *dso) 386 - { 387 - return &RC_CHK_ACCESS(dso)->bid; 388 - } 389 - 390 - static inline const struct build_id *dso__bid_const(const struct dso *dso) 391 - { 392 - return &RC_CHK_ACCESS(dso)->bid; 393 - } 394 - 395 365 static inline struct dso_bpf_prog *dso__bpf_prog(struct dso *dso) 396 366 { 397 367 return &RC_CHK_ACCESS(dso)->bpf_prog; 398 - } 399 - 400 - static inline bool dso__has_build_id(const struct dso *dso) 401 - { 402 - return RC_CHK_ACCESS(dso)->has_build_id; 403 - } 404 - 405 - static inline void dso__set_has_build_id(struct dso *dso) 406 - { 407 - RC_CHK_ACCESS(dso)->has_build_id = true; 408 368 } 409 369 410 370 static inline bool dso__has_srcline(const struct dso *dso) ··· 460 460 static inline const struct dso_id *dso__id_const(const struct dso *dso) 461 461 { 462 462 return &RC_CHK_ACCESS(dso)->id; 463 + } 464 + 465 + static inline const struct build_id *dso__bid(const struct dso *dso) 466 + { 467 + return &dso__id_const(dso)->build_id; 468 + } 469 + 470 + static inline bool dso__has_build_id(const struct dso *dso) 471 + { 472 + return build_id__is_defined(dso__bid(dso)); 463 473 } 464 474 465 475 static inline struct rb_root_cached *dso__inlined_nodes(struct dso *dso) ··· 709 699 RC_CHK_ACCESS(dso)->text_offset = val; 710 700 } 711 701 712 - int dso_id__cmp(const struct dso_id *a, const struct dso_id *b); 713 - bool dso_id__empty(const struct dso_id *id); 714 - 715 702 struct dso *dso__new_id(const char *name, const struct dso_id *id); 716 703 struct dso *dso__new(const char *name); 717 704 void dso__delete(struct dso *dso); ··· 716 709 int dso__cmp_id(struct dso *a, struct dso *b); 717 710 void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated); 718 711 void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated); 719 - void __dso__inject_id(struct dso *dso, const struct dso_id *id); 712 + void __dso__improve_id(struct dso *dso, const struct dso_id *id); 720 713 721 714 int dso__name_len(const struct dso *dso); 722 715 ··· 746 739 747 740 int dso__swap_init(struct dso *dso, unsigned char eidata); 748 741 749 - void dso__set_build_id(struct dso *dso, struct build_id *bid); 750 - bool dso__build_id_equal(const struct dso *dso, struct build_id *bid); 742 + void dso__set_build_id(struct dso *dso, const struct build_id *bid); 743 + bool dso__build_id_equal(const struct dso *dso, const struct build_id *bid); 751 744 void dso__read_running_kernel_build_id(struct dso *dso, 752 745 struct machine *machine); 753 746 int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
+10 -8
tools/perf/util/dsos.c
··· 72 72 { 73 73 struct dsos__read_build_ids_cb_args *args = data; 74 74 struct nscookie nsc; 75 + struct build_id bid = { .size = 0, }; 75 76 76 77 if (args->with_hits && !dso__hit(dso) && !dso__is_vdso(dso)) 77 78 return 0; ··· 81 80 return 0; 82 81 } 83 82 nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 84 - if (filename__read_build_id(dso__long_name(dso), dso__bid(dso)) > 0) { 83 + if (filename__read_build_id(dso__long_name(dso), &bid) > 0) { 84 + dso__set_build_id(dso, &bid); 85 85 args->have_build_id = true; 86 - dso__set_has_build_id(dso); 87 86 } else if (errno == ENOENT && dso__nsinfo(dso)) { 88 87 char *new_name = dso__filename_with_chroot(dso, dso__long_name(dso)); 89 88 90 - if (new_name && filename__read_build_id(new_name, dso__bid(dso)) > 0) { 89 + if (new_name && filename__read_build_id(new_name, &bid) > 0) { 90 + dso__set_build_id(dso, &bid); 91 91 args->have_build_id = true; 92 - dso__set_has_build_id(dso); 93 92 } 94 93 free(new_name); 95 94 } ··· 287 286 struct dso *res; 288 287 289 288 down_read(&dsos->lock); 290 - res = __dsos__find_id(dsos, name, NULL, cmp_short, /*write_locked=*/false); 289 + res = __dsos__find_id(dsos, name, &dso_id_empty, cmp_short, /*write_locked=*/false); 291 290 up_read(&dsos->lock); 292 291 return res; 293 292 } ··· 345 344 { 346 345 struct dso *dso = __dsos__find_id(dsos, name, id, false, /*write_locked=*/true); 347 346 348 - if (dso && dso_id__empty(dso__id(dso)) && !dso_id__empty(id)) 349 - __dso__inject_id(dso, id); 347 + if (dso) 348 + __dso__improve_id(dso, id); 350 349 351 350 return dso ? dso : __dsos__addnew_id(dsos, name, id); 352 351 } ··· 437 436 438 437 down_write(&dsos->lock); 439 438 440 - dso = __dsos__find_id(dsos, m->name, NULL, /*cmp_short=*/true, /*write_locked=*/true); 439 + dso = __dsos__find_id(dsos, m->name, &dso_id_empty, /*cmp_short=*/true, 440 + /*write_locked=*/true); 441 441 if (dso) { 442 442 up_write(&dsos->lock); 443 443 return dso;
+14 -14
tools/perf/util/machine.c
··· 1731 1731 { 1732 1732 struct thread *thread; 1733 1733 struct map *map; 1734 - struct dso_id dso_id = { 1735 - .maj = event->mmap2.maj, 1736 - .min = event->mmap2.min, 1737 - .ino = event->mmap2.ino, 1738 - .ino_generation = event->mmap2.ino_generation, 1739 - }; 1740 - struct build_id __bid, *bid = NULL; 1734 + struct dso_id dso_id = dso_id_empty; 1741 1735 int ret = 0; 1742 1736 1743 1737 if (dump_trace) 1744 1738 perf_event__fprintf_mmap2(event, stdout); 1745 1739 1746 1740 if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) { 1747 - bid = &__bid; 1748 - build_id__init(bid, event->mmap2.build_id, event->mmap2.build_id_size); 1741 + build_id__init(&dso_id.build_id, event->mmap2.build_id, event->mmap2.build_id_size); 1742 + } else { 1743 + dso_id.maj = event->mmap2.maj; 1744 + dso_id.min = event->mmap2.min; 1745 + dso_id.ino = event->mmap2.ino; 1746 + dso_id.ino_generation = event->mmap2.ino_generation; 1747 + dso_id.mmap2_valid = true; 1748 + dso_id.mmap2_ino_generation_valid = true; 1749 1749 } 1750 1750 1751 1751 if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL || ··· 1757 1757 }; 1758 1758 1759 1759 strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN); 1760 - ret = machine__process_kernel_mmap_event(machine, &xm, bid); 1760 + ret = machine__process_kernel_mmap_event(machine, &xm, &dso_id.build_id); 1761 1761 if (ret < 0) 1762 1762 goto out_problem; 1763 1763 return 0; ··· 1771 1771 map = map__new(machine, event->mmap2.start, 1772 1772 event->mmap2.len, event->mmap2.pgoff, 1773 1773 &dso_id, event->mmap2.prot, 1774 - event->mmap2.flags, bid, 1774 + event->mmap2.flags, 1775 1775 event->mmap2.filename, thread); 1776 1776 1777 1777 if (map == NULL) ··· 1829 1829 prot = PROT_EXEC; 1830 1830 1831 1831 map = map__new(machine, event->mmap.start, 1832 - event->mmap.len, event->mmap.pgoff, 1833 - NULL, prot, 0, NULL, event->mmap.filename, thread); 1832 + event->mmap.len, event->mmap.pgoff, 1833 + &dso_id_empty, prot, /*flags=*/0, event->mmap.filename, thread); 1834 1834 1835 1835 if (map == NULL) 1836 1836 goto out_problem_map; ··· 3192 3192 3193 3193 struct dso *machine__findnew_dso(struct machine *machine, const char *filename) 3194 3194 { 3195 - return machine__findnew_dso_id(machine, filename, NULL); 3195 + return machine__findnew_dso_id(machine, filename, &dso_id_empty); 3196 3196 } 3197 3197 3198 3198 char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
+6 -7
tools/perf/util/map.c
··· 120 120 } 121 121 122 122 struct map *map__new(struct machine *machine, u64 start, u64 len, 123 - u64 pgoff, struct dso_id *id, 124 - u32 prot, u32 flags, struct build_id *bid, 123 + u64 pgoff, const struct dso_id *id, 124 + u32 prot, u32 flags, 125 125 char *filename, struct thread *thread) 126 126 { 127 127 struct map *result; ··· 132 132 map = zalloc(sizeof(*map)); 133 133 if (ADD_RC_CHK(result, map)) { 134 134 char newfilename[PATH_MAX]; 135 - struct dso *dso, *header_bid_dso; 135 + struct dso *dso; 136 136 int anon, no_dso, vdso, android; 137 137 138 138 android = is_android_lib(filename); ··· 189 189 dso__set_nsinfo(dso, nsi); 190 190 mutex_unlock(dso__lock(dso)); 191 191 192 - if (build_id__is_defined(bid)) { 193 - dso__set_build_id(dso, bid); 194 - } else { 192 + if (!build_id__is_defined(&id->build_id)) { 195 193 /* 196 194 * If the mmap event had no build ID, search for an existing dso from the 197 195 * build ID header by name. Otherwise only the dso loaded at the time of 198 196 * reading the header will have the build ID set and all future mmaps will 199 197 * have it missing. 200 198 */ 201 - header_bid_dso = dsos__find(&machine->dsos, filename, false); 199 + struct dso *header_bid_dso = dsos__find(&machine->dsos, filename, false); 200 + 202 201 if (header_bid_dso && dso__header_build_id(header_bid_dso)) { 203 202 dso__set_build_id(dso, dso__bid(header_bid_dso)); 204 203 dso__set_header_build_id(dso, 1);
+2 -3
tools/perf/util/map.h
··· 173 173 __map__for_each_symbol_by_name(map, sym_name, (pos), idx) 174 174 175 175 struct dso_id; 176 - struct build_id; 177 176 178 177 struct map *map__new(struct machine *machine, u64 start, u64 len, 179 - u64 pgoff, struct dso_id *id, u32 prot, u32 flags, 180 - struct build_id *bid, char *filename, struct thread *thread); 178 + u64 pgoff, const struct dso_id *id, u32 prot, u32 flags, 179 + char *filename, struct thread *thread); 181 180 struct map *map__new2(u64 start, struct dso *dso); 182 181 void map__delete(struct map *map); 183 182 struct map *map__clone(struct map *map);
+16 -11
tools/perf/util/sort.c
··· 1746 1746 if (rc) 1747 1747 return rc; 1748 1748 /* 1749 - * Addresses with no major/minor numbers are assumed to be 1749 + * Addresses with no major/minor numbers or build ID are assumed to be 1750 1750 * anonymous in userspace. Sort those on pid then address. 1751 1751 * 1752 1752 * The kernel and non-zero major/minor mapped areas are 1753 1753 * assumed to be unity mapped. Sort those on address. 1754 1754 */ 1755 + if (left->cpumode != PERF_RECORD_MISC_KERNEL && (map__flags(l_map) & MAP_SHARED) == 0) { 1756 + const struct dso_id *dso_id = dso__id_const(l_dso); 1755 1757 1756 - if ((left->cpumode != PERF_RECORD_MISC_KERNEL) && 1757 - (!(map__flags(l_map) & MAP_SHARED)) && !dso__id(l_dso)->maj && !dso__id(l_dso)->min && 1758 - !dso__id(l_dso)->ino && !dso__id(l_dso)->ino_generation) { 1759 - /* userspace anonymous */ 1758 + if (!dso_id->mmap2_valid) 1759 + dso_id = dso__id_const(r_dso); 1760 1760 1761 - if (thread__pid(left->thread) > thread__pid(right->thread)) 1762 - return -1; 1763 - if (thread__pid(left->thread) < thread__pid(right->thread)) 1764 - return 1; 1761 + if (!build_id__is_defined(&dso_id->build_id) && 1762 + (!dso_id->mmap2_valid || (dso_id->maj == 0 && dso_id->min == 0))) { 1763 + /* userspace anonymous */ 1764 + 1765 + if (thread__pid(left->thread) > thread__pid(right->thread)) 1766 + return -1; 1767 + if (thread__pid(left->thread) < thread__pid(right->thread)) 1768 + return 1; 1769 + } 1765 1770 } 1766 1771 1767 1772 addr: ··· 1791 1786 if (he->mem_info) { 1792 1787 struct map *map = mem_info__daddr(he->mem_info)->ms.map; 1793 1788 struct dso *dso = map ? map__dso(map) : NULL; 1789 + const struct dso_id *dso_id = dso ? dso__id_const(dso) : &dso_id_empty; 1794 1790 1795 1791 addr = cl_address(mem_info__daddr(he->mem_info)->al_addr, chk_double_cl); 1796 1792 ms = &mem_info__daddr(he->mem_info)->ms; ··· 1800 1794 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && 1801 1795 map && !(map__prot(map) & PROT_EXEC) && 1802 1796 (map__flags(map) & MAP_SHARED) && 1803 - (dso__id(dso)->maj || dso__id(dso)->min || dso__id(dso)->ino || 1804 - dso__id(dso)->ino_generation)) 1797 + (!dso_id->mmap2_valid || (dso_id->maj == 0 && dso_id->min == 0))) 1805 1798 level = 's'; 1806 1799 else if (!map) 1807 1800 level = 'X';
+12 -6
tools/perf/util/synthetic-events.c
··· 372 372 struct nsinfo *nsi; 373 373 struct nscookie nc; 374 374 struct dso *dso = NULL; 375 - struct dso_id id; 375 + struct dso_id dso_id = dso_id_empty; 376 376 int rc; 377 377 378 378 if (is_kernel) { ··· 380 380 goto out; 381 381 } 382 382 383 - id.maj = event->maj; 384 - id.min = event->min; 385 - id.ino = event->ino; 386 - id.ino_generation = event->ino_generation; 383 + if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) { 384 + build_id__init(&dso_id.build_id, event->build_id, event->build_id_size); 385 + } else { 386 + dso_id.maj = event->maj; 387 + dso_id.min = event->min; 388 + dso_id.ino = event->ino; 389 + dso_id.ino_generation = event->ino_generation; 390 + dso_id.mmap2_valid = true; 391 + dso_id.mmap2_ino_generation_valid = true; 392 + }; 387 393 388 - dso = dsos__findnew_id(&machine->dsos, event->filename, &id); 394 + dso = dsos__findnew_id(&machine->dsos, event->filename, &dso_id); 389 395 if (dso && dso__has_build_id(dso)) { 390 396 bid = *dso__bid(dso); 391 397 rc = 0;