[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