From 39d80a4a5875a649269a15314ed49014ed7bdac9 Mon Sep 17 00:00:00 2001 From: Alan Maguire Date: Thu, 20 Nov 2025 22:42:56 +0000 Subject: [PATCH] libbpf: Add debug messaging in dedup equivalence/identity matching We have seen a number of issues like [1]; failures to deduplicate key kernel data structures like task_struct. These are often hard to debug from pahole even with verbose output, especially when identity/equivalence checks fail deep in a nested struct comparison. Here we add debug messages of the form libbpf: struct 'task_struct' (size 2560 vlen 194) appears equivalent but differs for 23-indexed cand/canon member 'sched_class'/'sched_class': 0 These will be emitted during dedup from pahole when --verbose/-V is specified. This greatly helps identify exactly where dedup failures are experienced. [1] https://lore.kernel.org/bpf/b8e8b560-bce5-414b-846d-0da6d22a9983@oracle.com/ Signed-off-by: Alan Maguire Acked-by: Eduard Zingerman --- tools/lib/bpf/btf.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 84a4b0abc8be..c220ba1fbcab 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -4431,11 +4431,14 @@ static bool btf_dedup_identical_types(struct btf_dedup *d, __u32 id1, __u32 id2, struct btf_type *t1, *t2; int k1, k2; recur: - if (depth <= 0) - return false; - t1 = btf_type_by_id(d->btf, id1); t2 = btf_type_by_id(d->btf, id2); + if (depth <= 0) { + pr_debug("Reached depth limit for identical type comparison for '%s'/'%s'\n", + btf__name_by_offset(d->btf, t1->name_off), + btf__name_by_offset(d->btf, t2->name_off)); + return false; + } k1 = btf_kind(t1); k2 = btf_kind(t2); @@ -4497,8 +4500,18 @@ static bool btf_dedup_identical_types(struct btf_dedup *d, __u32 id1, __u32 id2, for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) { if (m1->type == m2->type) continue; - if (!btf_dedup_identical_types(d, m1->type, m2->type, depth - 1)) + if (!btf_dedup_identical_types(d, m1->type, m2->type, depth - 1)) { + /* provide debug message for named types. */ + if (t1->name_off) { + pr_debug("%s '%s' (size %d vlen %d) appears equal but differs for %d-indexed members '%s'/'%s'\n", + k1 == BTF_KIND_STRUCT ? "struct" : "union", + btf__name_by_offset(d->btf, t1->name_off), + t1->size, btf_vlen(t1), i, + btf__name_by_offset(d->btf, m1->name_off), + btf__name_by_offset(d->btf, m2->name_off)); + } return false; + } } return true; } @@ -4739,8 +4752,21 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, canon_m = btf_members(canon_type); for (i = 0; i < vlen; i++) { eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type); - if (eq <= 0) + if (eq <= 0) { + /* provide debug message for named types only; + * too many anon struct/unions match. + */ + if (cand_type->name_off) { + pr_debug("%s '%s' (size %d vlen %d) appears equivalent but differs for %d-indexed cand/canon member '%s'/'%s': %d\n", + cand_kind == BTF_KIND_STRUCT ? "struct" : "union", + btf__name_by_offset(d->btf, cand_type->name_off), + vlen, cand_type->size, i, + btf__name_by_offset(d->btf, cand_m->name_off), + btf__name_by_offset(d->btf, canon_m->name_off), + eq); + } return eq; + } cand_m++; canon_m++; }