Bug 32025 - Fatal error when the disassemble command is interrupted with SIGINT
Summary: Fatal error when the disassemble command is interrupted with SIGINT
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: 15.1
: P2 normal
Target Milestone: 15.2
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-07-26 14:24 UTC by Dmitry Neverov
Modified: 2024-08-22 09:43 UTC (History)
2 users (show)

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


Attachments
gdb session log (18.13 KB, text/plain)
2024-07-26 14:24 UTC, Dmitry Neverov
Details
tentative patch (1.16 KB, patch)
2024-07-30 12:49 UTC, Tom de Vries
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dmitry Neverov 2024-07-26 14:24:53 UTC
Created attachment 15643 [details]
gdb session log

I was debugging the following program in a graphical gdb client:

#include <iostream>

void f0() {
    std::cout << "ok" << std::endl;
}
void f1() { f0(); }
void f2() { f1(); }
void f3() { f2(); }
void f4() { f3(); }
void f5() { f4(); }
void f6() { f5(); }
void f7() { f6(); }
void f8() { f7(); }
void f9() { f8(); }

int main() {
    f9(); //break
    return 0;
}

When the breakpoint was reached, I disassembled the function and stepped
by instruction. When the program suspends, the gdb client tries to
load disassembly the current function. When user steps in UI, disassemble
is cancelled by sending SIGINT to gdb. Such a signal leads to the
fatal error:

