[gdb/symtab] Work around a gcc PR fixed in gcc 9

Message ID 20250410074756.32539-1-tdevries@suse.de
State New
Headers
Series [gdb/symtab] Work around a gcc PR fixed in gcc 9 |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed

Commit Message

Tom de Vries April 10, 2025, 7:47 a.m. UTC
  When running test-case gdb.base/bg-execution-repeat.exp with target board
dwarf5-fission-debug-types, I get:
...
(gdb) break -qualified main^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 bg-execution-repeat]^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 bg-execution-repeat]^M
(gdb) FAIL: $exp: c&: gdb_breakpoint: set breakpoint at main
...

This happens with gcc 7 and 8, but not with gcc 9 and later.

We're using dwarf5, so the .debug_str_offsets section is supposed to have a
header, but there's none:
...
        .section        .debug_str_offsets.dwo,"e",@progbits
        .long   0       # indexed string 0x0: do_wait
        .long   0x8     # indexed string 0x1: unsigned int
        .long   0x15    # indexed string 0x2: wait
...

In other words, we have a v4-style .debug_str_offsets section.

Workaround this by detecting that it's not a valid v5 header by comparing the
initial length to the the section size, and handling it as a v4 section.

IWBN to enable this workaround only for gcc version < 9, but unfortunately the
workaround is required to correctly read the producer string, so that's not
possible.

Tested on x86_64-linux.

PR symtab/32861
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32861
---
 gdb/dwarf2/read.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)


base-commit: 6fe4e5bd10b996428a557e036c07c5839a8e0a49
  

Patch

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 6e96afe65e1..bacce6573c2 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -15361,18 +15361,33 @@  cutu_reader::read_dwo_str_index (ULONGEST str_index)
 {
   unsigned offset_size;
   ULONGEST str_offsets_base;
+
+  unsigned int bytes_read = 0;
+  bfd *abfd = m_dwo_file->sections.str_offsets.get_bfd_owner ();
+  const gdb_byte *p = m_dwo_file->sections.str_offsets.buffer;
+
+  bool valid_header = false;
   if (m_cu->header.version >= 5)
     {
       /* We have a DWARF5 CU with a reference to a .debug_str_offsets section,
 	 so assume the .debug_str_offsets section is DWARF5 as well, and
 	 parse the header.  FIXME: Parse the header only once.  */
-      unsigned int bytes_read = 0;
-      bfd *abfd = m_dwo_file->sections.str_offsets.get_bfd_owner ();
-      const gdb_byte *p = m_dwo_file->sections.str_offsets.buffer;
 
       /* Header: Initial length.  */
-      read_initial_length (abfd, p + bytes_read, &bytes_read);
+      LONGEST initial_length
+	= read_initial_length (abfd, p + bytes_read, &bytes_read);
 
+      /* GCC 8 and earlier have a bug that for dwarf5 it produces a
+	 pre-dwarf5 .debug_str_offsets section.  We'd wish we could make
+	 this work-around more precise by checking that producer is gcc and
+	 gcc version <= 8, but that doesn't work if we need this workaround
+	 to read the producer string.  */
+      valid_header
+	= initial_length + bytes_read == m_dwo_file->sections.str_offsets.size;
+    }
+
+  if (m_cu->header.version >= 5 && valid_header)
+    {
       /* Determine offset_size based on the .debug_str_offsets header.  */
       const bool dwarf5_is_dwarf64 = bytes_read != 4;
       offset_size = dwarf5_is_dwarf64 ? 8 : 4;