Skip to content

Commit d9f2ecb

Browse files
captain5050namhyung
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Namhyung Kim <[email protected]>
1 parent eee4b66 commit d9f2ecb

File tree

14 files changed

+197
-155
lines changed

14 files changed

+197
-155
lines changed

tools/perf/builtin-buildid-list.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static int buildid__map_cb(struct map *map, void *arg __maybe_unused)
3131

3232
memset(bid_buf, 0, sizeof(bid_buf));
3333
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));
3535
printf("%s %16" PRIx64 " %16" PRIx64, bid_buf, map__start(map), map__end(map));
3636
if (dso_long_name != NULL)
3737
printf(" %s", dso_long_name);

tools/perf/builtin-inject.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -587,23 +587,25 @@ static int perf_event__repipe_mmap2(const struct perf_tool *tool,
587587
struct perf_sample *sample,
588588
struct machine *machine)
589589
{
590-
struct dso_id id;
591-
struct dso_id *dso_id = NULL;
590+
struct dso_id id = dso_id_empty;
592591

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 {
594595
id.maj = event->mmap2.maj;
595596
id.min = event->mmap2.min;
596597
id.ino = event->mmap2.ino;
597598
id.ino_generation = event->mmap2.ino_generation;
598-
dso_id = &id;
599+
id.mmap2_valid = true;
600+
id.mmap2_ino_generation_valid = true;
599601
}
600602

601603
return perf_event__repipe_common_mmap(
602604
tool, event, sample, machine,
603605
event->mmap2.pid, event->mmap2.tid,
604606
event->mmap2.start, event->mmap2.len, event->mmap2.pgoff,
605607
event->mmap2.flags, event->mmap2.prot,
606-
event->mmap2.filename, dso_id,
608+
event->mmap2.filename, &id,
607609
perf_event__process_mmap2);
608610
}
609611

@@ -671,19 +673,20 @@ static int perf_event__repipe_tracing_data(struct perf_session *session,
671673
static int dso__read_build_id(struct dso *dso)
672674
{
673675
struct nscookie nsc;
676+
struct build_id bid = { .size = 0, };
674677

675678
if (dso__has_build_id(dso))
676679
return 0;
677680

678681
mutex_lock(dso__lock(dso));
679682
nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
680-
if (filename__read_build_id(dso__long_name(dso), dso__bid(dso)) > 0)
681-
dso__set_has_build_id(dso);
683+
if (filename__read_build_id(dso__long_name(dso), &bid) > 0)
684+
dso__set_build_id(dso, &bid);
682685
else if (dso__nsinfo(dso)) {
683686
char *new_name = dso__filename_with_chroot(dso, dso__long_name(dso));
684687

685-
if (new_name && filename__read_build_id(new_name, dso__bid(dso)) > 0)
686-
dso__set_has_build_id(dso);
688+
if (new_name && filename__read_build_id(new_name, &bid) > 0)
689+
dso__set_build_id(dso, &bid);
687690
free(new_name);
688691
}
689692
nsinfo__mountns_exit(&nsc);
@@ -732,23 +735,26 @@ static bool perf_inject__lookup_known_build_id(struct perf_inject *inject,
732735
struct dso *dso)
733736
{
734737
struct str_node *pos;
735-
int bid_len;
736738

737739
strlist__for_each_entry(pos, inject->known_build_ids) {
740+
struct build_id bid;
738741
const char *build_id, *dso_name;
742+
size_t bid_len;
739743

740744
build_id = skip_spaces(pos->s);
741745
dso_name = strchr(build_id, ' ');
742746
bid_len = dso_name - pos->s;
747+
if (bid_len > sizeof(bid.data))
748+
bid_len = sizeof(bid.data);
743749
dso_name = skip_spaces(dso_name);
744750
if (strcmp(dso__long_name(dso), dso_name))
745751
continue;
746-
for (int ix = 0; 2 * ix + 1 < bid_len; ++ix) {
747-
dso__bid(dso)->data[ix] = (hex(build_id[2 * ix]) << 4 |
748-
hex(build_id[2 * ix + 1]));
752+
for (size_t ix = 0; 2 * ix + 1 < bid_len; ++ix) {
753+
bid.data[ix] = (hex(build_id[2 * ix]) << 4 |
754+
hex(build_id[2 * ix + 1]));
749755
}
750-
dso__bid(dso)->size = bid_len / 2;
751-
dso__set_has_build_id(dso);
756+
bid.size = bid_len / 2;
757+
dso__set_build_id(dso, &bid);
752758
return true;
753759
}
754760
return false;

tools/perf/builtin-report.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -861,17 +861,24 @@ static int maps__fprintf_task_cb(struct map *map, void *data)
861861
struct maps__fprintf_task_args *args = data;
862862
const struct dso *dso = map__dso(map);
863863
u32 prot = map__prot(map);
864+
const struct dso_id *dso_id = dso__id_const(dso);
864865
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));
865872

866873
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",
868875
args->indent, "", map__start(map), map__end(map),
869876
prot & PROT_READ ? 'r' : '-',
870877
prot & PROT_WRITE ? 'w' : '-',
871878
prot & PROT_EXEC ? 'x' : '-',
872879
map__flags(map) ? 's' : 'p',
873880
map__pgoff(map),
874-
dso__id_const(dso)->ino, dso__name(dso));
881+
buf, dso__name(dso));
875882

876883
if (ret < 0)
877884
return ret;

