[PATCH] readelf: Add some support for locviews.

Mark Wielaard mark@klomp.org
Thu Mar 1 13:55:00 GMT 2018


This adds minimal support for locviews as output by GCC8.
It changes readelf to keep track of loclistptrs from DW_AT_GNU_locviews
and prints the locview pairs for those. Since there is no terminator
we have to keep track of where the next loclist entry starts.
The --debug-dump=loc output looks as follows:

 CU [   714] base: +0x0000000000003020 <elf_hash>
 [    b4] view pair 1, 2
 [    b6] range 4, 7f
          +0x0000000000003024 <elf_hash+0x4>..
          +0x000000000000309e <elf_hash+0x7e>
           [ 0] reg5
 [    d9] view pair 3, 1
          view pair 1, 2
 [    dd] range 4, 4c
          +0x0000000000003024 <elf_hash+0x4>..
          +0x000000000000306b <elf_hash+0x4b>
           [ 0] reg5
          range 4c, 7f
          +0x000000000000306c <elf_hash+0x4c>..
          +0x000000000000309e <elf_hash+0x7e>
           [ 0] reg2

Note that in the above output the view pairs correspond to the ranges
immediately following in the loc list. This is how GCC8 currently
outputs the locview pairs and ranges, but this is not guaranteed and
you'll need to look at the location and GNU_locviews attributes of the
DIE to know which really match up together. We might want to adjust the
output to make this more clear.

This does not yet add an locview accessor to libdw. It just recognizes
the DW_AT_GNU_locviews attribute as a loclistptr when encoded as a
sec_offset form.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog         |  6 ++++
 libdw/dwarf.h           |  2 ++
 libdw/dwarf_formudata.c |  1 +
 src/ChangeLog           | 15 ++++++++++
 src/readelf.c           | 79 ++++++++++++++++++++++++++++++++++++++++++++-----
 5 files changed, 96 insertions(+), 7 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index b86fb13f..4c3587b4 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,9 @@
+2018-03-01  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_AT_GNU_locviews and DW_AT_GNU_entry_view.
+	* dwarf_formudata.c (dwarf_formudata): Handle DW_AT_GNU_locviews
+	as a loclistptr.
+
 2018-02-09  Mark Wielaard  <mark@klomp.org>
 
 	* dwarf_formblock.c (dwarf_formblock): Handle DW_FORM_data16 as a
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index 4f362066..d53a30d8 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -339,6 +339,8 @@ enum
     DW_AT_GNU_all_tail_call_sites = 0x2116,
     DW_AT_GNU_all_call_sites = 0x2117,
     DW_AT_GNU_all_source_call_sites = 0x2118,
+    DW_AT_GNU_locviews = 0x2137,
+    DW_AT_GNU_entry_view = 0x2138,
     DW_AT_GNU_macros = 0x2119,
     DW_AT_GNU_deleted = 0x211a,
 
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index 9c1644ef..95872d6b 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -141,6 +141,7 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
 	    case DW_AT_string_length:
 	    case DW_AT_use_location:
 	    case DW_AT_vtable_elem_location:
+	    case DW_AT_GNU_locviews:
 	      /* loclistptr */
 	      if (__libdw_formptr (attr, IDX_debug_loc,
 				   DWARF_E_NO_LOCLIST, NULL,
diff --git a/src/ChangeLog b/src/ChangeLog
index 0ae01e92..61140ba3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,18 @@
+2018-03-01  Mark Wielaard  <mark@klomp.org>
+
+	* readelf.c (struct listptr): Add attr field.
+	(compare_listptr): Warn when two listptrs for the same offset have
+	different attributes.
+	(notice_listptr): Take attr as argument and add it to listptr.
+	(skip_listptr_hole): New attr argument.
+	(next_listptr_offset): New function.
+	(print_debug_ranges_section): Pass NULL attr to skip_listptr_hole.
+	(attr_callback): Handle DW_AT_GNU_locviews. Call notice_listptr with
+	attr.
+	(print_debug_loc_section): Keep track of which attr is associated with
+	a listptr. If the attr is DW_AT_GNU_locview print view pairs till the
+	next listptr offset.
+
 2018-02-09  Mark Wielaard  <mark@klomp.org>
 
 	* readelf.c (attr_callback): Handle DW_FORM_data16 as Dwarf_Block.
diff --git a/src/readelf.c b/src/readelf.c
index 2d49af34..098209f0 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4532,6 +4532,7 @@ struct listptr
   bool dwarf64:1;
   bool warned:1;
   struct Dwarf_CU *cu;
+  unsigned int attr;
 };
 
 #define listptr_offset_size(p)	((p)->dwarf64 ? 8 : 4)
@@ -4592,6 +4593,15 @@ compare_listptr (const void *a, const void *b, void *arg)
 		 gettext ("%s %#" PRIx64 " used with different base addresses"),
 		 name, (uint64_t) p1->offset);
 	}
+      if (p1->attr != p2 ->attr)
+	{
+	  p1->warned = p2->warned = true;
+	  error (0, 0,
+		 gettext ("%s %#" PRIx64
+			  " used with different attribute %s and %s"),
+		 name, (uint64_t) p1->offset, dwarf_attr_name (p2->attr),
+		 dwarf_attr_name (p2->attr));
+	}
     }
 
   return 0;
