public inbox for dwz@sourceware.org
 help / color / mirror / Atom feed
From: Mark Wielaard <mark@klomp.org>
To: dwz@sourceware.org
Cc: Mark Wielaard <mark@klomp.org>
Subject: [PATCH] Support updating DWARF5 .debug_loclists.
Date: Mon, 28 Sep 2020 10:07:59 +0200	[thread overview]
Message-ID: <20200928080759.8619-1-mark@klomp.org> (raw)

This patch updates dwz to handle .debug_loclists as it updates .debug_locs.
Both sections can be present at the same time (if there are both DWARF5 CUs
and older DWARF CUs). So we need to keep both a loc_htab and loclists_htab.

	* dwz.c (read_loclist_low_mem_phase1): Add cu as argument.
	Track which section we are reading based on cu->cu_version.
	Read DWARF5 loclists entries setting ptr and len up to the
	start and length of the location lists to read.
	(add_locexpr_dummy_dies): Pass cu to read_loclist_low_mem_phase1.
	(loclists_htab): New static htab variable.
	(read_loclist): Update like read_loclist_low_mem_phase1 and create
	and update loclists_htab for DEBUG_LOCLISTS.
	(checksum_die): Pass cu to read_loclists.
	(adjust_loclists): New function like adjust_loclist for
	DEBUG_LOCLISTS.
	(write_loclists): New function like write_locs.
	(cleanup): Delete loclists_htab.
	(dwz): Call write_loclists.

At this time binutils readelf doesn't display .debug_loclists with view
pairs correctly.  To test the updates are correct when GCC emits view
pairs as GNU extension you'll need elfutils eu-readelf with the following
patch: https://sourceware.org/pipermail/elfutils-devel/2020q3/002900.html
---
 dwz.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 302 insertions(+), 54 deletions(-)

diff --git a/dwz.c b/dwz.c
index e772954..588ee50 100644
--- a/dwz.c
+++ b/dwz.c
@@ -2374,50 +2374,114 @@ read_exprloc_low_mem_phase1 (DSO *dso, dw_die_ref die, unsigned char *ptr,
 
 /* Add dummy DIEs for loclist at OFFSET.  */
 static int
-read_loclist_low_mem_phase1 (DSO *dso, dw_die_ref die, GElf_Addr offset)
+read_loclist_low_mem_phase1 (DSO *dso, dw_cu_ref cu, dw_die_ref die,
+			     GElf_Addr offset)
 {
   unsigned char *ptr, *endsec;
   GElf_Addr low, high;
-  size_t len;
+  size_t len = 0;
+  int sec;
 
-  ptr = debug_sections[DEBUG_LOC].data;
+  sec = cu->cu_version < 5 ? DEBUG_LOC : DEBUG_LOCLISTS;
+  ptr = debug_sections[sec].data;
   if (ptr == NULL)
     {
-      error (0, 0, "%s: loclistptr attribute, yet no .debug_loc section",
-	     dso->filename);
+      error (0, 0, "%s: loclistptr attribute, yet no %s section",
+	     dso->filename, debug_sections[sec].name);
       return 1;
     }
-  if (offset >= debug_sections[DEBUG_LOC].size)
+  if (offset >= debug_sections[sec].size)
     {
       error (0, 0,
-	     "%s: loclistptr offset %Ld outside of .debug_loc section",
-	     dso->filename, (long long) offset);
+	     "%s: loclistptr offset %Ld outside of %s section",
+	     dso->filename, (long long) offset, debug_sections[sec].name);
       return 1;
     }
-  endsec = ptr + debug_sections[DEBUG_LOC].size;
+  endsec = ptr + debug_sections[sec].size;
   ptr += offset;
   while (ptr < endsec)
     {
-      low = read_size (ptr, ptr_size);
-      high = read_size (ptr + ptr_size, ptr_size);
-      ptr += 2 * ptr_size;
-      if (low == 0 && high == 0)
-	break;
+      if (cu->cu_version < 5)
+	{
+	  low = read_size (ptr, ptr_size);
+	  high = read_size (ptr + ptr_size, ptr_size);
+	  ptr += 2 * ptr_size;
+	  if (low == 0 && high == 0)
+	    break;
 
-      if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff))
-	continue;
+	  if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff))
+	    continue;
+
+	  len = read_16 (ptr);
+	}
+      else
+	{
+	  uint8_t lle = *ptr++;
+	  switch (lle)
+	    {
+	    case DW_LLE_end_of_list:
+	      return 0;
+
+	    case DW_LLE_base_addressx:
+	      skip_leb128 (ptr);
+	      continue;
+
+	    case DW_LLE_startx_endx:
+	      skip_leb128 (ptr);
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_startx_length:
+	      skip_leb128 (ptr);
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_offset_pair:
+	      skip_leb128 (ptr);
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_default_location:
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_base_address:
+	      ptr += ptr_size;
+	      continue;
+
+	    case DW_LLE_start_end:
+	      ptr += 2 * ptr_size;
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_start_length:
+	      ptr += ptr_size;
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    default:
+	      error (0, 0,
+		     "%s: unhandled location list entry 0x%x in %s section",
+		     dso->filename, lle, debug_sections[sec].name);
+	      return 1;
+	    }
+	}
 
