From 4d90b859146b7aacc1067ff1a77c123e77391ee0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E2=80=9Cbhkumarn=E2=80=9D?= <Bhuvanendra.KumarN@amd.com>
Date: Fri, 10 Jun 2022 22:00:34 +0530
Subject: [PATCH] [PATCH] Binutils support for split-dwarf and dwarf-5.

This patch adds support for split-dwarf and dwarf5, for both gcc and clang.
Basic sections dump like .debug_info.dwo, .debug_abbrev.dwo, .debug_str.dwo
etc are supported in this patch.

There are few differences b/w dwarf4 and dwarf5, w.r.t. split-dwarf like
different attributes/forms used to represent DWO name and ID,
.debug_str_offsets section etc. All these are addressed.

	* dwarf.c (fetch_indexed_string): Added new parameter str_offsets_base
	to calculate the string offset.
	(read_and_display_attr_value): Read DW_AT_str_offsets_base attribute.
	(process_debug_info): While allocating memory and initializing
	debug_information, do it for do_debug_info also, if its true.
	(load_separate_debug_files): Load .debug_str_offsets if exists.
	* dwarf.h (struct debug_info): Add str_offsets_base field.
---
 binutils/dwarf.c | 54 ++++++++++++++++++++++++++++++++----------------
 binutils/dwarf.h |  1 +
 2 files changed, 37 insertions(+), 18 deletions(-)

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index e8f0ea4cf0c..6d2541039e5 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -118,8 +118,6 @@ int dwarf_cutoff_level = -1;
 unsigned long dwarf_start_die;
 
 int dwarf_check = 0;
-static dwarf_vma str_offsets_base = 0;
-#define DEBUG_STR_OFFSETS_HEADER_LEN 8
 
 /* Convenient constant, to avoid having to cast -1 to dwarf_vma when
    testing whether e.g. a locview list is present.  */
@@ -693,7 +691,7 @@ fetch_indirect_line_string (dwarf_vma offset)
 
 static const char *
 fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
-		      dwarf_vma offset_size, bool dwo)
+		      dwarf_vma offset_size, bool dwo, dwarf_vma str_offsets_base)
 {
   enum dwarf_section_display_enum str_sec_idx = dwo ? str_dwo : str;
   enum dwarf_section_display_enum idx_sec_idx = dwo ? str_index_dwo : str_index;
@@ -781,6 +779,13 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
       return _("<index offset is too big>");
     }
 
+  if (str_offsets_base > 0 )
+    {
+      if (offset_size == 8)
+        str_offsets_base -= 16;
+      else
+        str_offsets_base -= 8;
+    }
   str_offset = byte_get (curr + index_offset + str_offsets_base, offset_size);
   str_offset -= str_section->address;
   if (str_offset >= str_section->size)
@@ -2487,8 +2492,6 @@ read_and_display_attr_value (unsigned long           attribute,
     case DW_FORM_GNU_ref_alt:
     case DW_FORM_GNU_strp_alt:
       SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
-      if (attribute == DW_AT_str_offsets_base)
-        str_offsets_base = uvalue - DEBUG_STR_OFFSETS_HEADER_LEN;
       break;
 
     case DW_FORM_flag_present:
@@ -2737,11 +2740,13 @@ read_and_display_attr_value (unsigned long           attribute,
 	    /* We have already displayed the form name.  */
 	    printf (_("%c(offset: 0x%s): %s"), delimiter,
 		    dwarf_vmatoa ("x", uvalue),
-		    fetch_indexed_string (uvalue, this_set, offset_size, dwo));
+		    fetch_indexed_string (uvalue, this_set, offset_size, dwo,
+	                                  debug_info_p->str_offsets_base));
 	  else
 	    printf (_("%c(indexed string: 0x%s): %s"), delimiter,
 		    dwarf_vmatoa ("x", uvalue),
-		    fetch_indexed_string (uvalue, this_set, offset_size, dwo));
+		    fetch_indexed_string (uvalue, this_set, offset_size, dwo,
+	                                  debug_info_p->str_offsets_base));
 	}
       break;
 
@@ -2816,7 +2821,7 @@ read_and_display_attr_value (unsigned long           attribute,
       break;
     }
 
-  if ((do_loc || do_debug_loc || do_debug_ranges)
+  if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info)
       && num_debug_info_entries == 0
       && debug_info_p != NULL)
     {
@@ -2829,6 +2834,13 @@ read_and_display_attr_value (unsigned long           attribute,
 	  debug_info_p->loclists_base = uvalue;
 	  break;
 
+	case DW_AT_str_offsets_base:
+	  if (debug_info_p->str_offsets_base)
+	    warn (_("CU @ 0x%s has multiple str_offsets_base values"),
+		  dwarf_vmatoa ("x", debug_info_p->cu_offset));
+	  debug_info_p->str_offsets_base = uvalue;
+	  break;
+
 	case DW_AT_frame_base:
 	  have_frame_base = 1;
 	  /* Fall through.  */
@@ -2967,7 +2979,8 @@ read_and_display_attr_value (unsigned long           attribute,
 	      case DW_FORM_strx2:
 	      case DW_FORM_strx3:
 	      case DW_FORM_strx4:
-		add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, false), cu_offset);
+		add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, false,
+		                                    debug_info_p->str_offsets_base), cu_offset);
 		break;
 	      case DW_FORM_string:
 		add_dwo_name ((const char *) orig_data, cu_offset);
