From 3a36175125ad01cd00174f51a004fa6c490da14c Mon Sep 17 00:00:00 2001
From: Nagajyothi Eggone <Nagajyothi.E@amd.com>
Date: Sun, 16 May 2021 16:02:25 +0530
Subject: [PATCH 1/2] PR27375, PR27434 - Recognize new DWARF5 sections
 .debug_addr, .debug_str_offsets

This adds support for sections .debug_addr and .debug_str_offsets, and related forms DW_FORM_addrx,
DW_FORM_strx[1|2|3|4], which are generated by clang. DW_FORM_addrx[1|2|3|4] are not handled as they are not produced by clang as yet. DW_FORM_loclistx and DW_FORM_rnglistx are also handled in several places as required.

     Changelog:
   * dwz.c (do_read_24) : New function to read DW_FORM_strx3.
           (buf_read_ule24) : Likewise.
           (buf_read_ube24) : Likewise.
           (read_24) : New macro for 24-bit read.
           (read_size) : Add case for 24-bit read.
           (init_endian): Likewise.
           (enum debug_section_kind): Add DEBUG_STR_OFFSETS and DEBUG_ADDR.
           (debug_sections): Add .debug_str_offsets and .debug_addr entries.
           (struct dw_cu): New member cu_str_offsets_base to hold str_offsets_base.
           (read_abbrev): Add DW_FORM_addrx, DW_FORM_strx[1|2|3|4], DW_FORM_loclistx, DW_FORM_rnglistx.
           (skip_attr_no_dw_form_indirect): Likewise.
           (checksum_die): Likewise.
           (checksum_ref_die): Likewise.
           (die_eq_1): Likewise.
           (mark_refs): Likewise.
           (build_abbrevs_for_die): Likewise.
           (write_unit_die): Likewise.
           (write_die): Likewise.
           (read_debug_info): Add DW_FORM_addrx, DW_FORM_strx[1|2|3|4].
                              record str_offsets_base in dw_cu member cu_str_offsets_base for use in
                              reading strings referenced with DW_FORM_strx[1|2|3|4].
           (partition_dups_1): Add size of str_offsets_base to CU/PU header size estimate.

           (read_debug_line): Add case for DW_LNCT_MD5.
           (get_AT_string): Read string index from .debug_str_offsets sections and read string
                            from .debug_str section using this as offset.
           (read_exprloc): Add DW_OP_addrx.
           (adjust_exprloc): Likewise.

    This patch does not address ODR and multifile support, which will be added through subsequent patches. Due to this,
	make check CC="clang -gdwarf-5" CXX="clang++ -gdwarf-5"
has the following tests failing:
	testsuite/dwz.tests/cycle.sh
	testsuite/dwz.tests/odr-class-ns.sh
	testsuite/dwz.tests/odr-loc.sh
	testsuite/dwz.tests/odr-struct-ns.sh
	testsuite/dwz.tests/odr-class.sh
	testsuite/dwz.tests/odr-union-ns.sh
	testsuite/dwz.tests/odr-struct-multifile.sh
	testsuite/dwz.tests/odr-struct.sh
	testsuite/dwz.tests/odr-union.sh
---
 dwz.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 253 insertions(+), 4 deletions(-)

diff --git a/dwz.c b/dwz.c
index a3b289f..f758ddb 100644
--- a/dwz.c
+++ b/dwz.c
@@ -475,6 +475,7 @@ static unsigned int lowest_line_version = 5;
    given ELF endianity, which might be different from host endianity.
    No specific alignment is expected.  */
 static uint16_t (*do_read_16) (unsigned char *ptr);
+static uint32_t (*do_read_24) (unsigned char *ptr);
 static uint32_t (*do_read_32) (unsigned char *ptr);
 static uint64_t (*do_read_64) (unsigned char *ptr);
 static void (*do_write_16) (unsigned char *ptr, unsigned short val);