-      len = read_16 (ptr);
       if (unlikely (!(ptr + len <= endsec)))
 	{
 	  error (0, 0,
-		 "%s: locexpr length 0x%Lx exceeds .debug_loc section",
-		 dso->filename, (long long) len);
+		 "%s: locexpr length 0x%Lx exceeds %s section",
+		 dso->filename, (long long) len, debug_sections[sec].name);
 	  return 1;
 	}
 
-      if (read_exprloc_low_mem_phase1 (dso, die, ptr, len))
-	return 1;
+      if (len > 0)
+	if (read_exprloc_low_mem_phase1 (dso, die, ptr, len))
+	  return 1;
 
       ptr += len;
     }
@@ -2492,13 +2556,13 @@ add_locexpr_dummy_dies (DSO *dso, dw_cu_ref cu, dw_die_ref die,
       if ((cu->cu_version < 4 && form == DW_FORM_data4)
 	  || form == DW_FORM_sec_offset)
 	{
-	  if (read_loclist_low_mem_phase1 (dso, die, do_read_32 (ptr)))
+	  if (read_loclist_low_mem_phase1 (dso, cu, die, do_read_32 (ptr)))
 	    return 1;
 	  break;
 	}
       else if (cu->cu_version < 4 && form == DW_FORM_data8)
 	{
-	  if (read_loclist_low_mem_phase1 (dso, die, do_read_64 (ptr)))
+	  if (read_loclist_low_mem_phase1 (dso, cu, die, do_read_64 (ptr)))
 	    return 1;
 	  break;
 	}
@@ -2526,10 +2590,12 @@ struct debug_loc_adjust
 };
 ALIGN_STRUCT (debug_loc_adjust)
 
-/* Hash table and obstack for recording .debug_loc adjustment ranges.  */
+/* Hash table and obstack for recording .debug_loc and .debug_loclists
+   adjustment ranges.  */
 static htab_t loc_htab;
+static htab_t loclists_htab;
 
-/* Hash function for loc_htab.  */
+/* Hash function for loc[lists]_htab.  */
 static hashval_t
 loc_hash (const void *p)
 {
@@ -2538,7 +2604,7 @@ loc_hash (const void *p)
   return a->end_offset;
 }
 
-/* Equality function for loc_htab.  */
+/* Equality function for loc[lists]_htab.  */
 static int
 loc_eq (const void *p, const void *q)
 {
@@ -2552,47 +2618,109 @@ loc_eq (const void *p, const void *q)
    DIE.  Call read_exprloc on each of the DWARF expressions
    contained in it.  */
 static int
-read_loclist (DSO *dso, dw_die_ref die, GElf_Addr offset)
+read_loclist (DSO *dso, dw_cu_ref cu, dw_die_ref die, GElf_Addr offset)
 {
   unsigned char *ptr, *endsec;
   GElf_Addr low, high;
   size_t len;
+  int sec;
   bool need_adjust = false;
 
   die->die_ck_state = CK_BAD;
-  ptr = debug_sections[DEBUG_LOC].data;
+  sec = cu->cu_version < 5 ? DEBUG_LOC : DEBUG_LOCLISTS;
+  ptr = debug_sections[sec].data;
   if (ptr == NULL)
     {
-      error (0, 0, "%s: loclistptr attribute, yet no .debug_loc section",
-	     dso->filename);
+      error (0, 0, "%s: loclistptr attribute, yet no %s section",
+	     dso->filename, debug_sections[sec].name);
       return 1;
     }
-  if (offset >= debug_sections[DEBUG_LOC].size)
+  if (offset >= debug_sections[sec].size)
     {
       error (0, 0,
-	     "%s: loclistptr offset %Ld outside of .debug_loc section",
-	     dso->filename, (long long) offset);
+	     "%s: loclistptr offset %Ld outside of %s section",
+	     dso->filename, (long long) offset, debug_sections[sec].name);
       return 1;
     }
-  endsec = ptr + debug_sections[DEBUG_LOC].size;
+  endsec = ptr + debug_sections[sec].size;
   ptr += offset;
   while (ptr < endsec)
     {
-      low = read_size (ptr, ptr_size);
-      high = read_size (ptr + ptr_size, ptr_size);
-      ptr += 2 * ptr_size;
-      if (low == 0 && high == 0)
-	break;
+      if (cu->cu_version < 5)
+	{
+	  low = read_size (ptr, ptr_size);
+	  high = read_size (ptr + ptr_size, ptr_size);
+	  ptr += 2 * ptr_size;
+	  if (low == 0 && high == 0)
+	    break;
 
-      if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff))
-	continue;
+	  if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff))
+	    continue;
+
+	  len = read_16 (ptr);
+	}
+      else
+	{
+	  uint8_t lle = *ptr++;
+	  switch (lle)
+	    {
+	    case DW_LLE_end_of_list:
+	      return 0;
+
+	    case DW_LLE_base_addressx:
+	      skip_leb128 (ptr);
+	      continue;
+
+	    case DW_LLE_startx_endx:
+	      skip_leb128 (ptr);
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_startx_length:
+	      skip_leb128 (ptr);
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_offset_pair:
+	      skip_leb128 (ptr);
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_default_location:
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_base_address:
+	      ptr += ptr_size;
+	      continue;
+
+	    case DW_LLE_start_end:
+	      ptr += 2 * ptr_size;
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    case DW_LLE_start_length:
+	      ptr += ptr_size;
+	      skip_leb128 (ptr);
+	      len = read_uleb128 (ptr);
+	      break;
+
+	    default:
+	      error (0, 0,
+		     "%s: unhandled location list entry 0x%x in %s section",
+		     dso->filename, lle, debug_sections[sec].name);
+	      return 1;
+	    }
+	}
 
