]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
readelf, libdw: Add GNU DebugFission .debug_loc support.
authorMark Wielaard <mark@klomp.org>
Mon, 28 May 2018 22:59:28 +0000 (00:59 +0200)
committerMark Wielaard <mark@klomp.org>
Thu, 31 May 2018 12:42:27 +0000 (14:42 +0200)
GNU DebugFission .debug_loc location lists uses the .debug_loc section
in the split dwarf .dwo file. The encoding is a mix of old style DWARF
.debug_loc and new style .debug_loclists.

Add two testcases for the readelf and libdw decoders.

Signed-off-by: Mark Wielaard <mark@klomp.org>
libdw/ChangeLog
libdw/dwarf.h
libdw/dwarf_ranges.c
src/ChangeLog
src/readelf.c
tests/ChangeLog
tests/run-readelf-loc.sh
tests/run-varlocs.sh

index d187930847f77835d3016af3ebcee2274235fa7b..eb0b01ada2fc656df5c6ef60926363a0d01ad8d4 100644 (file)
@@ -1,3 +1,12 @@
+2018-05-29  Mark Wielaard  <mark@klomp.org>
+
+       * dwarf.h: Add GNU DebugFission list entry encodings
+       DW_LLE_GNU_end_of_list_entry,
+       DW_LLE_GNU_base_address_selection_entry,
+       DW_LLE_GNU_start_end_entry and DW_LLE_GNU_start_length_entry.
+       * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Handle
+       GNU DebugFission list entries.
+
 2018-05-28  Mark Wielaard  <mark@klomp.org>
 
        * libdw_find_split_unit.c (__libdw_find_split_unit): End split_dwarf
index 8985a9d4fa90bf4104029061e4096b8bbdbb74b8..dc5973352ab7011e4a5c2f4a624b58e0d2e62c3b 100644 (file)
@@ -915,6 +915,16 @@ enum
   };
 
 
+/* GNU DebugFission list entry encodings (.debug_loc.dwo).  */
+enum
+  {
+    DW_LLE_GNU_end_of_list_entry = 0x0,
+    DW_LLE_GNU_base_address_selection_entry = 0x1,
+    DW_LLE_GNU_start_end_entry = 0x2,
+    DW_LLE_GNU_start_length_entry = 0x3
+  };
+
+
 /* DWARF call frame instruction encodings.  */
 enum
   {
index 0f3ee6b53eb89c6f7bb019aaba7855a74d3c50ef..f67d8a5a8cbe86c355b027fe484e9344d0996e6a 100644 (file)
@@ -49,7 +49,70 @@ __libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
                                 Dwarf_Addr *basep)
 {
   Dwarf *dbg = cu->dbg;
-  if (sec_index == IDX_debug_ranges || sec_index == IDX_debug_loc)
+  if (sec_index == IDX_debug_loc
+      && cu->version < 5
+      && cu->unit_type == DW_UT_split_compile)
+    {
+      /* GNU DebugFission.  */
+      const unsigned char *addr = *addrp;
+      if (addrend - addr < 1)
+       goto invalid;
+
+      const char code = *addr++;
+      uint64_t begin = 0, end = 0, base = *basep, addr_idx;
+      switch (code)
+       {
+       case DW_LLE_GNU_end_of_list_entry:
+         *addrp = addr;
+         return 2;
+
+       case DW_LLE_GNU_base_address_selection_entry:
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &base) != 0)
+           return -1;
+         *basep = base;
+         *addrp = addr;
+         return 1;
+
+       case DW_LLE_GNU_start_end_entry:
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+           return -1;
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &end) != 0)
+           return -1;
+
+         *beginp = begin;
+         *endp = end;
+         *addrp = addr;
+         return 0;
+
+       case DW_LLE_GNU_start_length_entry:
+         if (addrend - addr < 1)
+           goto invalid;
+         get_uleb128 (addr_idx, addr, addrend);
+         if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+           return -1;
+         if (addrend - addr < 4)
+           goto invalid;
+         end = read_4ubyte_unaligned_inc (dbg, addr);
+
+         *beginp = begin;
+         *endp = begin + end;
+         *addrp = addr;
+         return 0;
+
+       default:
+         goto invalid;
+       }
+    }
+  else if (sec_index == IDX_debug_ranges || sec_index == IDX_debug_loc)
     {
       Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
                           : (Elf64_Addr) (Elf32_Addr) -1);
index e7ba6cb12f9943c5a1809693e85c82bc15db55c1..f424fb7f689d495cb2c48a1f1b4e8315c362a101 100644 (file)
@@ -1,3 +1,8 @@
+2018-05-29  Mark Wielaard  <mark@klomp.org>
+
+       * readelf.c (print_debug_loc_section): Handle GNU DebugFission list
+       entries.
+
 2018-05-29  Mark Wielaard  <mark@klomp.org>
 
        * readelf.c (print_debug): Record and reset section_info status in
