diff options
author | Mark Wielaard <mark@klomp.org> | 2018-05-29 00:59:28 +0200 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2018-05-31 14:42:27 +0200 |
commit | b37feac1a8ceebb0748cb28d219aa8387d0885dd (patch) | |
tree | 33beb2c916d4bd0d94fcb94ceb5cdef0d809c9a5 /src | |
parent | c7fc54a27c0eac667f0060f277606df8208f05d7 (diff) | |
download | elfutils-b37feac1a8ceebb0748cb28d219aa8387d0885dd.tar.gz |
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 <mark@klomp.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/ChangeLog | 5 | ||||
-rw-r--r-- | src/readelf.c | 80 |
2 files changed, 79 insertions, 6 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index e7ba6cb1..f424fb7f 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 390f2444..2ccbea5b 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); |