[PATCH v5 3/5] objdump: Add variable types and structure for DWARF info parsing
Guillaume VACHERIAS
guillaume.vacherias@foss.st.com
Fri Sep 26 12:22:30 GMT 2025
Introduce structures to represent DWARF debug information. Each structure
simplifies the parsing of attributes under DW_TAG_variable,
DW_TAG_pointer_type, DW_TAG_volatile_type, DW_TAG_const_type,
DW_TAG_union_type, DW_TAG_structure_type, DW_TAG_member, DW_TAG_array_type,
DW_TAG_subrange_type, DW_TAG_enumeration_type, DW_TAG_enumerator,
DW_TAG_typedef and DW_TAG_base_type.
Below is an example of a global variable `unsigned char foo`. The debug
information entry DW_TAG_variable gives the name (DW_AT_name) and location
(DW_AT_location) of the variable foo. It provides also its type with
DW_AT_type which is an offset that corresponds to the entry of
DW_TAG_base_type. Finally with DW_TAG_base_type we can determine the type
(DW_AT_name) and size (DW_AT_byte_size) of `foo`.
<1><1e>: Abbrev Number: 2 (DW_TAG_variable)
<1f> DW_AT_name : foo
<21> DW_AT_decl_file : 1
<22> DW_AT_decl_line : 1
<23> DW_AT_decl_column : 11
<24> DW_AT_type : <0x2e>
<28> DW_AT_external : 1
<28> DW_AT_location : 5 byte block: 3 0 80 0 0 (DW_OP_addr: 8000)
<1><2e>: Abbrev Number: 3 (DW_TAG_base_type)
<2f> DW_AT_byte_size : 1
<30> DW_AT_encoding : 8 (unsigned char)
<31> DW_AT_name : (indirect string, offset: 0x66): char
We declare in each structure a member `die_offset` which is the offset of the
debug entry in DWARF info section. Furthermore we use structure generic_type
to abstract and manipulate the kind of type the structure represents. Some of
the structure contains a member `ptr_die` that will be useful to indicate what
type of structure a variable is. For example, to know that `foo` variable is
char type. The structure generic_type that represents `foo` has its union
member `variable_type` set and will have in his turn the member `ptr_type`
set. Lastly `ptr_type` points to a generic_type which represents the structure
base_type that contains information of char type in his union member
`base_type`.
binutils/
* dwarf.h (base_type): New typedef. Hold DW_TAG_base_type information.
(type_def): Likewise for DW_TAG_typedef.
(enum_constant): Likewise for DW_TAG_enumerator.
(enum_type): Likewise for DW_TAG_enumeration_type.
(subrange_type): Likewise for DW_TAG_subrange_type.
(tab_type): Likewise for DW_TAG_array_type.
(member_type): Likewise for DW_TAG_member_type.
(member_parent): Likewise for DW_TAG_struct_type, DW_TAG_union_type.
(type_ref): Likewise for DW_TAG_pointer_type, DW_TAG_const_type and
DW_TAG_volatile_type.
(variable_type): Likewise for DW_TAG_variable_type.
(generic_type): New typedef. Generic type that abstract all types
defined above.
(generic_type_l): New typedef. Contains head and tail of generic_type
linked list for faster insertion of elements.
(free_mapping_info_struct): New definition.
* dwarf.c (get_or_create_or_generic_base_type): New function.
(get_or_create_generic_type_def): Likewise.
(get_or_create_enum_constant): Likewise.
(get_or_create_generic_enum_type): Likewise.
(get_or_create_subrange_type): Likewise.
(get_or_create_generic_tab_type): Likewise.
(get_or_create_generic_member_type): Likewise.
(get_or_create_generic_member_parent): Likewise.
(get_or_create_generic_type_ref): Likewise.
(get_or_create_generic_variable_type): Likewise.
(free_enum_constant): Likewise.
(free_subrange_type): Likewise.
(free_generic_type): Likewise.
(free_generic_type_list): Likewise.
(free_mapping_info_struct): Likewise.
(insert_element_in_list): Create and populate structures that hold
DWARF information to display global variable information.
* objdump.c (dump_global_variable_info): Free created and populated
structures.
Signed-off-by: Guillaume VACHERIAS <guillaume.vacherias@foss.st.com>
---
binutils/dwarf.c | 604 ++++++++++++++++++++++++++++++++++++++++++++-
binutils/dwarf.h | 169 +++++++++++++
binutils/objdump.c | 1 +
3 files changed, 765 insertions(+), 9 deletions(-)
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 33887112e12..3809d5ed48b 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -65,6 +65,18 @@ static int need_base_address;
static unsigned int num_debug_info_entries = 0;
static unsigned int alloc_num_debug_info_entries = 0;
static debug_info *debug_information = NULL;
+
+static generic_type_l base_type_list = {NULL, NULL};
+static generic_type_l type_def_list = {NULL, NULL};
+static generic_type_l enum_type_list = {NULL, NULL};
+static generic_type_l tab_type_list = {NULL, NULL};
+static generic_type_l struct_type_list = {NULL, NULL};
+static generic_type_l union_type_list = {NULL, NULL};
+static generic_type_l ptr_type_list = {NULL, NULL};
+static generic_type_l const_type_list = {NULL, NULL};
+static generic_type_l volatile_type_list = {NULL, NULL};
+static generic_type_l variable_type_list = {NULL, NULL};
+
/* Special value for num_debug_info_entries to indicate
that the .debug_info section could not be loaded/parsed. */
#define DEBUG_INFO_UNAVAILABLE (unsigned int) -1
@@ -1190,6 +1202,18 @@ get_location_expression (int die_tag,
{
case DW_OP_addr:
SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+ if (die_tag == DW_TAG_variable && attribute == DW_AT_location)
+ {
+ assert (variable_type_list.tail != NULL);
+ if (!variable_type_list.tail->die_type.variable_type
+ .has_location_addr)
+ {
+ variable_type_list.tail->die_type.variable_type
+ .location_addr = uvalue;
+ variable_type_list.tail->die_type.variable_type
+ .has_location_addr = true;
+ }
+ }
break;
case DW_OP_const1u:
SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
@@ -2569,41 +2593,517 @@ display_lang (uint64_t uvalue)
}
}
+static generic_type *
+get_or_create_generic_base_type (uint64_t die_offset)
+{
+ if (base_type_list.tail == NULL
+ || base_type_list.tail->die_type.base_type.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ base_type bt = {die_offset, 0, 0, NULL};
+ ret->type = BASE_TYPE;
+ ret->die_type.base_type = bt;
+ ret->linked = false;
+ ret->next = NULL;
+ if (base_type_list.head == NULL)
+ {
+ base_type_list.head = ret;
+ base_type_list.tail = base_type_list.head;
+ }
+ else
+ {
+ base_type_list.tail->next = ret;
+ base_type_list.tail = ret;
+ }
+ }
+ return base_type_list.tail;
+}
+
+static generic_type*
+get_or_create_generic_type_def (uint64_t die_offset)
+{
+ if (type_def_list.tail == NULL
+ || type_def_list.tail->die_type.type_def.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ type_def td = {die_offset, 0, NULL, NULL};
+ ret->type = TYPE_DEF;
+ ret->die_type.type_def = td;
+ ret->linked = false;
+ ret->next = NULL;
+ if (type_def_list.head == NULL)
+ {
+ type_def_list.head = ret;
+ type_def_list.tail = type_def_list.head;
+ }
+ else
+ {
+ type_def_list.tail->next = ret;
+ type_def_list.tail = ret;
+ }
+ }
+ return type_def_list.tail;
+}
+
+static enum_constant *
+get_or_create_enum_constant (enum_type *et, uint64_t die_offset)
+{
+ assert (et != NULL);
+ if (et->enum_const_tail == NULL
+ || et->enum_const_tail->die_offset != die_offset)
+ {
+ enum_constant *enum_const = xmalloc (sizeof (*enum_const));
+ enum_const->die_offset = die_offset;
+ enum_const->name = NULL;
+ enum_const->value = 0;
+ enum_const->next = NULL;
+ if (et->enum_const_head == NULL)
+ {
+ et->enum_const_head = enum_const;
+ et->enum_const_tail = et->enum_const_head;
+ }
+ else
+ {
+ et->enum_const_tail->next = enum_const;
+ et->enum_const_tail = enum_const;
+ }
+ }
+ return et->enum_const_tail;
+}
+
+static generic_type *
+get_or_create_generic_enum_type (uint64_t die_offset)
+{
+ if (enum_type_list.tail == NULL
+ || enum_type_list.tail->die_type.enum_type.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ enum_type et = {die_offset, 0, 0, NULL, NULL, NULL};
+ ret->type = ENUM_TYPE;
+ ret->die_type.enum_type = et;
+ ret->linked = false;
+ ret->next = NULL;
+ if (enum_type_list.head == NULL)
+ {
+ enum_type_list.head = ret;
+ enum_type_list.tail = enum_type_list.head;
+ }
+ else
+ {
+ enum_type_list.tail->next = ret;
+ enum_type_list.tail = ret;
+ }
+ }
+ return enum_type_list.tail;
+}
+
+static subrange_type *
+get_or_create_subrange_type (tab_type *tt, uint64_t die_offset)
+{
+ assert (tt != NULL);
+ if (tt->subrange_tail == NULL
+ || tt->subrange_tail->die_offset != die_offset)
+ {
+ subrange_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->usize = 0;
+ ret->ssize = 0;
+ ret->next = NULL;
+ if (tt->subrange_head == NULL)
+ {
+ tt->subrange_head = ret;
+ tt->subrange_tail = tt->subrange_head;
+ }
+ else
+ {
+ tt->subrange_tail->next = ret;
+ tt->subrange_tail = ret;
+ }
+ }
+ return tt->subrange_tail;
+}
+
+static generic_type *
+get_or_create_generic_tab_type (uint64_t die_offset)
+{
+ if (tab_type_list.tail == NULL
+ || tab_type_list.tail->die_type.tab_type.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ tab_type tt = {die_offset, 0, NULL, NULL, NULL};
+ ret->type = TAB_TYPE;
+ ret->die_type.tab_type = tt;
+ ret->linked = false;
+ ret->next = NULL;
+ if (tab_type_list.head == NULL)
+ {
+ tab_type_list.head = ret;
+ tab_type_list.tail = tab_type_list.head;
+ }
+ else
+ {
+ tab_type_list.tail->next = ret;
+ tab_type_list.tail = ret;
+ }
+ }
+ return tab_type_list.tail;
+}
+
+static generic_type *
+get_or_create_generic_member_type (generic_type *mp, uint64_t die_offset)
+{
+ assert (mp != NULL);
+ member_parent *parent = &mp->die_type.member_parent;
+ if (parent->member_tail == NULL
+ || parent->member_tail->die_type.member_type.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ member_type mt = {die_offset, 0, 0, NULL, NULL};
+ ret->type = MEMBER_TYPE;
+ ret->die_type.member_type = mt;
+ ret->linked = false;
+ ret->next = NULL;
+ if (parent->member_head == NULL)
+ {
+ parent->member_head = ret;
+ parent->member_tail = parent->member_head;
+ }
+ else
+ {
+ parent->member_tail->next = ret;
+ parent->member_tail = ret;
+ }
+ }
+ return parent->member_tail;
+}
+
+static generic_type *
+get_or_create_generic_member_parent (generic_type_l *mp_list,
+ uint64_t die_offset)
+{
+ if (mp_list->tail == NULL
+ || mp_list->tail->die_type.member_parent.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ /* Default to UNION_TYPE at initialization. */
+ member_parent mp = {die_offset, 0, 0, NULL, NULL,
+ NULL, false, UNION_TYPE};
+ ret->type = MEMBER_PARENT;
+ ret->die_type.member_parent = mp;
+ ret->linked = false;
+ ret->next = NULL;
+ if (mp_list->head == NULL)
+ {
+ mp_list->head = ret;
+ mp_list->tail = mp_list->head;
+ }
+ else
+ {
+ mp_list->tail->next = ret;
+ mp_list->tail = ret;
+ }
+ }
+ return mp_list->tail;
+}
+
+static generic_type *
+get_or_create_generic_type_ref (generic_type_l *tr_list,
+ uint64_t die_offset)
+{
+ if (tr_list->tail == NULL
+ || tr_list->tail->die_type.type_ref.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ /* Default to PTR_TYPE at initialization. */
+ type_ref tr = {die_offset, 0, 0, 0, PTR_TYPE, NULL};
+ ret->type = TYPE_REF;
+ ret->die_type.type_ref = tr;
+ ret->linked = false;
+ ret->next = NULL;
+ if (tr_list->head == NULL)
+ {
+ tr_list->head = ret;
+ tr_list->tail = tr_list->head;
+ }
+ else
+ {
+ tr_list->tail->next = ret;
+ tr_list->tail = ret;
+ }
+ }
+ return tr_list->tail;
+}
+
+static generic_type *
+get_or_create_generic_variable_type (uint64_t die_offset)
+{
+ if (variable_type_list.tail == NULL
+ || variable_type_list.tail->die_type.variable_type.die_offset != die_offset)
+ {
+ generic_type *ret = xmalloc (sizeof (*ret));
+ variable_type vt = {die_offset, 0, 0, 0, false, NULL, NULL, 0};
+ ret->type = VARIABLE_TYPE;
+ ret->die_type.variable_type = vt;
+ ret->linked = false;
+ ret->next = NULL;
+ if (variable_type_list.head == NULL)
+ {
+ variable_type_list.head = ret;
+ variable_type_list.tail = variable_type_list.head;
+ }
+ else
+ {
+ variable_type_list.tail->next = ret;
+ variable_type_list.tail = ret;
+ }
+ }
+ return variable_type_list.tail;
+}
+
static void
insert_element_in_list (enum dwarf_tag dw_tag,
- enum dwarf_attribute dw_attr ATTRIBUTE_UNUSED,
- uint64_t die_offset ATTRIBUTE_UNUSED,
- const uint64_t *uvalue ATTRIBUTE_UNUSED,
- const int64_t *svalue ATTRIBUTE_UNUSED,
- const char *data ATTRIBUTE_UNUSED,
- bool is_union ATTRIBUTE_UNUSED)
-{
- /* TODO: Retrieve attributes information from
- below dwarf entries tag. */
+ enum dwarf_attribute dw_attr,
+ uint64_t die_offset,
+ const uint64_t *uvalue,
+ const int64_t *svalue,
+ const char *data,
+ bool is_union)
+{
switch (dw_tag)
{
case DW_TAG_base_type:
+ {
+ generic_type *bt = get_or_create_generic_base_type (die_offset);
+ if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ bt->die_type.base_type.usize = ((uvalue != NULL) ? *uvalue : 0);
+ bt->die_type.base_type.ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ else if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ bt->die_type.base_type.name = (const char *) data;
+ else if (uvalue != NULL)
+ bt->die_type.base_type.name =
+ (const char *) fetch_indirect_string (*uvalue);
+ }
+ }
break;
case DW_TAG_typedef:
+ {
+ generic_type *td = get_or_create_generic_type_def (die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ td->die_type.type_def.ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ td->die_type.type_def.name = (const char *) data;
+ else if (uvalue != NULL)
+ td->die_type.type_def.name =
+ (const char *) fetch_indirect_string (*uvalue);
+ }
+ }
break;
case DW_TAG_enumerator:
+ {
+ enum_constant *ec =
+ get_or_create_enum_constant (&enum_type_list.tail->die_type.enum_type,
+ die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (data != NULL || uvalue != NULL);
+ if (data != NULL)
+ ec->name = (const char *) data;
+ else if (uvalue != NULL)
+ ec->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_const_value)
+ {
+ assert (uvalue != NULL);
+ ec->value = *uvalue;
+ }
+ }
break;
case DW_TAG_enumeration_type:
+ {
+ generic_type *et = get_or_create_generic_enum_type (die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ et->die_type.enum_type.name = (const char *) data;
+ else if (uvalue != NULL)
+ et->die_type.enum_type.name =
+ (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ et->die_type.enum_type.usize = ((uvalue != NULL) ? *uvalue : 0);
+ et->die_type.enum_type.ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ }
break;
case DW_TAG_subrange_type:
+ {
+ subrange_type *st =
+ get_or_create_subrange_type (&tab_type_list.tail->die_type.tab_type,
+ die_offset);
+ if (dw_attr == DW_AT_upper_bound || dw_attr == DW_AT_count)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ if (dw_attr == DW_AT_upper_bound)
+ {
+ st->ssize = ((svalue != NULL) ? *svalue + 1 : 0);
+ st->usize = ((uvalue != NULL) ? *uvalue + 1 : 0);
+ }
+ else if (dw_attr == DW_AT_count)
+ {
+ st->ssize = ((svalue != NULL) ? *svalue : 0);
+ st->usize = ((uvalue != NULL) ? *uvalue : 0);
+ }
+ }
+ }
break;
case DW_TAG_array_type:
+ {
+ generic_type *tt = get_or_create_generic_tab_type (die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ tt->die_type.tab_type.ptr_die_offset = *uvalue;
+ }
+ }
break;
case DW_TAG_member:
+ {
+ generic_type *mt = NULL;
+ if (is_union)
+ mt = get_or_create_generic_member_type (union_type_list.tail,
+ die_offset);
+ else
+ mt = get_or_create_generic_member_type (struct_type_list.tail,
+ die_offset);
+
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ mt->die_type.member_type.name = (const char *) data;
+ else if (uvalue != NULL)
+ mt->die_type.member_type.name =
+ (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ mt->die_type.member_type.ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_data_member_location)
+ {
+ assert (svalue != NULL || uvalue != NULL);
+ if (svalue != NULL)
+ mt->die_type.member_type.member_offset = *svalue;
+ if (uvalue != NULL)
+ mt->die_type.member_type.member_offset = *uvalue;
+ }
+ }
break;
case DW_TAG_structure_type:
case DW_TAG_union_type:
+ {
+ generic_type *mb = NULL;
+ if (dw_tag == DW_TAG_union_type)
+ mb = get_or_create_generic_member_parent (&union_type_list,
+ die_offset);
+ else if (dw_tag == DW_TAG_structure_type)
+ {
+ mb = get_or_create_generic_member_parent (&struct_type_list,
+ die_offset);
+ mb->die_type.member_parent.type = STRUCT_TYPE;
+ }
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ mb->die_type.member_parent.name = (const char *) data;
+ else if (uvalue != NULL)
+ mb->die_type.member_parent.name =
+ (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ mb->die_type.member_parent.usize = ((uvalue != NULL) ? *uvalue : 0);
+ mb->die_type.member_parent.ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ }
break;
case DW_TAG_const_type:
case DW_TAG_volatile_type:
case DW_TAG_pointer_type:
+ {
+ generic_type *tr = NULL;
+ if (dw_tag == DW_TAG_const_type)
+ {
+ tr = get_or_create_generic_type_ref (&const_type_list, die_offset);
+ tr->die_type.type_ref.type = CONST_TYPE;
+ }
+ else if (dw_tag == DW_TAG_volatile_type)
+ {
+ tr = get_or_create_generic_type_ref (&volatile_type_list,
+ die_offset);
+ tr->die_type.type_ref.type = VOLATILE_TYPE;
+ }
+ else if (dw_tag == DW_TAG_pointer_type)
+ tr = get_or_create_generic_type_ref (&ptr_type_list, die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ tr->die_type.type_ref.ptr_die_offset = *uvalue;
+ }
+ if (dw_attr == DW_AT_byte_size && dw_tag == DW_TAG_pointer_type)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ tr->die_type.type_ref.usize = ((uvalue != NULL) ? *uvalue : 0);
+ tr->die_type.type_ref.ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ }
break;
case DW_TAG_variable:
+ {
+ generic_type *vt = get_or_create_generic_variable_type (die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ vt->die_type.variable_type.name = (const char *) data;
+ else if (uvalue != NULL)
+ vt->die_type.variable_type.name =
+ (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ vt->die_type.variable_type.ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_specification)
+ {
+ assert (uvalue != NULL);
+ vt->die_type.variable_type.ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_abstract_origin)
+ {
+ assert (uvalue != NULL);
+ vt->die_type.variable_type.ptr_die_offset = *uvalue;
+ }
+ }
break;
default:
break;
@@ -13280,3 +13780,89 @@ struct dwarf_section_display debug_displays[] =
/* A static assertion. */
extern int debug_displays_assert[ARRAY_SIZE (debug_displays) == max ? 1 : -1];
+
+static void
+free_enum_constant (enum_constant *ec)
+{
+ enum_constant *head = ec;
+ while (head != NULL)
+ {
+ enum_constant *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_subrange_type (subrange_type *st)
+{
+ subrange_type * head = st;
+ while (head != NULL)
+ {
+ subrange_type *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_generic_type (generic_type *die_type)
+{
+ switch (die_type->type)
+ {
+ case BASE_TYPE:
+ case TYPE_DEF:
+ case TYPE_REF:
+ case VARIABLE_TYPE:
+ case MEMBER_TYPE:
+ free (die_type);
+ break;
+ case ENUM_TYPE:
+ free_enum_constant (die_type->die_type.enum_type.enum_const_head);
+ free (die_type);
+ break;
+ case TAB_TYPE:
+ free_subrange_type (die_type->die_type.tab_type.subrange_head);
+ free (die_type);
+ break;
+ case MEMBER_PARENT:
+ {
+ generic_type *mt_head = die_type->die_type.member_parent.member_head;
+ while (mt_head != NULL)
+ {
+ generic_type *mt_next = mt_head->next;
+ free_generic_type (mt_head);
+ mt_head = mt_next;
+ }
+ }
+ free (die_type);
+ break;
+ }
+}
+
+static void
+free_generic_type_list (generic_type_l gt_list)
+{
+ generic_type *head = gt_list.head;
+ while (head != NULL)
+ {
+ generic_type *next = head->next;
+ free_generic_type (head);
+ head = next;
+ }
+}
+
+void
+free_mapping_info_struct ()
+{
+ free_generic_type_list (base_type_list);
+ free_generic_type_list (type_def_list);
+ free_generic_type_list (enum_type_list);
+ free_generic_type_list (tab_type_list);
+ free_generic_type_list (struct_type_list);
+ free_generic_type_list (union_type_list);
+ free_generic_type_list (ptr_type_list);
+ free_generic_type_list (const_type_list);
+ free_generic_type_list (volatile_type_list);
+ free_generic_type_list (variable_type_list);
+}
diff --git a/binutils/dwarf.h b/binutils/dwarf.h
index 8efd0c37b5b..818d280db5a 100644
--- a/binutils/dwarf.h
+++ b/binutils/dwarf.h
@@ -71,6 +71,174 @@ typedef struct
}
DWARF2_Internal_ARange;
+/* Forward declaration */
+typedef struct generic_type generic_type;
+typedef struct base_type base_type;
+typedef struct type_def type_def;
+typedef struct enum_constant enum_constant;
+typedef struct enum_type enum_type;
+typedef struct subrange_type subrange_type;
+typedef struct tab_type tab_type;
+typedef struct member_type member_type;
+typedef struct member_parent member_parent;
+typedef struct type_ref type_ref;
+typedef struct variable_type variable_type;
+
+/* Container for map info information to be generated. */
+struct base_type
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+ const char *name;
+};
+
+struct type_def
+{
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ const char *name;
+
+ /* Field where information retrievable by resolving the type. */
+ generic_type *ptr_type;
+};
+
+struct enum_constant
+{
+ uint64_t die_offset;
+ uint64_t value;
+ const char *name;
+
+ enum_constant *next;
+};
+
+struct enum_type
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+ const char *name;
+ enum_constant *enum_const_head;
+ enum_constant *enum_const_tail;
+};
+
+struct subrange_type
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+
+ struct subrange_type *next;
+};
+
+struct tab_type
+{
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ subrange_type *subrange_head;
+ subrange_type *subrange_tail;
+
+ /* Field where information retrievable by resolving the type. */
+ generic_type *ptr_type;
+};
+
+struct member_type
+{
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ int64_t member_offset;
+ const char *name;
+
+ /* Field where information retrievable by resolving the type. */
+ generic_type *ptr_type;
+};
+
+/* N.B. member_parent holds information on struct or union variables. */
+struct member_parent
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+ const char *name;
+ generic_type *member_head;
+ generic_type *member_tail;
+ bool displayed; /* Treat nested structure. */
+ enum
+ {
+ UNION_TYPE,
+ STRUCT_TYPE
+ } type;
+};
+
+/* N.B. type_ref holds information on pointer, constant and volatile
+ type variables. */
+struct type_ref
+{
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ uint64_t usize;
+ int64_t ssize;
+ enum
+ {
+ PTR_TYPE,
+ VOLATILE_TYPE,
+ CONST_TYPE
+ } type;
+
+ /* Field where information retrievable by resolving the type. */
+ generic_type *ptr_type;
+};
+
+struct variable_type
+{
+ /* field where information retrievable by parsing DWARF. */
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ uint64_t location_addr; /* DW_OP_addr value. */
+ uint64_t ttsize;
+ int has_location_addr;
+ const char *name;
+
+ /* Field where information retrievable by resolving the type. */
+ generic_type *ptr_type;
+ uint64_t total_size;
+};
+
+struct generic_type
+{
+ enum
+ {
+ BASE_TYPE,
+ TYPE_DEF,
+ ENUM_TYPE,
+ TAB_TYPE,
+ MEMBER_PARENT,
+ MEMBER_TYPE,
+ TYPE_REF,
+ VARIABLE_TYPE
+ } type;
+ union
+ {
+ base_type base_type;
+ type_def type_def;
+ enum_type enum_type;
+ tab_type tab_type;
+ member_parent member_parent;
+ member_type member_type;
+ type_ref type_ref;
+ variable_type variable_type;
+ } die_type;
+ bool linked; /* Treat nested structure. */
+
+ struct generic_type *next;
+};
+
+typedef struct generic_type_l
+{
+ generic_type *head;
+ generic_type *tail;
+} generic_type_l;
+
/* N.B. The order here must match the order in debug_displays. */
enum dwarf_section_display_enum
@@ -253,6 +421,7 @@ extern void close_debug_file (void *);
extern void *open_debug_file (const char *);
extern void free_debug_memory (void);
+extern void free_mapping_info_struct (void);
extern int dwarf_select_sections_by_names (const char *);
extern int dwarf_select_sections_by_letters (const char *);
diff --git a/binutils/objdump.c b/binutils/objdump.c
index cbc0aac9ddb..97ec2698a0e 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);
+ free_mapping_info_struct ();
free_debug_section (info);
}
}
--
2.25.1
More information about the Binutils
mailing list