From nobody Thu Sep 24 15:10:09 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AF54541E5C; Tue, 22 Sep 2026 12:26:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080011; cv=none; b=gBG3djLPgAO1nR+4nv7kwf24XJzPO+x+ofCwrUrk2yLm6+cqSGCSPupJ2djj+27WKql6g4QAuHnk02upETg34aoJKRJ++Lk931HzEW6lxAJ1kG73NwzbW+mCjcK7RTEvnQ09mMVmFy0vvJbmVoV/ieEZqATnAEndS6Nn+Q1Z1wo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080011; c=relaxed/simple; bh=Rfu25ECYoXI+/kV6W/6MswO7S3WKPtf1KRF1KE0xcMM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=U0ZNEuZBuTC6OjhfEDtroURfNjFwQ7TBaBFIw7JvQ9PGoz3S8M4eeZoAD0a+G5trFGhg+0h3HfH1o7VlvJboDgtan2Gwh7zqxnWKtNYbcO3V70TCfabASAR+iolKXEO85P0boY32JqzYu9uJrqIJlUwdVFz+Ef/J8meoLR4ZIzQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=k0oVngKQ; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="k0oVngKQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 169801F00893; Tue, 22 Sep 2026 12:26:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790080009; bh=/o0j4IyBit4x0M7siaLpgTimP2fXGHf326McwkQdspI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=k0oVngKQr0aG+xAvigp9v8+hZAx5z6jiv8b4E4zb2QwvZsdj7+E2xLLDa7id1s352 BxjTR93iDaheVPLE8WFb6OPcwxXwAR2wd9yu5OZLQYb0jlPO7WUad6srsvFznwwgq6 7g7DaVif5RiMrMgSiEAPQ6/69ykgnHOUaMHRpIxBwsiLc0ysprIQWAbO9px2PWq5UL pLx6bDhN0aX1L/vrbTYapVQMZWhqlSEM/EBTdUFRHpsr0K6yNGhwcD0BVLBIQqz8qA FI68DC0os4TjkuJfdCmV0rIC7q5s3T7Ow7Oj59ZID+R9EmEp6PL5oSYMAlx5SVM4BN RXLaC9vMzeAjQ== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH v3 1/7] perf dwarf-aux: Bound the type chases for broken debug info Date: Tue, 22 Sep 2026 14:26:17 +0200 Message-ID: <20260922122623.1029132-2-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922122623.1029132-1-acme@kernel.org> References: <20260922122623.1029132-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo A DIE that is not what it looks like, e.g. one parsed at an offset that is not the start of a DIE, can have a DW_AT_type that refers back to itself, making the typedef/qualifier chases in die_get_real_type() and die_get_pointer_type() spin forever, and the same for the type name recursion in die_get_typename_from_type(); 'perf report -s type' did exactly that on the dwz compressed debug info of zlib-ng (libz.so.1). No sane chain of typedefs and qualifiers is 32 DIEs long, so give up on the type with a pr_debug instead of hanging. Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 88 ++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index d7160f87ac7d7ab3..b5ffeea54446408d 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -266,16 +266,29 @@ Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die = *die_mem) return NULL; } =20 +/* + * A DIE that is not what it looks like, e.g. one parsed at an offset + * that is not the start of a DIE, can have a DW_AT_type that refers + * back to itself, making these chases spin forever: bound them and + * report, instead of hanging. + */ +#define MAX_TYPE_CHASE 32 + /* Get a type die, but skip qualifiers */ Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) { - int tag; + int tag, chase =3D 0; =20 do { vr_die =3D die_get_type(vr_die, die_mem); if (!vr_die) - break; + return NULL; tag =3D dwarf_tag(vr_die); + if (++chase > MAX_TYPE_CHASE) { + pr_debug("DWARF: qualifier chase limit reached at DIE 0x%lx\n", + (unsigned long)dwarf_dieoffset(vr_die)); + return NULL; + } } while (tag =3D=3D DW_TAG_const_type || tag =3D=3D DW_TAG_restrict_type || tag =3D=3D DW_TAG_volatile_type || @@ -296,8 +309,15 @@ Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwar= f_Die *die_mem) */ Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) { + int chase =3D 0; + do { vr_die =3D __die_get_real_type(vr_die, die_mem); + if (++chase > MAX_TYPE_CHASE) { + pr_debug("DWARF: typedef chase limit reached at DIE 0x%lx\n", + vr_die ? (unsigned long)dwarf_dieoffset(vr_die) : 0); + return NULL; + } } while (vr_die && dwarf_tag(vr_die) =3D=3D DW_TAG_typedef); =20 return vr_die; @@ -314,7 +334,7 @@ Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_D= ie *die_mem) */ Dwarf_Die *die_get_pointer_type(Dwarf_Die *type_die, Dwarf_Die *die_mem) { - int tag; + int tag, chase =3D 0; =20 do { tag =3D dwarf_tag(type_die); @@ -324,6 +344,11 @@ Dwarf_Die *die_get_pointer_type(Dwarf_Die *type_die, D= warf_Die *die_mem) tag !=3D DW_TAG_restrict_type && tag !=3D DW_TAG_volatile_type && tag !=3D DW_TAG_shared_type) return NULL; + if (++chase > MAX_TYPE_CHASE) { + pr_debug("DWARF: pointer type chase limit reached at DIE 0x%lx\n", + (unsigned long)dwarf_dieoffset(type_die)); + return NULL; + } type_die =3D die_get_type(type_die, die_mem); } while (type_die); =20 @@ -1118,17 +1143,25 @@ Dwarf_Die *die_find_member(Dwarf_Die *st_die, const= char *name, die_mem); } =20 -/** - * die_get_typename_from_type - Get the name of given type DIE - * @type_die: a type DIE - * @buf: a strbuf for result type name - * - * Get the name of @type_die and stores it to @buf. Return 0 if succeeded. - * and Return -ENOENT if failed to find type name. - * Note that the result will stores typedef name if possible, and stores - * "*(function_type)" if the type is a function pointer. +/* + * The name follows DW_AT_type, so a self-referring DIE makes this + * recurse forever: bound it like the chases above. */ -int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf) +static int __die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf= *buf, + int depth); + +static int __die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf, int d= epth) +{ + Dwarf_Die type; + + if (__die_get_real_type(vr_die, &type) =3D=3D NULL) + return -ENOENT; + + return __die_get_typename_from_type(&type, buf, depth); +} + +static int __die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf= *buf, + int depth) { int tag, ret; const char *tmp =3D ""; @@ -1155,7 +1188,12 @@ int die_get_typename_from_type(Dwarf_Die *type_die, = struct strbuf *buf) /* Write a base name */ return strbuf_addf(buf, "%s%s", tmp, name ?: ""); } - ret =3D die_get_typename(type_die, buf); + if (depth >=3D MAX_TYPE_CHASE) { + pr_debug("DWARF: type name recursion limit reached at DIE 0x%lx\n", + (unsigned long)dwarf_dieoffset(type_die)); + return -ENOENT; + } + ret =3D __die_get_typename(type_die, buf, depth + 1); if (ret < 0) { /* void pointer has no type attribute */ if (tag =3D=3D DW_TAG_pointer_type && ret =3D=3D -ENOENT) @@ -1166,6 +1204,21 @@ int die_get_typename_from_type(Dwarf_Die *type_die, = struct strbuf *buf) return strbuf_addstr(buf, tmp); } =20 +/** + * die_get_typename_from_type - Get the name of given type DIE + * @type_die: a type DIE + * @buf: a strbuf for result type name + * + * Get the name of @type_die and stores it to @buf. Return 0 if succeeded. + * and Return -ENOENT if failed to find type name. + * Note that the result will stores typedef name if possible, and stores + * "*(function_type)" if the type is a function pointer. + */ +int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf) +{ + return __die_get_typename_from_type(type_die, buf, 0); +} + /** * die_get_typename - Get the name of given variable DIE * @vr_die: a variable DIE @@ -1178,12 +1231,7 @@ int die_get_typename_from_type(Dwarf_Die *type_die, = struct strbuf *buf) */ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) { - Dwarf_Die type; - - if (__die_get_real_type(vr_die, &type) =3D=3D NULL) - return -ENOENT; - - return die_get_typename_from_type(&type, buf); + return __die_get_typename(vr_die, buf, 0); } =20 /** --=20 2.55.0 From nobody Thu Sep 24 15:10:09 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C348853FD54; Tue, 22 Sep 2026 12:26:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080021; cv=none; b=Kw2SUsfLxxVOHHJ6W5kPlnP+kaIqMDOUa+/XDqPS7ADcyaLutJ/btFcxMk31nxwuchszy2NQ4EEx2WrpKxzOAAZDWHSZ354nDsrtYYbYLrRQ4jh2exJXmUFGDvKvynWWAkpOScX1uv4pXAzsgYVYMfh+ER91L6gH5wmroAe1vHk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080021; c=relaxed/simple; bh=iLULfbRqUOyy8sxLo0T8y0j5XmaveAsYQ7eAm5INT10=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mJ3be95txj9D1WcKZhLPou/nL5WkJW5unF6yP8xC8xzMXnENmFhaqLF6fvYBBQcoiHl5ApQ26w/47uUTmbf+Ka5ugoMFkM1n3yHuC+LlNGboJR302RJ/D+kFAB61DY5ZPqdths1XpxiJ01jclox8Btv98bkyRH4A71EstFnQVTQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eK9BaU/T; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eK9BaU/T" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9CB551F000FF; Tue, 22 Sep 2026 12:26:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790080018; bh=tlvNEhVstLx2sb9EmNRJfJzlsNgRVw9d8I//uWSkWn8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=eK9BaU/TCOdkhg/awzIQ+3YbI7kOHCXhh/gaYWMWd2bX3P8gtEbY0nzuAR76V+yLn pZCkk0pVeMUHzsWE1hd/G1v7es5zbLszsHdvwNfPeGRjYTvgDr1nHoUWE/HnYpX+/7 6W2eTto2M2JbxDZoVPhDHdlAh9iQ07B24YjS/npRlsfEgJuLZNhEMwECupKO6sMxi8 L1ctsOvTRen0mogpsC64KWOl8184SFidQYVnZ1JDHz0jSqmrbN+MNrd+Nfvfo9rb18 uCmij+aIN8I2csOV5FXRCWEAqVnObAz1mwBdc2pehVx6eReNAS7PZJCexC8e3kgBW1 jlNABlF7tm0hw== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH v3 2/7] perf dwarf-aux: Add die_same_file() and die_get_type_die() Date: Tue, 22 Sep 2026 14:26:18 +0200 Message-ID: <20260922122623.1029132-3-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922122623.1029132-1-acme@kernel.org> References: <20260922122623.1029132-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo dwarf_dieoffset() is relative to the file the DIE is in, so an offset saved by die_collect_vars()/die_collect_global_vars() is only meaningful in that file: add die_same_file(), comparing the Dwarf each DIE's CU belongs to, to record which file that is, and die_get_type_die() to resolve the offset in it, with the saved tag as a sanity check. Resolving the offset in the main file instead parses whatever is at it when it came from the dwz common file. dwarf_cu_getdwarf() is new in elfutils 0.160, so the libdw feature test probes for it and Makefile.config says 0.160. Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/feature/test-libdw.c | 13 ++++++- tools/perf/Makefile.config | 2 +- tools/perf/util/dwarf-aux.c | 62 ++++++++++++++++++++++++++++++-- tools/perf/util/dwarf-aux.h | 17 +++++++++ 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/tools/build/feature/test-libdw.c b/tools/build/feature/test-li= bdw.c index aabd63ca76b4d7e6..0ebe7bb4adf9d0bc 100644 --- a/tools/build/feature/test-libdw.c +++ b/tools/build/feature/test-libdw.c @@ -49,8 +49,19 @@ int test_elfutils(void) return 0; } =20 +/* + * dwarf_cu_getdwarf() needs elfutils 0.160: take its address only, so + * that older versions fail the probe instead of the link. + */ +int test_libdw_cu_getdwarf(void) +{ + void *sym =3D (void *)dwarf_cu_getdwarf; + + return sym =3D=3D NULL; +} + int main(void) { return test_libdw() + test_libdw_unwind() + test_libdw_getlocations() + - test_libdw_getcfi() + test_elfutils(); + test_libdw_getcfi() + test_libdw_cu_getdwarf() + test_elfutils(); } diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 4ee7393a39f91d85..0585d71e3182c6dd 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -470,7 +470,7 @@ else else ifneq ($(feature-libdw), 1) ifndef NO_LIBDW - $(warning No libdw.h found or old libdw.h found or elfutils is old= er than 0.157, disables dwarf support. Please install new elfutils-devel/li= bdw-dev) + $(warning No libdw.h found or old libdw.h found or elfutils is old= er than 0.160, disables dwarf support. Please install new elfutils-devel/li= bdw-dev) NO_LIBDW :=3D 1 endif endif # Dwarf support diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index b5ffeea54446408d..de14d18a9d2f87d8 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1680,6 +1680,16 @@ Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_d= ie, Dwarf_Addr addr, return result; } =20 +/* + * Whether two DIEs live in the same debug file, i.e. whether their + * offsets have to be resolved in the same file: dwarf_dieoffset() is + * relative to the file the DIE is in. + */ +bool die_same_file(Dwarf_Die *die_a, Dwarf_Die *die_b) +{ + return dwarf_cu_getdwarf(die_a->cu) =3D=3D dwarf_cu_getdwarf(die_b->cu); +} + static int __die_collect_vars_cb(Dwarf_Die *die_mem, void *arg) { struct die_var_type **var_types =3D arg; @@ -1724,6 +1734,8 @@ static int __die_collect_vars_cb(Dwarf_Die *die_mem, = void *arg) vt->is_reg_var_addr =3D true; =20 vt->die_off =3D dwarf_dieoffset(&type_die); + vt->die_tag =3D dwarf_tag(&type_die); + vt->from_alt =3D !die_same_file(die_mem, &type_die); vt->addr =3D start; vt->end =3D end; vt->has_range =3D (end !=3D 0 || start !=3D 0); @@ -1743,7 +1755,8 @@ static int __die_collect_vars_cb(Dwarf_Die *die_mem, = void *arg) * * Save all variables and parameters in the @sc_die and save them to @var_= types. * The @var_types is a singly-linked list containing type and location inf= o. - * Actual type can be retrieved using dwarf_offdie() with 'die_off' later. + * Actual type can be retrieved using die_get_type_die() with 'die_off', + * 'die_tag' and 'from_alt' later. * * Callers should free @var_types. */ @@ -1789,6 +1802,8 @@ static int __die_collect_global_vars_cb(Dwarf_Die *di= e_mem, void *arg) return DIE_FIND_CB_END; =20 vt->die_off =3D dwarf_dieoffset(&type_die); + vt->die_tag =3D dwarf_tag(&type_die); + vt->from_alt =3D !die_same_file(die_mem, &type_die); vt->addr =3D ops->number; vt->end =3D 0; vt->has_range =3D false; @@ -1800,6 +1815,48 @@ static int __die_collect_global_vars_cb(Dwarf_Die *d= ie_mem, void *arg) return DIE_FIND_CB_SIBLING; } =20 +/** + * die_get_type_die - Get a type DIE saved by die_collect_vars() + * @dbg: the main debug info + * @die_off: offset of the type DIE, from dwarf_dieoffset() + * @die_tag: tag that DIE had when the offset was saved + * @from_alt: whether the type DIE is in the dwz alt file + * @die_mem: where to store the resulting DIE + * + * Resolve @die_off in the file it was recorded as belonging to: the + * offset is only meaningful there, and there is deliberately no + * fallback, as resolving an alt file offset in the main file parses + * whatever is at it. @die_tag is a sanity check. + */ +Dwarf_Die *die_get_type_die(Dwarf *dbg, u64 die_off, int die_tag, bool fro= m_alt, + Dwarf_Die *die_mem) +{ + Dwarf *target =3D dbg; + Dwarf_Die die; + + if (from_alt) { + /* + * No fallback to the main file: resolving an alt file offset in it + * does not fail, it parses whatever is there as a DIE. + */ + target =3D dwarf_getalt(dbg); + if (target =3D=3D NULL) { + pr_debug("DWARF: no alt (dwz) debug file to resolve the type DIE at off= set 0x%lx in\n", + (unsigned long)die_off); + return NULL; + } + } + + if (dwarf_offdie(target, die_off, &die) && dwarf_tag(&die) =3D=3D die_tag= ) { + *die_mem =3D die; + return die_mem; + } + + pr_debug("DWARF: no DIE with tag %d at offset 0x%lx in the %s debug file\= n", + die_tag, (unsigned long)die_off, from_alt ? "alt" : "main"); + return NULL; +} + /** * die_collect_global_vars - Save all global variables * @cu_die: a CU DIE @@ -1807,7 +1864,8 @@ static int __die_collect_global_vars_cb(Dwarf_Die *di= e_mem, void *arg) * * Save all global variables in the @cu_die and save them to @var_types. * The @var_types is a singly-linked list containing type and location inf= o. - * Actual type can be retrieved using dwarf_offdie() with 'die_off' later. + * Actual type can be retrieved using die_get_type_die() with 'die_off', + * 'die_tag' and 'from_alt' later. * * Callers should free @var_types. */ diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 161f0bf980b6ee6a..299ffddab0358baa 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -152,6 +152,8 @@ int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dw= arf_Die **scopes); struct die_var_type { struct die_var_type *next; u64 die_off; + int die_tag; + bool from_alt; /* die_off is relative to the alt (dwz) file */ u64 addr; u64 end; /* end address of location range */ int reg; @@ -183,6 +185,21 @@ Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die= , Dwarf_Addr addr, /* Save all variables and parameters in this scope */ void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types); =20 +/* + * Get the type DIE saved by die_collect_vars()/die_collect_global_vars(). + * + * Those save the dwarf_dieoffset() of the type DIE, which is relative + * to the file it lives in, so @from_alt, recorded when the offset was + * saved, says which file to resolve it in; @die_tag is a sanity check. + * Resolving an alt file offset in the main file parses whatever is at + * it, which is what hung 'perf report -s type'. + */ +Dwarf_Die *die_get_type_die(Dwarf *dbg, u64 die_off, int die_tag, bool fro= m_alt, + Dwarf_Die *die_mem); + +/* Whether two DIEs live in the same debug file */ +bool die_same_file(Dwarf_Die *die_a, Dwarf_Die *die_b); + /* Save all global variables in this CU */ void die_collect_global_vars(Dwarf_Die *cu_die, struct die_var_type **var_= types); =20 --=20 2.55.0 From nobody Thu Sep 24 15:10:09 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F9655427E3; Tue, 22 Sep 2026 12:27:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080028; cv=none; b=ChOhZTIiJiZgV37HQOIls6BW2jJu9Dau+qXFdPzidjdSu6ccMbsCiWb7QsurJew98LLQ1aWhXnAaZ/NhvMmOEGw4ZDeywRdI1KgOn38UUUsx2h+ZvN7N5N4JKhNXBSFOvswavLtVBivx6v2PT8tysS/OaIN2+A5qSYakORekYw8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080028; c=relaxed/simple; bh=xxiNI9/2opfYfVGzSxTkvlXp/rdC3Wlpw3sG77B3pCI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rZB3CQdtRQ9vFaZmGDU1OrHT8WOlQRDcplHNmZ7RIGfU1wNxgX0tDFG6+7LQXDWXcovIZ0Yxhfak0kxvgsHNuHdGN3DkNRlgJvYtR1iEwUg916eNx0YYenCLwirhZKVAWcB5lixcYzYxrfpugMeIPa01D1XG5jMprTzQwlYNhjc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=H8UrGSXK; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="H8UrGSXK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 59BCA1F00893; Tue, 22 Sep 2026 12:26:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790080026; bh=aPv8hIl8pd1TTEMUwVRyvbk3noeKznEU2ge1GAQyBvY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=H8UrGSXKsdxMTmukNvtmU6s7L2q0/byaF/qD2FAIhoJn/It+MVG9xJ+mbbh/h8zVl 8XwpNB3kC4xdR1Ap+Y5tk+nqfmQxZ58T/SDWAnyqlzVZUPFjKISh4NEXhi3i000ByX jv5trbj+2txn4KkG5uDZSwatC5L4OnhUsEsDVsr3cMgPfFpn+b9fctmuu6TEHbGkjF T/Or+o5EDxgDuX3fxzWxwJ7wb3FpgieyfjSPYkwyMgR6Qjt7GjGc7JNB2G6rjgCOg+ ozH+6JZg/bNYRo5+8Gq6phQPPPaFHrsHKq8hkEyuXbZvpvxUBTTXU9ANE9mK8l0e51 DEeivmvuJlwYA== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH v3 3/7] perf annotate-data: Resolve type DIEs in the debug file they came from Date: Tue, 22 Sep 2026 14:26:19 +0200 Message-ID: <20260922122623.1029132-4-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922122623.1029132-1-acme@kernel.org> References: <20260922122623.1029132-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo 'perf report -s type' hangs, burning all of a CPU with no output, when resolving a hist entry on the dwz compressed debug info of libz.so.1 (zlib-ng): die_collect_vars() saves the dwarf_dieoffset() of the type DIE, which is relative to the file it lives in - the dwz alt file for the types shared by more than one CU - and update_var_state() resolves that offset in the main debug file, where it parses whatever is at that offset, here a typedef whose DW_AT_type refers to itself, making the type chase spin forever. Record whether the type DIE came from the alt file and resolve the offset with die_get_type_die() in that file, with no fallback: resolving an alt file offset in the main file is exactly the misparse above. Fixes: 06b2ce75386df04b ("perf annotate-data: Maintain variable type info") Fixes: 55ee3d005d62279d ("perf annotate-data: Add a cache for global variab= le types") Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-dat= a.c index aff60a630fd05b01..2ad6d012e069c522 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -645,6 +645,8 @@ struct global_var_entry { u64 start; u64 end; u64 die_offset; + int die_tag; + bool from_alt; /* die_offset is relative to the alt (dwz) file */ }; =20 static int global_var_cmp(const void *_key, const struct rb_node *node) @@ -682,7 +684,7 @@ static struct global_var_entry *global_var__find(struct= data_loc_info *dloc, u64 } =20 static bool global_var__add(struct data_loc_info *dloc, u64 addr, - const char *name, Dwarf_Die *type_die) + const char *name, Dwarf_Die *type_die, bool from_alt) { struct dso *dso =3D map__dso(dloc->ms->map); struct global_var_entry *gvar; @@ -704,6 +706,8 @@ static bool global_var__add(struct data_loc_info *dloc,= u64 addr, gvar->start =3D addr; gvar->end =3D addr + size; gvar->die_offset =3D dwarf_dieoffset(type_die); + gvar->die_tag =3D dwarf_tag(type_die); + gvar->from_alt =3D from_alt; =20 rb_add(&gvar->node, dso__global_vars(dso), global_var_less); return true; @@ -778,12 +782,14 @@ static void global_var__collect(struct data_loc_info = *dloc) if (pos->reg !=3D -1) continue; =20 - if (!dwarf_offdie(dwarf, pos->die_off, &type_die)) + if (!die_get_type_die(dwarf, pos->die_off, pos->die_tag, + pos->from_alt, &type_die)) continue; =20 get_global_var_info(dloc, pos->addr, &var_name, &var_offset); =20 - global_var__add(dloc, pos->addr, var_name, &type_die); + global_var__add(dloc, pos->addr, var_name, &type_die, + pos->from_alt); } =20 delete_var_types(var_types); @@ -808,7 +814,8 @@ bool get_global_var_type(Dwarf_Die *cu_die, struct data= _loc_info *dloc, =20 gvar =3D global_var__find(dloc, var_addr); if (gvar) { - if (!dwarf_offdie(dloc->di->dbg, gvar->die_offset, type_die)) + if (!die_get_type_die(dloc->di->dbg, gvar->die_offset, + gvar->die_tag, gvar->from_alt, type_die)) return false; =20 *var_offset =3D var_addr - gvar->start; @@ -838,7 +845,8 @@ bool get_global_var_type(Dwarf_Die *cu_die, struct data= _loc_info *dloc, =20 ok: /* The address should point to the start of the variable */ - global_var__add(dloc, var_addr - *var_offset, var_name, type_die); + global_var__add(dloc, var_addr - *var_offset, var_name, type_die, + !die_same_file(cu_die, type_die)); return true; } =20 @@ -893,7 +901,8 @@ static void update_var_state(struct type_state *state, = struct data_loc_info *dlo continue; } /* Get the type DIE using the offset */ - if (!dwarf_offdie(dloc->di->dbg, var->die_off, &mem_die)) + if (!die_get_type_die(dloc->di->dbg, var->die_off, + var->die_tag, var->from_alt, &mem_die)) continue; =20 if (var->reg =3D=3D DWARF_REG_FB || var->reg =3D=3D fbreg || var->reg = =3D=3D state->stack_reg) { --=20 2.55.0 From nobody Thu Sep 24 15:10:09 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA4E739CD19; Tue, 22 Sep 2026 12:27:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080036; cv=none; b=oa0V4AQxtZbMRsaS3wzgr5flBlkYJ8COg7DWdvtZIu1DnltUin85TB6Z3D5ntwZdSVto2I/CLARqgDzHGgTfWtyOrPIvLh2IdNsapsK5GtztLuJXXgthlYmLADpX0B9dsAyRDhkPtRBr+kAQJv3CvKzWDc8A2CrKfQGZ2TcE6cE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080036; c=relaxed/simple; bh=ry7RvaQvCyx8PVDPMx2T4Ot5MGZBNJR47tiXNPK6jPM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bzhKFmTEaYXMuqrPUmNwBqIKFFTUoIG8BB87cjIKZHP5g9E2KwDWQf+2Q6Sh4CeCLM3b58Bicm3n20SRuJgqrFM4pb7xB9xme5zEsqA+EGKpsMlWPTaxDf54jyGzGxnOCcdWwKpha9pnHtLMCNiLyo01ADIoWNAabKCocu1axf0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Dvwq4sAO; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Dvwq4sAO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3C51F1F000FF; Tue, 22 Sep 2026 12:27:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790080034; bh=0ksv4bkAAggNOsXlCZ2OGQbl1L2IBrjnYABIaalGLao=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Dvwq4sAODIXdho5Fszli8Do4UrhQ5SXPSbGIpuGsjGla+/KPwJDXOBu+KkfoqTdPo 1FwPeOL8NvvxtHYyhT/koPf7ockXybPQC4YifAFK/ue0xaBUYjCxCKoJW0N4ryYo4e 3GpOl1qMG/zBYaNQJJivVIFbmiQgxQeAqdPY5bOgFV/2piT38ZJVbPB3k8gbGNs4ar +QPeN53ruVRMUMmjrg5l7vDcgWketD+IfVVp33qMjD3I65Zd7jcpdO5zzEERItblJn Gh8jDkDOv8v+2vrpwkwHxQ9AAVf5NkXOVRQJttHbV0tZx3+0aDrbgX2nDkD9yNhAhP zxM24sVwLnKrw== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH v3 4/7] perf annotate-data: Bound the member nesting recursion Date: Tue, 22 Sep 2026 14:26:20 +0200 Message-ID: <20260922122623.1029132-5-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922122623.1029132-1-acme@kernel.org> References: <20260922122623.1029132-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo Members are added recursively, and the same kind of broken DIE can make a member's type point back at one of its own ancestors, recursing until the stack is gone; nothing usable comes out of nesting members 32 deep anyway, so stop there, marking the member as truncated (reported by the JSON exporter added in a later series) and giving up on member types that don't resolve. The limit is checked where the children of an aggregate would be expanded, so only struct/union members get marked as truncated: a primitive member that merely lands on the limit has no children to expand and is reported as complete. Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 36 +++++++++++++++++++++++++++------ tools/perf/util/annotate-data.h | 3 +++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-dat= a.c index 2ad6d012e069c522..a0f63a91d45614cb 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -221,6 +221,13 @@ static bool data_type_less(struct rb_node *node_a, con= st struct rb_node *node_b) return strcmp(a->self.type_name, b->self.type_name) < 0; } =20 +/* + * Members are added recursively; bound the nesting so that a broken + * type that points back at one of its own ancestors doesn't recurse + * until the stack is gone. + */ +#define MAX_MEMBER_DEPTH 32 + /* Recursively add new members for struct/union */ static int __add_member_cb(Dwarf_Die *die, void *arg) { @@ -235,6 +242,16 @@ static int __add_member_cb(Dwarf_Die *die, void *arg) if (dwarf_tag(die) !=3D DW_TAG_member) return DIE_FIND_CB_SIBLING; =20 + if (__die_get_real_type(die, &member_type) =3D=3D NULL) + return DIE_FIND_CB_SIBLING; + + if (dwarf_tag(&member_type) =3D=3D DW_TAG_typedef) { + if (die_get_real_type(&member_type, &die_mem) =3D=3D NULL) + return DIE_FIND_CB_SIBLING; + } else { + die_mem =3D member_type; + } + member =3D zalloc(sizeof(*member)); if (member =3D=3D NULL) return DIE_FIND_CB_END; @@ -242,12 +259,6 @@ static int __add_member_cb(Dwarf_Die *die, void *arg) strbuf_init(&sb, 32); die_get_typename(die, &sb); =20 - __die_get_real_type(die, &member_type); - if (dwarf_tag(&member_type) =3D=3D DW_TAG_typedef) - die_get_real_type(&member_type, &die_mem); - else - die_mem =3D member_type; - if (dwarf_aggregate_size(&die_mem, &size) < 0) size =3D 0; =20 @@ -289,6 +300,7 @@ static int __add_member_cb(Dwarf_Die *die, void *arg) } member->size =3D size; member->offset =3D loc + parent->offset; + member->depth =3D parent->depth + 1; INIT_LIST_HEAD(&member->children); list_add_tail(&member->node, &parent->children); =20 @@ -296,6 +308,18 @@ static int __add_member_cb(Dwarf_Die *die, void *arg) switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: + /* + * Only aggregates have children to expand: a primitive + * member that happens to land on the limit is complete, + * not truncated. + */ + if (member->depth >=3D MAX_MEMBER_DEPTH) { + /* Reported by the JSON exporter so consumers can tell a truncated tree= . */ + member->truncated =3D true; + pr_debug_dtp("member nesting limit reached at %s\n", + member->type_name ?: "(unknown type)"); + break; + } die_find_child(&die_mem, __add_member_cb, member, &die_mem); break; default: diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-dat= a.h index ca2096a9ee62cbfe..cc576232f55b5fb0 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -57,6 +57,9 @@ struct annotated_member { char *var_name; int offset; int size; + unsigned int depth; + /* Children not expanded because the nesting limit was reached */ + bool truncated; }; =20 /** --=20 2.55.0 From nobody Thu Sep 24 15:10:09 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E3CAE541E6D; Tue, 22 Sep 2026 12:27:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080044; cv=none; b=myPwOXXJk2r3ApiUn1GvKWXXVeZQ6zd6kgoPuNruRYugFcMGJpAj4cpfAQpO9abP7H4AbCnPn03/zykM0wWJsCDw8M+9LwfKTg5n8Hdb1M1vvdaWvSW6LC+tJJG6AMU6OWW93q/s03hr9nZp/N9nW2SvpxQJ/zoifIWbxIf1H3Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080044; c=relaxed/simple; bh=DNopuPVnqP+asREDoo6vMJtkbDlJq9GpboXsXm1flyo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rkB7+eRLeIo0Oqp47+QbhY8ejTrx26v12rO8pKDI1DZAmMIkWpAo9C9DMdYNk9oDCKhm7NV0Y4EUlWERH4xUfTt1BB88lTbq5q+z32HeeBv1LAT4QSoei2dUSw4A0UVpp9A0uk4BdU1vtKNFSJEReN1RSIqAR2gARriG6etgA3c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WjHQB2Qj; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WjHQB2Qj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8563B1F00899; Tue, 22 Sep 2026 12:27:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790080042; bh=ZLhEWeFQugaxDSS3tO5Vf31pY8c4lSsBqp2RGaQInkk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=WjHQB2Qj0hUzdB65DZFWBlTFvbqtcd//cyKHDQ+SVayHGAG7iRsOYa0gZ8eO79wVD oT/O3k5bUZfLjd0q0jxHPsplv+Xog5oLRi28xf/8nmNPa6cXng90fCXtxyn797HXNF FopTdEhF+Rzi4L1ZzLKoDq/lKWeIgJUI8z0AxEA1DSRijMF1Ed9i5TRB920+IgGH6M fTYm8AJFw0LIHmYD0iOjffzYan4s4Tr8ptwrafD7Xh4G/iKcGxmfC9JRNr/GeqHQGz iJXzZ1Gqmgta0xoeDW27Kki67wN7ZhacUB8NlzoDCRyE3aAlrtIhtC23ovss3vpt0E eTplttHLqmgKg== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH v3 5/7] perf annotate-data: Show the sample count in the data-type browser Date: Tue, 22 Sep 2026 14:26:21 +0200 Message-ID: <20260922122623.1029132-6-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922122623.1029132-1-acme@kernel.org> References: <20260922122623.1029132-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo The samples view (-n, annotate.show_nr_samples) prints a local nr_samples variable that is initialized to zero and never updated, so every member is listed as having no samples while the period and percent columns for the same entry are filled in. Print the histogram entry's own count instead. Fixes: d001c7a7f4736743 ("perf annotate-data: Add hist_entry__annotate_data= _tui()") Acked-by: Namhyung Kim Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate-data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/annotate-data.c b/tools/perf/ui/browser= s/annotate-data.c index c6e07a9b64089ab5..a15608f6ee53335f 100644 --- a/tools/perf/ui/browsers/annotate-data.c +++ b/tools/perf/ui/browsers/annotate-data.c @@ -374,7 +374,7 @@ static void browser__write_overhead(struct ui_browser *= uib, u64 period =3D hist->period; double percent =3D total->period ? (100.0 * period / total->period) : 0; bool current =3D ui_browser__is_current_entry(uib, row); - int nr_samples =3D 0; + int nr_samples =3D hist->nr_samples; =20 ui_browser__set_percent_color(uib, percent, current); =20 --=20 2.55.0 From nobody Thu Sep 24 15:10:09 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E656542817; Tue, 22 Sep 2026 12:27:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080054; cv=none; b=qDerVPuPl6FrY4M3bjxayHYp1mXNxHbUzJodMg//4CWpXyFnEl+dnI1Mp/qqdIhLmYcFxq1saDVQhXAiTvEC5SDFuXBiXe45GTqFv+wpXJCevOw7kQXjkj1p9CnzFX6Bk90dWrfiUR0aEPaftfxeNEHKg9Fx5MIdr2dKJ/mhgwI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080054; c=relaxed/simple; bh=wxs2XxPjV4TsQRFaOZYnOMvLj8n/AHgTau/C8WqoWYA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=O1l/KlA3xjzunAnd11Mo2tYu8NtfM2VEU2S2/yQ/hGV/T4RqFgzI1pVRCva1HcUyw3sc28UmShZZGv0l2B0CJIFHuTJWZN2AsgNGAdK9Ewudk+2QcN1RX8Lw8HvOqbiD9K7POjh5BVRs405Gyp8wmq448reNs3S3F09RlfByXVA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kn2T4Erw; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kn2T4Erw" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E52311F00898; Tue, 22 Sep 2026 12:27:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790080051; bh=eLkJrvnAeHJo+bmYbI04lAs1t48D/OuOuWuJv/uf5x0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=kn2T4ErwBh5d1UvDyjn+p95G47Es66PmknKm0QSSIvAIPN5sZlGGe01A1KS/sUfqa eK40cEiNzfqvwSXFNSMYjSO0NJThPiG4+sZPaEWngWQ3RbdEnJwKmHZXhBQGl9rHXh fN/Fr4CDMvsSC4rZkABYCWNhQ1Cr9uJMT/t/cuAlA/INzZ3eZ/hwRF1w6ldXoH3SXA bi6Y2YlMJVpUoKK4p3hI7cvZboVhOujismS31QvSiA8eWBwMlpPMAYk8GdXwZFA6CU wr3NJPIrqx/GdbxA8ibplVaTvgGizMb/RXFO26f76ZNTJzorQZ4l6gHOw5FrR416F5 6J7kNz1Ays2mA== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH v3 6/7] perf mem record: Request PERF_SAMPLE_CPU by default Date: Tue, 22 Sep 2026 14:26:22 +0200 Message-ID: <20260922122623.1029132-7-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922122623.1029132-1-acme@kernel.org> References: <20260922122623.1029132-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo The data type profiling per-sample stream keys cross-CPU contention on sample->cpu; without PERF_SAMPLE_CPU that field is the (u32)-1 "no CPU info" sentinel, so same-instance accesses from different cores are indistinguishable from same-CPU traffic. 'perf mem record' already passes -d (addr) and -W (weight) explicitly to the record parser, add --sample-cpu as well and document it in perf-mem(1). The rec_argv array only had room for nine arguments per PMU plus the user arguments, not counting the up to eight __cmd_record() adds itself, which a new argument would overflow on PMUs with separate load and store events; reserve space for the fixed arguments too. Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-mem.txt | 4 ++++ tools/perf/builtin-mem.c | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentati= on/perf-mem.txt index 4d164836d0943119..fe51c5e3333dc4a0 100644 --- a/tools/perf/Documentation/perf-mem.txt +++ b/tools/perf/Documentation/perf-mem.txt @@ -14,6 +14,10 @@ DESCRIPTION ----------- "perf mem record" runs a command and gathers memory operation data from it, into perf.data. Perf record options are accepted and are passed t= hrough. +It also requests the address (-d), the weight (-W, where supported) and the +CPU id (--sample-cpu) of every sampled access by default; the CPU id is wh= at +lets per-sample analysis tell reads and writes to the same data from +different cores apart from same-CPU traffic. =20 "perf mem report" displays the result. It invokes perf report with the right set of options to display a memory access profile. By default, loads diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 6101a26b3a781e69..f25592bc52728655 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -99,8 +99,8 @@ static int __cmd_record(int argc, const char **argv, stru= ct perf_mem *mem, argc =3D parse_options(argc, argv, options, record_usage, PARSE_OPT_KEEP_UNKNOWN); =20 - /* Max number of arguments multiplied by number of PMUs that can support = them. */ - rec_argc =3D argc + 9 * (perf_pmu__mem_events_num_mem_pmus(pmu) + 1); + /* Max number of arguments per PMU plus the fixed ones added below. */ + rec_argc =3D argc + 8 + 9 * (perf_pmu__mem_events_num_mem_pmus(pmu) + 1); =20 if (mem->cpu_list) rec_argc +=3D 2; @@ -135,6 +135,13 @@ static int __cmd_record(int argc, const char **argv, s= truct perf_mem *mem, =20 rec_argv[i++] =3D "-d"; =20 + /* + * The data type profiling per-sample stream keys cross-CPU contention + * on sample->cpu; without PERF_SAMPLE_CPU it is the (u32)-1 'no CPU + * info' sentinel. + */ + rec_argv[i++] =3D "--sample-cpu"; + if (mem->phys_addr) rec_argv[i++] =3D "--phys-data"; =20 --=20 2.55.0 From nobody Thu Sep 24 15:10:09 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3602154281D; Tue, 22 Sep 2026 12:27:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080062; cv=none; b=SIMOWANu6xceACrZvqGCV4TPJ/yWE1Ro9fzfyhjuqZDjcGfYgea6R/w+rTvn2XR8WEdoILEDF38/tzWWNrKjyzQvaLGuo900T5TiscnrGvQH6F+mHfELGxT5b3le+C0sFlworzKiz0E1BKYEUpoW6y0KM4VrlRXqbnU82ATbD9A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790080062; c=relaxed/simple; bh=Y+hIDSycxSkmcW2fwShdG/1YSOl2of5puIAQv+44AW4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=u63wXLAHqwXgKl/K14Y6cyd6Tmmi9r10Ssv5wYhYdefRFeGpMsJvz0sgq9V6GBV7CffyYxeNHhTt5HXzXlEhMiJmuO+QTGgCOfOeHFc0bPVwC8Gxr7IiUTsNWWta8C+k6PDIZf4BwhkqudK5E8ubBqiLEwNLAtEIyr2g6HuphPw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LerDFv/g; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LerDFv/g" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 282BF1F00899; Tue, 22 Sep 2026 12:27:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790080061; bh=56iPBEObqEQyLLnKTG226uN4zi7yH1BIqjbv2lqlrNk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=LerDFv/gP5eVHizYRdo8Tn6rFe7L3qRKHqTT/zMcs5aMZguA0Nvi3ey/OdU1QJpvt vZPdCtOZnxxb1z+nHq14sk1E6xXYaWflBGSJln0SPYMB+V+76U9JGy68pJJfqhYZ9q 7WWdbG/8OTmlJLd7YKkr+gPqPr5kcgfhk1VaQnz+V+T9b+JOUGVE6VB5g55bO/wT9e xi6sX4dXxE6sp2bAyjPq8Fg2PJ4Sf0hFOmmuSdQ5rYhlex1cLtkODVoj4SY17sHqE3 dOu2XgzMz4W0N0VjGnOGsHDG4Fx6qgrhGFKFcyL6Nn5hO9yLz4VW6Zrsf7fDQjrk49 4zmzdQPF8aK1Q== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo , Ravi Bangoria Subject: [PATCH v3 7/7] perf mem record: Use the IBS swfilt filter when available Date: Tue, 22 Sep 2026 14:26:23 +0200 Message-ID: <20260922122623.1029132-8-acme@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922122623.1029132-1-acme@kernel.org> References: <20260922122623.1029132-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo IBS events with exclude_{user,kernel} bits, as used for per-thread recording when kernel samples are not allowed, are rejected by the kernel on hardware without the privilege filter, so per-thread 'perf mem record' fails on AMD: $ perf mem record -o /dev/null -- true Error: Failure to open event 'ibs_op/ldlat=3D0/u' on PMU 'ibs_op' which will be = removed. Invalid event (ibs_op/ldlat=3D0/u) in per-thread mode, enable system wide= with '-a'. Kernel v6.14 added swfilt, a software privilege filter exposed as the 'swfilt' format term, making those events usable per-thread: $ perf record -e ibs_op/ldlat=3D0,swfilt=3D1/ -- true Give the ibs_op memory events extra tables with the swfilt term in the event names, selected in perf_pmu__arch_init() when the PMU exposes the term, keeping the names that need system wide mode otherwise, with the knowledge that IBS needs this staying in the arch code: the generic mem-events table and name builder don't know about it. The variant is used even for records that end up without exclude bits: 'perf record' adds those bits itself when the first open fails, after the name was built, and that retry needs the term. With the term in the event name, the per-thread 'perf mem record' done by the 'data type profiling' shell test works on AMD kernels with swfilt, so the skip 29f320d2 added to it no longer triggers there, and the 'Test data symbol' shell test adjusts its event regex for the added term. Suggested-by: Namhyung Kim Suggested-by: Ravi Bangoria Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/mem-events.c | 24 ++++++++++++++++++++++ tools/perf/arch/x86/util/mem-events.h | 2 ++ tools/perf/arch/x86/util/pmu.c | 10 +++++++-- tools/perf/tests/shell/test_data_symbol.sh | 6 ++++-- tools/perf/util/mem-events.c | 11 ++++++---- 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/tools/perf/arch/x86/util/mem-events.c b/tools/perf/arch/x86/ut= il/mem-events.c index b38f519020ff8c6f..2052750cd707c7e5 100644 --- a/tools/perf/arch/x86/util/mem-events.c +++ b/tools/perf/arch/x86/util/mem-events.c @@ -21,14 +21,38 @@ struct perf_mem_event perf_mem_events_intel_aux[PERF_ME= M_EVENTS__MAX] =3D { E(NULL, NULL, NULL, false, 0), }; =20 +/* + * IBS events with exclude_{user,kernel} bits set, as used by perf to + * record per-thread when kernel samples are not allowed, are rejected + * by the kernel on hardware without the privilege filter unless the + * swfilt software filter is used, so there are extra sets of tables + * with the swfilt term in the event names, selected in + * perf_pmu__arch_init() when the PMU exposes the term. The term is not + * conditional on the event already having exclude bits: perf record + * adds those bits itself when the first open fails with EACCES on an + * unprivileged setup, after the name was built, and that retry only + * succeeds with the term in it. + */ struct perf_mem_event perf_mem_events_amd[PERF_MEM_EVENTS__MAX] =3D { E(NULL, NULL, NULL, false, 0), E(NULL, NULL, NULL, false, 0), E("mem-ldst", "%s//", NULL, false, 0), }; =20 +struct perf_mem_event perf_mem_events_amd_swfilt[PERF_MEM_EVENTS__MAX] =3D= { + E(NULL, NULL, NULL, false, 0), + E(NULL, NULL, NULL, false, 0), + E("mem-ldst", "%s/swfilt=3D1/", NULL, false, 0), +}; + struct perf_mem_event perf_mem_events_amd_ldlat[PERF_MEM_EVENTS__MAX] =3D { E(NULL, NULL, NULL, false, 0), E(NULL, NULL, NULL, false, 0), E("mem-ldst", "%s/ldlat=3D%u/", NULL, true, 0), }; + +struct perf_mem_event perf_mem_events_amd_ldlat_swfilt[PERF_MEM_EVENTS__MA= X] =3D { + E(NULL, NULL, NULL, false, 0), + E(NULL, NULL, NULL, false, 0), + E("mem-ldst", "%s/ldlat=3D%u,swfilt=3D1/", NULL, true, 0), +}; diff --git a/tools/perf/arch/x86/util/mem-events.h b/tools/perf/arch/x86/ut= il/mem-events.h index 11e09a256f5bb084..f707de38037017c1 100644 --- a/tools/perf/arch/x86/util/mem-events.h +++ b/tools/perf/arch/x86/util/mem-events.h @@ -6,6 +6,8 @@ extern struct perf_mem_event perf_mem_events_intel[PERF_MEM= _EVENTS__MAX]; extern struct perf_mem_event perf_mem_events_intel_aux[PERF_MEM_EVENTS__MA= X]; =20 extern struct perf_mem_event perf_mem_events_amd[PERF_MEM_EVENTS__MAX]; +extern struct perf_mem_event perf_mem_events_amd_swfilt[PERF_MEM_EVENTS__M= AX]; extern struct perf_mem_event perf_mem_events_amd_ldlat[PERF_MEM_EVENTS__MA= X]; +extern struct perf_mem_event perf_mem_events_amd_ldlat_swfilt[PERF_MEM_EVE= NTS__MAX]; =20 #endif /* _X86_MEM_EVENTS_H */ diff --git a/tools/perf/arch/x86/util/pmu.c b/tools/perf/arch/x86/util/pmu.c index 2c24ef3140da5e9b..fd4491fda117e51a 100644 --- a/tools/perf/arch/x86/util/pmu.c +++ b/tools/perf/arch/x86/util/pmu.c @@ -333,6 +333,7 @@ static void uncore_cha_imc_adjust_cpumask_for_snc(struc= t perf_pmu *pmu, bool cha void perf_pmu__arch_init(struct perf_pmu *pmu) { struct perf_pmu_caps *ldlat_cap; + bool swfilt_format; =20 if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) { pmu->auxtrace =3D true; @@ -348,7 +349,10 @@ void perf_pmu__arch_init(struct perf_pmu *pmu) if (strcmp(pmu->name, "ibs_op")) return; =20 - pmu->mem_events =3D perf_mem_events_amd; + swfilt_format =3D perf_pmu__has_format(pmu, "swfilt"); + pmu->mem_events =3D swfilt_format ? + perf_mem_events_amd_swfilt : + perf_mem_events_amd; =20 if (!perf_pmu__caps_parse(pmu)) return; @@ -358,7 +362,9 @@ void perf_pmu__arch_init(struct perf_pmu *pmu) return; =20 perf_mem_events__loads_ldlat =3D 0; - pmu->mem_events =3D perf_mem_events_amd_ldlat; + pmu->mem_events =3D swfilt_format ? + perf_mem_events_amd_ldlat_swfilt : + perf_mem_events_amd_ldlat; } else { if (pmu->is_core) { if (perf_pmu__have_event(pmu, "mem-loads-aux")) diff --git a/tools/perf/tests/shell/test_data_symbol.sh b/tools/perf/tests/= shell/test_data_symbol.sh index d61b5659a46d9a77..52c837fddb639595 100755 --- a/tools/perf/tests/shell/test_data_symbol.sh +++ b/tools/perf/tests/shell/test_data_symbol.sh @@ -65,15 +65,17 @@ if (($is_amd >=3D 1)); then # --ldlat on AMD: # o Zen4 and earlier uarch does not support ldlat # o Even on supported platforms, it's disabled (--ldlat=3D0) by default. + # o Kernels with the swfilt term add it even when ldlat is not + # supported, so only check ldlat when the term is present. ldlat=3D${BASH_REMATCH[1]} - if [[ -n $ldlat ]]; then + if [[ $ldlat =3D=3D *ldlat=3D* ]]; then if ! [[ "$ldlat" =3D~ ldlat=3D0 ]]; then echo "ERROR: ldlat not initialized to 0?" exit 1 fi =20 mem_events=3D"$(perf mem record -v --ldlat=3D150 -e list 2>&1)" - if ! [[ "$mem_events" =3D~ ^mem-ldst.*ibs_op/ldlat=3D150/.*available ]];= then + if ! [[ "$mem_events" =3D~ ^mem-ldst.*ibs_op/ldlat=3D150[,/].*available = ]]; then echo "ERROR: --ldlat not honored?" exit 1 fi diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index 0b49fce251fcc184..0b07011939d7d7c3 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c @@ -82,6 +82,7 @@ static const char *perf_pmu__mem_events_name(struct perf_= pmu *pmu, int i, char *buf, size_t buf_size) { struct perf_mem_event *e; + const char *name; =20 if (i >=3D PERF_MEM_EVENTS__MAX || !pmu) return NULL; @@ -90,24 +91,26 @@ static const char *perf_pmu__mem_events_name(struct per= f_pmu *pmu, int i, if (!e || !e->name) return NULL; =20 + name =3D e->name; + if (i =3D=3D PERF_MEM_EVENTS__LOAD || i =3D=3D PERF_MEM_EVENTS__LOAD_STOR= E) { if (e->ldlat) { if (!e->aux_event) { /* ARM and Most of Intel */ scnprintf(buf, buf_size, - e->name, pmu->name, + name, pmu->name, perf_mem_events__loads_ldlat); } else { /* Intel with mem-loads-aux event */ scnprintf(buf, buf_size, - e->name, pmu->name, pmu->name, + name, pmu->name, pmu->name, perf_mem_events__loads_ldlat); } } else { if (!e->aux_event) { /* AMD and POWER */ scnprintf(buf, buf_size, - e->name, pmu->name); + name, pmu->name); } else { return NULL; } @@ -117,7 +120,7 @@ static const char *perf_pmu__mem_events_name(struct per= f_pmu *pmu, int i, =20 if (i =3D=3D PERF_MEM_EVENTS__STORE) { scnprintf(buf, buf_size, - e->name, pmu->name); + name, pmu->name); return buf; } =20 --=20 2.55.0