From 9b60ae0d44425f87091919a653ba8d6b6bb59411 Mon Sep 17 00:00:00 2001
From: nitachra <Nitika.Achra@amd.com>
Date: Wed, 21 Jul 2021 15:32:44 +0530
Subject: [PATCH] DWARFv5: Support for unit type DW_UT_type and
 DW_TAG_type_unit.

In Dwarfv5, .debug_types section is eliminated and its contents are
moved into the .debug_info section.

This patch handles DW_UT_type units.

ChangeLog:
	* dwz.c (struct dw_cu): Add a type signature field.
	(try_debug_info): Add DW_UT_type in the if condition.
	(read_debug_info): Add DW_UT_type in the if condition.
	Set the boolean flag is_UT_type if the unit_type is
	DW_UT_type. Read the type signature from the header.
	Rewrite the DW_TAG_type_unit as partial unit.
	(build_abbrevs_for_die): Convert the DW_FORM_ref_sig8
	reference to DW_FORM_ref_addr.
	(write_die): Write the DW_FORM_ref_addr reference if
	the orignal form is DW_FORM_ref_sig8. Look for the
	compilation unit with the given type signature and
	write the reference to the first die after the unit
	die.
---
 dwz.c | 44 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 39 insertions(+), 5 deletions(-)

diff --git a/dwz.c b/dwz.c
index f758ddb..fc8bfc3 100644
--- a/dwz.c
+++ b/dwz.c
@@ -929,6 +929,8 @@ struct dw_cu
   unsigned int cu_offset;
   /* DWARF version of the CU.  */
   unsigned int cu_version;
+  /* A unique 8-byte signature of the type described in this type unit.  */
+  uint64_t cu_type_signature;
   /* Cached DW_AT_comp_dir value from DW_TAG_*_unit cu_die,
      or NULL if that attribute is not present.  */
   char *cu_comp_dir;
@@ -6471,7 +6473,7 @@ try_debug_info (DSO *dso)
       if (cu_version == 5)
 	{
 	  value = read_8 (ptr);
-	  if (value != DW_UT_compile && value != DW_UT_partial)
+	  if (value != DW_UT_compile && value != DW_UT_partial && value != DW_UT_type)
 	    error (0, 0, "%s: DWARF CU type %s unhandled", dso->filename,
 		   get_DW_UT_str (value));
 	}
@@ -6700,6 +6702,8 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
       bool present;
       unsigned int debug_line_off;
       unsigned int type_offset = 0;
+      uint64_t type_signature = 0;
+      bool is_UT_type = false;
 
       /* Note header is one bigger with DWARF version 5.  */
       if (ptr + (kind == DEBUG_TYPES ? 23 : 11) > endsec)
@@ -6742,12 +6746,13 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
       if (cu_version == 5)
 	{
 	  value = read_8 (ptr);
-	  if (value != DW_UT_compile && value != DW_UT_partial)
+	  if (value != DW_UT_compile && value != DW_UT_partial && value != DW_UT_type)
 	    {
 	      error (0, 0, "%s: DWARF CU type %s unhandled", dso->filename,
 		     get_DW_UT_str (value));
 	      goto fail;
 	    }
+	  is_UT_type = (value == DW_UT_type);
 	}
       else
 	{
@@ -6889,9 +6894,9 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
 	}
       last_abbrev_offset = value;
 
-      if (unlikely (kind == DEBUG_TYPES))
+      if (unlikely (kind == DEBUG_TYPES) || is_UT_type)
 	{
-	  ptr += 8;
+	  type_signature = read_64 (ptr);
 	  type_offset = read_32 (ptr);
 	}
 
@@ -6904,6 +6909,7 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
       cu->cu_offset = cu_offset;
       cu->cu_version = cu_version;
       cu->cu_chunk = cu_chunk;
+      cu->cu_type_signature = type_signature;
       if (unlikely (op_multifile || low_mem))
 	cu->cu_abbrev = abbrev;
       diep = &cu->cu_die;
@@ -6996,7 +7002,10 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
 	      memset (die, '\0', offsetof (struct dw_die, die_dup));
 	    }
 	  *diep = die;
-	  die->die_tag = t->tag;
+	  if (t->tag == DW_TAG_type_unit)
+	    die->die_tag = DW_TAG_partial_unit;
+	  else
+	    die->die_tag = t->tag;
 	  die->die_abbrev = t;
 	  die->die_offset = die_offset;
 	  if (parent)
@@ -10750,6 +10759,7 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	    case DW_FORM_ref4:
 	    case DW_FORM_ref8:
 	    case DW_FORM_ref_udata:
+	    case DW_FORM_ref_sig8:
 	    case DW_FORM_indirect:
 	      i = -2U;
 	      break;
@@ -11010,6 +11020,13 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 		  ptr += 8;
 		  break;
 		case DW_FORM_ref_sig8:
+		  if (refcu->cu_version > 4)
+		    {
+		      t->attr[j].attr = reft->attr[i].attr;
+		      t->attr[j++].form = DW_FORM_ref_addr;
+		      die->die_size += 4;
+		      continue;
+		    }
 		  ptr += 8;
 		  break;
 		case DW_FORM_data16:
@@ -12692,6 +12709,23 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die,
 	      inptr += 8;
 	      break;
 	    case DW_FORM_ref_sig8:
+	      if (t->attr[j].form != reft->attr[i].form)
+		{
+		  value = read_64 (inptr);
+		  dw_cu_ref comp_unit;
+		  for (comp_unit = first_cu; comp_unit; comp_unit = comp_unit->cu_next)
+		    {
+		      if (value == comp_unit->cu_type_signature)
+			{
+			  value = comp_unit->cu_new_offset + comp_unit->cu_die->u.p2.die_new_offset
+				  + comp_unit->cu_die->die_size;
+			  break;
+			}
+		    }
+		  write_32(ptr, value);
+		  j++;
+		  continue;
+		}
 	      inptr += 8;
 	      break;
 	    case DW_FORM_data16:
-- 
2.17.1

