[2/2] gdb/dwarf: keep going even if reading macro information fails

Message ID 20250311190252.290553-2-simon.marchi@efficios.com
State New
Headers
Series [1/2] gdb/testsuite: fail less catastrophically in gdb.base/style.exp |

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

Simon Marchi March 11, 2025, 7:02 p.m. UTC
  On Debian 12, with gcc 12 and ld 2.40, I get some failures when running:

    $ make check TESTS="gdb.base/style.exp" RUNTESTFLAGS="--target_board=fission"

I think I stumble on this bug [1], preventing the test from doing
anything that requires expanding the compilation unit:

    $ ./gdb -nx -q --data-directory=data-directory testsuite/outputs/gdb.base/style/style
    Reading symbols from testsuite/outputs/gdb.base/style/style...
    (gdb) p main
    DW_FORM_strp pointing outside of .debug_str section [in module /home/smarchi/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/style/style]
    (gdb)

The error is thrown here:

    #0  0x00007ffff693f0a1 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc++.so.6
    #1  0x0000555569ce6852 in throw_it(return_reason, errors, const char *, typedef __va_list_tag __va_list_tag *) (reason=RETURN_ERROR, error=GENERIC_ERROR, fmt=0x555562a9fc40 "%s pointing outside of %s section [in module %s]", ap=0x7fffffff8df0) at /home/smarchi/src/binutils-gdb/gdbsupport/common-exceptions.cc:203
    #2  0x0000555569ce690f in throw_verror (error=GENERIC_ERROR, fmt=0x555562a9fc40 "%s pointing outside of %s section [in module %s]", ap=0x7fffffff8df0) at /home/smarchi/src/binutils-gdb/gdbsupport/common-exceptions.cc:211
    #3  0x000055556879c0cb in verror (string=0x555562a9fc40 "%s pointing outside of %s section [in module %s]", args=0x7fffffff8df0) at /home/smarchi/src/binutils-gdb/gdb/utils.c:193
    #4  0x0000555569cfa88d in error (fmt=0x555562a9fc40 "%s pointing outside of %s section [in module %s]") at /home/smarchi/src/binutils-gdb/gdbsupport/errors.cc:45
    #5  0x000055556667dbff in dwarf2_section_info::read_string (this=0x61b000042a08, objfile=0x616000055e80, str_offset=262811, form_name=0x555562886b40 "DW_FORM_strp") at /home/smarchi/src/binutils-gdb/gdb/dwarf2/section.c:211
    #6  0x00005555662486b7 in dwarf_decode_macro_bytes (per_objfile=0x616000056180, builder=0x614000006040, abfd=0x6120000f4b40, mac_ptr=0x60300004f5be "", mac_end=0x60300004f5bb "\002\004", current_file=0x62100007ad70, lh=0x60f000028bd0, section=0x61700008ba78, section_is_gnu=1, section_is_dwz=0, offset_size=4, str_section=0x61700008bac8, str_offsets_section=0x61700008baf0, str_offsets_base=std::optional<unsigned long> = {...}, include_hash=..., cu=0x61700008b600) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/macro.c:511
    #7  0x000055556624af0e in dwarf_decode_macros (per_objfile=0x616000056180, builder=0x614000006040, section=0x61700008ba78, lh=0x60f000028bd0, offset_size=4, offset=0, str_section=0x61700008bac8, str_offsets_section=0x61700008baf0, str_offsets_base=std::optional<unsigned long> = {...}, section_is_gnu=1, cu=0x61700008b600) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/macro.c:934
    #8  0x000055556642cb82 in dwarf_decode_macros (cu=0x61700008b600, offset=0, section_is_gnu=1) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/read.c:19435
    #9  0x000055556639bd12 in read_file_scope (die=0x6210000885c0, cu=0x61700008b600) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/read.c:6366
    #10 0x0000555566392d99 in process_die (die=0x6210000885c0, cu=0x61700008b600) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/read.c:5310
    #11 0x0000555566390d72 in process_full_comp_unit (cu=0x61700008b600, pretend_language=language_minimal) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/read.c:5075

