Bug 31725 - [gdb/symtab] wrong .debug_str section used in dwarf_decode_macro_bytes
Summary: [gdb/symtab] wrong .debug_str section used in dwarf_decode_macro_bytes
Status: NEW
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: 14.1
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-05-10 13:40 UTC by Tom de Vries
Modified: 2024-05-22 06:12 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2024-05-10 13:40:44 UTC
Consider a hello world, compiled as the fission board does, with -g3 added:
...
$ gcc -gdwarf-4 -gsplit-dwarf -ggnu-pubnames -fdebug-types-section -Wl,--gdb-index -fuse-ld=gold ~/gdb/hello.c -g3
...

When loading the exec in gdb, we get:
...
$ gdb -q a.out
Reading symbols from a.out...
DW_FORM_strp pointing outside of .debug_str section [in module /home/vries/binutils/a.out]
(gdb) 
...

Debugging this shows that this is triggered from:
...
207       if (str_offset >= size)
208         error (_("%s pointing outside of %s section [in module %s]"),
209                form_name, get_name (), get_file_name ());
...
with:
...
(gdb) p size
$3 = 33
(gdb) p str_offset
$4 = 553845450
...

Clearly there's something going wrong with the str_offset, that's way too big.

But the size of 33 is very small.  It's correct though, it's the size of the .debug_str section in a.out.

Going up to dwarf_decode_macro_bytes, we see this is the reason we're using that .debug_str section:
...
533                       body = per_objfile->per_bfd->str.read_string (objfile,         
...

However, there's a str_section argument that points to the .debug_str section in a-hello.dwo:
...
gdb) p *str_section
$6 = {s = {section = 0xaaaaabc1a718, containing_section = 0xaaaaabc1a718}, 
  buffer = 0xaaaaabc1b5b0 "__LDBL_DECIMAL_DIG__ 36", size = 24351, virtual_offset = 0, 
  readin = true, is_virtual = false}
...

I wonder if we shouldn't be using that one.
Comment 1 Tom de Vries 2024-05-10 13:46:23 UTC
Using:
...
diff --git a/gdb/dwarf2/macro.c b/gdb/dwarf2/macro.c
index a511d0a3b44..7ecaf8044b9 100644
--- a/gdb/dwarf2/macro.c
+++ b/gdb/dwarf2/macro.c
@@ -529,9 +529,8 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
                    body = dwz->read_string (objfile, str_offset);
                  }
                else
-                 body = per_objfile->per_bfd->str.read_string (objfile,
-                                                               str_offset,
-                                                               "DW_FORM_strp");
+                 body = str_section->read_string (objfile, str_offset,
+                                                  "DW_FORM_strp");
              }
 
            is_define = (macinfo_type == DW_MACRO_define
...
I get instead:
...
$ gdb -q -batch a.out -ex "p main"
DW_FORM_strp pointing outside of .debug_str.dwo section [in module /home/vries/gdb/a-hello.dwo]
...
Comment 2 Tom de Vries 2024-05-10 14:36:36 UTC
When compiling the test-case with gcc 14 instead of 13 the error disappears.

But that's due to a complaint, which is silently ignored by default:
...
$ gdb -q -batch -iex "set complaints 1000" a.out -ex "p main"
During symbol reading: unrecognized DW_MACINFO or DW_MACRO opcode 0xcc
$1 = {int (void)} 0x4006ac <main>
...
and aborts reading of .debug_macros before reaching the second pass in dwarf_decode_macros.
Comment 3 Tom de Vries 2024-05-13 10:32:45 UTC
I found a bug in gcc dwarf generation ( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115066 ), and the tentative fix makes this problem unlikely to hit.

Nevertheless, using the fixed dwarf, we run into a bug in gdb, observable, by enabling complaints.

Fixed by:
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 049ee4d52ff..e2cfa46516b 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -21200,7 +21200,10 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset,
       str_offsets_section = &cu->dwo_unit->dwo_file
 			       ->sections.str_offsets;
       str_section = &cu->dwo_unit->dwo_file->sections.str;
-      str_offsets_base = cu->header.addr_size;
+      if (cu->per_cu->version () <= 4)
+	str_offsets_base = 0;
+      else
+	str_offsets_base = cu->header.addr_size;
     }
   else
     {
...

FWIW, the "str_offsets_base = cu->header.addr_size" makes no sense to me atm.
Comment 4 Tom de Vries 2024-05-13 11:58:14 UTC
(In reply to Tom de Vries from comment #3)
> FWIW, the "str_offsets_base = cu->header.addr_size" makes no sense to me atm.

Yeah, that's gotta be 8 for dwarf32 and 16 for dwarf64.
Comment 5 Tom de Vries 2024-05-13 12:05:10 UTC
(In reply to Tom de Vries from comment #4)
> (In reply to Tom de Vries from comment #3)
> > FWIW, the "str_offsets_base = cu->header.addr_size" makes no sense to me atm.
> 
> Yeah, that's gotta be 8 for dwarf32 and 16 for dwarf64.

Which probably should be handled elsewhere.

At the point we're assigning this, there's no knowledge of whether the .debug_str_offsets section is dwarf32 or dwarf64.
Comment 6 Tom de Vries 2024-05-13 15:58:29 UTC
This seems to work:
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 049ee4d52ff..2ab94b0dd27 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -21200,7 +21200,21 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset,
       str_offsets_section = &cu->dwo_unit->dwo_file
 			       ->sections.str_offsets;
       str_section = &cu->dwo_unit->dwo_file->sections.str;
-      str_offsets_base = cu->header.addr_size;
+      if (cu->per_cu->version () <= 4)
+	str_offsets_base = 0;
+      else
+	{
+	  bfd *abfd = str_offsets_section->get_bfd_owner ();
+	  unsigned int bytes_read;
+	  read_initial_length (abfd, str_offsets_section->buffer, &bytes_read, false);
+	  if (!(bytes_read == 4 || bytes_read == 12))
+	    {
+	      complaint (_("Can't get initial length of %s"), str_offsets_section->get_name ());
+	      return;
+	    }
+	  const bool is_dwarf64 = bytes_read != 4;
+	  str_offsets_base = is_dwarf64 ? 16 : 8;
+	}
     }
   else
     {
...
Comment 7 Tom de Vries 2024-05-22 06:12:53 UTC
The fix from comment 1 is probably a good fix, but it'll need a dwarf assembly test-case to trigger it.

The fix from comment 6 is submitted in bits and pieces in the patch series submitted here ( https://sourceware.org/pipermail/gdb-patches/2024-May/209298.html ).