0x566d19a476d1 gdb_internal_backtrace_1 gdb/bt-utils.c:121
0x566d19a47794 _Z22gdb_internal_backtracev gdb/bt-utils.c:169
0x566d19c5efe1 handle_fatal_signal gdb/event-top.c:916
0x7c7d8064298f ??? ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
0x7c7d80699a1b __pthread_kill_implementation ./nptl/pthread_kill.c:44
0x7c7d80699a1b __pthread_kill_internal ./nptl/pthread_kill.c:78
0x7c7d80699a1b __GI___pthread_kill ./nptl/pthread_kill.c:89
0x7c7d806428e5 __GI_raise ../sysdeps/posix/raise.c:26
0x7c7d806268b6 __GI_abort ./stdlib/abort.c:79
0x7c7d80aa4f05 _ZN9__gnu_cxx27__verbose_terminate_handlerEv ../../../../src/libstdc++-v3/libsupc++/vterminate.cc:95
0x7c7d80ab6e6b _ZN10__cxxabiv111__terminateEPFvvE ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:48
0x7c7d80ab5e18 __cxa_call_terminate ../../../../src/libstdc++-v3/libsupc++/eh_call.cc:54
0x7c7d80ab6588 __gxx_personality_v0 ../../../../src/libstdc++-v3/libsupc++/eh_personality.cc:688
0x7c7d8160ba58 ??? 0x7c7d8160c180 ???
0x7c7d80ab712a __cxa_throw ../../../../src/libstdc++-v3/libsupc++/eh_throw.cc:93
0x566d1a27985c throw_it gdbsupport/common-exceptions.cc:199
0x566d1a2799c4 _Z11throw_vquitPKcP13__va_list_tag gdbsupport/common-exceptions.cc:217
0x566d1a279b60 _Z10throw_quitPKcz gdbsupport/common-exceptions.cc:236
0x566d19c5f3a7 _Z4quitv gdb/event-top.c:1087
0x566d19c5f459 _Z20default_quit_handlerv gdb/event-top.c:1140
0x566d19c5f3e8 _Z10maybe_quitv gdb/event-top.c:1104
0x566d1a011b3c _Z11target_readP10target_ops13target_objectPKcPhml gdb/target.c:1980
0x566d1a011646 _Z16target_read_codemPhl gdb/target.c:1823
0x566d19b4c8c4 _ZN30gdb_disassembler_memory_reader19dis_asm_read_memoryEmPhjP16disassemble_info gdb/disasm.c:200
0x566d1a101cfd fetch_code opcodes/i386-dis.c:342
0x566d1a101f77 ckprefix opcodes/i386-dis.c:8472
0x566d1a10498d print_insn opcodes/i386-dis.c:9530
0x566d1a106154 print_insn_i386 opcodes/i386-dis.c:10024
0x566d199abb60 _Z18default_print_insnmP16disassemble_info gdb/arch-utils.c:1043
0x566d19cdaad3 i386_print_insn gdb/i386-tdep.c:3999
0x566d199b698d _Z18gdbarch_print_insnP7gdbarchmP16disassemble_info gdb/gdbarch.c:3374
0x566d19b4f9bb gdb_print_insn_1 gdb/disasm.c:1102
0x566d19b4fa7d _ZN16gdb_disassembler10print_insnEmPi gdb/disasm.c:1119
0x566d19b4d460 _ZN29gdb_pretty_print_disassembler17pretty_print_insnEPK11disasm_insn10enum_flagsI20gdb_disassembly_flagE gdb/disasm.c:449
0x566d19b4da31 dump_insns gdb/disasm.c:546
0x566d19b4f31b do_assembly_only gdb/disasm.c:960
0x566d19b4ff48 _Z15gdb_disassemblyP7gdbarchP6ui_out10enum_flagsI20gdb_disassembly_flagEimm gdb/disasm.c:1202
0x566d19a9eb5d print_disassembly gdb/cli/cli-cmds.c:1537
0x566d19a9f417 disassemble_command gdb/cli/cli-cmds.c:1717
0x566d19aa6bbc do_simple_func gdb/cli/cli-decode.c:94
0x566d19aacc18 _Z8cmd_funcP16cmd_list_elementPKci gdb/cli/cli-decode.c:2741
0x566d1a045ce7 _Z15execute_commandPKci gdb/top.c:569
0x566d19ab2a6a _ZN10cli_interp4execEPKc gdb/cli/cli-interp.c:241
0x566d19d3f1fb _Z11interp_execP6interpPKc gdb/interps.c:267
0x566d19de1188 _Z23mi_cmd_interpreter_execPKcPKS0_i gdb/mi/mi-interp.c:186
0x566d19dea3c4 captured_mi_execute_command gdb/mi/mi-main.c:1870
0x566d19dea7bb _Z18mi_execute_commandPKci gdb/mi/mi-main.c:1955
0x566d19de1279 mi_execute_command_wrapper gdb/mi/mi-interp.c:219
0x566d19de12f8 mi_execute_command_input_handler gdb/mi/mi-interp.c:241
0x566d19c5ede4 _Z32gdb_readline_no_editing_callbackPv gdb/event-top.c:873
0x566d1a0782a6 stdin_event_handler gdb/ui.c:154
0x566d1a2807ae handle_file_event gdbsupport/event-loop.cc:551
0x566d1a280e2f gdb_wait_for_event gdbsupport/event-loop.cc:672
0x566d1a27fbed _Z16gdb_do_one_eventi gdbsupport/event-loop.cc:263
0x566d19dacc55 start_event_loop gdb/main.c:400
0x566d19dace35 captured_command_loop gdb/main.c:464
0x566d19daea68 captured_main gdb/main.c:1337
0x566d19daeb12 _Z8gdb_mainP18captured_main_args gdb/main.c:1356
0x566d1990d6ae main gdb/gdb.c:38
Comment 1 Tom Tromey 2024-07-26 18:15:54 UTC
I'm not 100% sure of what's happening here, but I wonder
if your libopcodes is being built in a way that doesn't
allow an exception to propagate across it.
This could cause a crash.
Comment 2 Tom de Vries 2024-07-29 07:21:25 UTC
I wonder if something like this would fix it:
...
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 16736e54997..a642b4634ab 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -197,7 +197,20 @@ gdb_disassembler_memory_reader::dis_asm_read_memory
   (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
    struct disassemble_info *info) noexcept
 {
-  return target_read_code (memaddr, myaddr, len);
+  try
+    {
+      return target_read_code (memaddr, myaddr, len);
+    }
+  catch (const gdb_exception_quit &)
+    {
+      set_quit_flag ();
+    }
+  catch (const gdb_exception_forced_quit &)
+    {
+      set_force_quit_flag ();
+    }
+
+  return -1;
 }
 
 /* Wrapper of memory_error.  */
...
Comment 3 Tom de Vries 2024-07-30 12:07:50 UTC
I managed to reproduce this on aarch64-linux, leap 15.5 container on fedora 40 host, using this trigger patch:
...
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 16736e54997..962756415ad 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -197,6 +197,7 @@ gdb_disassembler_memory_reader::dis_asm_read_memory
   (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
    struct disassemble_info *info) noexcept
 {
+  set_quit_flag ();
   return target_read_code (memaddr, myaddr, len);
 }
 
