[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