mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
perf dwarf-aux: Bound the type chases for broken debug info
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. Reviewed-by: Ian Rogers <irogers@google.com> Reviewed-by: Namhyung Kim <namhyung@kernel.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
906af9e1c9
commit
a6ac1e9ca9
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user