[PATCH v3 3/5] objdump: Add variable types and structure for DWARF info parsing
Guillaume VACHERIAS
guillaume.vacherias@foss.st.com
Mon Sep 1 17:50:42 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 member `type` associated
with member `ptr_type` to indicate the kind of type the structure represents.
Hence these two fields let us determine the exact type of a variable or
member. For example, to know that `foo` variable is char type, the structure
for `foo` will have:
- member `type` set to `BASE_TYPE`.
- member `ptr_type` pointing to a base_type structure that describes the
char type.
binutils/
* dwarf.h (types): New enum. Useful to identify structure type which
holds DWARF information.
(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.
(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): Likewise.
(get_or_create_member_type): Likewise.
(get_or_create_member_parent): Likewise.
(get_or_create_type_ref): Likewise.
(get_or_create_variable_type): Likewise.
(free_base_type): Likewise.
(free_type_def): Likewise.
(free_enum_type): Likewise.
(free_tab_type): Likewise.
(free_member_parent): Likewise.
(free_struct_type): Likewise.
(free_type_ref): Likewise.
(free_ptr_type): Likewise.
(free_volatile_type): Likewise.
(free_const_type): Likewise.
(free_variable_type): 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/ChangeLog | 18 ++
binutils/dwarf.c | 601 ++++++++++++++++++++++++++++++++++++++++++++-
binutils/dwarf.h | 145 +++++++++++
binutils/objdump.c | 1 +
4 files changed, 757 insertions(+), 8 deletions(-)
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 72f0ed9eb0a..cc2ed133ad7 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -16,6 +16,24 @@
(process_debug_info): Add argument to process DWARF information entry
for the display of global variable information.
(display_variable_mapping_info): New function.
+ (get_or_create_base_type, get_or_create_type_def, get_or_create_tab,
+ get_or_create_enum_constant, get_or_create_enum_type,
+ get_or_create_member_type, get_or_create_member_parent,
+ get_or_create_type_ref, get_or_create_variable_type): Likewise.
+ Structure element creation to hold DWARF info attributes values.
+ (free_base_type, free_type_def, free_enum_type, free_tab_type,
+ free_member_parent, free_struct_type, free_type_ref, free_ptr_type,
+ free_volatile_type, free_const_type, free_variable_type,
+ free_mapping_info_struct): Likewise. Free allocated structure elements.
+ (insert_element_in_list): Likewise. Create and populate structures that
+ hold DWARF information to display global variable information.
+
+ * dwarf.h (types): New enum. Useful to identify structure type which
+ holds DWARF information.
+ (base_type, type_def, enum_constant, enum_type, subrange_type, tab_type,
+ tab_type, member_type, member_parent, type_ref, variable_type): New
+ typedef.
+ (free_mapping_info_struct): New definition.
* objdump.c (dump_global_vars_info): New function. Entry point of
display of variable information option.
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 29aec096d95..cbe2a0a4a5e 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -65,6 +65,19 @@ 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 base_type *base_type_list = NULL;
+static type_def *type_def_list = NULL;
+static enum_type *enum_type_list = NULL;
+static tab_type *tab_type_list = NULL;
+static member_parent *struct_type_list = NULL;
+static member_parent *union_type_list = NULL;
+static type_ref *ptr_type_list = NULL;
+static type_ref *const_type_list = NULL;
+static type_ref *volatile_type_list = NULL;
+static variable_type *variable_type_list = NULL;
+
+static int is_union = false;
/* 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
@@ -1192,6 +1205,21 @@ 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)
+ {
+ if (variable_type_list == NULL)
+ {
+ fprintf (stderr,
+ _ ("m_var_map for DW_OP_addr should not be NULL!\n"));
+ free_mapping_info_struct ();
+ xexit (1);
+ }
+ if (!variable_type_list->has_location_addr)
+ {
+ variable_type_list->location_addr = uvalue;
+ variable_type_list->has_location_addr = true;
+ }
+ }
break;
case DW_OP_const1u:
SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
@@ -2571,47 +2599,434 @@ display_lang (uint64_t uvalue)
}
}
+static base_type *
+get_or_create_base_type (uint64_t die_offset)
+{
+ if (base_type_list == NULL || base_type_list->die_offset != die_offset)
+ {
+ base_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->usize = 0;
+ ret->ssize = 0;
+ ret->next = base_type_list;
+ base_type_list = ret;
+ }
+ return base_type_list;
+}
+
+static type_def *
+get_or_create_type_def (uint64_t die_offset)
+{
+ if (type_def_list == NULL || type_def_list->die_offset != die_offset)
+ {
+ type_def *ret = xmalloc (sizeof (*ret));
+ ret->name = NULL;
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->type = UNKNOWN_TYPE;
+ ret->ptr_type = NULL;
+ ret->next = type_def_list;
+ type_def_list = ret;
+ }
+ return type_def_list;
+}
+
+static enum_constant *
+get_or_create_enum_constant (enum_type *head, uint64_t die_offset)
+{
+ assert (head != NULL);
+ if (head->enumeration == NULL || head->enumeration->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 = head->enumeration;
+ head->enumeration = enum_const;
+ }
+ return head->enumeration;
+}
+
+static enum_type *
+get_or_create_enum_type (uint64_t die_offset)
+{
+ if (enum_type_list == NULL || enum_type_list->die_offset != die_offset)
+ {
+ enum_type *ret = xmalloc (sizeof (*ret));
+ ret->name = NULL;
+ ret->die_offset = die_offset;
+ ret->usize = 0;
+ ret->ssize = 0;
+ ret->enumeration = NULL;
+ ret->next = enum_type_list;
+ enum_type_list = ret;
+ }
+ return enum_type_list;
+}
+
+static subrange_type *
+get_or_create_subrange_type (tab_type * head, uint64_t die_offset)
+{
+ assert (head != NULL);
+ if (head->subrange == NULL || head->subrange->die_offset != die_offset)
+ {
+ subrange_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->usize = 0;
+ ret->ssize = 0;
+ ret->next = head->subrange;
+ head->subrange = ret;
+ }
+ return head->subrange;
+}
+
+static tab_type *
+get_or_create_tab (uint64_t die_offset)
+{
+ if (tab_type_list == NULL || tab_type_list->die_offset != die_offset)
+ {
+ tab_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->subrange = NULL;
+ ret->type = UNKNOWN_TYPE;
+ ret->ptr_type = NULL;
+ ret->next = tab_type_list;
+ tab_type_list = ret;
+ }
+ return tab_type_list;
+}
+
+static member_type *
+get_or_create_member_type (member_type *head, uint64_t die_offset)
+{
+ if (head == NULL || head->die_offset != die_offset)
+ {
+ member_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->member_offset = 0;
+ ret->name = NULL;
+ ret->type = UNKNOWN_TYPE;
+ ret->ptr_type = NULL;
+ ret->next = head;
+ head = ret;
+ }
+ return head;
+}
+
+static member_parent *
+get_or_create_member_parent (member_parent **head, uint64_t die_offset)
+{
+ if (*head == NULL || (*head)->die_offset != die_offset)
+ {
+ member_parent *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->usize = 0;
+ ret->ssize = 0;
+ ret->name = NULL;
+ ret->members = NULL;
+ ret->displayed = false;
+ ret->next = *head;
+ *head = ret;
+ }
+ return *head;
+}
+
+static type_ref *
+get_or_create_type_ref (type_ref **head, uint64_t die_offset)
+{
+ if (*head == NULL || (*head)->die_offset != die_offset)
+ {
+ type_ref *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->usize = 0;
+ ret->ssize = 0;
+ ret->type = UNKNOWN_TYPE;
+ ret->ptr_type = NULL;
+ ret->next = *head;
+ *head = ret;
+ }
+ return *head;
+}
+
+static variable_type *
+get_or_create_variable_type (uint64_t die_offset)
+{
+ if (variable_type_list == NULL
+ || variable_type_list->die_offset != die_offset)
+ {
+ variable_type *ret = xmalloc (sizeof (*ret));
+ ret->die_offset = die_offset;
+ ret->ptr_die_offset = 0;
+ ret->location_addr = 0;
+ ret->has_location_addr = false;
+ ret->name = NULL;
+ ret->type = UNKNOWN_TYPE;
+ ret->ptr_type = NULL;
+ ret->total_size = 0;
+ ret->next = variable_type_list;
+ variable_type_list = ret;
+ }
+ return variable_type_list;
+}
+
static void
insert_element_in_list (enum dwarf_tag dw_tag,
- enum dwarf_attribute dw_attr ATTRIBUTE_UNUSED,
- uint64_t die_offset ATTRIBUTE_UNUSED,
- uint64_t *uvalue ATTRIBUTE_UNUSED,
- int64_t *svalue ATTRIBUTE_UNUSED,
- const unsigned char *data ATTRIBUTE_UNUSED)
-{
- /* TODO: Retrieve attributes information from
- below dwarf entries tag. */
+ enum dwarf_attribute dw_attr,
+ uint64_t die_offset,
+ uint64_t *uvalue,
+ int64_t *svalue,
+ const unsigned char *data)
+{
switch (dw_tag)
{
/* Base type. */
case DW_TAG_base_type:
+ {
+ base_type *base = get_or_create_base_type (die_offset);
+ if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ base->usize = ((uvalue != NULL) ? *uvalue : 0);
+ base->ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ else if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ base->name = (const char *) data;
+ else if (uvalue != NULL)
+ base->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ }
break;
/* typedef type. */
case DW_TAG_typedef:
+ {
+ type_def *type = get_or_create_type_def (die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ type->ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ type->name = (const char *) data;
+ else if (uvalue != NULL)
+ type->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ }
break;
/* enumeration type. */
case DW_TAG_enumerator:
+ {
+ enum_constant *head = get_or_create_enum_constant (
+ enum_type_list, die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (data != NULL || uvalue != NULL);
+ if (data != NULL)
+ head->name = (const char *) data;
+ else if (uvalue != NULL)
+ head->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_const_value)
+ {
+ assert (uvalue != NULL);
+ head->value = *uvalue;
+ }
+ }
break;
case DW_TAG_enumeration_type:
+ {
+ enum_type *head = get_or_create_enum_type (die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ head->name = (const char *) data;
+ else if (uvalue != NULL)
+ head->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ head->usize = ((uvalue != NULL) ? *uvalue : 0);
+ head->ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ }
break;
/* Array type. */
case DW_TAG_subrange_type:
+ {
+ subrange_type *head = get_or_create_subrange_type (tab_type_list,
+ 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)
+ {
+ head->ssize = ((svalue != NULL) ? *svalue + 1 : 0);
+ head->usize = ((uvalue != NULL) ? *uvalue + 1 : 0);
+ }
+ else if (dw_attr == DW_AT_count)
+ {
+ head->ssize = ((svalue != NULL) ? *svalue : 0);
+ head->usize = ((uvalue != NULL) ? *uvalue : 0);
+ }
+ }
+ }
break;
case DW_TAG_array_type:
+ {
+ tab_type *head = get_or_create_tab (die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ head->ptr_die_offset = *uvalue;
+ }
+ }
break;
/* Member type. */
case DW_TAG_member:
+ {
+ member_type *member = NULL;
+ if (is_union)
+ {
+ member = get_or_create_member_type (union_type_list->members,
+ die_offset);
+ if (union_type_list->members == NULL
+ || union_type_list->members->die_offset != die_offset)
+ {
+ member->next = union_type_list->members;
+ union_type_list->members = member;
+ }
+ else
+ union_type_list->members = member;
+ }
+ else
+ {
+ member = get_or_create_member_type (struct_type_list->members,
+ die_offset);
+ if (struct_type_list->members == NULL
+ || struct_type_list->members->die_offset != die_offset)
+ {
+ member->next = struct_type_list->members;
+ struct_type_list->members = member;
+ }
+ else
+ struct_type_list->members = member;
+ }
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ member->name = (const char *) data;
+ else if (uvalue != NULL)
+ member->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ member->ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_data_member_location)
+ {
+ assert (svalue != NULL || uvalue != NULL);
+ if (svalue != NULL)
+ member->member_offset = *svalue;
+ if (uvalue != NULL)
+ member->member_offset = *uvalue;
+ }
+ }
break;
/* Structure type. */
case DW_TAG_structure_type:
/* Union type. */
case DW_TAG_union_type:
+ {
+ member_parent *head = NULL;
+ if (dw_tag == DW_TAG_union_type)
+ {
+ is_union = true;
+ head = get_or_create_member_parent (&union_type_list, die_offset);
+ }
+ else if (dw_tag == DW_TAG_structure_type)
+ {
+ is_union = false;
+ head = get_or_create_member_parent (&struct_type_list,
+ die_offset);
+ }
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ head->name = (const char *) data;
+ else if (uvalue != NULL)
+ head->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_byte_size)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ head->usize = ((uvalue != NULL) ? *uvalue : 0);
+ head->ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ }
break;
case DW_TAG_const_type:
case DW_TAG_volatile_type:
case DW_TAG_pointer_type:
+ {
+ type_ref *head = NULL;
+ if (dw_tag == DW_TAG_const_type)
+ head = get_or_create_type_ref (&const_type_list, die_offset);
+ else if (dw_tag == DW_TAG_volatile_type)
+ head = get_or_create_type_ref (&volatile_type_list, die_offset);
+ else if (dw_tag == DW_TAG_pointer_type)
+ head = get_or_create_type_ref (&ptr_type_list, die_offset);
+ if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ head->ptr_die_offset = *uvalue;
+ }
+ if (dw_attr == DW_AT_byte_size && dw_tag == DW_TAG_pointer_type)
+ {
+ assert (uvalue != NULL || svalue != NULL);
+ head->usize = ((uvalue != NULL) ? *uvalue : 0);
+ head->ssize = ((svalue != NULL) ? *svalue : 0);
+ }
+ }
break;
case DW_TAG_variable:
+ {
+ variable_type *head = get_or_create_variable_type (die_offset);
+ if (dw_attr == DW_AT_name)
+ {
+ assert (uvalue != NULL || data != NULL);
+ if (data != NULL)
+ head->name = (const char *) data;
+ else if (uvalue != NULL)
+ head->name = (const char *) fetch_indirect_string (*uvalue);
+ }
+ else if (dw_attr == DW_AT_type)
+ {
+ assert (uvalue != NULL);
+ head->ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_specification)
+ {
+ assert (uvalue != NULL);
+ head->ptr_die_offset = *uvalue;
+ }
+ else if (dw_attr == DW_AT_abstract_origin)
+ {
+ assert (uvalue != NULL);
+ head->ptr_die_offset = *uvalue;
+ }
+ }
break;
default:
break;
@@ -13276,3 +13691,173 @@ 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 (void)
+{
+ base_type *current = base_type_list;
+ base_type *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ free (current);
+ current = next;
+ }
+ base_type_list = NULL;
+}
+
+static void
+free_type_def (void)
+{
+ type_def *current = type_def_list;
+ type_def *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ free (current);
+ current = next;
+ }
+ type_def_list = NULL;
+}
+
+static void
+free_enum_type (void)
+{
+ enum_type *current = enum_type_list;
+ enum_type *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ enum_constant *current_enums = current->enumeration;
+ enum_constant *next_enums = NULL;
+ while (current_enums != NULL)
+ {
+ next_enums = current_enums->next;
+ free (current_enums);
+ current_enums = next_enums;
+ }
+ current->enumeration = NULL;
+ free (current);
+ current = next;
+ }
+ enum_type_list = NULL;
+}
+
+static void
+free_tab_type (void)
+{
+ tab_type *current = tab_type_list;
+ tab_type *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ subrange_type *current_subrange = current->subrange;
+ subrange_type *next_subrange = NULL;
+ while (current_subrange != NULL)
+ {
+ next_subrange = current_subrange->next;
+ free (current_subrange);
+ current_subrange = next_subrange;
+ }
+ current->subrange = NULL;
+ free (current);
+ current = next;
+ }
+ tab_type_list = NULL;
+}
+
+static void
+free_member_parent (member_parent **head)
+{
+ member_parent *current = *head;
+ member_parent *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ member_type *current_member = current->members;
+ member_type *next_member = NULL;
+ while (current_member != NULL)
+ {
+ next_member = current_member->next;
+ free (current_member);
+ current_member = next_member;
+ }
+ current->members = NULL;
+ free (current);
+ current = next;
+ }
+ *head = NULL;
+}
+
+static void
+free_struct_type (void)
+{
+ free_member_parent (&struct_type_list);
+}
+
+static void
+free_union_type (void)
+{
+ free_member_parent (&union_type_list);
+}
+
+static void
+free_type_ref (type_ref *head)
+{
+ type_ref *current = head;
+ type_ref *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ free (current);
+ current = next;
+ }
+ head = NULL;
+}
+
+static void
+free_ptr_type (void)
+{
+ free_type_ref (ptr_type_list);
+}
+
+static void
+free_volatile_type (void)
+{
+ free_type_ref (volatile_type_list);
+}
+
+static void
+free_const_type (void)
+{
+ free_type_ref (const_type_list);
+}
+
+static void
+free_variable_type (void)
+{
+ variable_type *current = variable_type_list;
+ variable_type *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ free (current);
+ current = next;
+ }
+ variable_type_list = NULL;
+}
+
+void
+free_mapping_info_struct ()
+{
+ free_base_type ();
+ free_type_def ();
+ free_enum_type ();
+ free_tab_type ();
+ free_struct_type ();
+ free_union_type ();
+ free_ptr_type ();
+ free_volatile_type ();
+ free_const_type ();
+ free_variable_type ();
+}
diff --git a/binutils/dwarf.h b/binutils/dwarf.h
index 8efd0c37b5b..c85d83fcf8e 100644
--- a/binutils/dwarf.h
+++ b/binutils/dwarf.h
@@ -71,6 +71,150 @@ typedef struct
}
DWARF2_Internal_ARange;
+enum types
+{
+ UNKNOWN_TYPE = 0,
+ BASE_TYPE,
+ TYPE_DEF,
+ ENUM_TYPE,
+ TAB_TYPE,
+ MEMBER_TYPE,
+ STRUCT_TYPE,
+ UNION_TYPE,
+ PTR_TYPE,
+ VOLATILE_TYPE,
+ CONST_TYPE,
+ VARIABLE_TYPE
+};
+
+/* Container for map info information to be generated. */
+typedef struct base_type
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+ const char *name;
+
+ struct base_type *next;
+}
+base_type;
+
+typedef struct type_def
+{
+ const char *name;
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+
+ enum types type;
+ void *ptr_type;
+ struct type_def *next;
+}
+type_def;
+
+typedef struct enum_constant
+{
+ uint64_t die_offset;
+ uint64_t value;
+ const char *name;
+
+ struct enum_constant *next;
+}
+enum_constant;
+
+typedef struct enum_type
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+ const char *name;
+ enum_constant *enumeration;
+
+ struct enum_type *next;
+}
+enum_type;
+
+typedef struct subrange_type
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+
+ struct subrange_type *next;
+}
+subrange_type;
+
+typedef struct tab_type
+{
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ subrange_type *subrange;
+
+ enum types type;
+ void *ptr_type;
+ struct tab_type *next;
+}
+tab_type;
+
+typedef struct member_type
+{
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ int64_t member_offset;
+ const char *name;
+
+ enum types type;
+ void *ptr_type;
+ struct member_type *next;
+}
+member_type;
+
+/* N.B. member_parent holds information on struct or union variables. */
+typedef struct member_parent
+{
+ uint64_t die_offset;
+ uint64_t usize;
+ int64_t ssize;
+ const char *name;
+ member_type *members;
+ bool displayed; /* Treat nested structure. */
+
+ struct member_parent *next;
+}
+member_parent;
+
+/* N.B. type_ref holds information on pointer, constant and volatile
+ type variables. */
+typedef struct type_ref
+{
+ uint64_t die_offset;
+ uint64_t ptr_die_offset;
+ uint64_t usize;
+ int64_t ssize;
+
+ enum types type;
+ void *ptr_type;
+ struct type_ref *next;
+}
+type_ref;
+
+typedef 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. */
+ enum types type;
+ void *ptr_type;
+ uint64_t total_size;
+ struct variable_type *next;
+}
+variable_type;
+
/* N.B. The order here must match the order in debug_displays. */
enum dwarf_section_display_enum
@@ -253,6 +397,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 d6014e5a5e1..b27bc5e30f9 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -4564,6 +4564,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