From b37feac1a8ceebb0748cb28d219aa8387d0885dd Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 29 May 2018 00:59:28 +0200 Subject: readelf, libdw: Add GNU DebugFission .debug_loc support. 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 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) (limited to 'libdw') diff --git a/libdw/ChangeLog b/libdw/ChangeLog index d1879308..eb0b01ad 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 8985a9d4..dc597335 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 0f3ee6b5..f67d8a5a 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); -- cgit v1.2.3