index 390f244438ac17d2f4dd9703d001245a63094678..2ccbea5b75c31d800bd64c2cb694b534cdd06ef4 100644 (file)
@@ -9276,15 +9276,81 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
          continue;
        }
 
-      if (unlikely (data->d_size - offset < (size_t) address_size * 2))
-       {
+      /* GNU DebugFission encoded addresses as addrx.  */
+      bool is_debugfission = ((cu != NULL
+                              || split_dwarf_cu_base (dbg, &cu, &base))
+                             && (cu->version < 5
+                                 && cu->unit_type == DW_UT_split_compile));
+      if (!is_debugfission
+         && unlikely (data->d_size - offset < (size_t) address_size * 2))
+        {
+       invalid_data:
          printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
          break;
        }
 
       Dwarf_Addr begin;
       Dwarf_Addr end;
-      if (address_size == 8)
+      bool use_base = true;
+      if (is_debugfission)
+       {
+         const unsigned char *locp = readp;
+         const unsigned char *locendp = readp + data->d_size;
+         if (locp >= locendp)
+           goto invalid_data;
+
+         Dwarf_Word idx;
+         unsigned char code = *locp++;
+         switch (code)
+           {
+           case DW_LLE_GNU_end_of_list_entry:
+             begin = 0;
+             end = 0;
+             break;
+
+           case DW_LLE_GNU_base_address_selection_entry:
+             if (locp >= locendp)
+               goto invalid_data;
+             begin = (Dwarf_Addr) -1;
+             get_uleb128 (idx, locp, locendp);
+             if (get_indexed_addr (cu, idx, &end) != 0)
+               end = idx; /* ... */
+             break;
+
+           case DW_LLE_GNU_start_end_entry:
+             if (locp >= locendp)
+               goto invalid_data;
+             get_uleb128 (idx, locp, locendp);
+             if (get_indexed_addr (cu, idx, &begin) != 0)
+               end = idx; /* ... */
+             if (locp >= locendp)
+               goto invalid_data;
+             get_uleb128 (idx, locp, locendp);
+             if (get_indexed_addr (cu, idx, &end) != 0)
+               end = idx; /* ... */
+             use_base = false;
+             break;
+
+           case DW_LLE_GNU_start_length_entry:
+             if (locp >= locendp)
+               goto invalid_data;
+             get_uleb128 (idx, locp, locendp);
+             if (get_indexed_addr (cu, idx, &begin) != 0)
+               begin = idx; /* ... */
+             if (locendp - locp < 4)
+               goto invalid_data;
+             end = read_4ubyte_unaligned_inc (dbg, locp);
+             end += begin;
+             use_base = false;
+             break;
+
+           default:
+               goto invalid_data;
+           }
+
+         readp = (unsigned char *) locp;
+       }
+      else if (address_size == 8)
        {
          begin = read_8ubyte_unaligned_inc (dbg, readp);
          end = read_8ubyte_unaligned_inc (dbg, readp);
@@ -9323,10 +9389,12 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
          printf ("range %" PRIx64 ", %" PRIx64 "\n", begin, end);
          if (! print_unresolved_addresses)
            {
-             char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
-                                          base + begin);
+             Dwarf_Addr dab = use_base ? base + begin : begin;
+             Dwarf_Addr dae = use_base ? base + end : end;
+             char *b = format_dwarf_addr (dwflmod, address_size,
+                                          dab, dab);
              char *e = format_dwarf_addr (dwflmod, address_size,
-                                          base + end - 1, base + end);
+                                          dae - 1, dae);
              printf ("          %s..\n", b);
              printf ("          %s\n", e);
              free (b);
index 682fffcda3d739f8b827aa0ad5cee3a4873e7b04..2b255c7298d5ec28f3b536fc00d2b6891fc31fc2 100644 (file)
@@ -1,3 +1,8 @@
+2018-05-29  Mark Wielaard  <mark@klomp.org>
+
+       * run-readelf-loc.sh: Add GNU DebugFission split-dwarf variant.
+       * run-varlocs.sh: Likewise.
+
 2018-05-29  Mark Wielaard  <mark@klomp.org>
 
        * run-readelf-twofiles.sh: Add --debug-dump=loc testcase.
index 622cc1962896cdeb41fb35630c0139ba659644f9..484db4668f2b8c328bf16c795f5a830acebc3524 100755 (executable)
@@ -727,4 +727,145 @@ Table at Offset 0x0:
 
 EOF
 
+# GNU DebugFission split-dwarf variant. Still uses .debug_loc, but now in
+# .dwo file, with somewhat similar, but different encoding from DWARF5.
+testfiles testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=loc --dwarf-skeleton=testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo <<\EOF
+
+testfile-hello4.dwo:
+
+
+DWARF section [ 3] '.debug_loc.dwo' at offset 0x253:
+
+ CU [     b] base: 0x0000000000401160 <foo>
+ [     0] range 401160, 40116a
+          0x0000000000401160 <foo>..
+          0x0000000000401169 <foo+0x9>
+           [ 0] reg5
+          range 40116a, 401194
+          0x000000000040116a <foo+0xa>..
+          0x0000000000401193 <foo+0x33>
+           [ 0] GNU_entry_value:
+                [ 0] reg5
+           [ 3] stack_value
+ [    16] range 40117b, 40118d
+          0x000000000040117b <foo+0x1b>..
+          0x000000000040118c <foo+0x2c>
+           [ 0] GNU_addr_index [18] 0x404038 <m>
+ [    21] range 40117b, 401181
+          0x000000000040117b <foo+0x1b>..
+          0x0000000000401180 <foo+0x20>
+           [ 0] reg5
+ [    2b] range 40117b, 401187
+          0x000000000040117b <foo+0x1b>..
+          0x0000000000401186 <foo+0x26>
+           [ 0] reg5
+          range 401189, 40118d
+          0x0000000000401189 <foo+0x29>..
+          0x000000000040118c <foo+0x2c>
+           [ 0] reg5
+ [    3e] range 401181, 401187
+          0x0000000000401181 <foo+0x21>..
+          0x0000000000401186 <foo+0x26>
+           [ 0] reg5
+          range 401189, 40118d
+          0x0000000000401189 <foo+0x29>..
+          0x000000000040118c <foo+0x2c>
+           [ 0] reg5
+ [    51] range 401181, 40118d
+          0x0000000000401181 <foo+0x21>..
+          0x000000000040118c <foo+0x2c>
+           [ 0] reg5
+ [    5b] range 40118d, 401193
+          0x000000000040118d <foo+0x2d>..
+          0x0000000000401192 <foo+0x32>
+           [ 0] reg5
+ [    65] range 4011a0, 4011af
+          0x00000000004011a0 <baz>..
+          0x00000000004011ae <baz+0xe>
+           [ 0] reg5
+          range 4011af, 4011b1
+          0x00000000004011af <baz+0xf>..
+          0x00000000004011b0 <baz+0x10>
+           [ 0] GNU_entry_value:
+                [ 0] reg5
+           [ 3] stack_value
+ [    7b] range 4011a0, 4011b0
+          0x00000000004011a0 <baz>..
+          0x00000000004011af <baz+0xf>
+           [ 0] reg5
+
+testfile-world4.dwo:
+
+
+DWARF section [ 3] '.debug_loc.dwo' at offset 0x225:
+
+ CU [     b] base: 000000000000000000
+ [     0] range 401060, 401074
+          0x0000000000401060 <main>..
+          0x0000000000401073 <main+0x13>
+           [ 0] reg5
+          range 401074, 401080
+          0x0000000000401074 <main+0x14>..
+          0x000000000040107f <main+0x1f>
+           [ 0] GNU_entry_value:
+                [ 0] reg5
+           [ 3] stack_value
+ [    16] range 401060, 401078
+          0x0000000000401060 <main>..
+          0x0000000000401077 <main+0x17>
+           [ 0] reg4
+          range 401078, 40107e
+          0x0000000000401078 <main+0x18>..
+          0x000000000040107d <main+0x1d>
+           [ 0] GNU_entry_value:
+                [ 0] reg4
+           [ 3] stack_value
+ [    2c] range 401071, 401078
+          0x0000000000401071 <main+0x11>..
+          0x0000000000401077 <main+0x17>
+           [ 0] reg0
+ [    36] range 4011c0, 4011c8
+          0x00000000004011c0 <calc>..
+          0x00000000004011c7 <calc+0x7>
+           [ 0] reg5
+          range 4011c8, 4011eb
+          0x00000000004011c8 <calc+0x8>..
+          0x00000000004011ea <calc+0x2a>
+           [ 0] GNU_entry_value:
+                [ 0] reg5
+           [ 3] stack_value
+ [    4c] range 4011d8, 4011e3
+          0x00000000004011d8 <calc+0x18>..
+          0x00000000004011e2 <calc+0x22>
+           [ 0] reg0
+ [    56] range 4011d8, 4011da
+          0x00000000004011d8 <calc+0x18>..
+          0x00000000004011d9 <calc+0x19>
+           [ 0] reg1
+          range 4011da, 4011df
+          0x00000000004011da <calc+0x1a>..
+          0x00000000004011de <calc+0x1e>
+           [ 0] reg5
+          range 4011df, 4011e3
+          0x00000000004011df <calc+0x1f>..
+          0x00000000004011e2 <calc+0x22>
+           [ 0] GNU_entry_value:
+                [ 0] reg5
+           [ 3] deref_size 1
+           [ 5] const1u 56
+           [ 7] shl
+           [ 8] const1u 56
+           [10] shra
+           [11] stack_value
+ [    7d] range 4011d8, 4011da
+          0x00000000004011d8 <calc+0x18>..
+          0x00000000004011d9 <calc+0x19>
+           [ 0] reg1
+          range 4011da, 4011e3
+          0x00000000004011da <calc+0x1a>..
+          0x00000000004011e2 <calc+0x22>
+           [ 0] reg5
+EOF
+
 exit 0
index 8426d20db57606a32d6c2ef50aa57a4b96a707f6..e98d8e94b7358e680c8d2a68f2c20a6fae702b2d 100755 (executable)
@@ -277,6 +277,80 @@ module 'testfilesplitranges5.debug'
       [4011c0,4011d0) {reg4}
 EOF
 
+# GNU DebugFissuon Multi CU Split DWARF. See run-dwarf-ranges.sh.
+testfiles testfilesplitranges4.debug
+testfiles testfile-ranges-hello.dwo testfile-ranges-world.dwo
+testrun_compare ${abs_top_builddir}/tests/varlocs --debug -e testfilesplitranges4.debug <<\EOF
+module 'testfilesplitranges4.debug'
+[b] CU 'hello.c'
+  [18] function 'no_say'@4004f0
+    frame_base: {call_frame_cfa {...}}
+    [2f] parameter 'prefix'
+      [4004f0,4004fa) {reg5}
+      [4004fa,4004ff) {GNU_entry_value(1) {reg5}, stack_value}
+    [3b] variable 'world'
+      <no value>
+  [60] function 'main'@4003e0
+    frame_base: {call_frame_cfa {...}}
+    [77] parameter 'argc'
+      [4003e0,4003f2) {reg5}
+      [4003f2,4003f7) {GNU_entry_value(1) {reg5}, stack_value}
+    [83] parameter 'argv'
+      [4003e0,4003f6) {reg4}
+      [4003f6,1004003f5) {GNU_entry_value(1) {reg4}, stack_value}
+  [8f] inlined function 'subject'@4003e3
+    [a3] parameter 'count'
+      [4003e3,4003ef) {reg5}
+    [ac] parameter 'word'
+      [4003e3,4003ef) {reg0}
+  [e7] function 'subject'@4004e0
+    frame_base: {call_frame_cfa {...}}
+    [fb] parameter 'word'
+      [4004e0,4004f0) {reg5}
+    [102] parameter 'count'
+      [4004e0,4004f0) {reg4}
+module 'testfilesplitranges4.debug'
+[b] CU 'world.c'
+  [18] function 'no_main'@400550
+    frame_base: {call_frame_cfa {...}}
+    [2f] parameter 'argc'
+      [400550,400562) {reg5}
+      [400562,400567) {GNU_entry_value(1) {reg5}, stack_value}
+    [3b] parameter 'argv'
+      [400550,400566) {reg4}
+      [400566,100400565) {GNU_entry_value(1) {reg4}, stack_value}
+  [47] inlined function 'no_subject'@400553
+    [5b] parameter 'count'
+      [400553,40055f) {reg5}
+    [64] parameter 'word'
+      [400553,40055f) {reg0}
+  [af] function 'say'@400500
+    frame_base: {call_frame_cfa {...}}
+    [c9] parameter 'prefix'
+      [400500,40050e) {reg5}
+      [40050e,40051c) {reg3}
+      [40051c,400527) {GNU_entry_value(1) {reg5}, stack_value}
+      [400527,400535) {reg3}
+      [400535,400540) {GNU_entry_value(1) {reg5}, stack_value}
+    [d5] variable 'world'
+      [400513,40051b) {reg0}
+      [400527,400534) {reg0}
+  [e1] inlined function 'happy'@40051c
+    [f1] parameter 'w'
+      [400527,400534) {reg0}
+  [fa] inlined function 'sad'@40051c
+    [106] parameter 'c'
+      [40051b,400526) {reg0}
+      [400526,400527) {GNU_entry_value(1) {reg5}}
+      [400534,40053f) {reg0}
+  [15c] function 'no_subject'@400540
+    frame_base: {call_frame_cfa {...}}
+    [170] parameter 'word'
+      [400540,400550) {reg5}
+    [177] parameter 'count'
+      [400540,400550) {reg4}
+EOF
+
 # DW_OP_addrx and DW_OP_constx testcases.
 #
 # int i, j, k;