diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 1560e721479a..2c135ebb1551 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); } /**