mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-08 00:23:09 +00:00
Fix signal unsafe call inside a signal
It can easily happen that the signal handler function `handle_fatal_signal` uses various signal unsafe functions. The problematic functions are `_` and `strsignal` which can be pre-computed after the `setlocale` call is done. Unfortunately when compiled with --disable-libbacktrace a different code path is used, that calls the glibc function `backtrace` which calls `malloc` and `free` and is therefore also signal unsafe, that is probably unfixable, so there is no attempt to fix anything in this code path. Approved-By: Andrew Burgess <aburgess@redhat.com> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31713#c9
This commit is contained in:
@@ -145,10 +145,25 @@ gdb_internal_backtrace_1 ()
|
|||||||
#else
|
#else
|
||||||
#error "unexpected internal backtrace policy"
|
#error "unexpected internal backtrace policy"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const char *str_backtrace = "----- Backtrace -----\n";
|
||||||
|
static const char *str_backtrace_unavailable = "Backtrace unavailable\n";
|
||||||
|
|
||||||
#endif /* GDB_PRINT_INTERNAL_BACKTRACE */
|
#endif /* GDB_PRINT_INTERNAL_BACKTRACE */
|
||||||
|
|
||||||
/* See bt-utils.h. */
|
/* See bt-utils.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
gdb_internal_backtrace_init_str ()
|
||||||
|
{
|
||||||
|
#ifdef GDB_PRINT_INTERNAL_BACKTRACE
|
||||||
|
str_backtrace = _("----- Backtrace -----\n");
|
||||||
|
str_backtrace_unavailable = _("Backtrace unavailable\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See bt-utils.h. */
|
||||||
|
|
||||||
void
|
void
|
||||||
gdb_internal_backtrace ()
|
gdb_internal_backtrace ()
|
||||||
{
|
{
|
||||||
@@ -161,12 +176,12 @@ gdb_internal_backtrace ()
|
|||||||
gdb_stderr->write_async_safe (msg, strlen (msg));
|
gdb_stderr->write_async_safe (msg, strlen (msg));
|
||||||
};
|
};
|
||||||
|
|
||||||
sig_write (_("----- Backtrace -----\n"));
|
sig_write (str_backtrace);
|
||||||
|
|
||||||
if (gdb_stderr->fd () > -1)
|
if (gdb_stderr->fd () > -1)
|
||||||
gdb_internal_backtrace_1 ();
|
gdb_internal_backtrace_1 ();
|
||||||
else
|
else
|
||||||
sig_write (_("Backtrace unavailable\n"));
|
sig_write (str_backtrace_unavailable);
|
||||||
|
|
||||||
sig_write ("---------------------\n");
|
sig_write ("---------------------\n");
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -71,4 +71,8 @@ extern void gdb_internal_backtrace ();
|
|||||||
extern void gdb_internal_backtrace_set_cmd (const char *args, int from_tty,
|
extern void gdb_internal_backtrace_set_cmd (const char *args, int from_tty,
|
||||||
cmd_list_element *c);
|
cmd_list_element *c);
|
||||||
|
|
||||||
|
/* Initialize language specific strings. */
|
||||||
|
|
||||||
|
extern void gdb_internal_backtrace_init_str ();
|
||||||
|
|
||||||
#endif /* BT_UTILS_H */
|
#endif /* BT_UTILS_H */
|
||||||
|
|||||||
@@ -908,6 +908,51 @@ unblock_signal (int sig)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Signal safe language specific strings. */
|
||||||
|
|
||||||
|
#ifdef GDB_PRINT_INTERNAL_BACKTRACE
|
||||||
|
static const char *str_fatal_signal;
|
||||||
|
static const char *str_sigsegv;
|
||||||
|
#ifdef SIGFPE
|
||||||
|
static const char *str_sigfpe;
|
||||||
|
#endif
|
||||||
|
#ifdef SIGBUS
|
||||||
|
static const char *str_sigbus;
|
||||||
|
#endif
|
||||||
|
#ifdef SIGABRT
|
||||||
|
static const char *str_sigabrt;
|
||||||
|
#endif
|
||||||
|
static const char *str_unknown_signal;
|
||||||
|
static const char *str_fatal_error_detected_gdb_will_now_terminate;
|
||||||
|
static const char *str_this_is_a_bug;
|
||||||
|
static const char *str_for_instructions_see;
|
||||||
|
|
||||||
|
/* Initialize language specific strings. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_str_handle_fatal_signal ()
|
||||||
|
{
|
||||||
|
str_fatal_signal = _("Fatal signal: ");
|
||||||
|
str_sigsegv = strsignal (SIGSEGV);
|
||||||
|
#ifdef SIGFPE
|
||||||
|
str_sigfpe = strsignal (SIGFPE);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGBUS
|
||||||
|
str_sigbus = strsignal (SIGBUS);
|
||||||
|
#endif
|
||||||
|
#ifdef SIGABRT
|
||||||
|
str_sigabrt = strsignal (SIGABRT);
|
||||||
|
#endif
|
||||||
|
str_unknown_signal = _("Unknown signal");
|
||||||
|
str_fatal_error_detected_gdb_will_now_terminate =
|
||||||
|
_("A fatal error internal to GDB has been detected, "
|
||||||
|
"further\ndebugging is not possible. GDB will now "
|
||||||
|
"terminate.\n\n");
|
||||||
|
str_this_is_a_bug = _("This is a bug, please report it.");
|
||||||
|
str_for_instructions_see = _(" For instructions, see:\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Called to handle fatal signals. SIG is the signal number. */
|
/* Called to handle fatal signals. SIG is the signal number. */
|
||||||
|
|
||||||
[[noreturn]] static void
|
[[noreturn]] static void
|
||||||
@@ -926,19 +971,40 @@ handle_fatal_signal (int sig)
|
|||||||
if (bt_on_fatal_signal)
|
if (bt_on_fatal_signal)
|
||||||
{
|
{
|
||||||
sig_write ("\n\n");
|
sig_write ("\n\n");
|
||||||
sig_write (_("Fatal signal: "));
|
sig_write (str_fatal_signal);
|
||||||
sig_write (strsignal (sig));
|
switch (sig)
|
||||||
|
{
|
||||||
|
case SIGSEGV:
|
||||||
|
sig_write (str_sigsegv);
|
||||||
|
break;
|
||||||
|
#ifdef SIGFPE
|
||||||
|
case SIGFPE:
|
||||||
|
sig_write (str_sigfpe);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SIGBUS
|
||||||
|
case SIGBUS:
|
||||||
|
sig_write (str_sigbus);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SIGABRT
|
||||||
|
case SIGABRT:
|
||||||
|
sig_write (str_sigabrt);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
sig_write (str_unknown_signal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
sig_write ("\n");
|
sig_write ("\n");
|
||||||
|
|
||||||
gdb_internal_backtrace ();
|
gdb_internal_backtrace ();
|
||||||
|
|
||||||
sig_write (_("A fatal error internal to GDB has been detected, "
|
sig_write (str_fatal_error_detected_gdb_will_now_terminate);
|
||||||
"further\ndebugging is not possible. GDB will now "
|
sig_write (str_this_is_a_bug);
|
||||||
"terminate.\n\n"));
|
|
||||||
sig_write (_("This is a bug, please report it."));
|
|
||||||
if (REPORT_BUGS_TO[0] != '\0')
|
if (REPORT_BUGS_TO[0] != '\0')
|
||||||
{
|
{
|
||||||
sig_write (_(" For instructions, see:\n"));
|
sig_write (str_for_instructions_see);
|
||||||
sig_write (REPORT_BUGS_TO);
|
sig_write (REPORT_BUGS_TO);
|
||||||
sig_write (".");
|
sig_write (".");
|
||||||
}
|
}
|
||||||
@@ -1066,6 +1132,10 @@ gdb_init_signals (void)
|
|||||||
create_async_signal_handler (async_sigtstp_handler, NULL, "sigtstp");
|
create_async_signal_handler (async_sigtstp_handler, NULL, "sigtstp");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef GDB_PRINT_INTERNAL_BACKTRACE
|
||||||
|
init_str_handle_fatal_signal ();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SIGFPE
|
#ifdef SIGFPE
|
||||||
signal (SIGFPE, handle_fatal_signal);
|
signal (SIGFPE, handle_fatal_signal);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
#include "observable.h"
|
#include "observable.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "cli-out.h"
|
#include "cli-out.h"
|
||||||
|
#include "bt-utils.h"
|
||||||
|
|
||||||
/* The selected interpreter. */
|
/* The selected interpreter. */
|
||||||
std::string interpreter_p;
|
std::string interpreter_p;
|
||||||
@@ -676,6 +677,7 @@ captured_main_1 (struct captured_main_args *context)
|
|||||||
/* Note: `error' cannot be called before this point, because the
|
/* Note: `error' cannot be called before this point, because the
|
||||||
caller will crash when trying to print the exception. */
|
caller will crash when trying to print the exception. */
|
||||||
main_ui = new ui (stdin, stdout, stderr);
|
main_ui = new ui (stdin, stdout, stderr);
|
||||||
|
gdb_internal_backtrace_init_str ();
|
||||||
current_ui = main_ui;
|
current_ui = main_ui;
|
||||||
|
|
||||||
gdb_stdtarg = gdb_stderr;
|
gdb_stdtarg = gdb_stderr;
|
||||||
|
|||||||
Reference in New Issue
Block a user