@@ -493,6 +494,20 @@ buf_read_ube16 (unsigned char *data)
   return data[1] | (data[0] << 8);
 }
 
+static inline uint32_t
+buf_read_ule24 (unsigned char *data)
+{
+  return (data[0] | (data[1] << 8) | (data[2] << 16)
+          | ((unsigned int)0x0 << 24));
+}
+
+static inline uint32_t
+buf_read_ube24 (unsigned char *data)
+{
+  return ((0x0) | (data[2] << 8) | (data[1] << 16)
+	   | ((unsigned int)data[0] << 24));
+}
+
 static inline uint32_t
 buf_read_ule32 (unsigned char *data)
 {
@@ -529,6 +544,12 @@ buf_read_ube64 (unsigned char *data)
   ret;							\
 })
 
+#define read_24(ptr) ({					\
+  uint32_t ret = do_read_24 (ptr);			\
+  ptr += 3;						\
+  ret;							\
+})
+
 #define read_32(ptr) ({					\
   uint32_t ret = do_read_32 (ptr);			\
   ptr += 4;						\
@@ -577,6 +598,7 @@ read_size (unsigned char *p, int size)
     {
     case 1: return read_8 (p);
     case 2: return read_16 (p);
+    case 3: return read_24 (p);
     case 4: return read_32 (p);
     case 8: return read_64 (p);
     default: abort ();
@@ -720,9 +742,11 @@ enum debug_section_kind
   DEBUG_ABBREV,
   DEBUG_LINE,
   DEBUG_STR,
+  DEBUG_STR_OFFSETS,
   DEBUG_MACRO,
   DEBUG_TYPES,
   DEBUG_ARANGES,
+  DEBUG_ADDR,
   DEBUG_PUBNAMES,
   DEBUG_PUBTYPES,
   DEBUG_GNU_PUBNAMES,
@@ -757,9 +781,11 @@ static struct
     { ".debug_abbrev", NULL, NULL, 0, 0, 0 },
     { ".debug_line", NULL, NULL, 0, 0, 0 },
     { ".debug_str", NULL, NULL, 0, 0, 0 },
+    { ".debug_str_offsets", NULL, NULL, 0, 0, 0 },
     { ".debug_macro", NULL, NULL, 0, 0, 0 },
     { ".debug_types", NULL, NULL, 0, 0, 0 },
     { ".debug_aranges", NULL, NULL, 0, 0, 0 },
+    { ".debug_addr", NULL, NULL, 0, 0, 0 },
     { ".debug_pubnames", NULL, NULL, 0, 0, 0 },
     { ".debug_pubtypes", NULL, NULL, 0, 0, 0 },
     { ".debug_gnu_pubnames", NULL, NULL, 0, 0, 0 },
@@ -942,6 +968,7 @@ struct dw_cu
   /* Intracusize argument to init_new_die_offsets.  Set in compute_abbrevs,
      used in recompute_abbrevs.  */
   unsigned int initial_intracusize;
+  unsigned int cu_str_offsets_base;
   enum dwarf_source_language lang;
 };
 