The exception is then only caught at the event-loop level
(start_event_loop), causing the whole debug info reading process to be
aborted.  I think it's a little harsh, considering that a lot of things
could work even if we failed to read macro information.

Catch the exception inside read_file_scope, print the exception, and
carry on.  We could go even more fine-grained: if reading the string for
one macro definition fails, we could continue reading the macro
information.  Perhaps it's just that one macro definition that is
broken.  However, I don't need this level of granularity, so I haven't
attempted this.  Also, my experience is that macro reading fails when
the compiler or linker has a bug, in which case pretty much everything
is messed up.

With this patch, it now looks like:

    $ ./gdb -nx -q --data-directory=data-directory testsuite/outputs/gdb.base/style/style
    Reading symbols from testsuite/outputs/gdb.base/style/style...
    (gdb) p main
    While reading section .debug_macro.dwo: DW_FORM_strp pointing outside of .debug_str section [in module /home/smarchi/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/style/style]
    $1 = {int (int, char **)} 0x684 <main>
    (gdb)

In the test I am investigating (gdb.base/style.exp with the fission
board), it allows more tests to run:

    -# of expected passes           107
    -# of unexpected failures       17
    +# of expected passes           448
    +# of unexpected failures       19

Of course, we still see the error about the macro information, and some
macro-related tests still fail (those would be kfailed ideally), but
many tests that are not macro-dependent now pass.

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111409

Change-Id: I0bdb01f153eff23c63c96ce3f41114bb027e5796
---
 gdb/dwarf2/read.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)
  

Comments

Tom Tromey March 13, 2025, 3:33 p.m. UTC | #1
>>>>> "Simon" == Simon Marchi <simon.marchi@efficios.com> writes:

Simon> Catch the exception inside read_file_scope, print the exception, and
Simon> carry on.

Thanks for doing this.
Approved-By: Tom Tromey <tom@tromey.com>


[finer-grained exception handling]
Simon> However, I don't need this level of granularity, so I haven't
Simon> attempted this.  Also, my experience is that macro reading fails when
Simon> the compiler or linker has a bug, in which case pretty much everything
Simon> is messed up.

FWIW I agree with this approach.

Tom
  
Simon Marchi March 13, 2025, 4:10 p.m. UTC | #2
On 3/13/25 11:33 AM, Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simon.marchi@efficios.com> writes:
> 
> Simon> Catch the exception inside read_file_scope, print the exception, and
> Simon> carry on.
> 
> Thanks for doing this.
> Approved-By: Tom Tromey <tom@tromey.com>
> 
> 
> [finer-grained exception handling]
> Simon> However, I don't need this level of granularity, so I haven't
> Simon> attempted this.  Also, my experience is that macro reading fails when
> Simon> the compiler or linker has a bug, in which case pretty much everything
> Simon> is messed up.
> 
> FWIW I agree with this approach.
> 
> Tom

Thanks, pushed both.

Simon
  

Patch

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index a25daa36d38c..831289858556 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -50,6 +50,7 @@ 
 #include "bfd.h"
 #include "elf-bfd.h"
 #include "event-top.h"
+#include "exceptions.h"
 #include "gdbsupport/task-group.h"
 #include "symtab.h"
 #include "gdbtypes.h"
@@ -19432,9 +19433,19 @@  dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset,
       str_offsets_base = cu->str_offsets_base;
     }
 
-  dwarf_decode_macros (per_objfile, builder, section, lh,
-		       offset_size, offset, str_section, str_offsets_section,
-		       str_offsets_base, section_is_gnu, cu);
+  try
+    {
+      dwarf_decode_macros (per_objfile, builder, section, lh, offset_size,
+			   offset, str_section, str_offsets_section,
+			   str_offsets_base, section_is_gnu, cu);
+    }
+  catch (const gdb_exception_error &error)
+    {
+      /* Print the error and carry on with no (or partial) macro
+	 information.  */
+      exception_fprintf (gdb_stderr, error, _("While reading section %s: "),
+			 section->get_name ());
+    }
 }
 
 /* Return the .debug_loc section to use for CU.