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/dwarf2 | |
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/dwarf2')
-rw-r--r-- | gdb/dwarf2/line-header.c | 15 | ||||
-rw-r--r-- | gdb/dwarf2/read.c | 12 | ||||
-rw-r--r-- | gdb/dwarf2/read.h | 5 |
3 files changed, 26 insertions, 6 deletions
diff --git a/gdb/dwarf2/line-header.c b/gdb/dwarf2/line-header.c index 1519576..852e285 100644 --- a/gdb/dwarf2/line-header.c +++ b/gdb/dwarf2/line-header.c @@ -137,7 +137,7 @@ read_checked_initial_length_and_offset (bfd *abfd, const gdb_byte *buf, static void read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd, const gdb_byte **bufp, struct line_header *lh, - const struct comp_unit_head *cu_header, + unsigned int offset_size, void (*callback) (struct line_header *lh, const char *name, dir_index d_index, @@ -187,9 +187,12 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd, break; case DW_FORM_line_strp: - string.emplace - (per_objfile->read_line_string (buf, cu_header, &bytes_read)); - buf += bytes_read; + { + const char *str + = per_objfile->read_line_string (buf, offset_size); + string.emplace (str); + buf += offset_size; + } break; case DW_FORM_data1: @@ -372,7 +375,7 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz, { /* Read directory table. */ read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (), - cu_header, + offset_size, [] (struct line_header *header, const char *name, dir_index d_index, unsigned int mod_time, unsigned int length) @@ -382,7 +385,7 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz, /* Read file name table. */ read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (), - cu_header, + offset_size, [] (struct line_header *header, const char *name, dir_index d_index, unsigned int mod_time, unsigned int length) diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 4a963e4..a513cc4 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -20306,6 +20306,18 @@ read_indirect_string (dwarf2_per_objfile *per_objfile, bfd *abfd, const char * dwarf2_per_objfile::read_line_string (const gdb_byte *buf, + unsigned int offset_size) +{ + bfd *abfd = objfile->obfd; + ULONGEST str_offset = read_offset (abfd, buf, offset_size); + + return per_bfd->line_str.read_string (objfile, str_offset, "DW_FORM_line_strp"); +} + +/* See read.h. */ + +const char * +dwarf2_per_objfile::read_line_string (const gdb_byte *buf, const struct comp_unit_head *cu_header, unsigned int *bytes_read_ptr) { diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 1638d85..fe34e3f 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -517,6 +517,11 @@ struct dwarf2_per_objfile const struct comp_unit_head *cu_header, unsigned int *bytes_read_ptr); + /* Return pointer to string at .debug_line_str offset as read from BUF. + The offset_size is OFFSET_SIZE. */ + const char *read_line_string (const gdb_byte *buf, + unsigned int offset_size); + /* Return true if the symtab corresponding to PER_CU has been set, false otherwise. */ bool symtab_set_p (const dwarf2_per_cu_data *per_cu) const; |