Skip to content

Commit

Permalink
readelf, libdw: Add GNU DebugFission .debug_loc support.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Mark Wielaard committed May 31, 2018
1 parent c7fc54a commit b37feac
Show file tree
Hide file tree
Showing 8 changed files with 382 additions and 7 deletions.
9 changes: 9 additions & 0 deletions libdw/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
2018-05-29 Mark Wielaard <[email protected]>

* 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 <[email protected]>

* libdw_find_split_unit.c (__libdw_find_split_unit): End split_dwarf
Expand Down
10 changes: 10 additions & 0 deletions libdw/dwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
65 changes: 64 additions & 1 deletion libdw/dwarf_ranges.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2018-05-29 Mark Wielaard <[email protected]>

* readelf.c (print_debug_loc_section): Handle GNU DebugFission list
entries.

2018-05-29 Mark Wielaard <[email protected]>

* readelf.c (print_debug): Record and reset section_info status in
Expand Down
80 changes: 74 additions & 6 deletions src/readelf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions tests/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2018-05-29 Mark Wielaard <[email protected]>

* run-readelf-loc.sh: Add GNU DebugFission split-dwarf variant.
* run-varlocs.sh: Likewise.

2018-05-29 Mark Wielaard <[email protected]>

* run-readelf-twofiles.sh: Add --debug-dump=loc testcase.
Expand Down
141 changes: 141 additions & 0 deletions tests/run-readelf-loc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit b37feac

Please sign in to comment.