-      len = read_16 (ptr);
       if (unlikely (!(ptr + len <= endsec)))
 	{
 	  error (0, 0,
-		 "%s: locexpr length 0x%Lx exceeds .debug_loc section",
-		 dso->filename, (long long) len);
+		 "%s: locexpr length 0x%Lx exceeds %s section",
+		 dso->filename, (long long) len, debug_sections[sec].name);
 	  return 1;
 	}
 
@@ -2608,15 +2736,30 @@ read_loclist (DSO *dso, dw_die_ref die, GElf_Addr offset)
       void **slot;
 
       adj.start_offset = offset;
-      adj.end_offset = ptr - debug_sections[DEBUG_LOC].data;
-      adj.cu = die_cu (die);
-      if (loc_htab == NULL)
+      adj.end_offset = ptr - debug_sections[sec].data;
+      adj.cu = cu;
+      if (sec == DEBUG_LOC)
 	{
-	  loc_htab = htab_try_create (50, loc_hash, loc_eq, NULL);
 	  if (loc_htab == NULL)
-	    dwz_oom ();
+	    {
+	      loc_htab = htab_try_create (50, loc_hash, loc_eq, NULL);
+	      if (loc_htab == NULL)
+		dwz_oom ();
+	    }
+	  slot = htab_find_slot_with_hash (loc_htab, &adj, adj.end_offset,
+					   INSERT);
+	}
+      else
+	{
+	  if (loclists_htab == NULL)
+	    {
+	      loclists_htab = htab_try_create (50, loc_hash, loc_eq, NULL);
+	      if (loclists_htab == NULL)
+		dwz_oom ();
+	    }
+	  slot = htab_find_slot_with_hash (loclists_htab, &adj, adj.end_offset,
+					   INSERT);
 	}
-      slot = htab_find_slot_with_hash (loc_htab, &adj, adj.end_offset, INSERT);
       if (slot == NULL)
 	dwz_oom ();
       if (*slot == NULL)
@@ -2627,8 +2770,8 @@ read_loclist (DSO *dso, dw_die_ref die, GElf_Addr offset)
 	}
       else if (((struct debug_loc_adjust *)*slot)->cu != adj.cu)
 	{
-	  error (0, 0, "%s: can't adjust .debug_loc section because multiple "
-		       "CUs refer to it", dso->filename);
+	  error (0, 0, "%s: can't adjust %s section because multiple "
+		 "CUs refer to it", dso->filename, debug_sections[sec].name);
 	  return 1;
 	}
       else if (((struct debug_loc_adjust *)*slot)->start_offset > offset)
@@ -2848,14 +2991,14 @@ checksum_die (DSO *dso, dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die)
 	  if ((cu->cu_version < 4 && form == DW_FORM_data4)
 	      || form == DW_FORM_sec_offset)
 	    {
-	      if (read_loclist (dso, die, read_32 (ptr)))
+	      if (read_loclist (dso, cu, die, read_32 (ptr)))
 		return 1;
 	      ptr = old_ptr;
 	      break;
 	    }
 	  else if (cu->cu_version < 4 && form == DW_FORM_data8)
 	    {
-	      if (read_loclist (dso, die, read_64 (ptr)))
+	      if (read_loclist (dso, cu, die, read_64 (ptr)))
 		return 1;
 	      ptr = old_ptr;
 	      break;
@@ -12128,6 +12271,85 @@ adjust_loclist (void **slot, void *data)
   return 1;
 }
 
