[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