@@ -2999,7 +3012,8 @@ read_and_display_attr_value (unsigned long           attribute,
 	      case DW_FORM_strx2:
 	      case DW_FORM_strx3:
 	      case DW_FORM_strx4:
-		add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, false), cu_offset);
+		add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, false,
+		                                   debug_info_p->str_offsets_base), cu_offset);
 		break;
 	      case DW_FORM_string:
 		add_dwo_dir ((const char *) orig_data, cu_offset);
@@ -3319,6 +3333,7 @@ read_and_display_attr_value (unsigned long           attribute,
       /* Fall through.  */
     case DW_AT_location:
     case DW_AT_loclists_base:
+    case DW_AT_str_offsets_base:
     case DW_AT_string_length:
     case DW_AT_return_addr:
     case DW_AT_data_member_location:
@@ -3337,8 +3352,10 @@ read_and_display_attr_value (unsigned long           attribute,
       if ((dwarf_version < 4
 	   && (form == DW_FORM_data4 || form == DW_FORM_data8))
 	  || form == DW_FORM_sec_offset
-	  || form == DW_FORM_loclistx)
-	printf (_(" (location list)"));
+	  || form == DW_FORM_loclistx) {
+	if (attribute != DW_AT_str_offsets_base)
+	  printf (_(" (location list)"));
+      }
       /* Fall through.  */
     case DW_AT_allocated:
     case DW_AT_associated:
@@ -3569,7 +3586,7 @@ process_debug_info (struct dwarf_section * section,
       return false;
     }
 
-  if ((do_loc || do_debug_loc || do_debug_ranges)
+  if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info)
       && num_debug_info_entries == 0
       && ! do_types)
     {
@@ -3804,7 +3821,7 @@ process_debug_info (struct dwarf_section * section,
 	  continue;
 	}
 
-      if ((do_loc || do_debug_loc || do_debug_ranges)
+      if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info)
 	  && num_debug_info_entries == 0
 	  && alloc_num_debug_info_entries > unit
 	  && ! do_types)
@@ -3825,6 +3842,7 @@ process_debug_info (struct dwarf_section * section,
 	  debug_information [unit].range_lists = NULL;
 	  debug_information [unit].max_range_lists= 0;
 	  debug_information [unit].num_range_lists = 0;
+	  debug_information [unit].str_offsets_base = 0;
 	}
 
       if (!do_loc && dwarf_start_die == 0)
@@ -4064,7 +4082,6 @@ process_debug_info (struct dwarf_section * section,
 					    level);
 	    }
 
-	  str_offsets_base = 0;
 	  /* If a locview attribute appears before a location one,
 	     make sure we don't associate it with an earlier
 	     loclist. */
@@ -4097,7 +4114,7 @@ process_debug_info (struct dwarf_section * section,
 
   /* Set num_debug_info_entries here so that it can be used to check if
      we need to process .debug_loc and .debug_ranges sections.  */
-  if ((do_loc || do_debug_loc || do_debug_ranges)
+  if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info)
       && num_debug_info_entries == 0
       && ! do_types)
     {
@@ -6245,7 +6262,7 @@ display_debug_macro (struct dwarf_section *section,
 	      READ_ULEB (lineno, curr, end);
 	      READ_ULEB (offset, curr, end);
 	      string = (const unsigned char *)
-		fetch_indexed_string (offset, NULL, offset_size, false);
+		fetch_indexed_string (offset, NULL, offset_size, false, 0);
 	      if (op == DW_MACRO_define_strx)
 		printf (" DW_MACRO_define_strx ");
 	      else
@@ -7860,7 +7877,7 @@ display_debug_str_offsets (struct dwarf_section *section,
 	  SAFE_BYTE_GET_AND_INC (offset, curr, entry_length, entries_end);
 	  if (dwo)
 	    string = (const unsigned char *)
-	      fetch_indexed_string (idx, NULL, entry_length, dwo);
+	      fetch_indexed_string (idx, NULL, entry_length, dwo, 0);
 	  else
 	    string = fetch_indirect_string (offset);
 
@@ -11895,6 +11912,7 @@ load_separate_debug_files (void * file, const char * filename)
       && load_debug_section (abbrev, file)
       && load_debug_section (info, file))
     {
+      /* Load .debug_str_offsets section, if exists.  */
       load_debug_section (str_index, file);
       free_dwo_info ();
 
diff --git a/binutils/dwarf.h b/binutils/dwarf.h
index 040e674c6ce..ce38858d609 100644
--- a/binutils/dwarf.h
+++ b/binutils/dwarf.h
@@ -192,6 +192,7 @@ typedef struct
   dwarf_vma *    range_lists;
   unsigned int   num_range_lists;
   unsigned int   max_range_lists;
+  dwarf_vma      str_offsets_base;
 }
 debug_info;
 
-- 
2.17.1

