mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-06 07:33:08 +00:00
[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
This commit is contained in:
@@ -37,6 +37,7 @@
|
|||||||
#include "auxv.h"
|
#include "auxv.h"
|
||||||
#include "observable.h"
|
#include "observable.h"
|
||||||
#include "solib-target.h"
|
#include "solib-target.h"
|
||||||
|
#include "event-top.h"
|
||||||
|
|
||||||
#include "gdbsupport/version.h"
|
#include "gdbsupport/version.h"
|
||||||
|
|
||||||
@@ -1040,7 +1041,11 @@ default_print_insn (bfd_vma memaddr, disassemble_info *info)
|
|||||||
info->mach, current_program_space->exec_bfd ());
|
info->mach, current_program_space->exec_bfd ());
|
||||||
|
|
||||||
gdb_assert (disassemble_fn != NULL);
|
gdb_assert (disassemble_fn != NULL);
|
||||||
return (*disassemble_fn) (memaddr, info);
|
int res = (*disassemble_fn) (memaddr, info);
|
||||||
|
|
||||||
|
QUIT;
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See arch-utils.h. */
|
/* See arch-utils.h. */
|
||||||
|
|||||||
@@ -197,7 +197,12 @@ gdb_disassembler_memory_reader::dis_asm_read_memory
|
|||||||
(bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
|
(bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
|
||||||
struct disassemble_info *info) noexcept
|
struct disassemble_info *info) noexcept
|
||||||
{
|
{
|
||||||
|
auto res = catch_exceptions<int, -1> ([&]
|
||||||
|
{
|
||||||
return target_read_code (memaddr, myaddr, len);
|
return target_read_code (memaddr, myaddr, len);
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrapper of memory_error. */
|
/* Wrapper of memory_error. */
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "extension.h"
|
||||||
|
|
||||||
struct cmd_list_element;
|
struct cmd_list_element;
|
||||||
|
|
||||||
/* The current quit handler (and its type). This is called from the
|
/* The current quit handler (and its type). This is called from the
|
||||||
@@ -81,6 +83,29 @@ extern void quit_serial_event_set ();
|
|||||||
|
|
||||||
extern void quit_serial_event_clear ();
|
extern void quit_serial_event_clear ();
|
||||||
|
|
||||||
|
/* Wrap f (args) and handle exceptions by:
|
||||||
|
- returning val, and
|
||||||
|
- calling set_quit_flag or set_force_quit_flag, if needed. */
|
||||||
|
|
||||||
|
template <typename R, R val, typename F, typename... Args>
|
||||||
|
static R
|
||||||
|
catch_exceptions (F &&f, Args&&... args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return f (std::forward<Args> (args)...);
|
||||||
|
}
|
||||||
|
catch (const gdb_exception &ex)
|
||||||
|
{
|
||||||
|
if (ex.reason == RETURN_QUIT)
|
||||||
|
set_quit_flag ();
|
||||||
|
else if (ex.reason == RETURN_FORCED_QUIT)
|
||||||
|
set_force_quit_flag ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
extern void display_gdb_prompt (const char *new_prompt);
|
extern void display_gdb_prompt (const char *new_prompt);
|
||||||
extern void gdb_setup_readline (int);
|
extern void gdb_setup_readline (int);
|
||||||
extern void gdb_disable_readline (void);
|
extern void gdb_disable_readline (void);
|
||||||
|
|||||||
@@ -930,29 +930,6 @@ gdb_bfd_openw (const char *filename, const char *target)
|
|||||||
return gdb_bfd_ref_ptr::new_reference (result);
|
return gdb_bfd_ref_ptr::new_reference (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrap f (args) and handle exceptions by:
|
|
||||||
- returning val, and
|
|
||||||
- calling set_quit_flag or set_force_quit_flag, if needed. */
|
|
||||||
|
|
||||||
template <typename R, R val, typename F, typename... Args>
|
|
||||||
static R
|
|
||||||
catch_exceptions (F &&f, Args&&... args)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return f (std::forward<Args> (args)...);
|
|
||||||
}
|
|
||||||
catch (const gdb_exception &ex)
|
|
||||||
{
|
|
||||||
if (ex.reason == RETURN_QUIT)
|
|
||||||
set_quit_flag ();
|
|
||||||
else if (ex.reason == RETURN_FORCED_QUIT)
|
|
||||||
set_force_quit_flag ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See gdb_bfd.h. */
|
/* See gdb_bfd.h. */
|
||||||
|
|
||||||
gdb_bfd_ref_ptr
|
gdb_bfd_ref_ptr
|
||||||
|
|||||||
Reference in New Issue
Block a user