diff options
author | Tom de Vries <tdevries@suse.de> | 2021-11-22 09:14:16 +0100 |
---|---|---|
committer | Tom de Vries <tdevries@suse.de> | 2021-11-22 09:14:16 +0100 |
commit | bab31d145160cd4dec7b9ad0e79346382ebf8385 (patch) | |
tree | 85261ec6bfe218eb40d187efe56da0d409e05ea9 /gdb/testsuite/lib/dwarf.exp | |
parent | 26bf28e29d7b3bddc6d2f8f34f07000f2b858588 (diff) | |
download | gdb-bab31d145160cd4dec7b9ad0e79346382ebf8385.zip gdb-bab31d145160cd4dec7b9ad0e79346382ebf8385.tar.gz gdb-bab31d145160cd4dec7b9ad0e79346382ebf8385.tar.bz2 |
[gdb/symtab] Support .debug_line with DW_FORM_line_strp
I noticed a new gcc option -gdwarf64 and tried it out (using gcc 11.2.1).
With a test-case hello.c:
...
int
main (void)
{
printf ("hello\n");
return 0;
}
...
compiled like this:
...
$ gcc -g -gdwarf64 ~/hello.c
...
I ran into:
...
$ gdb -q -batch a.out
DW_FORM_line_strp pointing outside of .debug_line_str section \
[in module a.out]
...
Debugging gdb revealed that the string offset is:
...
(gdb) up
objfile=0x182ab70, str_offset=1378684502312,
form_name=0xeae9b5 "DW_FORM_line_strp")
at src/gdb/dwarf2/section.c:208
208 error (_("%s pointing outside of %s section [in module %s]"),
(gdb) p /x str_offset
$1 = 0x14100000128
(gdb)
...
which is read when parsing a .debug_line entry at 0x1e0.
Looking with readelf at the 0x1e0 entry, we have:
...
The Directory Table (offset 0x202, lines 2, columns 1):
Entry Name
0 (indirect line string, offset: 0x128): /data/gdb_versions/devel
1 (indirect line string, offset: 0x141): /home/vries
...
which in a hexdump looks like:
...
0x00000200 1f022801 00004101 00000201 1f020f02
...
What happens is the following:
- readelf interprets the DW_FORM_line_strp reference to .debug_line_str as
a 4 byte value, and sees entries 0x00000128 and 0x00000141.
- gdb instead interprets it as an 8 byte value, and sees as first entry
0x0000014100000128, which is too big so it bails out.
AFAIU, gdb is wrong. It assumes DW_FORM_line_strp is 8 bytes on the basis
that the corresponding CU is 64-bit DWARF. However, the .debug_line
contribution has it's own initial_length field, and encodes there that it's
32-bit DWARF.
Fix this by using the correct offset size for DW_FORM_line_strp references
in .debug_line.
Note: the described test-case does trigger this complaint (both with and
without this patch):
...
$ gdb -q -batch -iex "set complaints 10" a.out
During symbol reading: intermixed 32-bit and 64-bit DWARF sections
...
The reason that the CU has 64-bit dwarf is because -gdwarf64 was passed to
gcc. The reason that the .debug_line entry has 32-bit dwarf is because that's
what gas generates. Perhaps this is complaint-worthy, but I don't think it
is wrong.
Tested on x86_64-linux, using native and target board dwarf64.exp.
Diffstat (limited to 'gdb/testsuite/lib/dwarf.exp')
-rw-r--r-- | gdb/testsuite/lib/dwarf.exp | 75 |
1 files changed, 65 insertions, 10 deletions
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index b2a3372..cbb1bf6 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -2185,9 +2185,11 @@ namespace eval Dwarf { variable _line_saw_program variable _line_header_end_label variable _line_unit_version + variable _line_is_64 + variable _line_string_form # Establish the defaults. - set is_64 0 + set _line_is_64 0 set _line_unit_version 4 set _unit_addr_size default set _line_saw_program 0 @@ -2197,14 +2199,17 @@ namespace eval Dwarf { set _line_header_finalized 0 set _default_is_stmt 1 set _seg_sel_size 0 + #set _line_string_form string + set _line_string_form line_strp foreach { name value } $options { switch -exact -- $name { - is_64 { set is_64 $value } + is_64 { set _line_is_64 $value } version { set _line_unit_version $value } addr_size { set _unit_addr_size $value } seg_sel_size { set _seg_sel_size $value } default_is_stmt { set _default_is_stmt $value } + string_form { set $_line_string_form $value } default { error "unknown option $name" } } } @@ -2231,7 +2236,7 @@ namespace eval Dwarf { set header_len_label [_compute_label "line${_line_count}_header_start"] set _line_header_end_label [_compute_label "line${_line_count}_header_end"] - if {$is_64} { + if {$_line_is_64} { _op .4byte 0xffffffff _op .8byte "$unit_end_label - $unit_len_label" "unit_length" } else { @@ -2248,7 +2253,7 @@ namespace eval Dwarf { _op .byte $_seg_sel_size "seg_sel_size" } - if {$is_64} { + if {$_line_is_64} { _op .8byte "$_line_header_end_label - $header_len_label" "header_length" } else { _op .4byte "$_line_header_end_label - $header_len_label" "header_length" @@ -2306,12 +2311,22 @@ namespace eval Dwarf { variable _line_file_names variable _line_unit_version + variable _line_is_64 + variable _line_string_form if { $_line_unit_version >= 5 } { _op .byte 1 "directory_entry_format_count" _op .uleb128 1 \ "directory_entry_format (content type code: DW_LNCT_path)" - _op .uleb128 0x08 \ - "directory_entry_format (form: DW_FORM_string)" + switch $_line_string_form { + string { + _op .uleb128 0x08 \ + "directory_entry_format (form: DW_FORM_string)" + } + line_strp { + _op .uleb128 0x1f \ + "directory_entry_format (form: DW_FORM_line_strp)" + } + } set nr_dirs [llength $_line_include_dirs] # For entry 0. @@ -2324,14 +2339,38 @@ namespace eval Dwarf { [concat [list $dirname] $_line_include_dirs] foreach dirname $_line_include_dirs { - _op .ascii [_quote $dirname] + switch $_line_string_form { + string { + _op .ascii [_quote $dirname] + } + line_strp { + declare_labels string_ptr + _defer_output .debug_line_str { + string_ptr: + _op .ascii [_quote $dirname] + } + if { $_line_is_64 } { + _op .8byte $string_ptr + } else { + _op .4byte $string_ptr + } + } + } } _op .byte 2 "file_name_entry_format_count" _op .uleb128 1 \ "file_name_entry_format (content type code: DW_LNCT_path)" - _op .uleb128 0x08 \ - "file_name_entry_format (form: DW_FORM_string)" + switch $_line_string_form { + string { + _op .uleb128 0x08 \ + "directory_entry_format (form: DW_FORM_string)" + } + line_strp { + _op .uleb128 0x1f \ + "directory_entry_format (form: DW_FORM_line_strp)" + } + } _op .uleb128 2 \ "file_name_entry_format (content type code: DW_LNCT_directory_index)" _op .uleb128 0x0f \ @@ -2349,7 +2388,23 @@ namespace eval Dwarf { [concat [list $filename $diridx] $_line_file_names] foreach { filename diridx } $_line_file_names { - _op .ascii [_quote $filename] + switch $_line_string_form { + string { + _op .ascii [_quote $filename] + } + line_strp { + declare_labels string_ptr + _defer_output .debug_line_str { + string_ptr: + _op .ascii [_quote $filename] + } + if { $_line_is_64 } { + _op .8byte $string_ptr + } else { + _op .4byte $string_ptr + } + } + } _op .uleb128 $diridx } } else { |