[PATCH v4 1/3] perf dwarf-aux: Add die_has_flex_array() helper
From: Namhyung Kim
Date: Wed Sep 16 2026 - 02:19:35 EST
The die_has_flex_array() returns true when the given type is a compound
type and contains an array at the end. To prevent an infinite recursion
add a depth field to the internal function.
Cc: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx>
---
tools/perf/util/dwarf-aux.c | 107 ++++++++++++++++++++++++++++++++++++
tools/perf/util/dwarf-aux.h | 3 +
2 files changed, 110 insertions(+)
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index d7160f87ac7d7ab3..1560e721479a1ac2 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -7,6 +7,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
#include "debug.h"
#include "dwarf-aux.h"
#include "dwarf-regs.h"
@@ -2180,3 +2181,109 @@ Dwarf_Die *die_deref_ptr_type(Dwarf_Die *ptr_die, int offset,
return die_get_member_type(&type_die, offset, die_mem);
}
+
+static bool is_flex_array_member(Dwarf_Die *mb_die)
+{
+ Dwarf_Die type_die;
+ Dwarf_Word size;
+
+ /* get the type of the member */
+ if (die_get_real_type(mb_die, &type_die) == NULL)
+ return false;
+
+ if (dwarf_tag(&type_die) != DW_TAG_array_type)
+ return false;
+
+ return dwarf_aggregate_size(&type_die, &size) < 0 || size == 0;
+}
+
+#define MAX_FLEX_ARRAY_RECURSION 256 /* arbitrary */
+
+static bool die_has_flex_array_recurse(Dwarf_Die *parent_die, int depth)
+{
+ Dwarf_Die die_mem, last_mb;
+ int tag = dwarf_tag(parent_die);
+ bool found = false;
+ Dwarf_Word loc, last_loc = 0;
+
+ if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type)
+ return false;
+
+ /* prevent infinite recursion */
+ if (depth > MAX_FLEX_ARRAY_RECURSION)
+ return false;
+
+ if (dwarf_child(parent_die, &die_mem))
+ return false;
+
+ do {
+ if (dwarf_tag(&die_mem) != DW_TAG_member)
+ continue;
+
+ if (tag == DW_TAG_union_type) {
+ if (is_flex_array_member(&die_mem))
+ return true;
+
+ if (die_get_real_type(&die_mem, &last_mb) &&
+ die_has_flex_array_recurse(&last_mb, depth + 1))
+ return true;
+ }
+
+ if (tag == DW_TAG_structure_type) {
+ if (die_get_data_member_location(&die_mem, &loc) < 0) {
+ /* ignore bitfields */
+ loc = 0;
+ }
+
+ if (last_loc <= loc) {
+ memcpy(&last_mb, &die_mem, sizeof(last_mb));
+ last_loc = loc;
+ }
+ }
+
+ found = true;
+ } while (dwarf_siblingof(&die_mem, &die_mem) == 0);
+
+ if (tag == DW_TAG_structure_type && found) {
+ if (is_flex_array_member(&last_mb))
+ return true;
+
+ if (die_get_real_type(&last_mb, &die_mem))
+ return die_has_flex_array_recurse(&die_mem, depth + 1);
+ }
+
+ return false;
+}
+
+/**
+ * die_has_flex_array - Check if the given type has a flex-array at the end
+ * @type_die: a pointer to type DIE
+ *
+ * This function returns %true iff @type_die is a struct or union type and has
+ * an array at the end. Note that the flex-array has no element, it should have
+ * no size and the parent size doesn't include the flex-array. So it should
+ * locate at the offset of the parent size.
+ *
+ * For simplicity, it assumes the parent size of aligned with the flex-array.
+ */
+bool die_has_flex_array(Dwarf_Die *type_die)
+{
+ Dwarf_Die real_type;
+
+ switch (dwarf_tag(type_die)) {
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_shared_type:
+ if (die_get_real_type(type_die, &real_type) == NULL)
+ return false;
+
+ type_die = &real_type;
+ break;
+ default:
+ break;
+ }
+
+ return die_has_flex_array_recurse(type_die, 0);
+}
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index 161f0bf980b6ee6a..9b662db710220522 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -189,4 +189,7 @@ void die_collect_global_vars(Dwarf_Die *cu_die, struct die_var_type **var_types)
/* Get the frame base information from CFA */
int die_get_cfa(Dwarf *dwarf, u64 pc, int *preg, int *poffset);
+/* Check whether given type has a flex array */
+bool die_has_flex_array(Dwarf_Die *parent_die);
+
#endif /* _DWARF_AUX_H */
--
2.55.0.1032.g73a4cd73de-goog