[PATCH] readelf, libdw: Add GNU DebugFission .debug_loc support.

Mark Wielaard mark@klomp.org
Tue May 29 10:08:00 GMT 2018


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          |   9 +++
 libdw/dwarf.h            |  10 ++++
 libdw/dwarf_ranges.c     |  65 +++++++++++++++++++++-
 src/ChangeLog            |   5 ++
 src/readelf.c            |  80 +++++++++++++++++++++++++--
 tests/ChangeLog          |   5 ++
 tests/run-readelf-loc.sh | 141 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/run-varlocs.sh     |  74 +++++++++++++++++++++++++
 8 files changed, 382 insertions(+), 7 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index d187930..eb0b01a 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -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
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index 8985a9d..dc59733 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -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
   {
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
index 0f3ee6b..f67d8a5 100644
--- a/libdw/dwarf_ranges.c
+++ b/libdw/dwarf_ranges.c
@@ -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);
diff --git a/src/ChangeLog b/src/ChangeLog
index e7ba6cb..f424fb7 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,10 @@
 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
 	implicit_debug_sections and print_debug_sections.
 
diff --git a/src/readelf.c b/src/readelf.c
index 390f244..2ccbea5 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -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);
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 682fffc..2b255c7 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,5 +1,10 @@
 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.
 
 2018-05-28  Mark Wielaard  <mark@klomp.org>
diff --git a/tests/run-readelf-loc.sh b/tests/run-readelf-loc.sh
index 622cc19..484db46 100755
--- a/tests/run-readelf-loc.sh
+++ b/tests/run-readelf-loc.sh
@@ -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
diff --git a/tests/run-varlocs.sh b/tests/run-varlocs.sh
index 8426d20..e98d8e9 100755
--- a/tests/run-varlocs.sh
+++ b/tests/run-varlocs.sh
@@ -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;
-- 
1.8.3.1



More information about the Elfutils-devel mailing list