+/* Adjust .debug_loclists range determined by *SLOT, called through
+   htab_traverse.  */
+static int
+adjust_loclists (void **slot, void *data)
+{
+  struct debug_loc_adjust *adj = (struct debug_loc_adjust *) *slot;
+  unsigned char *ptr, *endsec;
+  size_t len = 0;
+
+  (void)data;
+
+  ptr = debug_sections[DEBUG_LOCLISTS].new_data + adj->start_offset;
+  endsec = ptr + debug_sections[DEBUG_LOCLISTS].size;
+
+  while (ptr < endsec)
+    {
+      uint8_t lle = *ptr++;
+      switch (lle)
+	{
+	case DW_LLE_end_of_list:
+	  return 1;
+
+	case DW_LLE_base_addressx:
+	  skip_leb128 (ptr);
+	  continue;
+
+	case DW_LLE_startx_endx:
+	  skip_leb128 (ptr);
+	  skip_leb128 (ptr);
+	  len = read_uleb128 (ptr);
+	  break;
+
+	case DW_LLE_startx_length:
+	  skip_leb128 (ptr);
+	  skip_leb128 (ptr);
+	  len = read_uleb128 (ptr);
+	  break;
+
+	case DW_LLE_offset_pair:
+	  skip_leb128 (ptr);
+	  skip_leb128 (ptr);
+	  len = read_uleb128 (ptr);
+	  break;
+
+	case DW_LLE_default_location:
+	  len = read_uleb128 (ptr);
+	  break;
+
+	case DW_LLE_base_address:
+	  ptr += ptr_size;
+	  continue;
+
+	case DW_LLE_start_end:
+	  ptr += 2 * ptr_size;
+	  len = read_uleb128 (ptr);
+	  break;
+
+	case DW_LLE_start_length:
+	  ptr += ptr_size;
+	  skip_leb128 (ptr);
+	  len = read_uleb128 (ptr);
+	  break;
+
+	default:
+	  error (0, 0, "unhandled location list entry 0x%x", lle);
+	  return 1;
+	}
+
+      assert (ptr + len <= endsec);
+
+      adjust_exprloc (adj->cu, adj->cu->cu_die, adj->cu, adj->cu->cu_die,
+		      ptr, len);
+
+      ptr += len;
+    }
+
+  return 1;
+}
+
 /* Create new .debug_loc section in malloced memory if .debug_loc
    needs to be adjusted.  */
 static void
@@ -12144,6 +12366,23 @@ write_loc (void)
   htab_traverse (loc_htab, adjust_loclist, NULL);
 }
 
+/* Create new .debug_loclists section in malloced memory if .debug_loclists
+   needs to be adjusted.  */
+static void
+write_loclists (void)
+{
+  unsigned char *loc;
+  if (loclists_htab == NULL)
+    return;
+  loc = malloc (debug_sections[DEBUG_LOCLISTS].size);
+  if (loc == NULL)
+    dwz_oom ();
+  memcpy (loc, debug_sections[DEBUG_LOCLISTS].data,
+	  debug_sections[DEBUG_LOCLISTS].size);
+  debug_sections[DEBUG_LOCLISTS].new_data = loc;
+  htab_traverse (loclists_htab, adjust_loclists, NULL);
+}
+
 /* Create new .debug_types section in malloced memory.  */
 static void
 write_types (void)
@@ -13439,6 +13678,9 @@ cleanup (void)
   if (loc_htab != NULL)
     htab_delete (loc_htab);
   loc_htab = NULL;
+  if (loclists_htab != NULL)
+    htab_delete (loclists_htab);
+  loclists_htab = NULL;
   if (dup_htab != NULL)
     htab_delete (dup_htab);
   dup_htab = NULL;
@@ -14440,6 +14682,12 @@ dwz (const char *file, const char *outfile, struct file_result *res,
 	      fprintf (stderr, "write_loc\n");
 	    }
 	  write_loc ();
+	  if (unlikely (progress_p))
+	    {
+	      report_progress ();
+	      fprintf (stderr, "write_loclists\n");
+	    }
+	  write_loclists ();
 	  if (unlikely (progress_p))
 	    {
 	      report_progress ();
-- 
2.18.4


             reply	other threads:[~2020-09-28  8:08 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-28  8:07 Mark Wielaard [this message]
2020-09-29  8:42 ` Jakub Jelinek
2020-09-29 17:59   ` Mark Wielaard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200928080759.8619-1-mark@klomp.org \
    --to=mark@klomp.org \
    --cc=dwz@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).