[gdb/symtab] Fix parsing of .debug_str_offsets header
When running test-case gdb.dwarf2/fission-mix.exp with target board dwarf64
and gcc-12 (defaulting to DWARF5), I run into:
...
(gdb) break func2^M
Offset from DW_FORM_GNU_str_index or DW_FORM_strx pointing outside of \
.debug_str.dwo section in CU at offset 0x0 [in module fission-mix]^M
(gdb) FAIL: gdb.dwarf2/fission-mix.exp: break func2
...
The .debug_str_offsets section has version 5, so as per the standard it has
it's own header, with initial length and version:
...
Contents of the .debug_str_offsets.dwo section (loaded from fission-mix2.dwo):
Length: 0x1c
Version: 0x5
Index Offset [String]
0 0 build/gdb/testsuite
1 33 GNU C17
2 8f src/gdb/testsuite/gdb.dwarf2/fission-mix-2.c
...
But when trying to read the string offset at index 0 in the table (which
is 0), we start reading at offset 8, which points in the header, at the last
4 bytes of the initial length (it's 12 bytes because of 64-bit dwarf), as well
at the 2-byte version field and 2 bytes of padding, so we get:
...
(gdb) p /x str_offset
$1 = 0x500000000
...
which indeed is an offset that doesn't fit in the .debug_str section.
The offset 8 is based on reader->cu->header.addr_size:
...
static const char *
read_dwo_str_index (const struct die_reader_specs *reader, ULONGEST str_index)
{
ULONGEST str_offsets_base = reader->cu->header.version >= 5
? reader->cu->header.addr_size : 0;
...
which doesn't in look in agreement with the standard.
Note that this happens to give the right answer for 32-bit dwarf and
addr_size == 8, because then we have header size ==
(initial length (4) + version (2) + padding (2)) == 8.
Conversely, for 32-bit dwarf and addr_size == 4 (target board unix/-m32)
we run into a similar problem. It just happens to not trigger the warning,
instead we get the wrong strings, like "func2" for DW_AT_producer and
"build/gdb/testsuite" for DW_AT_name of the DW_TAG_compile_unit DIE.
Fix this by parsing the .debug_str_offsets header in read_dwo_str_index.
Add a FIXME that we should not parse this for every call.
Tested on x86_64-linux.