...
and this gdb command using a hello world a.out:
...
$ gdb -q -batch a.out -ex "disassemble main"
Dump of assembler code for function main:
terminate called after throwing an instance of 'gdb_exception_quit'


Fatal signal: Aborted
----- Backtrace -----
...
Comment 4 Tom de Vries 2024-07-30 12:49:17 UTC
Created attachment 15655 [details]
tentative patch
Comment 6 Sourceware Commits 2024-08-08 21:51:46 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=c45c3b4162148077765e94fd17d4481f18d6d44c

commit c45c3b4162148077765e94fd17d4481f18d6d44c
Author: Tom de Vries <tdevries@suse.de>
Date:   Thu Aug 8 23:52:00 2024 +0200

    [gdb] Handle ^C during disassembly
    
    In PR gdb/32025, a fatal error was reported when sending a SIGINT to gdb while
    disassembling.
    
    I managed to reproduce this on aarch64-linux in a Leap 15.5 container using
    this trigger patch:
    ...
     gdb_disassembler_memory_reader::dis_asm_read_memory
       (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
        struct disassemble_info *info) noexcept
     {
    +  set_quit_flag ();
       return target_read_code (memaddr, myaddr, len);
     }
    ...
    and a simple gdb command line calling the disassemble command:
    ...
    $ gdb -q -batch a.out -ex "disassemble main"
    ...
    
    The following scenario leads to the fatal error:
    - the disassemble command is executed,
    - set_quit_flag is called in
      gdb_disassembler_memory_reader::dis_asm_read_memory, pretending that a
      user pressed ^C,
    - target_read_code calls QUIT, which throws a
      gdb_exception_quit,
    - the exception propagation mechanism reaches c code in libopcodes and a fatal
      error triggers because the c code is not compiled with -fexception.
    
    Fix this by:
    - wrapping the body of gdb_disassembler_memory_reader::dis_asm_read_memory in
      catch_exceptions (which consequently needs moving to a header file), and
    - reraising the caught exception in default_print_insn using QUIT.
    
    Tested on aarch64-linux.
    
    Approved-By: Andrew Burgess <aburgess@redhat.com>
    
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32025
Comment 7 Tom de Vries 2024-08-08 21:53:00 UTC
Fixed.
Comment 8 Sourceware Commits 2024-08-22 09:42:44 UTC
The gdb-15-branch branch has been updated by Tom de Vries <vries@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=de553d417e1c059edcd33f59fb20c780f6406668

commit de553d417e1c059edcd33f59fb20c780f6406668
Author: Tom de Vries <tdevries@suse.de>
Date:   Thu Aug 22 11:43:32 2024 +0200

    [gdb] Handle ^C during disassembly
    
    In PR gdb/32025, a fatal error was reported when sending a SIGINT to gdb while
    disassembling.
    
    I managed to reproduce this on aarch64-linux in a Leap 15.5 container using
    this trigger patch:
    ...
     gdb_disassembler_memory_reader::dis_asm_read_memory
       (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
        struct disassemble_info *info) noexcept
     {
    +  set_quit_flag ();
       return target_read_code (memaddr, myaddr, len);
     }
    ...
    and a simple gdb command line calling the disassemble command:
    ...
    $ gdb -q -batch a.out -ex "disassemble main"
    ...
    
    The following scenario leads to the fatal error:
    - the disassemble command is executed,
    - set_quit_flag is called in
      gdb_disassembler_memory_reader::dis_asm_read_memory, pretending that a
      user pressed ^C,
    - target_read_code calls QUIT, which throws a
      gdb_exception_quit,
    - the exception propagation mechanism reaches c code in libopcodes and a fatal
      error triggers because the c code is not compiled with -fexception.
    
    Fix this by:
    - wrapping the body of gdb_disassembler_memory_reader::dis_asm_read_memory in
      catch_exceptions (which consequently needs moving to a header file), and
    - reraising the caught exception in default_print_insn using QUIT.
    
    Tested on aarch64-linux.
    
    Approved-By: Andrew Burgess <aburgess@redhat.com>
    
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32025
    (cherry picked from commit c45c3b4162148077765e94fd17d4481f18d6d44c)