tools/perf/include/perf/perf_dlfilter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ struct perf_dlfilter_al {
8787
__u8 is_64_bit; /* Only valid if dso is not NULL */
8888
__u8 is_kernel_ip; /* True if in kernel space */
8989
__u32 buildid_size;
90-
__u8 *buildid;
90+
const __u8 *buildid;
9191
/* Below members are only populated by resolve_ip() */
9292
__u8 filtered; /* True if this sample event will be filtered out */
9393
const char *comm;

tools/perf/tests/symbols.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ static int create_map(struct test_info *ti, char *filename, struct map **map_p)
9696
dso__put(dso);
9797

9898
/* 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);
101101
if (!*map_p) {
102102
pr_debug("Failed to create map!");
103103
return TEST_FAIL;

tools/perf/util/build-id.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ char *__dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
251251
if (!dso__has_build_id(dso))
252252
return NULL;
253253

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));
255255
linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
256256
if (!linkname)
257257
return NULL;
@@ -334,7 +334,7 @@ static int machine__write_buildid_table_cb(struct dso *dso, void *data)
334334
}
335335

336336
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,
338338
in_kernel ? args->kmisc : args->umisc, args->fd);
339339
}
340340

tools/perf/util/dso.c

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
217217
break;
218218
}
219219

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));
221221
len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
222222
snprintf(filename + len, size - len, "%.2s/%s.debug",
223223
build_id_hex, build_id_hex + 2);
@@ -1382,64 +1382,76 @@ static void dso__set_long_name_id(struct dso *dso, const char *name, bool name_a
13821382

13831383
static int __dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
13841384
{
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;
13871388

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;
13901391

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) {
14041396
if (a->ino_generation > b->ino_generation) return -1;
14051397
if (a->ino_generation < b->ino_generation) return 1;
14061398
}
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+
}
14081404
return 0;
14091405
}
14101406

1411-
bool dso_id__empty(const struct dso_id *id)
1412-
{
1413-
if (!id)
1414-
return true;
1415-
1416-
return !id->maj && !id->min && !id->ino && !id->ino_generation;
1417-
}
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+
};
14181420

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)
14201422
{
14211423
struct dsos *dsos = dso__dsos(dso);
14221424
struct dso_id *dso_id = dso__id(dso);
1425+
bool changed = false;
14231426

14241427
/* dsos write lock held by caller. */
14251428

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)
14321446
dsos->sorted = false;
14331447
}
14341448

14351449
int dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
14361450
{
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. */
14421453
return 0;
1454+
}
14431455

14441456
return __dso_id__cmp(a, b);
14451457
}
@@ -1540,7 +1552,6 @@ struct dso *dso__new_id(const char *name, const struct dso_id *id)
15401552
dso->loaded = 0;
15411553
dso->rel = 0;
15421554
dso->sorted_by_name = 0;
1543-
dso->has_build_id = 0;
15441555
dso->has_srcline = 1;
15451556
dso->a2l_fails = 1;
15461557
dso->kernel = DSO_SPACE__USER;
@@ -1649,15 +1660,14 @@ int dso__swap_init(struct dso *dso, unsigned char eidata)
16491660
return 0;
16501661
}
16511662

1652-
void dso__set_build_id(struct dso *dso, struct build_id *bid)
1663+
void dso__set_build_id(struct dso *dso, const struct build_id *bid)
16531664
{
1654-
RC_CHK_ACCESS(dso)->bid = *bid;
1655-
RC_CHK_ACCESS(dso)->has_build_id = 1;
1665+
dso__id(dso)->build_id = *bid;
16561666
}
16571667

1658-
bool dso__build_id_equal(const struct dso *dso, struct build_id *bid)
1668+
bool dso__build_id_equal(const struct dso *dso, const struct build_id *bid)
16591669
{
1660-
const struct build_id *dso_bid = dso__bid_const(dso);
1670+
const struct build_id *dso_bid = dso__bid(dso);
16611671

16621672
if (dso_bid->size > bid->size && dso_bid->size == BUILD_ID_SIZE) {
16631673
/*
@@ -1676,18 +1686,20 @@ bool dso__build_id_equal(const struct dso *dso, struct build_id *bid)
16761686
void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
16771687
{
16781688
char path[PATH_MAX];
1689+
struct build_id bid = { .size = 0, };
16791690

16801691
if (machine__is_default_guest(machine))
16811692
return;
16821693
sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
1683-
if (sysfs__read_build_id(path, dso__bid(dso)) == 0)
1684-
dso__set_has_build_id(dso);
1694+
sysfs__read_build_id(path, &bid);
1695+
dso__set_build_id(dso, &bid);
16851696
}
16861697

16871698
int dso__kernel_module_get_build_id(struct dso *dso,
16881699
const char *root_dir)
16891700
{
16901701
char filename[PATH_MAX];
1702+
struct build_id bid = { .size = 0, };
16911703
/*
16921704
* kernel module short names are of the form "[module]" and
16931705
* we need just "module" here.
@@ -1698,9 +1710,8 @@ int dso__kernel_module_get_build_id(struct dso *dso,
16981710
"%s/sys/module/%.*s/notes/.note.gnu.build-id",
16991711
root_dir, (int)strlen(name) - 1, name);
17001712

1701-
if (sysfs__read_build_id(filename, dso__bid(dso)) == 0)
1702-
dso__set_has_build_id(dso);
1703-
1713+
sysfs__read_build_id(filename, &bid);
1714+
dso__set_build_id(dso, &bid);
17041715
return 0;
17051716
}
17061717

0 commit comments

Comments
 (0)