From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25584 invoked by alias); 29 May 2018 10:08:23 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 25572 invoked by uid 89); 29 May 2018 10:08:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.4 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy= X-Spam-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 29 May 2018 10:08:20 +0000 Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id 9A52030008B8; Tue, 29 May 2018 12:08:17 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id 55C194110E22; Tue, 29 May 2018 12:08:17 +0200 (CEST) From: Mark Wielaard To: elfutils-devel@sourceware.org Cc: Mark Wielaard Subject: [PATCH] readelf, libdw: Add GNU DebugFission .debug_loc support. Date: Tue, 29 May 2018 10:08:00 -0000 Message-Id: <1527588496-16063-1-git-send-email-mark@klomp.org> X-Mailer: git-send-email 1.8.3.1 X-Spam-Flag: NO X-IsSubscribed: yes X-SW-Source: 2018-q2/txt/msg00098.txt.bz2 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 --- 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 + + * 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 * 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 + * readelf.c (print_debug_loc_section): Handle GNU DebugFission list + entries. + +2018-05-29 Mark Wielaard + * 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] \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 + * run-readelf-loc.sh: Add GNU DebugFission split-dwarf variant. + * run-varlocs.sh: Likewise. + +2018-05-29 Mark Wielaard + * run-readelf-twofiles.sh: Add --debug-dump=loc testcase. 2018-05-28 Mark Wielaard 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 + [ 0] range 401160, 40116a + 0x0000000000401160 .. + 0x0000000000401169 + [ 0] reg5 + range 40116a, 401194 + 0x000000000040116a .. + 0x0000000000401193 + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 16] range 40117b, 40118d + 0x000000000040117b .. + 0x000000000040118c + [ 0] GNU_addr_index [18] 0x404038 + [ 21] range 40117b, 401181 + 0x000000000040117b .. + 0x0000000000401180 + [ 0] reg5 + [ 2b] range 40117b, 401187 + 0x000000000040117b .. + 0x0000000000401186 + [ 0] reg5 + range 401189, 40118d + 0x0000000000401189 .. + 0x000000000040118c + [ 0] reg5 + [ 3e] range 401181, 401187 + 0x0000000000401181 .. + 0x0000000000401186 + [ 0] reg5 + range 401189, 40118d + 0x0000000000401189 .. + 0x000000000040118c + [ 0] reg5 + [ 51] range 401181, 40118d + 0x0000000000401181 .. + 0x000000000040118c + [ 0] reg5 + [ 5b] range 40118d, 401193 + 0x000000000040118d .. + 0x0000000000401192 + [ 0] reg5 + [ 65] range 4011a0, 4011af + 0x00000000004011a0 .. + 0x00000000004011ae + [ 0] reg5 + range 4011af, 4011b1 + 0x00000000004011af .. + 0x00000000004011b0 + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 7b] range 4011a0, 4011b0 + 0x00000000004011a0 .. + 0x00000000004011af + [ 0] reg5 + +testfile-world4.dwo: + + +DWARF section [ 3] '.debug_loc.dwo' at offset 0x225: + + CU [ b] base: 000000000000000000 + [ 0] range 401060, 401074 + 0x0000000000401060
.. + 0x0000000000401073 + [ 0] reg5 + range 401074, 401080 + 0x0000000000401074 .. + 0x000000000040107f + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 16] range 401060, 401078 + 0x0000000000401060
.. + 0x0000000000401077 + [ 0] reg4 + range 401078, 40107e + 0x0000000000401078 .. + 0x000000000040107d + [ 0] GNU_entry_value: + [ 0] reg4 + [ 3] stack_value + [ 2c] range 401071, 401078 + 0x0000000000401071 .. + 0x0000000000401077 + [ 0] reg0 + [ 36] range 4011c0, 4011c8 + 0x00000000004011c0 .. + 0x00000000004011c7 + [ 0] reg5 + range 4011c8, 4011eb + 0x00000000004011c8 .. + 0x00000000004011ea + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 4c] range 4011d8, 4011e3 + 0x00000000004011d8 .. + 0x00000000004011e2 + [ 0] reg0 + [ 56] range 4011d8, 4011da + 0x00000000004011d8 .. + 0x00000000004011d9 + [ 0] reg1 + range 4011da, 4011df + 0x00000000004011da .. + 0x00000000004011de + [ 0] reg5 + range 4011df, 4011e3 + 0x00000000004011df .. + 0x00000000004011e2 + [ 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 .. + 0x00000000004011d9 + [ 0] reg1 + range 4011da, 4011e3 + 0x00000000004011da .. + 0x00000000004011e2 + [ 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' + + [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