Demangler crash handler
This commit wraps calls to the demangler with a segmentation fault handler. The first time a segmentation fault is caught a core file is generated and the user is prompted to file a bug and offered the choice to exit or to continue their GDB session. A maintainence option is provided to allow the user to disable the crash handler if required. gdb/ 2014-06-19 Gary Benson <gbenson@redhat.com> * configure.ac [AC_CHECK_FUNCS] <sigaltstack>: New check. * configure: Regenerate. * config.in: Likewise. * main.c (signal.h): New include. (setup_alternate_signal_stack): New function. (captured_main): Call the above. * cp-support.c (signal.h): New include. (catch_demangler_crashes): New flag. (SIGJMP_BUF): New define. (SIGSETJMP): Likewise. (SIGLONGJMP): Likewise. (gdb_demangle_jmp_buf): New static global. (gdb_demangle_attempt_core_dump): Likewise. (gdb_demangle_signal_handler): New function. (gdb_demangle): If catch_demangler_crashes is set, install the above signal handler before calling bfd_demangle, and restore the original signal handler afterwards. Display the offending symbol and call demangler_warning the first time a segmentation fault is caught. (_initialize_cp_support): New maint set/show command. gdb/doc/ 2014-06-19 Gary Benson <gbenson@redhat.com> * gdb.texinfo (Maintenance Commands): Document new "maint set/show catch-demangler-crashes" option.
This commit is contained in:
parent
eae7090bea
commit
992c7d700f
8 changed files with 214 additions and 3 deletions
|
@ -1,3 +1,26 @@
|
||||||
|
2014-06-19 Gary Benson <gbenson@redhat.com>
|
||||||
|
|
||||||
|
* configure.ac [AC_CHECK_FUNCS] <sigaltstack>: New check.
|
||||||
|
* configure: Regenerate.
|
||||||
|
* config.in: Likewise.
|
||||||
|
* main.c (signal.h): New include.
|
||||||
|
(setup_alternate_signal_stack): New function.
|
||||||
|
(captured_main): Call the above.
|
||||||
|
* cp-support.c (signal.h): New include.
|
||||||
|
(catch_demangler_crashes): New flag.
|
||||||
|
(SIGJMP_BUF): New define.
|
||||||
|
(SIGSETJMP): Likewise.
|
||||||
|
(SIGLONGJMP): Likewise.
|
||||||
|
(gdb_demangle_jmp_buf): New static global.
|
||||||
|
(gdb_demangle_attempt_core_dump): Likewise.
|
||||||
|
(gdb_demangle_signal_handler): New function.
|
||||||
|
(gdb_demangle): If catch_demangler_crashes is set, install the
|
||||||
|
above signal handler before calling bfd_demangle, and restore
|
||||||
|
the original signal handler afterwards. Display the offending
|
||||||
|
symbol and call demangler_warning the first time a segmentation
|
||||||
|
fault is caught.
|
||||||
|
(_initialize_cp_support): New maint set/show command.
|
||||||
|
|
||||||
2014-06-19 Gary Benson <gbenson@redhat.com>
|
2014-06-19 Gary Benson <gbenson@redhat.com>
|
||||||
|
|
||||||
* utils.h (resource_limit_kind): New enum.
|
* utils.h (resource_limit_kind): New enum.
|
||||||
|
|
|
@ -366,6 +366,9 @@
|
||||||
/* Define to 1 if you have the `sigaction' function. */
|
/* Define to 1 if you have the `sigaction' function. */
|
||||||
#undef HAVE_SIGACTION
|
#undef HAVE_SIGACTION
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `sigaltstack' function. */
|
||||||
|
#undef HAVE_SIGALTSTACK
|
||||||
|
|
||||||
/* Define to 1 if you have the <signal.h> header file. */
|
/* Define to 1 if you have the <signal.h> header file. */
|
||||||
#undef HAVE_SIGNAL_H
|
#undef HAVE_SIGNAL_H
|
||||||
|
|
||||||
|
|
2
gdb/configure
vendored
2
gdb/configure
vendored
|
@ -10507,7 +10507,7 @@ for ac_func in canonicalize_file_name realpath getrusage getuid getgid \
|
||||||
sigaction sigprocmask sigsetmask socketpair \
|
sigaction sigprocmask sigsetmask socketpair \
|
||||||
ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
|
ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
|
||||||
setrlimit getrlimit posix_madvise waitpid lstat \
|
setrlimit getrlimit posix_madvise waitpid lstat \
|
||||||
ptrace64
|
ptrace64 sigaltstack
|
||||||
do :
|
do :
|
||||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||||
|
|
|
@ -1328,7 +1328,7 @@ AC_CHECK_FUNCS([canonicalize_file_name realpath getrusage getuid getgid \
|
||||||
sigaction sigprocmask sigsetmask socketpair \
|
sigaction sigprocmask sigsetmask socketpair \
|
||||||
ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
|
ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
|
||||||
setrlimit getrlimit posix_madvise waitpid lstat \
|
setrlimit getrlimit posix_madvise waitpid lstat \
|
||||||
ptrace64])
|
ptrace64 sigaltstack])
|
||||||
AM_LANGINFO_CODESET
|
AM_LANGINFO_CODESET
|
||||||
GDB_AC_COMMON
|
GDB_AC_COMMON
|
||||||
|
|
||||||
|
|
146
gdb/cp-support.c
146
gdb/cp-support.c
|
@ -35,6 +35,7 @@
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "cp-abi.h"
|
#include "cp-abi.h"
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "safe-ctype.h"
|
#include "safe-ctype.h"
|
||||||
|
|
||||||
|
@ -1482,12 +1483,142 @@ cp_lookup_rtti_type (const char *name, struct block *block)
|
||||||
return rtti_type;
|
return rtti_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_WORKING_FORK
|
||||||
|
|
||||||
|
/* If nonzero, attempt to catch crashes in the demangler and print
|
||||||
|
useful debugging information. */
|
||||||
|
|
||||||
|
static int catch_demangler_crashes = 1;
|
||||||
|
|
||||||
|
/* Wrap set/long jmp so that it's more portable. */
|
||||||
|
|
||||||
|
#if defined(HAVE_SIGSETJMP)
|
||||||
|
#define SIGJMP_BUF sigjmp_buf
|
||||||
|
#define SIGSETJMP(buf) sigsetjmp((buf), 1)
|
||||||
|
#define SIGLONGJMP(buf,val) siglongjmp((buf), (val))
|
||||||
|
#else
|
||||||
|
#define SIGJMP_BUF jmp_buf
|
||||||
|
#define SIGSETJMP(buf) setjmp(buf)
|
||||||
|
#define SIGLONGJMP(buf,val) longjmp((buf), (val))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Stack context and environment for demangler crash recovery. */
|
||||||
|
|
||||||
|
static SIGJMP_BUF gdb_demangle_jmp_buf;
|
||||||
|
|
||||||
|
/* If nonzero, attempt to dump core from the signal handler. */
|
||||||
|
|
||||||
|
static int gdb_demangle_attempt_core_dump = 1;
|
||||||
|
|
||||||
|
/* Signal handler for gdb_demangle. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
gdb_demangle_signal_handler (int signo)
|
||||||
|
{
|
||||||
|
if (gdb_demangle_attempt_core_dump)
|
||||||
|
{
|
||||||
|
if (fork () == 0)
|
||||||
|
dump_core ();
|
||||||
|
|
||||||
|
gdb_demangle_attempt_core_dump = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIGLONGJMP (gdb_demangle_jmp_buf, signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* A wrapper for bfd_demangle. */
|
/* A wrapper for bfd_demangle. */
|
||||||
|
|
||||||
char *
|
char *
|
||||||
gdb_demangle (const char *name, int options)
|
gdb_demangle (const char *name, int options)
|
||||||
{
|
{
|
||||||
return bfd_demangle (NULL, name, options);
|
char *result = NULL;
|
||||||
|
int crash_signal = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_WORKING_FORK
|
||||||
|
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
|
||||||
|
struct sigaction sa, old_sa;
|
||||||
|
#else
|
||||||
|
void (*ofunc) ();
|
||||||
|
#endif
|
||||||
|
static int core_dump_allowed = -1;
|
||||||
|
|
||||||
|
if (core_dump_allowed == -1)
|
||||||
|
{
|
||||||
|
core_dump_allowed = can_dump_core (LIMIT_CUR);
|
||||||
|
|
||||||
|
if (!core_dump_allowed)
|
||||||
|
gdb_demangle_attempt_core_dump = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (catch_demangler_crashes)
|
||||||
|
{
|
||||||
|
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
|
||||||
|
sa.sa_handler = gdb_demangle_signal_handler;
|
||||||
|
sigemptyset (&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_ONSTACK;
|
||||||
|
sigaction (SIGSEGV, &sa, &old_sa);
|
||||||
|
#else
|
||||||
|
ofunc = (void (*)()) signal (SIGSEGV, gdb_demangle_signal_handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
crash_signal = SIGSETJMP (gdb_demangle_jmp_buf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (crash_signal == 0)
|
||||||
|
result = bfd_demangle (NULL, name, options);
|
||||||
|
|
||||||
|
#ifdef HAVE_WORKING_FORK
|
||||||
|
if (catch_demangler_crashes)
|
||||||
|
{
|
||||||
|
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
|
||||||
|
sigaction (SIGSEGV, &old_sa, NULL);
|
||||||
|
#else
|
||||||
|
signal (SIGSEGV, ofunc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (crash_signal != 0)
|
||||||
|
{
|
||||||
|
static int error_reported = 0;
|
||||||
|
|
||||||
|
if (!error_reported)
|
||||||
|
{
|
||||||
|
char *short_msg, *long_msg;
|
||||||
|
struct cleanup *back_to;
|
||||||
|
|
||||||
|
short_msg = xstrprintf (_("unable to demangle '%s' "
|
||||||
|
"(demangler failed with signal %d)"),
|
||||||
|
name, crash_signal);
|
||||||
|
back_to = make_cleanup (xfree, short_msg);
|
||||||
|
|
||||||
|
long_msg = xstrprintf ("%s:%d: %s: %s", __FILE__, __LINE__,
|
||||||
|
"demangler-warning", short_msg);
|
||||||
|
make_cleanup (xfree, long_msg);
|
||||||
|
|
||||||
|
target_terminal_ours ();
|
||||||
|
begin_line ();
|
||||||
|
if (core_dump_allowed)
|
||||||
|
fprintf_unfiltered (gdb_stderr,
|
||||||
|
_("%s\nAttempting to dump core.\n"),
|
||||||
|
long_msg);
|
||||||
|
else
|
||||||
|
warn_cant_dump_core (long_msg);
|
||||||
|
|
||||||
|
demangler_warning (__FILE__, __LINE__, "%s", short_msg);
|
||||||
|
|
||||||
|
do_cleanups (back_to);
|
||||||
|
|
||||||
|
error_reported = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't allow just "maintenance cplus". */
|
/* Don't allow just "maintenance cplus". */
|
||||||
|
@ -1562,4 +1693,17 @@ _initialize_cp_support (void)
|
||||||
Usage: info vtbl EXPRESSION\n\
|
Usage: info vtbl EXPRESSION\n\
|
||||||
Evaluate EXPRESSION and display the virtual function table for the\n\
|
Evaluate EXPRESSION and display the virtual function table for the\n\
|
||||||
resulting object."));
|
resulting object."));
|
||||||
|
|
||||||
|
#ifdef HAVE_WORKING_FORK
|
||||||
|
add_setshow_boolean_cmd ("catch-demangler-crashes", class_maintenance,
|
||||||
|
&catch_demangler_crashes, _("\
|
||||||
|
Set whether to attempt to catch demangler crashes."), _("\
|
||||||
|
Show whether to attempt to catch demangler crashes."), _("\
|
||||||
|
If enabled GDB will attempt to catch demangler crashes and\n\
|
||||||
|
display the offending symbol."),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&maintenance_set_cmdlist,
|
||||||
|
&maintenance_show_cmdlist);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2014-06-19 Gary Benson <gbenson@redhat.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Maintenance Commands): Document new
|
||||||
|
"maint set/show catch-demangler-crashes" option.
|
||||||
|
|
||||||
2014-06-19 Gary Benson <gbenson@redhat.com>
|
2014-06-19 Gary Benson <gbenson@redhat.com>
|
||||||
|
|
||||||
* gdb.texinfo (Maintenance Commands): Document new
|
* gdb.texinfo (Maintenance Commands): Document new
|
||||||
|
|
|
@ -33236,6 +33236,17 @@ Expand symbol tables.
|
||||||
If @var{regexp} is specified, only expand symbol tables for file
|
If @var{regexp} is specified, only expand symbol tables for file
|
||||||
names matching @var{regexp}.
|
names matching @var{regexp}.
|
||||||
|
|
||||||
|
@kindex maint set catch-demangler-crashes
|
||||||
|
@kindex maint show catch-demangler-crashes
|
||||||
|
@cindex demangler crashes
|
||||||
|
@item maint set catch-demangler-crashes [on|off]
|
||||||
|
@itemx maint show catch-demangler-crashes
|
||||||
|
Control whether @value{GDBN} should attempt to catch crashes in the
|
||||||
|
symbol name demangler. The default is to attempt to catch crashes.
|
||||||
|
If enabled, the first time a crash is caught, a core file is created,
|
||||||
|
the offending symbol is displayed and the user is presented with the
|
||||||
|
option to terminate the current session.
|
||||||
|
|
||||||
@kindex maint cplus first_component
|
@kindex maint cplus first_component
|
||||||
@item maint cplus first_component @var{name}
|
@item maint cplus first_component @var{name}
|
||||||
Print the first C@t{++} class/namespace component of @var{name}.
|
Print the first C@t{++} class/namespace component of @var{name}.
|
||||||
|
|
25
gdb/main.c
25
gdb/main.c
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
#include "filenames.h"
|
#include "filenames.h"
|
||||||
#include "filestuff.h"
|
#include "filestuff.h"
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
/* The selected interpreter. This will be used as a set command
|
/* The selected interpreter. This will be used as a set command
|
||||||
variable, so it should always be malloc'ed - since
|
variable, so it should always be malloc'ed - since
|
||||||
|
@ -288,6 +289,27 @@ get_init_files (const char **system_gdbinit,
|
||||||
*local_gdbinit = localinit;
|
*local_gdbinit = localinit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to set up an alternate signal stack for SIGSEGV handlers.
|
||||||
|
This allows us to handle SIGSEGV signals generated when the
|
||||||
|
normal process stack is exhausted. If this stack is not set
|
||||||
|
up (sigaltstack is unavailable or fails) and a SIGSEGV is
|
||||||
|
generated when the normal stack is exhausted then the program
|
||||||
|
will behave as though no SIGSEGV handler was installed. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_alternate_signal_stack (void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SIGALTSTACK
|
||||||
|
stack_t ss;
|
||||||
|
|
||||||
|
ss.ss_sp = xmalloc (SIGSTKSZ);
|
||||||
|
ss.ss_size = SIGSTKSZ;
|
||||||
|
ss.ss_flags = 0;
|
||||||
|
|
||||||
|
sigaltstack(&ss, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Call command_loop. If it happens to return, pass that through as a
|
/* Call command_loop. If it happens to return, pass that through as a
|
||||||
non-zero return status. */
|
non-zero return status. */
|
||||||
|
|
||||||
|
@ -785,6 +807,9 @@ captured_main (void *data)
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to set up an alternate signal stack for SIGSEGV handlers. */
|
||||||
|
setup_alternate_signal_stack ();
|
||||||
|
|
||||||
/* Initialize all files. Give the interpreter a chance to take
|
/* Initialize all files. Give the interpreter a chance to take
|
||||||
control of the console via the deprecated_init_ui_hook (). */
|
control of the console via the deprecated_init_ui_hook (). */
|
||||||
gdb_init (gdb_program_name);
|
gdb_init (gdb_program_name);
|
||||||
|
|
Loading…
Add table
Reference in a new issue