[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