[binutils/readelf] Fix printing of dwarf5 .debug_info.dwo
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Testing passed
|
Commit Message
When compiling a hello world like this:
...
$ gcc ~/data/hello.c -gsplit-dwarf -gdwarf-5
...
we get with readelf -w a-hello.dwo for the split full compilation unit entry
incorrect strings, for instance an incorrect producer string:
...
<15> DW_AT_producer : (indexed string: 0xb): /home/vries/data/hello.c
...
The problem is that a str_offsets_base of 0 is used, so the header of the
.debug_str_offsets section of size 8 is treated as two offsets, and the index
0xb is mapped to entry 9 instead of 11:
...
9 0000006c /home/vries/data/hello.c
...
11 00000097 GNU C17 15.0.0 -gsplit-dwarf -gdwarf-5
...
The DW_AT_str_offsets_base attribute is inherited from the corresponding
skeleton compilation unit in a.out, but:
- that's outside the scope of the .dwo file, and
- it's also not there (though it is there when using clang instead).
Fix this by assuming a sane default for str_offsets_base for dwarf5: the size
of the header of the .debug_str_offsets section, which is 8 for 32-bit dwarf
and 16 for 64-bit dwarf.
Implement this by moving the reading of DW_AT_str_offsets_base to read_bases,
which also fixes the printing of DW_FORM_strx strings in the skeleton
compilation unit entries for attributes before the DW_AT_str_offsets_base
attribute.
Conforming with the other code in read_bases, we only handle
DW_FORM_sec_offset, which means the code dealing with negative
str_offsets_base can be dropped.
Tested on x86_64-linux.
---
binutils/dwarf.c | 38 ++++++++++++-------
.../binutils-all/readelf-str-offsets-base.d | 17 +++++++++
.../binutils-all/readelf-str-offsets-base.s | 30 +++++++++++++++
binutils/testsuite/binutils-all/readelf.exp | 1 +
4 files changed, 72 insertions(+), 14 deletions(-)
create mode 100644 binutils/testsuite/binutils-all/readelf-str-offsets-base.d
create mode 100644 binutils/testsuite/binutils-all/readelf-str-offsets-base.s
base-commit: 84f7f8940760d0eaeb51a38b345db369b4207e5b
Comments
Hi Tom,
> Fix this by assuming a sane default for str_offsets_base for dwarf5: the size
> of the header of the .debug_str_offsets section, which is 8 for 32-bit dwarf
> and 16 for 64-bit dwarf.
>
> Implement this by moving the reading of DW_AT_str_offsets_base to read_bases,
> which also fixes the printing of DW_FORM_strx strings in the skeleton
> compilation unit entries for attributes before the DW_AT_str_offsets_base
> attribute.
>
> Conforming with the other code in read_bases, we only handle
> DW_FORM_sec_offset, which means the code dealing with negative
> str_offsets_base can be dropped.
>
> Tested on x86_64-linux.
The patch itself looks fine, but the new test fails for some targets, such as:
alpha-linux-gnu
mipsisa64r6-elf
nios2-elf
The failure message looks like this:
output: readelf: Warning: DIE at offset 0x14 refers to abbreviation number 15349 which does not exist
Also the sh-elf target fails but for a different reason:
readelf-str-offsets-base.s: Assembler messages:
readelf-str-offsets-base.s:17: Error: misaligned data
Would you mind taking a look at these please ?
It is OK to skip the test for a particular architecture if there
is a good reason for it. But if you do decide to do that, please
add the reason into the test driver file as a comment.
Cheers
Nick
On 5/30/24 13:03, Nick Clifton wrote:
> Hi Tom,
>
>> Fix this by assuming a sane default for str_offsets_base for dwarf5:
>> the size
>> of the header of the .debug_str_offsets section, which is 8 for 32-bit
>> dwarf
>> and 16 for 64-bit dwarf.
>>
>> Implement this by moving the reading of DW_AT_str_offsets_base to
>> read_bases,
>> which also fixes the printing of DW_FORM_strx strings in the skeleton
>> compilation unit entries for attributes before the DW_AT_str_offsets_base
>> attribute.
>>
>> Conforming with the other code in read_bases, we only handle
>> DW_FORM_sec_offset, which means the code dealing with negative
>> str_offsets_base can be dropped.
>>
>> Tested on x86_64-linux.
>
> The patch itself looks fine, but the new test fails for some targets,
> such as:
>
> alpha-linux-gnu
> mipsisa64r6-elf
> nios2-elf
>
> The failure message looks like this:
>
> output: readelf: Warning: DIE at offset 0x14 refers to abbreviation
> number 15349 which does not exist
>
> Also the sh-elf target fails but for a different reason:
>
> readelf-str-offsets-base.s: Assembler messages:
> readelf-str-offsets-base.s:17: Error: misaligned data
>
> Would you mind taking a look at these please ?
>
> It is OK to skip the test for a particular architecture if there
> is a good reason for it. But if you do decide to do that, please
> add the reason into the test driver file as a comment.
>
Hi Nick,
thanks for the review.
These failures where caused by using directives that were not a fixed
amount of bytes. Fixed in a v2 submitted here (
https://sourceware.org/pipermail/binutils/2024-May/134421.html ).
Thanks,
- Tom
> Cheers
> Nick
>
>
@@ -2874,20 +2874,7 @@ read_and_display_attr_value (unsigned long attribute,
break;
case DW_AT_str_offsets_base:
- if (debug_info_p->str_offsets_base)
- warn (_("CU @ %#" PRIx64 " has multiple str_offsets_base values "
- "%#" PRIx64 " and %#" PRIx64 ")\n"),
- debug_info_p->cu_offset,
- debug_info_p->str_offsets_base, uvalue);
- svalue = uvalue;
- if (svalue < 0)
- {
- warn (_("CU @ %#" PRIx64 " has has a negative stroffsets_base "
- "value of %#" PRIx64 " - treating as zero\n"),
- debug_info_p->cu_offset, svalue);
- uvalue = 0;
- }
- debug_info_p->str_offsets_base = uvalue;
+ /* Assignment to debug_info_p->str_offsets_base is now elsewhere. */
break;
case DW_AT_frame_base:
@@ -3685,6 +3672,8 @@ read_bases (abbrev_entry * entry,
{
abbrev_attr *attr;
+ uint64_t initial_str_offsets_base = debug_info_p->str_offsets_base;
+
for (attr = entry->first_attr;
attr && attr->attribute;
attr = attr->next)
@@ -3711,10 +3700,31 @@ read_bases (abbrev_entry * entry,
else
warn (_("Unexpected form of DW_AT_addr_base in the top DIE\n"));
}
+ if (attr->attribute == DW_AT_str_offsets_base)
+ {
+ if (attr->form == DW_FORM_sec_offset)
+ {
+ SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+ if (initial_str_offsets_base == 0 && debug_info_p->str_offsets_base != 0)
+ warn (_("CU @ %#" PRIx64 " has multiple str_offsets_base values "
+ "%#" PRIx64 " and %#" PRIx64 ")\n"),
+ debug_info_p->cu_offset,
+ debug_info_p->str_offsets_base, uvalue);
+ debug_info_p->str_offsets_base = uvalue;
+ }
+ else
+ warn (_("Unexpected form of DW_AT_str_offsets_base in the top DIE\n"));
+ }
else
data = skip_attribute (attr->form, data, end, pointer_size,
offset_size, dwarf_version);
}
+
+ /* Provide a sane default for str_offsets_base: the size of the header of
+ the .debug_str_offsets section. */
+ if (dwarf_version >= 5 && initial_str_offsets_base == 0
+ && debug_info_p->str_offsets_base == 0)
+ debug_info_p->str_offsets_base = offset_size == 4 ? 8 : 16;
}
/* Process the contents of a .debug_info section.
new file mode 100644
@@ -0,0 +1,17 @@
+#name: readelf -wi readelf-str-offsets-base
+#source: readelf-str-offsets-base.s
+#readelf: -wi
+
+Contents of the .debug_info.dwo section:
+
+ Compilation Unit @ offset 0:
+ Length: 0x13 \(32-bit\)
+ Version: 5
+ Unit Type: DW_UT_split_compile \(5\)
+ Abbrev Offset: 0
+ Pointer Size: 8
+ DWO ID: 0xba7e77f573c097b6
+ <0><14>: Abbrev Number: 1 \(DW_TAG_compile_unit\)
+ <15> DW_AT_producer : \(indexed string: 0\): FIRST
+ <1><16>: Abbrev Number: 0
+
new file mode 100644
@@ -0,0 +1,30 @@
+ .section .debug_str.dwo,"MS",%progbits,1
+ .asciz "FIRST"
+ .asciz "SECOND"
+ .section .debug_str_offsets.dwo,"MS",%progbits,1
+ .long 16
+ .short 5
+ .short 0
+ .4byte 0
+ .4byte 6
+ .section .debug_info.dwo,"e",%progbits
+ .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 /* Length of Unit */
+.Ldebug_info_dwo_start0:
+ .2byte 0x5 /* DWARF macro version number. */
+ .byte 5 /* DWARF Unit Type */
+ .byte 8 /* Address Size (in bytes) */
+ .long 0 /* Offset Into Abbrev. Section */
+ .quad -5008433839496718410 /* DWO ID */
+ .byte 1 /* Abbrev [1] 0x14:0x1a DW_TAG_compile_unit */
+ .byte 0 /* DW_AT_producer */
+ .byte 0 /* End Of Children Mark */
+.Ldebug_info_dwo_end0:
+ .section .debug_abbrev.dwo,"e",%progbits
+ .byte 1 /* Abbreviation Code */
+ .byte 17 /* DW_TAG_compile_unit */
+ .byte 1 /* DW_CHILDREN_yes */
+ .byte 37 /* DW_AT_producer */
+ .byte 37 /* DW_FORM_strx1 */
+ .byte 0 /* EOM(1) */
+ .byte 0 /* EOM(2) */
+ .byte 0 /* EOM(3) */
@@ -403,6 +403,7 @@ if {[which $AS] != 0} then {
run_dump_test "readelf-maskos-1a"
run_dump_test "readelf-maskos-1b"
run_dump_test "readelf-debug-str-offsets-dw4"
+ run_dump_test "readelf-str-offsets-base"
if {![istarget *-*-hpux*]} then {
run_dump_test pr26548
if {![binutils_assemble_flags $srcdir/$subdir/pr26548.s tmpdir/pr26548e.o {--defsym ERROR=1}]} then {