]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
readelf: Add some support for locviews.
authorMark Wielaard <mark@klomp.org>
Wed, 28 Feb 2018 23:14:52 +0000 (00:14 +0100)
committerMark Wielaard <mark@klomp.org>
Mon, 5 Mar 2018 14:30:22 +0000 (15:30 +0100)
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
libdw/dwarf.h
libdw/dwarf_formudata.c
src/ChangeLog
src/readelf.c

index b86fb13fdadb3cb95c91b83be8f4e866c0efce5f..4c3587b486f0011216640a5f5d865ec5d3fe3550 100644 (file)
@@ -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
index 4f362066bcc0eb67b619ddb4b6e58fedcd7b137a..d53a30d8fcec5803816cbd3f8f430ba58946e4fc 100644 (file)
@@ -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,
 
index 9c1644efae046cd819b677d46c9997c62ebbc553..95872d6be0501d2680e9a1b3fd36cc5b3b3cb45b 100644 (file)
@@ -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,
index e73c615462fdf9b411ea622644e20ec770e19dd2..70a2d43854fb6040bbfa83a5a3300ee946af7926 100644 (file)
@@ -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>
 
        * elflint.c (check_group): Make sure we can read a complete
index 2d49af346d67a8ed7460196984f14cd278fa1972..098209f0e6fda42945e7f8e8cb47dbb5de287460 100644 (file)
@@ -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);