[PATCH v6 4/5] objdump: Link and display all variables information
Guillaume VACHERIAS
guillaume.vacherias@foss.st.com
Fri Nov 21 12:51:31 GMT 2025
Implement linking mechanism to recursively resolve the DWARF type information
for variables, members and other type constructs. The linking mechanism is
central to populating field `ptr_type` in type_def, tab_type, member_type,
member_parent, type_ptr, type_ref and variable_type structures.
Implement the display for variables and types. It is based on recursively
accessing fields `ptr_type`, allowing the system to print complex types such
as pointers to structs, arrays of typedefs, or nested const or volatile types.
When displaying a variable information, it starts by accessing and printing
all information held by structure variable_type. It then recursevely access
the member `field_type` to traverse and display all underlying types of the
variable.
binutils/
* dwarf.h (resolve_and_display_variable_info): New definition.
* dwarf.c (PRINT_SPACE, PRINT_LBRACE, PRINT_RBRACE): New macros.
(display_base_type): New function. Display information hold by
base_type structure.
(display_type_def): Likewise for type_def structure.
(display_enum): Likewise for enum_constant structure.
(display_enum_type): Likewise for enum_type structure.
(display_subrange_type): Likewise for subrange_type structure.
(display_tab_type): Likewise for tab_type structure.
(display_member_type): Likewise for member_type structure.
(display_member_parent): Likewise for member_parent structure.
(display_type_ptr): Likewise for type_ptr structure.
(display_type_ref): Likewise for type_ref structure.
(display_variable_type): Likewise for variable_type structure.
(do_link_variable_information): New function. Link a structure which
represents a DWARF information entry to another by populating field
`ptr_type`.
(link_variable_information): New function. Go through all existing
structures that hold DWARF information to link each variable_type
element to the type of structure it represents.
(compute_variable_total_size): New function. Recursively go through
variable_type element and its structure information to calculate the
total size.
(reset_displayed_field): New function. Set field `displayed` of
member_parent to false to mark already displayed information for a
nested structure field.
(resolve_and_display_variable_info): New function. Go through all
elements in variable_type_list to link variable's information,
calculate variable's size and display variable's information.
* objdump.c (dump_global_variable_info): Add call to
resolve_and_display_variable_info function.
Signed-off-by: Guillaume VACHERIAS <guillaume.vacherias@foss.st.com>
---
binutils/dwarf.c | 570 +++++++++++++++++++++++++++++++++++++++++++++
binutils/dwarf.h | 7 +
binutils/objdump.c | 1 +
3 files changed, 578 insertions(+)
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 9f45d108100..b0d8a073d70 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -55,6 +55,24 @@
#define DO_TYPES 0x2
#define DO_GLOBAL_VARS 0x4
+#define PRINT_SPACE(n) do { \
+ int _i; \
+ for (_i = 0; _i < (n); ++_i) \
+ putchar (' '); \
+} while (0)
+
+#define PRINT_LBRACE(n) do { \
+ PRINT_SPACE (n); \
+ putchar ('{'); \
+ putchar ('\n'); \
+} while (0)
+
+#define PRINT_RBRACE(n) do { \
+ PRINT_SPACE (n); \
+ putchar ('}'); \
+ putchar ('\n'); \
+} while (0)
+
static const char *regname (unsigned int regno, int row);
static const char *regname_internal_by_table_only (unsigned int regno);
@@ -2590,6 +2608,16 @@ display_lang (uint64_t uvalue)
}
}
+static void
+display_base_type (const base_type bt)
+{
+ printf ("type: %s", bt.name);
+ if (bt.size_type == UNSIGNED_S)
+ printf (", size: %#lx\n", bt.size.usize);
+ else if (bt.size_type == SIGNED_S)
+ printf (", size: %#lx\n", bt.size.ssize);
+}
+
static base_type *
get_or_create_base_type (uint64_t die_offset)
{
@@ -2617,6 +2645,12 @@ get_or_create_base_type (uint64_t die_offset)
return base_type_list.tail;
}
+static void
+display_type_def (const type_def td)
+{
+ printf ("type: typedef %s\n", td.name);
+}
+
static type_def*
get_or_create_type_def (uint64_t die_offset)
{
@@ -2645,6 +2679,18 @@ get_or_create_type_def (uint64_t die_offset)
return type_def_list.tail;
}
+static void
+display_enum (enum_constant *ec, int nb_tab)
+{
+ enum_constant *head = ec;
+ while (head != NULL)
+ {
+ PRINT_SPACE (nb_tab);
+ printf ("value: %s = %ld\n", head->name, head->value);
+ head = head->next;
+ }
+}
+
static enum_constant *
get_or_create_enum_constant (enum_type *et, uint64_t die_offset)
{
@@ -2671,6 +2717,18 @@ get_or_create_enum_constant (enum_type *et, uint64_t die_offset)
return et->enum_const_tail;
}
+static void
+display_enum_type (const enum_type et, int nb_tab)
+{
+ if (et.name == NULL)
+ printf ("type: enum <anonymous>, size: %#lx\n", et.size.usize);
+ else
+ printf ("type: enum %s, size: %#lx\n", et.name, et.size.usize);
+ PRINT_LBRACE (nb_tab);
+ display_enum (et.enum_const_head, nb_tab + 1);
+ PRINT_RBRACE (nb_tab);
+}
+
static enum_type *
get_or_create_enum_type (uint64_t die_offset)
{
@@ -2700,6 +2758,20 @@ get_or_create_enum_type (uint64_t die_offset)
return enum_type_list.tail;
}
+static void
+display_subrange_type (subrange_type *st)
+{
+ subrange_type *head = st;
+ while (head != NULL)
+ {
+ if (head->size_type == UNSIGNED_S)
+ printf ("[%lu]", head->size.usize);
+ else if (head->size_type == SIGNED_S)
+ printf ("[%ld]", head->size.ssize);
+ head = head->next;
+ }
+}
+
static subrange_type *
get_or_create_subrange_type (tab_type *tt, uint64_t die_offset)
{
@@ -2726,6 +2798,14 @@ get_or_create_subrange_type (tab_type *tt, uint64_t die_offset)
return tt->subrange_tail;
}
+static void
+display_tab_type (const tab_type tt)
+{
+ printf ("type: array");
+ display_subrange_type (tt.subrange_head);
+ printf ("\n");
+}
+
static tab_type *
get_or_create_tab_type (uint64_t die_offset)
{
@@ -2755,6 +2835,15 @@ get_or_create_tab_type (uint64_t die_offset)
return tab_type_list.tail;
}
+static void
+display_member_type (const member_type mt)
+{
+ if (mt.name == NULL)
+ printf ("member: (anonymous), offset: %#lx\n", mt.member_offset);
+ else
+ printf ("member: %s, offset: %#lx\n", mt.name, mt.member_offset);
+}
+
static member_type *
get_or_create_member_type (member_parent *parent, uint64_t die_offset)
{
@@ -2785,6 +2874,39 @@ get_or_create_member_type (member_parent *parent, uint64_t die_offset)
return parent->member_tail;
}
+static bool
+display_member_parent (const member_parent mp)
+{
+ if (mp.displayed)
+ {
+ printf ("nested: struct %s\n", mp.name);
+ return true;
+ }
+ else if (mp.type == UNION_TYPE)
+ {
+ if (mp.name == NULL)
+ printf ("type: union <anonymous>");
+ else
+ printf ("type: union %s", mp.name);
+ }
+ else if (mp.type == STRUCT_TYPE)
+ {
+ if (mp.name == NULL)
+ printf ("type: struct <anonymous>");
+ else
+ printf ("type: struct %s", mp.name);
+ }
+
+ if (mp.is_declaration)
+ printf (", incomplete or non-defining declaration\n");
+ else if (mp.size_type == UNSIGNED_S)
+ printf (", size: %#lx\n", mp.size.usize);
+ else if (mp.size_type == SIGNED_S)
+ printf (", size: %#lx\n", mp.size.ssize);
+
+ return false;
+}
+
static member_parent *
get_or_create_member_parent (struct member_parent_l *mp_list,
uint64_t die_offset)
@@ -2803,6 +2925,8 @@ get_or_create_member_parent (struct member_parent_l *mp_list,
ret->field_type = MEMBER_PARENT;
ret->type = UNION_TYPE;
ret->is_declaration = false;
+ ret->linked = false;
+ ret->displayed = false;
if (mp_list->head == NULL)
{
mp_list->head = ret;
@@ -2817,6 +2941,15 @@ get_or_create_member_parent (struct member_parent_l *mp_list,
return mp_list->tail;
}
+static void
+display_type_ptr (const type_ptr tp)
+{
+ if (tp.size_type == UNSIGNED_S)
+ printf ("type: ptr, size: %#lx\n", tp.size.usize);
+ else if (tp.size_type == SIGNED_S)
+ printf ("type: ptr, size: %#lx\n", tp.size.ssize);
+}
+
static type_ptr *
get_or_create_type_ptr (uint64_t die_offset)
{
@@ -2846,6 +2979,20 @@ get_or_create_type_ptr (uint64_t die_offset)
return ptr_type_list.tail;
}
+static void
+display_type_ref (const type_ref tr)
+{
+ switch (tr.type)
+ {
+ case CONST_TYPE:
+ printf ("type: const\n");
+ break;
+ case VOLATILE_TYPE:
+ printf ("type: volatile\n");
+ break;
+ }
+}
+
static type_ref *
get_or_create_type_ref (struct type_ref_l *tr_list,
uint64_t die_offset)
@@ -2876,6 +3023,92 @@ get_or_create_type_ref (struct type_ref_l *tr_list,
return tr_list->tail;
}
+static void
+display_variable_type (generic_type gt,
+ int nb_tab)
+{
+ switch (gt.field_type)
+ {
+ case NO_TYPE:
+ break;
+ case BASE_TYPE:
+ PRINT_SPACE (nb_tab);
+ display_base_type (*gt.die_type.base_type);
+ break;
+ case TYPE_DEF:
+ PRINT_SPACE (nb_tab);
+ display_type_def (*gt.die_type.type_def);
+ PRINT_LBRACE (nb_tab);
+ display_variable_type (gt.die_type.type_def->ptr_type, nb_tab + 1);
+ PRINT_RBRACE (nb_tab);
+ break;
+ case ENUM_TYPE:
+ PRINT_SPACE (nb_tab);
+ display_enum_type (*gt.die_type.enum_type, nb_tab);
+ break;
+ case TAB_TYPE:
+ PRINT_SPACE (nb_tab);
+ display_tab_type (*gt.die_type.tab_type);
+ display_variable_type (gt.die_type.tab_type->ptr_type, nb_tab + 1);
+ break;
+ case MEMBER_PARENT:
+ {
+ PRINT_SPACE (nb_tab);
+ if (display_member_parent (*gt.die_type.member_parent))
+ break;
+ gt.die_type.member_parent->displayed = true;
+ if (gt.die_type.member_parent->member_head != NULL)
+ {
+ PRINT_LBRACE (nb_tab);
+ generic_type generic_mt
+ = { { .member_type = gt.die_type.member_parent->member_head },
+ MEMBER_TYPE };
+ display_variable_type (generic_mt, nb_tab + 1);
+ PRINT_RBRACE (nb_tab);
+ }
+ }
+ break;
+ case MEMBER_TYPE:
+ {
+ PRINT_SPACE (nb_tab + 1);
+ display_member_type (*gt.die_type.member_type);
+ display_variable_type (gt.die_type.member_type->ptr_type, nb_tab + 2);
+ if (gt.die_type.member_type->next != NULL)
+ {
+ generic_type generic_mt
+ = { { .member_type = gt.die_type.member_type->next },
+ MEMBER_TYPE };
+ display_variable_type (generic_mt, nb_tab);
+ }
+ }
+ break;
+ case TYPE_PTR:
+ PRINT_SPACE (nb_tab);
+ display_type_ptr (*gt.die_type.type_ptr);
+ display_variable_type (gt.die_type.type_ptr->ptr_type, nb_tab + 1);
+ break;
+ case TYPE_REF:
+ PRINT_SPACE (nb_tab);
+ display_type_ref (*gt.die_type.type_ref);
+ display_variable_type (gt.die_type.type_ref->ptr_type, nb_tab + 1);
+ break;
+ case VARIABLE_TYPE:
+ if (gt.die_type.variable_type->is_specification)
+ printf ("Incomplete, non-defining or separate declaration:\n");
+ else if (gt.die_type.variable_type->is_abstract_origin)
+ printf ("Inlined instance:\n");
+ else
+ {
+ uint64_t origin = gt.die_type.variable_type->location_addr;
+ uint64_t end = origin + gt.die_type.variable_type->total_size;
+ printf ("%s @ 0x%08lx 0x%08lx\n", gt.die_type.variable_type->name,
+ origin, end);
+ }
+ display_variable_type (gt.die_type.variable_type->ptr_type, nb_tab + 1);
+ break;
+ }
+}
+
static variable_type *
get_or_create_variable_type (uint64_t die_offset)
{
@@ -13883,6 +14116,343 @@ struct dwarf_section_display debug_displays[] =
/* A static assertion. */
extern int debug_displays_assert[ARRAY_SIZE (debug_displays) == max ? 1 : -1];
+static generic_type
+do_link_variable_information (generic_type src_die,
+ generic_type target_die)
+{
+ assert (src_die.field_type != NO_TYPE);
+
+ generic_type res = { { .base_type = NULL }, NO_TYPE };
+
+ switch (src_die.field_type)
+ {
+ case NO_TYPE:
+ case BASE_TYPE:
+ case ENUM_TYPE:
+ case MEMBER_PARENT:
+ break;
+ case MEMBER_TYPE:
+ src_die.die_type.member_type->ptr_type = target_die;
+ res = target_die;
+ break;
+ case TYPE_DEF:
+ src_die.die_type.type_def->ptr_type = target_die;
+ res = target_die;
+ break;
+ case TAB_TYPE:
+ src_die.die_type.tab_type->ptr_type = target_die;
+ res = target_die;
+ break;
+ case TYPE_PTR:
+ src_die.die_type.type_ptr->ptr_type = target_die;
+ res = target_die;
+ break;
+ case TYPE_REF:
+ src_die.die_type.type_ref->ptr_type = target_die;
+ res = target_die;
+ break;
+ case VARIABLE_TYPE:
+ src_die.die_type.variable_type->ptr_type = target_die;
+ /* If the variable_type of src_die has either DW_AT_specification or
+ DW_AT_abstract_origin present then src_die's variable_type could
+ have missing attributes such as DW_AT_name. Hence move the attribute
+ DW_AT_location held by src_die to target_die which have complete
+ attributes. */
+ if (src_die.die_type.variable_type->is_specification
+ || src_die.die_type.variable_type->is_abstract_origin)
+ {
+ assert (target_die.die_type.variable_type != NULL
+ && target_die.field_type == VARIABLE_TYPE);
+ target_die.die_type.variable_type->location_addr
+ = src_die.die_type.variable_type->location_addr;
+ }
+ res = target_die;
+ break;
+ }
+
+ return res;
+}
+
+static bool
+link_variable_information (generic_type src_die, uint64_t ptr_die_offset)
+{
+ assert (src_die.field_type != NO_TYPE
+ && src_die.die_type.base_type != NULL);
+
+ base_type *i_base_type = base_type_list.head;
+ while (i_base_type != NULL)
+ {
+ if (i_base_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_bt = { { .base_type = i_base_type }, BASE_TYPE };
+ do_link_variable_information (src_die, generic_bt);
+ return true;
+ }
+ i_base_type = i_base_type->next;
+ }
+
+ type_def *i_type_def = type_def_list.head;
+ while (i_type_def != NULL)
+ {
+ if (i_type_def->die_offset == ptr_die_offset)
+ {
+ generic_type generic_td = { { .type_def = i_type_def }, TYPE_DEF };
+ generic_td = do_link_variable_information (src_die, generic_td);
+ return link_variable_information (generic_td,
+ i_type_def->ptr_die_offset);
+ }
+ i_type_def = i_type_def->next;
+ }
+
+ enum_type *i_enum_type = enum_type_list.head;
+ while (i_enum_type != NULL)
+ {
+ if (i_enum_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_et = { { .enum_type = i_enum_type }, ENUM_TYPE };
+ do_link_variable_information (src_die, generic_et);
+ return true;
+ }
+ i_enum_type = i_enum_type->next;
+ }
+
+ tab_type *i_tab_type = tab_type_list.head;
+ while (i_tab_type != NULL)
+ {
+ if (i_tab_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_tt = { { .tab_type = i_tab_type }, TAB_TYPE };
+ generic_tt = do_link_variable_information (src_die, generic_tt);
+ return link_variable_information (generic_tt,
+ i_tab_type->ptr_die_offset);
+ }
+ i_tab_type = i_tab_type->next;
+ }
+
+ member_parent *i_struct_type = struct_type_list.head;
+ while (i_struct_type != NULL)
+ {
+ if (i_struct_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_mp = { { .member_parent = i_struct_type },
+ MEMBER_PARENT };
+ do_link_variable_information (src_die, generic_mp);
+
+ if (i_struct_type->linked)
+ return true;
+
+ i_struct_type->linked = true;
+ member_type *i_member_type = i_struct_type->member_head;
+ while (i_member_type != NULL)
+ {
+ generic_type generic_mt = { { .member_type = i_member_type },
+ MEMBER_TYPE };
+ link_variable_information (generic_mt,
+ i_member_type->ptr_die_offset);
+ i_member_type = i_member_type->next;
+ }
+ return true;
+ }
+ i_struct_type = i_struct_type->next;
+ }
+
+ member_parent *i_union_type = union_type_list.head;
+ while (i_union_type != NULL)
+ {
+ if (i_union_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_mp = { { .member_parent = i_union_type },
+ MEMBER_PARENT };
+ do_link_variable_information (src_die, generic_mp);
+
+ if (i_union_type->linked)
+ return true;
+
+ i_union_type->linked = true;
+ member_type *i_member_type = i_union_type->member_head;
+ while (i_member_type != NULL)
+ {
+ generic_type generic_mt = { { .member_type = i_member_type },
+ MEMBER_TYPE };
+ link_variable_information (generic_mt,
+ i_member_type->ptr_die_offset);
+ i_member_type = i_member_type->next;
+ }
+ return true;
+ }
+ i_union_type = i_union_type->next;
+ }
+
+ type_ptr *i_ptr_type = ptr_type_list.head;
+ while (i_ptr_type != NULL)
+ {
+ if (i_ptr_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_pt = { { .type_ptr = i_ptr_type }, TYPE_PTR };
+ generic_pt = do_link_variable_information (src_die, generic_pt);
+ return link_variable_information (generic_pt,
+ i_ptr_type->ptr_die_offset);
+ }
+ i_ptr_type = i_ptr_type->next;
+ }
+
+ type_ref *i_const_type = const_type_list.head;
+ while (i_const_type != NULL)
+ {
+ if (i_const_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_ref = { { .type_ref = i_const_type }, TYPE_REF };
+ generic_ref = do_link_variable_information (src_die, generic_ref);
+ return link_variable_information (generic_ref,
+ i_const_type->ptr_die_offset);
+ }
+ i_const_type = i_const_type->next;
+ }
+
+ type_ref *i_volatile_type = volatile_type_list.head;
+ while (i_volatile_type != NULL)
+ {
+ if (i_volatile_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_ref = { { .type_ref = i_volatile_type },
+ TYPE_REF };
+ generic_ref = do_link_variable_information (src_die, generic_ref);
+ return link_variable_information (generic_ref,
+ i_volatile_type->ptr_die_offset);
+ }
+ i_volatile_type = i_volatile_type->next;
+ }
+
+ variable_type *i_variable_type = variable_type_list.head;
+ while (i_variable_type != NULL)
+ {
+ if (i_variable_type->die_offset == ptr_die_offset)
+ {
+ generic_type generic_vt = { { .variable_type = i_variable_type },
+ VARIABLE_TYPE };
+ generic_vt = do_link_variable_information (src_die, generic_vt);
+ return link_variable_information (generic_vt,
+ i_variable_type->ptr_die_offset);
+ }
+ i_variable_type = i_variable_type->next;;
+ }
+
+ if (i_base_type == NULL && i_type_def == NULL
+ && i_enum_type == NULL && i_tab_type == NULL
+ && i_struct_type == NULL && i_union_type == NULL
+ && i_union_type == NULL && i_ptr_type == NULL
+ && i_const_type == NULL && i_volatile_type == NULL
+ && i_variable_type == NULL)
+ return false;
+
+ return true;
+}
+
+static uint64_t
+compute_variable_total_size (generic_type src_die)
+{
+ uint64_t size = 0;
+
+ switch (src_die.field_type)
+ {
+ case NO_TYPE:
+ break;
+ case BASE_TYPE:
+ if (src_die.die_type.base_type->size_type == UNSIGNED_S)
+ size = src_die.die_type.base_type->size.usize;
+ else if (src_die.die_type.base_type->size_type == SIGNED_S)
+ size = src_die.die_type.base_type->size.ssize;
+ return size;
+ case TYPE_DEF:
+ return compute_variable_total_size (src_die.die_type.type_def->ptr_type);
+ case ENUM_TYPE:
+ if (src_die.die_type.enum_type->size_type == UNSIGNED_S)
+ size = src_die.die_type.enum_type->size.usize;
+ else if (src_die.die_type.enum_type->size_type == SIGNED_S)
+ size = src_die.die_type.enum_type->size.ssize;
+ return size;
+ case TAB_TYPE:
+ {
+ size = (size == 0) ? 1 : size;
+ subrange_type *i_subrange = src_die.die_type.tab_type->subrange_head;
+ while (i_subrange != NULL)
+ {
+ if (i_subrange->size_type == UNSIGNED_S)
+ size = i_subrange->size.usize * size;
+ else if (i_subrange->size_type == SIGNED_S)
+ size = i_subrange->size.ssize * size;
+ i_subrange = i_subrange->next;
+ }
+ return size
+ * compute_variable_total_size (src_die.die_type.tab_type->ptr_type);
+ }
+ case MEMBER_TYPE:
+ return 0;
+ case MEMBER_PARENT:
+ if (src_die.die_type.member_parent->size_type == UNSIGNED_S)
+ size = src_die.die_type.member_parent->size.usize;
+ else if (src_die.die_type.member_parent->size_type == SIGNED_S)
+ size = src_die.die_type.member_parent->size.ssize;
+ return size;
+ case TYPE_PTR:
+ if (src_die.die_type.type_ptr->size_type == UNSIGNED_S)
+ size = src_die.die_type.type_ptr->size.usize;
+ else if (src_die.die_type.type_ptr->size_type == SIGNED_S)
+ size = src_die.die_type.type_ptr->size.ssize;
+ return size;
+ case TYPE_REF:
+ return compute_variable_total_size (src_die.die_type.type_ref->ptr_type);
+ case VARIABLE_TYPE:
+ return compute_variable_total_size (
+ src_die.die_type.variable_type->ptr_type);
+ }
+ return size;
+}
+
+static void
+reset_displayed_field (member_parent *mp_type)
+{
+ member_parent *i_mp = mp_type;
+ while (i_mp != NULL)
+ {
+ i_mp->displayed = false;
+ i_mp = i_mp->next;
+ }
+}
+
+void
+resolve_and_display_variable_info (void)
+{
+ variable_type *i_vt = variable_type_list.head;
+ while (i_vt != NULL)
+ {
+ generic_type generic_vt = { { .variable_type = i_vt }, VARIABLE_TYPE };
+ if (i_vt->has_location_addr
+ && link_variable_information (generic_vt, i_vt->ptr_die_offset))
+ {
+ uint64_t vt_size = compute_variable_total_size (generic_vt);
+ /* When is_specification or is_abstract_origin is true. The current
+ variable_type i_vt only holds DW_AT_location value and could be
+ missing DW_AT_name for example. Hence the move the size value to
+ the underlying DW_TAG_variable and display the underlying
+ DW_TAG_variable. */
+ if (i_vt->is_specification || i_vt->is_abstract_origin)
+ {
+ assert (i_vt->ptr_type.field_type == VARIABLE_TYPE
+ && i_vt->ptr_type.die_type.variable_type != NULL);
+ i_vt->ptr_type.die_type.variable_type->total_size = vt_size;
+ }
+ else
+ i_vt->total_size = vt_size;
+ display_variable_type (generic_vt, 0);
+ reset_displayed_field (struct_type_list.head);
+ reset_displayed_field (union_type_list.head);
+ printf ("\n");
+ }
+ i_vt = i_vt->next;
+ }
+}
+
static void
free_base_type (base_type *bt)
{
diff --git a/binutils/dwarf.h b/binutils/dwarf.h
index bdb6f669c8d..60b6ddeebf5 100644
--- a/binutils/dwarf.h
+++ b/binutils/dwarf.h
@@ -252,6 +252,12 @@ struct member_parent
this attribute is present the stucture/union is either incomplete,
non-defining or in a separate entity. */
bool is_declaration;
+ /* This field exists to avoid linking indefinitively nested structure. It is
+ set to true when the underlying type is known (linked). */
+ bool linked;
+ /* This field exists to avoid displaying indefinitvely nested structure. It
+ is set to true when informations from member_parent are displayed. */
+ bool displayed;
};
/* Structure used to hold DW_TAG_pointer_type. */
@@ -498,6 +504,7 @@ extern void free_debug_section (enum dwarf_section_display_enum);
extern bool load_separate_debug_files (void *, const char *);
extern void close_debug_file (void *);
extern void *open_debug_file (const char *);
+extern void resolve_and_display_variable_info (void);
extern void free_debug_memory (void);
extern void free_mapping_info_struct (void);
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 97ec2698a0e..e4e30f0f58a 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -4552,6 +4552,7 @@ dump_global_variable_info (bfd *abfd, asection *section,
if (load_specific_debug_section (info, section, abfd))
{
debug_displays [debug_variable_info].display (sec, abfd);
+ resolve_and_display_variable_info ();
free_mapping_info_struct ();
free_debug_section (info);
}
--
2.43.0
More information about the Binutils
mailing list