@@ -4619,7 +4629,7 @@ reset_listptr (struct listptr_table *table)
 static bool
 notice_listptr (enum section_e section, struct listptr_table *table,
 		uint_fast8_t address_size, uint_fast8_t offset_size,
-		struct Dwarf_CU *cu, Dwarf_Off offset)
+		struct Dwarf_CU *cu, Dwarf_Off offset, unsigned int attr)
 {
   if (print_debug_sections & section)
     {
@@ -4640,7 +4650,8 @@ notice_listptr (enum section_e section, struct listptr_table *table,
 	  .addr64 = address_size == 8,
 	  .dwarf64 = offset_size == 8,
 	  .offset = offset,
-	  .cu = cu
+	  .cu = cu,
+	  .attr = attr
 	};
 
       if (p->offset != offset)
@@ -4664,7 +4675,8 @@ static bool
 skip_listptr_hole (struct listptr_table *table, size_t *idxp,
 		   uint_fast8_t *address_sizep, uint_fast8_t *offset_sizep,
 		   Dwarf_Addr *base, struct Dwarf_CU **cu, ptrdiff_t offset,
-		   unsigned char **readp, unsigned char *endp)
+		   unsigned char **readp, unsigned char *endp,
+		   unsigned int *attr)
 {
   if (table->n == 0)
     return false;
@@ -4699,10 +4711,27 @@ skip_listptr_hole (struct listptr_table *table, size_t *idxp,
     *base = listptr_base (p);
   if (cu != NULL)
     *cu = p->cu;
+  if (attr != NULL)
+    *attr = p->attr;
 
   return false;
 }
 
+static Dwarf_Off
+next_listptr_offset (struct listptr_table *table, size_t idx)
+{
+  /* Note that multiple attributes could in theory point to the same loclist
+     offset, so make sure we pick one that is bigger than the current one.
+     The table is sorted on offset.  */
+  Dwarf_Off offset = table->table[idx].offset;
+  while (++idx < table->n)
+    {
+      Dwarf_Off next = table->table[idx].offset;
+      if (next > offset)
+	return next;
+    }
+  return 0;
+}
 
 static void
 print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
@@ -5042,7 +5071,7 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
 
       if (first && skip_listptr_hole (&known_rangelistptr, &listptr_idx,
 				      &address_size, NULL, &base, &cu,
-				      offset, &readp, endp))
+				      offset, &readp, endp, NULL))
 	continue;
 
       if (last_cu != cu)
@@ -6121,10 +6150,11 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 	case DW_AT_GNU_call_site_data_value:
 	case DW_AT_GNU_call_site_target:
 	case DW_AT_GNU_call_site_target_clobbered:
+	case DW_AT_GNU_locviews:
 	  {
 	    bool nlpt = notice_listptr (section_loc, &known_loclistptr,
 					cbargs->addrsize, cbargs->offset_size,
-					cbargs->cu, num);
+					cbargs->cu, num, attr);
 	    if (!cbargs->silent)
 	      printf ("           %*s%-20s (%s) location list [%6" PRIxMAX "]%s\n",
 		      (int) (level * 2), "", dwarf_attr_name (attr),
@@ -6137,7 +6167,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 	  {
 	    bool nlpt = notice_listptr (section_ranges, &known_rangelistptr,
 					cbargs->addrsize, cbargs->offset_size,
-					cbargs->cu, num);
+					cbargs->cu, num, attr);
 	    if (!cbargs->silent)
 	      printf ("           %*s%-20s (%s) range list [%6" PRIxMAX "]%s\n",
 		      (int) (level * 2), "", dwarf_attr_name (attr),
@@ -7215,10 +7245,11 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
     {
       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
       Dwarf_CU *cu = last_cu;
+      unsigned int attr = 0;
 
       if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx,
 				      &address_size, &offset_size, &base,
-				      &cu, offset, &readp, endp))
+				      &cu, offset, &readp, endp, &attr))
 	continue;
 
       if (last_cu != cu)
@@ -7237,6 +7268,40 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
        }
       last_cu = cu;
 
+      if (attr == DW_AT_GNU_locviews)
+	{
+	  Dwarf_Off next_off = next_listptr_offset (&known_loclistptr,
+						    listptr_idx);
+	  const unsigned char *locp = readp;
+	  const unsigned char *locendp;
+	  if (next_off == 0)
+	    locendp = endp;
+	  else
+	    locendp = (const unsigned char *) data->d_buf + next_off;
+
+	  while (locp < locendp)
+	    {
+	      uint64_t v1, v2;
+	      get_uleb128 (v1, locp, locendp);
+	      if (locp >= locendp)
+		{
+		  printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
+		  break;
+		}
+	      get_uleb128 (v2, locp, locendp);
+	      if (first)		/* First view pair in a list.  */
+		printf (" [%6tx] ", offset);
+	      else
+		printf ("          ");
+	      printf ("view pair %" PRId64 ", %" PRId64 "\n", v1, v2);
+	      first = false;
+	    }
+
+	  first = true;
+	  readp = (unsigned char *) locendp;
+	  continue;
+	}
+
       if (unlikely (data->d_size - offset < (size_t) address_size * 2))
 	{
 	  printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
-- 
2.16.1



More information about the Elfutils-devel mailing list