[PATCH v6 3/5] objdump: Add variable types and structure for DWARF info parsing
Guillaume VACHERIAS
guillaume.vacherias@foss.st.com
Fri Nov 21 12:51:30 GMT 2025
Introduce structures to represent/hold 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 information entry of the DWARF info section. We declare another member
`field_type` to identify the kind of information a structure contain.
Furthermore we use structure `generic_type` to abstract and manipulate all
possible structure at once. This is used to resolve complex variable type.
Notice that structures `type_def`, `tab_type`, `member_type`, `type_ptr`,
`type_ref` and `variable_type` have member `ptr_die` that is a `generic_type`.
By having `generic_type` used as a flexible container to link together all
structures that represents a DWARF type, it allows to process easily the DWARF
type information regardless of the underlying type. For example, to resolve
variable `foo`'s type. The `variable_type` structure that represents `foo`
will have its member `ptr_type` set to hold a `base_type` structure. This
`base_type` structure contains information of char type. Hence `foo` is a char
type variable.
binutils/
* dwarf.h (field_type): New enum. Holds all possible DWARF structure
container types defined below.
(size_type): New enum.
(generic_type): New typedef. Generic type that abstract all types
(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_ptr): Likewise for DW_TAG_pointer_type
(type_ref): Likewise for DW_TAG_const_type and DW_TAG_volatile_type.
(variable_type): Likewise for DW_TAG_variable_type.
defined above.
(base_type_l: New structure. Linked list container with head and tail.
(type_def_l): Likewise.
(enum_type_l): Likewise.
(tab_type_l): Likewise.
(type_ptr_l): Likewise.
(type_ref_l): Likewise.
(member_parent_l): Likewise.
(variable_type_l): Likewise.
(free_mapping_info_struct): New definition.
* dwarf.c (get_or_create_or_base_type): New function.
(get_or_create_type_def): Likewise.
(get_or_create_enum_constant): Likewise.
(get_or_create_enum_type): Likewise.
(get_or_create_subrange_type): Likewise.
(get_or_create_tab_type): Likewise.
(get_or_create_member_type): Likewise.
(get_or_create_member_parent): Likewise.
(get_or_create_type_ptr): Likewise.
(get_or_create_type_ref): Likewise.
(get_or_create_variable_type): Likewise.
(free_base_type): Likewise.
(free_type_def): Likewise.
(free_enum_constant): Likewise.
(free_enum_type): Likewise.
(free_subrange_type): Likewise.
(free_tab_type): Likewise.
(free_member_type): Likewise.
(free_member_parent): Likewise.
(free_type_ptr): Likewise.
(free_type_ref): Likewise.
(free_variable_type): Likewise.
(free_mapping_info_struct): Likewise.
(insert_element_in_list): Create and populate structures that hold
DWARF 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 | 772 ++++++++++++++++++++++++++++++++++++++++++++-
binutils/dwarf.h | 248 +++++++++++++++
binutils/objdump.c | 1 +
3 files changed, 1011 insertions(+), 10 deletions(-)
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 33887112e12..9f45d108100 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 struct base_type_l base_type_list = {NULL, NULL};
+static struct type_def_l type_def_list = {NULL, NULL};
+static struct enum_type_l enum_type_list = {NULL, NULL};
+static struct tab_type_l tab_type_list = {NULL, NULL};
+static struct member_parent_l struct_type_list = {NULL, NULL};
+static struct member_parent_l union_type_list = {NULL, NULL};
+static struct type_ptr_l ptr_type_list = {NULL, NULL};
+static struct type_ref_l const_type_list = {NULL, NULL};
+static struct type_ref_l volatile_type_list = {NULL, NULL};
+static struct variable_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,15 @@ 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->has_location_addr)
+ {
+ variable_type_list.tail->location_addr = uvalue;
+ variable_type_list.tail->has_location_addr = true;
+ }
+ }
break;
case DW_OP_const1u:
SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
@@ -2569,41 +2590,622 @@ display_lang (uint64_t uvalue)
}
}
+static base_type *
+get_or_create_base_type (uint64_t die_offset)
+{
+ if (base_type_list.tail == NULL
+ || base_type_list.tail->die_offset != die_offset)
+ {
+ base_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->name = NULL;
+ ret->next = NULL;
+ ret->field_type = BASE_TYPE;
+ ret->size_type = UNSIGNED_S;
+ ret->size.usize = 0;
+ if (base_type_list.head == NULL)
+ {
+ base_type_list.head = ret;
+ base_type_list.tail = ret;
+ }
+ else
+ {
+ base_type_list.tail->next = ret;
+ base_type_list.tail = ret;
+ }
+ }
+ return base_type_list.tail;
+}
+
+static type_def*
+get_or_create_type_def (uint64_t die_offset)
+{
+ if (type_def_list.tail == NULL
+ || type_def_list.tail->die_offset != die_offset)
+ {
+ generic_type gt = { { .base_type = NULL }, NO_TYPE };
+ type_def *ret = xmalloc (sizeof (*ret));
+ ret->ptr_type = gt;
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->name = NULL;
+ ret->next = NULL;
+ ret->field_type = TYPE_DEF;
+ if (type_def_list.head == NULL)
+ {
+ type_def_list.head = ret;
+ type_def_list.tail = ret;
+ }
+ 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->value = 0;
+ enum_const->name = NULL;
+ enum_const->next = NULL;
+ if (et->enum_const_head == NULL)
+ {
+ et->enum_const_head = enum_const;
+ et->enum_const_tail = enum_const;
+ }
+ else
+ {
+ et->enum_const_tail->next = enum_const;
+ et->enum_const_tail = enum_const;
+ }
+ }
+ return et->enum_const_tail;
+}
+
+static enum_type *
+get_or_create_enum_type (uint64_t die_offset)
+{
+ if (enum_type_list.tail == NULL
+ || enum_type_list.tail->die_offset != die_offset)
+ {
+ enum_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->size.usize = 0;
+ ret->name = NULL;
+ ret->enum_const_head = NULL;
+ ret->enum_const_tail = NULL;
+ ret->next = NULL;
+ ret->field_type = ENUM_TYPE;
+ ret->size_type = UNSIGNED_S;
+ if (enum_type_list.head == NULL)
+ {
+ enum_type_list.head = ret;
+ enum_type_list.tail = ret;
+ }
+ 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->size.usize = 0;
+ ret->next = NULL;
+ ret->size_type = UNSIGNED_S;
+ if (tt->subrange_head == NULL)
+ {
+ tt->subrange_head = ret;
+ tt->subrange_tail = ret;
+ }
+ else
+ {
+ tt->subrange_tail->next = ret;
+ tt->subrange_tail = ret;
+ }
+ }
+ return tt->subrange_tail;
+}
+
+static tab_type *
+get_or_create_tab_type (uint64_t die_offset)
+{
+ if (tab_type_list.tail == NULL
+ || tab_type_list.tail->die_offset != die_offset)
+ {
+ generic_type gt = { { .base_type = NULL }, NO_TYPE };
+ tab_type *ret = xmalloc (sizeof (*ret));
+ ret->ptr_type = gt;
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->subrange_head = NULL;
+ ret->subrange_tail = NULL;
+ ret->next = NULL;
+ ret->field_type = TAB_TYPE;
+ if (tab_type_list.head == NULL)
+ {
+ tab_type_list.head = ret;
+ tab_type_list.tail = ret;
+ }
+ else
+ {
+ tab_type_list.tail->next = ret;
+ tab_type_list.tail = ret;
+ }
+ }
+ return tab_type_list.tail;
+}
+
+static member_type *
+get_or_create_member_type (member_parent *parent, uint64_t die_offset)
+{
+ assert (parent != NULL);
+ if (parent->member_tail == NULL
+ || parent->member_tail->die_offset != die_offset)
+ {
+ generic_type gt = { { .base_type = NULL }, NO_TYPE };
+ member_type *ret = xmalloc (sizeof (*ret));
+ ret->ptr_type = gt;
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->member_offset = 0;
+ ret->name = 0;
+ ret->next = NULL;
+ ret->field_type = MEMBER_TYPE;
+ if (parent->member_head == NULL)
+ {
+ parent->member_head = ret;
+ parent->member_tail = ret;
+ }
+ else
+ {
+ parent->member_tail->next = ret;
+ parent->member_tail = ret;
+ }
+ }
+ return parent->member_tail;
+}
+
+static member_parent *
+get_or_create_member_parent (struct member_parent_l *mp_list,
+ uint64_t die_offset)
+{
+ if (mp_list->tail == NULL
+ || mp_list->tail->die_offset != die_offset)
+ {
+ member_parent *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->size.usize = 0;
+ ret->name = NULL;
+ ret->member_head = NULL;
+ ret->member_tail = NULL;
+ ret->next = NULL;
+ ret->size_type = UNSIGNED_S;
+ ret->field_type = MEMBER_PARENT;
+ ret->type = UNION_TYPE;
+ ret->is_declaration = false;
+ if (mp_list->head == NULL)
+ {
+ mp_list->head = ret;
+ mp_list->tail = ret;
+ }
+ else
+ {
+ mp_list->tail->next = ret;
+ mp_list->tail = ret;
+ }
+ }
+ return mp_list->tail;
+}
+
+static type_ptr *
+get_or_create_type_ptr (uint64_t die_offset)
+{
+ if (ptr_type_list.tail == NULL
+ || ptr_type_list.tail->die_offset != die_offset)
+ {
+ generic_type gt = { { .base_type = NULL }, NO_TYPE };
+ type_ptr *ret = xmalloc (sizeof (*ret));
+ ret->ptr_type = gt;
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->size.usize = 0;
+ ret->next = NULL;
+ ret->field_type = TYPE_PTR;
+ ret->size_type = UNSIGNED_S;
+ if (ptr_type_list.head == NULL)
+ {
+ ptr_type_list.head = ret;
+ ptr_type_list.tail = ret;
+ }
+ else
+ {
+ ptr_type_list.tail->next = ret;
+ ptr_type_list.tail = ret;
+ }
+ }
+ return ptr_type_list.tail;
+}
+
+static type_ref *
+get_or_create_type_ref (struct type_ref_l *tr_list,
+ uint64_t die_offset)
+{
+ if (tr_list->tail == NULL
+ || tr_list->tail->die_offset != die_offset)
+ {
+ generic_type gt = { { .base_type = NULL }, NO_TYPE };
+ type_ref *ret = xmalloc (sizeof (*ret));
+ ret->ptr_type = gt;
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->next = NULL;
+ /* Default to CONST_TYPE at initialization. */
+ ret->type = CONST_TYPE;
+ ret->field_type = TYPE_REF;
+ if (tr_list->head == NULL)
+ {
+ tr_list->head = ret;
+ tr_list->tail = ret;
+ }
+ else
+ {
+ tr_list->tail->next = ret;
+ tr_list->tail = ret;
+ }
+ }
+ return tr_list->tail;
+}
+
+static variable_type *
+get_or_create_variable_type (uint64_t die_offset)
+{
+ if (variable_type_list.tail == NULL
+ || variable_type_list.tail->die_offset != die_offset)
+ {
+ generic_type gt = { { .base_type = NULL }, NO_TYPE };
+ variable_type *ret = xmalloc (sizeof (*ret));
+ ret->field_type = VARIABLE_TYPE;
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->location_addr = 0;
+ ret->total_size = 0;
+ ret->has_location_addr = false;
+ ret->is_specification = false;
+ ret->is_abstract_origin = false;
+ ret->name = NULL;
+ ret->ptr_type = gt;
+ ret->next = NULL;
+ if (variable_type_list.head == NULL)
+ {
+ variable_type_list.head = ret;
+ variable_type_list.tail = ret;
+ }
+ 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:
+ {
+ base_type *bt = get_or_create_base_type (die_offset);
+ if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ if (uvalue != NULL)
+ {
+ bt->size.usize = *uvalue;
+ bt->size_type = UNSIGNED_S;
+ }
+ else
+ {
+ bt->size.ssize = *svalue;
+ bt->size_type = SIGNED_S;
+ }
+ }
+ else if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ bt->name = (const char *) data;
+ else if (uvalue != NULL)
+ bt->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ }
break;
case DW_TAG_typedef:
+ {
+ type_def *td = get_or_create_type_def (die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ td->ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ td->name = (const char *) data;
+ else if (uvalue != NULL)
+ td->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_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:
+ {
+ enum_type *et = get_or_create_enum_type (die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ et->name = (const char *) data;
+ else if (uvalue != NULL)
+ et->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ if (uvalue != NULL)
+ {
+ et->size.usize = *uvalue;
+ et->size_type = UNSIGNED_S;
+ }
+ else
+ {
+ et->size.ssize = *svalue;
+ et->size_type = SIGNED_S;
+ }
+ }
+ }
break;
case DW_TAG_subrange_type:
+ {
+ subrange_type *st = get_or_create_subrange_type (tab_type_list.tail,
+ 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)
+ {
+ if (uvalue != NULL)
+ {
+ st->size.usize = *uvalue + 1;
+ st->size_type = UNSIGNED_S;
+ }
+ else
+ {
+ st->size.ssize = *svalue + 1;
+ st->size_type = SIGNED_S;
+ }
+ }
+ else if (dw_attr == DW_AT_count)
+ {
+ if (uvalue != NULL)
+ {
+ st->size.usize = *uvalue;
+ st->size_type = UNSIGNED_S;
+ }
+ else
+ {
+ st->size.ssize = *svalue;
+ st->size_type = SIGNED_S;
+ }
+ }
+ }
+ }
break;
case DW_TAG_array_type:
+ {
+ tab_type *tt = get_or_create_tab_type (die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ tt->ptr_die_offset = *uvalue;
+ }
+ }
break;
case DW_TAG_member:
+ {
+ member_type *mt = NULL;
+ if (is_union)
+ mt = get_or_create_member_type (union_type_list.tail, die_offset);
+ else
+ mt = get_or_create_member_type (struct_type_list.tail, die_offset);
+
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ mt->name = (const char *) data;
+ else if (uvalue != NULL)
+ mt->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ mt->ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_data_member_location)
+ {
+ assert (svalue != NULL || uvalue != NULL);
+ if (svalue != NULL)
+ mt->member_offset = *svalue;
+ else if (uvalue != NULL)
+ mt->member_offset = *uvalue;
+ }
+ }
break;
case DW_TAG_structure_type:
case DW_TAG_union_type:
+ {
+ member_parent *mp = NULL;
+ if (dw_tag == DW_TAG_union_type)
+ mp = get_or_create_member_parent (&union_type_list, die_offset);
+ else if (dw_tag == DW_TAG_structure_type)
+ {
+ mp = get_or_create_member_parent (&struct_type_list, die_offset);
+ mp->type = STRUCT_TYPE;
+ }
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ mp->name = (const char *) data;
+ else if (uvalue != NULL)
+ mp->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ if (uvalue != NULL)
+ {
+ mp->size.usize = *uvalue;
+ mp->size_type = UNSIGNED_S;
+ }
+ else
+ {
+ mp->size.ssize = *svalue;
+ mp->size_type = SIGNED_S;
+ }
+ }
+ else if (dw_attr == DW_AT_declaration)
+ mp->is_declaration = true;
+ }
+ break;
+ case DW_TAG_pointer_type:
+ {
+ type_ptr* pt = get_or_create_type_ptr (die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ pt->ptr_die_offset = *uvalue;
+ }
+ if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ if (uvalue != NULL)
+ {
+ pt->size.usize = *uvalue;
+ pt->size_type = UNSIGNED_S;
+ }
+ else
+ {
+ pt->size.ssize = *svalue;
+ pt->size_type = SIGNED_S;
+ }
+ }
+ }
break;
case DW_TAG_const_type:
case DW_TAG_volatile_type:
- case DW_TAG_pointer_type:
+ {
+ type_ref *tr = NULL;
+ if (dw_tag == DW_TAG_const_type)
+ {
+ tr = get_or_create_type_ref (&const_type_list, die_offset);
+ tr->type = CONST_TYPE;
+ }
+ else if (dw_tag == DW_TAG_volatile_type)
+ {
+ tr = get_or_create_type_ref (&volatile_type_list, die_offset);
+ tr->type = VOLATILE_TYPE;
+ }
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ tr->ptr_die_offset = *uvalue;
+ }
+ }
break;
case DW_TAG_variable:
+ {
+ variable_type *vt = get_or_create_variable_type (die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ vt->name = (const char *) data;
+ else if (uvalue != NULL)
+ vt->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ if (!vt->is_specification && !vt->is_abstract_origin)
+ vt->ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_specification)
+ {
+ assert (uvalue != NULL);
+ if (!vt->is_abstract_origin)
+ {
+ vt->ptr_die_offset = *uvalue;
+ vt->is_specification = true;
+ }
+ }
+ else if (dw_attr == DW_AT_abstract_origin)
+ {
+ assert (uvalue != NULL);
+ if (!vt->is_specification)
+ {
+ vt->ptr_die_offset = *uvalue;
+ vt->is_abstract_origin = true;
+ }
+ }
+ }
break;
default:
break;
@@ -13280,3 +13882,153 @@ struct dwarf_section_display debug_displays[] =
/* A static assertion. */
extern int debug_displays_assert[ARRAY_SIZE (debug_displays) == max ? 1 : -1];
+
+static void
+free_base_type (base_type *bt)
+{
+ base_type *head = bt;
+ while (head != NULL)
+ {
+ base_type *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_type_def (type_def *td)
+{
+ type_def *head = td;
+ while (head != NULL)
+ {
+ type_def *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+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_enum_type (enum_type *et)
+{
+ enum_type *head = et;
+ while (head != NULL)
+ {
+ enum_type *next = head->next;
+ free_enum_constant (head->enum_const_head);
+ 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_tab_type (tab_type *tt)
+{
+ tab_type *head = tt;
+ while (head != NULL)
+ {
+ tab_type *next = head->next;
+ free_subrange_type (head->subrange_head);
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_member_type (member_type *mt)
+{
+ member_type *head = mt;
+ while (head != NULL)
+ {
+ member_type *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_member_parent (member_parent *mp)
+{
+ member_parent *head = mp;
+ while (head != NULL)
+ {
+ member_parent *next = head->next;
+ free_member_type (head->member_head);
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_type_ptr (type_ptr *tp)
+{
+ type_ptr *head = tp;
+ while (head != NULL)
+ {
+ type_ptr *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_type_ref (type_ref *tr)
+{
+ type_ref *head = tr;
+ while (head != NULL)
+ {
+ type_ref *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_variable_type (variable_type *vt)
+{
+ variable_type *head = vt;
+ while (head != NULL)
+ {
+ variable_type *next = head->next;
+ free (head);
+ head = next;
+ }
+}
+
+void
+free_mapping_info_struct ()
+{
+ free_base_type (base_type_list.head);
+ free_type_def (type_def_list.head);
+ free_enum_type (enum_type_list.head);
+ free_tab_type (tab_type_list.head);
+ free_member_parent (struct_type_list.head);
+ free_member_parent (union_type_list.head);
+ free_type_ptr (ptr_type_list.head);
+ free_type_ref (const_type_list.head);
+ free_type_ref (volatile_type_list.head);
+ free_variable_type (variable_type_list.head);
+}
diff --git a/binutils/dwarf.h b/binutils/dwarf.h
index 8efd0c37b5b..bdb6f669c8d 100644
--- a/binutils/dwarf.h
+++ b/binutils/dwarf.h
@@ -71,6 +71,253 @@ 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_ptr type_ptr;
+typedef struct type_ref type_ref;
+typedef struct variable_type variable_type;
+
+/* Structure used to optimize insertion of element in linked list. */
+struct base_type_l { base_type *head; base_type *tail; };
+struct type_def_l { type_def *head; type_def *tail; };
+struct enum_type_l { enum_type* head; enum_type* tail; };
+struct tab_type_l { tab_type *head; tab_type *tail; };
+struct type_ptr_l { type_ptr *head; type_ptr *tail; };
+struct type_ref_l { type_ref *head; type_ref *tail; };
+struct member_parent_l { member_parent *head; member_parent *tail; };
+struct variable_type_l { variable_type *head; variable_type *tail; };
+
+enum field_type
+{
+ NO_TYPE,
+ BASE_TYPE,
+ TYPE_DEF,
+ ENUM_TYPE,
+ TAB_TYPE,
+ MEMBER_PARENT,
+ MEMBER_TYPE,
+ TYPE_PTR,
+ TYPE_REF,
+ VARIABLE_TYPE
+};
+
+enum size_type
+{
+ UNSIGNED_S,
+ SIGNED_S
+};
+
+/* Structure used to abstract all structure below. */
+struct generic_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_ptr *type_ptr;
+ type_ref *type_ref;
+ variable_type *variable_type;
+ } die_type;
+ enum field_type field_type;
+};
+
+/* Structure used to hold DW_TAG_base_type. */
+struct base_type
+{
+ uint64_t die_offset;
+ union
+ {
+ uint64_t usize;
+ int64_t ssize;
+ } size;
+ const char *name;
+ struct base_type *next;
+ enum field_type field_type;
+ enum size_type size_type;
+};
+
+/* Structure used to hold DW_TAG_typedef. */
+struct type_def
+{
+ generic_type ptr_type;
+ uint64_t die_offset;
+ /* This field holds the offset of the underlying DIE type in the DWARF info
+ section. */
+ uint64_t ptr_die_offset;
+ const char *name;
+ struct type_def *next;
+ enum field_type field_type;
+};
+
+/* Structure used to hold DW_TAG_enumerator. */
+struct enum_constant
+{
+ uint64_t die_offset;
+ uint64_t value;
+ const char *name;
+ struct enum_constant *next;
+};
+
+/* Structure used to hold DW_TAG_enumeration. */
+struct enum_type
+{
+ uint64_t die_offset;
+ union
+ {
+ uint64_t usize;
+ int64_t ssize;
+ } size;
+ const char *name;
+ struct enum_constant *enum_const_head;
+ struct enum_constant *enum_const_tail;
+ struct enum_type *next;
+ enum field_type field_type;
+ enum size_type size_type;
+};
+
+/* Structure used to hold DW_TAG_subrange_type. */
+struct subrange_type
+{
+ uint64_t die_offset;
+ union
+ {
+ uint64_t usize;
+ int64_t ssize;
+ } size;
+ struct subrange_type *next;
+ enum size_type size_type;
+};
+
+/* Structure used to hold DW_TAG_array_type. */
+struct tab_type
+{
+ generic_type ptr_type;
+ uint64_t die_offset;
+ /* This field holds the offset of the underlying DIE type in the DWARF info
+ section. */
+ uint64_t ptr_die_offset;
+ subrange_type *subrange_head;
+ subrange_type *subrange_tail;
+ struct tab_type *next;
+ enum field_type field_type;
+};
+
+/* Structure used to hold DW_TAG_member. */
+struct member_type
+{
+ generic_type ptr_type;
+ uint64_t die_offset;
+ /* This field holds the offset of the underlying DIE type in the DWARF info
+ section. */
+ uint64_t ptr_die_offset;
+ int64_t member_offset;
+ const char *name;
+ struct member_type *next;
+ enum field_type field_type;
+};
+
+/* Structure used to hold either DW_TAG_structure_type or DW_TAG_union_type. */
+struct member_parent
+{
+ uint64_t die_offset;
+ union
+ {
+ uint64_t usize;
+ int64_t ssize;
+ } size;
+ const char *name;
+ member_type *member_head;
+ member_type *member_tail;
+ struct member_parent *next;
+ enum size_type size_type;
+ enum field_type field_type;
+ enum
+ {
+ UNION_TYPE,
+ STRUCT_TYPE
+ } type;
+ /* This field is set to true if the current DIE has DW_AT_declaration. When
+ this attribute is present the stucture/union is either incomplete,
+ non-defining or in a separate entity. */
+ bool is_declaration;
+};
+
+/* Structure used to hold DW_TAG_pointer_type. */
+struct type_ptr
+{
+ generic_type ptr_type;
+ uint64_t die_offset;
+ /* This field holds the offset of the underlying DIE type in the DWARF info
+ section. */
+ uint64_t ptr_die_offset;
+ union
+ {
+ uint64_t usize;
+ int64_t ssize;
+ } size;
+ struct type_ptr *next;
+ enum field_type field_type;
+ enum size_type size_type;
+};
+
+/* Structure used to hold either DW_TAG_const_type or DW_TAG_volatile_type. */
+struct type_ref
+{
+ generic_type ptr_type;
+ uint64_t die_offset;
+ /* This field holds the offset of the underlying DIE type in the DWARF info
+ section. */
+ uint64_t ptr_die_offset;
+ struct type_ref *next;
+ enum
+ {
+ CONST_TYPE,
+ VOLATILE_TYPE
+ } type;
+ enum field_type field_type;
+};
+
+/* Structure used to hold either DW_TAG_variable_type. */
+struct variable_type
+{
+ generic_type ptr_type;
+ uint64_t die_offset;
+ /* This field holds the offset of the underlying DIE type in the DWARF info
+ section. */
+ uint64_t ptr_die_offset;
+ /* This field holds the value in DW_AT_location when the operaion is
+ DW_OP_addr. It represents the location within the virtual address space of
+ the program. */
+ uint64_t location_addr;
+ /* This field holds the total size of the variable. */
+ uint64_t total_size;
+ const char *name;
+ struct variable_type *next;
+ enum field_type field_type;
+ /* This field is set to true if DW_AT_location is present with DW_OP_addr
+ operand. */
+ bool has_location_addr;
+ /* This field is set to true if DW_AT_specification is present. It represents
+ an incomplete, non-defining, or separate declaration corresponding to a
+ declaration. */
+ bool is_specification;
+ /* This field is set to true if DW_AT_abstract_origin is present. It
+ represents an inlined instances of inline subprograms. */
+ bool is_abstract_origin;
+};
+
/* N.B. The order here must match the order in debug_displays. */
enum dwarf_section_display_enum
@@ -253,6 +500,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.43.0
More information about the Binutils
mailing list