From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Namhyung Kim <namhyung@kernel.org>
Cc: Ingo Molnar <mingo@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
James Clark <james.clark@linaro.org>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
Clark Williams <williams@redhat.com>,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
Arnaldo Carvalho de Melo <acme@redhat.com>,
Masami Hiramatsu <mhiramat@kernel.org>
Subject: [PATCH 1/6] perf dwarf-aux: Bound the type chases for broken debug info
Date: Fri, 25 Sep 2026 17:06:52 +0200 [thread overview]
Message-ID: <20260925150657.1826942-2-acme@kernel.org> (raw)
In-Reply-To: <20260925150657.1826942-1-acme@kernel.org>
From: Arnaldo Carvalho de Melo <acme@redhat.com>
A DIE 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(), die_get_pointer_type() and
die_get_typename_from_type() spin forever; 'perf report -s type' did
that on the dwz compressed debug info of zlib-ng (libz.so.1).
No sane typedef/qualifier chain is 32 DIEs long, so give up on the type
with a pr_debug instead of hanging.
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/dwarf-aux.c | 84 ++++++++++++++++++++++++++++---------
1 file changed, 64 insertions(+), 20 deletions(-)
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 1560e721479a1ac2..2c135ebb1551fca4 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -267,16 +267,27 @@ Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
return NULL;
}
+/*
+ * A DIE parsed at an offset that is not the start of a DIE can refer
+ * back to itself via DW_AT_type: bound these chases.
+ */
+#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 = 0;
do {
vr_die = die_get_type(vr_die, die_mem);
if (!vr_die)
- break;
+ return NULL;
tag = 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 == DW_TAG_const_type ||
tag == DW_TAG_restrict_type ||
tag == DW_TAG_volatile_type ||
@@ -297,8 +308,15 @@ Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
*/
Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
{
+ int chase = 0;
+
do {
vr_die = __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) == DW_TAG_typedef);
return vr_die;
@@ -315,7 +333,7 @@ Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
*/
Dwarf_Die *die_get_pointer_type(Dwarf_Die *type_die, Dwarf_Die *die_mem)
{
- int tag;
+ int tag, chase = 0;
do {
tag = dwarf_tag(type_die);
@@ -325,6 +343,11 @@ Dwarf_Die *die_get_pointer_type(Dwarf_Die *type_die, Dwarf_Die *die_mem)
tag != DW_TAG_restrict_type && tag != DW_TAG_volatile_type &&
tag != 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 = die_get_type(type_die, die_mem);
} while (type_die);
@@ -1119,17 +1142,25 @@ Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
die_mem);
}
-/**
- * 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 depth)
+{
+ Dwarf_Die type;
+
+ if (__die_get_real_type(vr_die, &type) == 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 = "";
@@ -1156,7 +1187,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 = die_get_typename(type_die, buf);
+ if (depth >= 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 = __die_get_typename(type_die, buf, depth + 1);
if (ret < 0) {
/* void pointer has no type attribute */
if (tag == DW_TAG_pointer_type && ret == -ENOENT)
@@ -1167,6 +1203,19 @@ int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf)
return strbuf_addstr(buf, tmp);
}
+/**
+ * die_get_typename_from_type - Get the name of a type DIE
+ * @type_die: a type DIE
+ * @buf: a strbuf for the result type name
+ *
+ * Stores the typedef name if possible, "*(function_type)" for function
+ * pointers. Returns 0 or -ENOENT.
+ */
+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
@@ -1179,12 +1228,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) == NULL)
- return -ENOENT;
-
- return die_get_typename_from_type(&type, buf);
+ return __die_get_typename(vr_die, buf, 0);
}
/**
--
2.53.0
next prev parent reply other threads:[~2026-09-25 15:07 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 15:06 [PATCH v5 0/6] perf annotate-data: Fix hangs on broken debug info, AMD mem record Arnaldo Carvalho de Melo
2026-09-25 15:06 ` Arnaldo Carvalho de Melo [this message]
2026-09-25 15:13 ` [PATCH 1/6] perf dwarf-aux: Bound the type chases for broken debug info sashiko-bot
2026-09-25 15:18 ` Ian Rogers
2026-09-25 15:06 ` [PATCH 2/6] perf dwarf-aux: Add die_same_file() and die_get_type_die() Arnaldo Carvalho de Melo
2026-09-25 15:16 ` sashiko-bot
2026-09-25 15:20 ` Ian Rogers
2026-09-25 15:06 ` [PATCH 3/6] perf annotate-data: Resolve type DIEs in the debug file they came from Arnaldo Carvalho de Melo
2026-09-25 15:11 ` sashiko-bot
2026-09-25 15:35 ` Ian Rogers
2026-09-25 15:06 ` [PATCH 4/6] perf annotate-data: Bound the member nesting recursion Arnaldo Carvalho de Melo
2026-09-25 15:14 ` sashiko-bot
2026-09-25 15:37 ` Ian Rogers
2026-09-25 15:39 ` Namhyung Kim
2026-09-25 15:43 ` Arnaldo Carvalho de Melo
2026-09-25 16:11 ` Arnaldo Carvalho de Melo
2026-09-25 15:06 ` [PATCH 5/6] perf mem record: Request PERF_SAMPLE_CPU by default Arnaldo Carvalho de Melo
2026-09-25 15:17 ` sashiko-bot
2026-09-25 15:47 ` Ian Rogers
2026-09-25 15:06 ` [PATCH 6/6] perf mem record: Use the IBS swfilt filter when available Arnaldo Carvalho de Melo
2026-09-25 15:15 ` sashiko-bot
2026-09-25 15:46 ` [PATCH v5 0/6] perf annotate-data: Fix hangs on broken debug info, AMD mem record Namhyung Kim
2026-09-25 15:48 ` Arnaldo Carvalho de Melo
2026-09-25 15:58 ` Arnaldo Carvalho de Melo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260925150657.1826942-2-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=adrian.hunter@intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mhiramat@kernel.org \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=tglx@linutronix.de \
--cc=williams@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.