@@ -1236,6 +1263,14 @@ read_abbrev (DSO *dso, unsigned char *ptr)
 	      || (form > DW_FORM_flag_present
 		  && !(form == DW_FORM_ref_sig8
 		       || form == DW_FORM_data16
+		       || form == DW_FORM_addrx
+		       || form == DW_FORM_loclistx
+		       || form == DW_FORM_rnglistx
+		       || form == DW_FORM_strx
+		       || form == DW_FORM_strx1
+		       || form == DW_FORM_strx2
+		       || form == DW_FORM_strx3
+		       || form == DW_FORM_strx4
 		       || form == DW_FORM_line_strp)))
 	    {
 	      error (0, 0, "%s: Unknown DWARF %s",
@@ -1316,15 +1351,21 @@ skip_attr_no_dw_form_indirect (unsigned int cu_version, uint32_t form,
     case DW_FORM_implicit_const:
       break;
     case DW_FORM_ref1:
+    case DW_FORM_strx1:
     case DW_FORM_flag:
     case DW_FORM_data1:
       ++ptr;
       break;
     case DW_FORM_ref2:
+    case DW_FORM_strx2:
     case DW_FORM_data2:
       ptr += 2;
       break;
+    case DW_FORM_strx3:
+      ptr += 3;
+      break;
     case DW_FORM_ref4:
+    case DW_FORM_strx4:
     case DW_FORM_data4:
     case DW_FORM_sec_offset:
     case DW_FORM_strp:
@@ -1342,6 +1383,10 @@ skip_attr_no_dw_form_indirect (unsigned int cu_version, uint32_t form,
     case DW_FORM_sdata:
     case DW_FORM_ref_udata:
     case DW_FORM_udata:
+    case DW_FORM_addrx:
+    case DW_FORM_loclistx:
+    case DW_FORM_rnglistx:
+    case DW_FORM_strx:
       skip_leb128 (ptr);
       break;
     case DW_FORM_string:
@@ -1716,6 +1761,9 @@ read_debug_line (DSO *dso, dw_cu_ref cu, uint32_t off)
 		}
 	      break;
 
+            case DW_LNCT_MD5:
+              break;
+
 	    default:
 	      error (0, 0, "%s: .debug_line unhandled file element %s",
 		     dso->filename, get_DW_LNCT_str (lnct));
@@ -2201,6 +2249,39 @@ get_AT_string (dw_die_ref die, enum dwarf_attribute at)
 	  return NULL;
 	return (char *) debug_sections[DEBUG_STR].data + strp;
       }
+    case DW_FORM_strx:
+    case DW_FORM_strx1:
+    case DW_FORM_strx2:
+    case DW_FORM_strx3:
+    case DW_FORM_strx4:
+      {
+	unsigned int str_offsets_base = die_cu(die)->cu_str_offsets_base;
+
+	uint64_t str_idx = 0;
+	if (form == DW_FORM_strx)
+	  str_idx = read_uleb128 (ptr);
+	if (form == DW_FORM_strx1)
+	  str_idx = read_8 (ptr);
+	if (form == DW_FORM_strx2)
+	  str_idx = read_16 (ptr);
+	if (form == DW_FORM_strx3)
+	  str_idx = read_24 (ptr);
+	if (form == DW_FORM_strx4)
+	  str_idx = read_32 (ptr);
+
+        if (str_idx >= debug_sections[DEBUG_STR_OFFSETS].size)
+          return NULL;
+
+	unsigned char *str_offset_ptr = str_offsets_base +
+		debug_sections[DEBUG_STR_OFFSETS].data +
+		(str_idx * 4); /* Each index entry is 4 bytes long*/
+
+        unsigned int str_offset = read_32(str_offset_ptr);
+        if (str_offset >= debug_sections[DEBUG_STR].size)
+          return NULL;
+
+	return (char *) debug_sections[DEBUG_STR].data + str_offset;
+      }
     case DW_FORM_line_strp:
       {
 	unsigned int line_strp = read_32 (ptr);
@@ -2239,6 +2320,10 @@ read_exprloc (DSO *dso, dw_die_ref die, unsigned char *ptr, size_t len,
 	  die->die_no_multifile = 1;
 	  ptr += ptr_size;
 	  break;
+	case DW_OP_addrx:
+	  die->die_no_multifile = 1;
+	  skip_leb128 (ptr);
+	  break;
 	case DW_OP_deref:
 	case DW_OP_dup:
 	case DW_OP_drop:
@@ -3560,6 +3645,10 @@ checksum_die (DSO *dso, dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die)
 	  die->die_no_multifile = 1;
 	  ptr += ptr_size;
 	  break;
+	case DW_FORM_addrx:
+	  die->die_no_multifile = 1;
+	  skip_leb128 (ptr);
+	  break;
 	case DW_FORM_flag_present:
 	  break;
 	case DW_FORM_implicit_const:
@@ -3575,13 +3664,19 @@ checksum_die (DSO *dso, dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die)
 	  break;
 	case DW_FORM_flag:
 	case DW_FORM_data1:
+	case DW_FORM_strx1:
 	  ++ptr;
 	  break;
 	case DW_FORM_data2:
+	case DW_FORM_strx2:
 	  ptr += 2;
 	  break;
+	case DW_FORM_strx3:
+	  ptr += 3;
+	  break;
 	case DW_FORM_data4:
 	case DW_FORM_sec_offset:
+	case DW_FORM_strx4:
 	  ptr += 4;
 	  break;
 	case DW_FORM_data8:
@@ -3596,6 +3691,9 @@ checksum_die (DSO *dso, dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die)
 	  break;
 	case DW_FORM_sdata:
 	case DW_FORM_udata:
+	case DW_FORM_strx:
+	case DW_FORM_loclistx:
+	case DW_FORM_rnglistx:
 	  skip_leb128 (ptr);
 	  break;
 	case DW_FORM_ref_udata:
@@ -4018,15 +4116,21 @@ checksum_ref_die (dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die,
 	      break;
 	    case DW_FORM_flag:
 	    case DW_FORM_data1:
+	    case DW_FORM_strx1:
 	      ++ptr;
 	      break;
 	    case DW_FORM_data2:
+	    case DW_FORM_strx2:
 	      ptr += 2;
 	      break;
+	    case DW_FORM_strx3:
+	      ptr += 3;
+	      break;
 	    case DW_FORM_data4:
 	    case DW_FORM_sec_offset:
 	    case DW_FORM_strp:
 	    case DW_FORM_line_strp:
+	    case DW_FORM_strx4:
 	      ptr += 4;
 	      break;
 	    case DW_FORM_data8:
@@ -4038,6 +4142,10 @@ checksum_ref_die (dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die,
 	      break;
 	    case DW_FORM_sdata:
 	    case DW_FORM_udata:
+	    case DW_FORM_addrx:
+	    case DW_FORM_loclistx:
+	    case DW_FORM_rnglistx:
+	    case DW_FORM_strx:
 	      skip_leb128 (ptr);
 	      break;
 	    case DW_FORM_ref_udata:
@@ -4877,15 +4985,22 @@ die_eq_1 (dw_cu_ref cu1, dw_cu_ref cu2,
 	  break;
 	case DW_FORM_flag:
 	case DW_FORM_data1:
+	case DW_FORM_strx1:
 	  ++ptr1;
 	  ++ptr2;
 	  break;
 	case DW_FORM_data2:
+	case DW_FORM_strx2:
 	  ptr1 += 2;
 	  ptr2 += 2;
 	  break;
+	case DW_FORM_strx3:
+	  ptr1 += 3;
+	  ptr2 += 3;
+	  break;
 	case DW_FORM_data4:
 	case DW_FORM_sec_offset:
+	case DW_FORM_strx4:
 	  ptr1 += 4;
 	  ptr2 += 4;
 	  break;
@@ -4900,6 +5015,10 @@ die_eq_1 (dw_cu_ref cu1, dw_cu_ref cu2,
 	  break;
 	case DW_FORM_sdata:
 	case DW_FORM_udata:
+	case DW_FORM_addrx:
+	case DW_FORM_loclistx:
+	case DW_FORM_rnglistx:
+	case DW_FORM_strx:
 	  skip_leb128 (ptr1);
 	  skip_leb128 (ptr2);
 	  break;
@@ -5972,12 +6091,18 @@ mark_refs (dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die, int mode)
 	    case DW_FORM_implicit_const:
 	      break;
 	    case DW_FORM_flag:
+            case DW_FORM_strx1:
 	    case DW_FORM_data1:
 	      ++ptr;
 	      break;
+            case DW_FORM_strx2:
 	    case DW_FORM_data2:
 	      ptr += 2;
 	      break;
+	    case DW_FORM_strx3:
+	      ptr += 3;
+	      break;
+	    case DW_FORM_strx4:
 	    case DW_FORM_data4:
 	    case DW_FORM_sec_offset:
 	    case DW_FORM_strp:
@@ -5993,6 +6118,10 @@ mark_refs (dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die, int mode)
 	      break;
 	    case DW_FORM_sdata:
 	    case DW_FORM_udata:
+	    case DW_FORM_addrx:
+	    case DW_FORM_loclistx:
+	    case DW_FORM_rnglistx:
+	    case DW_FORM_strx:
 	      skip_leb128 (ptr);
 	      break;
 	    case DW_FORM_ref_udata:
@@ -6967,6 +7096,7 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
 		    cu->lang = *ptr;
 		  /* FALLTHRU */
 		case DW_FORM_ref1:
+		case DW_FORM_strx1:
 		case DW_FORM_flag:
 		  ++ptr;
 		  break;
@@ -6978,8 +7108,20 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
 		    cu->lang = do_read_16 (ptr);
 		  /* FALLTHRU */
 		case DW_FORM_ref2:
+		case DW_FORM_strx2:
 		  ptr += 2;
 		  break;
+		case DW_FORM_strx3:
+		  ptr += 3;
+		  break;
+		case DW_FORM_sec_offset:
+		  if ((die->die_tag == DW_TAG_compile_unit
+			  || die->die_tag == DW_TAG_partial_unit)
+		      && t->attr[i].attr == DW_AT_str_offsets_base)
+		    cu->cu_str_offsets_base = read_32(ptr);
+		  else
+		    ptr += 4;
+		  break;
 		case DW_FORM_data4:
 		  if (lang_p
 		      && (die->die_tag == DW_TAG_compile_unit
@@ -6988,7 +7130,7 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
 		    read_lang (ptr, form, &cu->lang);
 		  /* FALLTHRU */
 		case DW_FORM_ref4:
-		case DW_FORM_sec_offset:
+		case DW_FORM_strx4:
 		  ptr += 4;
 		  break;
 		case DW_FORM_data8:
@@ -7017,6 +7159,10 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
 		    }
 		  /* FALLTHRU */
 		case DW_FORM_ref_udata:
+		case DW_FORM_addrx:
+		case DW_FORM_rnglistx:
+		case DW_FORM_loclistx:
+		case DW_FORM_strx:
 		  skip_leb128 (ptr);
 		  break;
 		case DW_FORM_strp:
@@ -8052,6 +8198,7 @@ partition_dups_1 (dw_die_ref *arr, size_t nr_partitions, size_t *partitions,
 	   + ((uni_lang_p || part_lang)
 	      ? nr_bytes_for (die_cu (arr[i])->lang)
 	      : 0)
+	   + (die_cu (arr[i])->cu_str_offsets_base ? 4: 0)
 	   /* CU root DIE children terminator: abbreviation code 0
 					       (unsigned LEB128).
 	      1 byte.  */
@@ -10805,12 +10952,17 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 		case DW_FORM_implicit_const:
 		  break;
 		case DW_FORM_flag:
+		case DW_FORM_strx1:
 		case DW_FORM_data1:
 		  ++ptr;
 		  break;
+		case DW_FORM_strx2:
 		case DW_FORM_data2:
 		  ptr += 2;
 		  break;
+		case DW_FORM_strx3:
+		  ptr += 3;
+		  break;
 		case DW_FORM_data4:
 		  if (reft->attr[i].attr == DW_AT_high_pc)
 		    {
@@ -10827,6 +10979,7 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 		    }
 		  ptr += 4;
 		  break;
+		case DW_FORM_strx4:
 		case DW_FORM_sec_offset:
 		  ptr += 4;
 		  break;
@@ -10864,6 +11017,10 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 		  break;
 		case DW_FORM_sdata:
 		case DW_FORM_udata:
+		case DW_FORM_addrx:
+		case DW_FORM_loclistx:
+		case DW_FORM_rnglistx:
+		case DW_FORM_strx:
 		  skip_leb128 (ptr);
 		  break;
 		case DW_FORM_strp:
@@ -11038,7 +11195,12 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	    unsigned char *ptr = get_AT (origin, DW_AT_comp_dir, &form);
 	    assert (ptr && (form == DW_FORM_string
 			    || form == DW_FORM_strp
-			    || form == DW_FORM_line_strp));
+			    || form == DW_FORM_line_strp
+                            || form == DW_FORM_strx
+                            || form == DW_FORM_strx1
+                            || form == DW_FORM_strx2
+                            || form == DW_FORM_strx3
+                            || form == DW_FORM_strx4));
 	    if (form == DW_FORM_strp)
 	      {
 		if (unlikely (op_multifile || fi_multifile))
@@ -11047,6 +11209,20 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	      }
 	    else if (form == DW_FORM_line_strp)
 	      die->die_size += 4;
+	    else if (form == DW_FORM_strx)
+              {
+                uint64_t idx = read_uleb128(ptr);
+                unsigned int len = size_of_uleb128(idx);
+                die->die_size += len;
+              }
+            else if (form == DW_FORM_strx1)
+              die->die_size += 1;
+            else if (form == DW_FORM_strx2)
+              die->die_size += 2;
+            else if (form == DW_FORM_strx3)
+              die->die_size += 3;
+            else if (form == DW_FORM_strx4)
+              die->die_size += 4;
 	    else
 	      die->die_size
 		+= strlen (refcu->cu_comp_dir) + 1;
@@ -11054,6 +11230,16 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	    t->attr[t->nattr].form = form;
 	    t->nattr++;
 	  }
+	if (refcu->cu_str_offsets_base)
+          {
+            enum dwarf_form form;
+            unsigned char *ptr = get_AT (origin, DW_AT_str_offsets_base, &form);
+            assert (ptr && (form == DW_FORM_sec_offset));
+            die->die_size += 4;
+            t->attr[t->nattr].attr = DW_AT_str_offsets_base;
+            t->attr[t->nattr].form = form;
+            t->nattr++;
+          }
 	break;
       case DW_TAG_namespace:
       case DW_TAG_module:
@@ -11062,7 +11248,12 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	  unsigned char *ptr = get_AT (origin, DW_AT_name, &form);
 	  assert (ptr && (form == DW_FORM_string
 			  || form == DW_FORM_strp
-			  || form == DW_FORM_line_strp));
+			  || form == DW_FORM_line_strp
+                          || form == DW_FORM_strx
+                          || form == DW_FORM_strx1
+                          || form == DW_FORM_strx2
+                          || form == DW_FORM_strx3
+                          || form == DW_FORM_strx4));
 	  if (form == DW_FORM_strp)
 	    {
 	      if (unlikely (op_multifile || fi_multifile))
@@ -11071,6 +11262,20 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	    }
 	  else if (form == DW_FORM_line_strp)
 	    die->die_size += 4;
+	  else if (form == DW_FORM_strx)
+            {
+              uint64_t idx = read_uleb128(ptr);
+              unsigned int len = size_of_uleb128(idx);
+              die->die_size = len;
+            }
+	  else if (form == DW_FORM_strx1)
+            die->die_size = 1;
+          else if (form == DW_FORM_strx2)
+            die->die_size = 2;
+          else if (form == DW_FORM_strx3)
+            die->die_size = 3;
+          else if (form == DW_FORM_strx4)
+            die->die_size = 4;
 	  else
 	    die->die_size = strlen ((char *) ptr) + 1;
 	  t->attr[0].attr = DW_AT_name;
@@ -12044,6 +12249,7 @@ adjust_exprloc (dw_cu_ref cu, dw_die_ref die, dw_cu_ref refcu,
 	case DW_OP_constu:
 	case DW_OP_plus_uconst:
 	case DW_OP_regx:
+	case DW_OP_addrx:
 	case DW_OP_piece:
 	case DW_OP_consts:
 	case DW_OP_breg0 ... DW_OP_breg31:
@@ -12171,11 +12377,33 @@ write_unit_die (unsigned char *ptr, dw_die_ref die, dw_die_ref origin)
 		    ptr += 4;
 		  }
 	      }
-	    else if (form == DW_FORM_line_strp)
+	    else if (form == DW_FORM_line_strp || form == DW_FORM_strx4)
 	      {
 		memcpy (ptr, p, 4);
 		ptr += 4;
 	      }
+	    else if (form == DW_FORM_strx)
+	      {
+                uint64_t idx = read_uleb128(p);
+		unsigned int len = size_of_uleb128(idx);
+	        memcpy (ptr, p, len);
+		ptr += len;
+	      }
+	    else if (form == DW_FORM_strx1)
+              {
+                memcpy (ptr, p, 1);
+                ptr += 1;
+              }
+            else if (form == DW_FORM_strx2)
+              {
+                memcpy (ptr, p, 2);
+                ptr += 2;
+              }
+            else if (form == DW_FORM_strx3)
+              {
+                memcpy (ptr, p, 3);
+                ptr += 3;
+              }
 	    else
 	      {
 		size_t len = strlen ((char *) p) + 1;
@@ -12191,6 +12419,15 @@ write_unit_die (unsigned char *ptr, dw_die_ref die, dw_die_ref origin)
 	    write_size (ptr, lang_size, lang);
 	    ptr += lang_size;
 	  }
+          break;
+        case DW_AT_str_offsets_base:
+          {
+            enum dwarf_form form;
+            unsigned char *p = get_AT (origin, DW_AT_str_offsets_base, &form);
+            assert (p && (form == DW_FORM_sec_offset));
+            memcpy(ptr, p, 4);
+            ptr += 4;
+	  }
 	  break;
 	default:
 	  assert (false);
@@ -12400,12 +12637,17 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die,
 	    case DW_FORM_implicit_const:
 	      break;
 	    case DW_FORM_flag:
+	    case DW_FORM_strx1:
 	    case DW_FORM_data1:
 	      ++inptr;
 	      break;
 	    case DW_FORM_data2:
+	    case DW_FORM_strx2:
 	      inptr += 2;
 	      break;
+	    case DW_FORM_strx3:
+	      inptr += 3;
+	      break;
 	    case DW_FORM_data4:
 	      if (reft->attr[i].attr == DW_AT_high_pc
 		  && t->attr[j].form != reft->attr[i].form)
@@ -12425,6 +12667,7 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die,
 	      inptr += 4;
 	      break;
 	    case DW_FORM_sec_offset:
+	    case DW_FORM_strx4:
 	      inptr += 4;
 	      break;
 	    case DW_FORM_data8:
@@ -12456,6 +12699,10 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die,
 	      break;
 	    case DW_FORM_sdata:
 	    case DW_FORM_udata:
+	    case DW_FORM_addrx:
+	    case DW_FORM_loclistx:
+	    case DW_FORM_rnglistx:
+	    case DW_FORM_strx:
 	      skip_leb128 (inptr);
 	      break;
 	    case DW_FORM_strp:
@@ -13508,6 +13755,7 @@ init_endian (int endianity)
   if (endianity == ELFDATA2LSB)
     {
       do_read_16 = buf_read_ule16;
+      do_read_24 = buf_read_ule24;
       do_read_32 = buf_read_ule32;
       do_read_64 = buf_read_ule64;
       do_write_16 = buf_write_le16;
@@ -13517,6 +13765,7 @@ init_endian (int endianity)
   else if (endianity == ELFDATA2MSB)
     {
       do_read_16 = buf_read_ube16;
+      do_read_24 = buf_read_ube24;
       do_read_32 = buf_read_ube32;
       do_read_64 = buf_read_ube64;
       do_write_16 = buf_write_be16;
-- 
2.25.1

