diff options
author | Gary Benson <gbenson@redhat.com> | 2014-06-19 09:13:57 +0100 |
---|---|---|
committer | Gary Benson <gbenson@redhat.com> | 2014-06-19 09:13:57 +0100 |
commit | 992c7d700f99002ed455b0588488e0e42719ba81 (patch) | |
tree | c24351fbcff74f41550b27263995ec03be1988ed /gdb | |
parent | eae7090bea9d7f129be7dddf89f8e177cdb2003d (diff) | |
download | gdb-992c7d700f99002ed455b0588488e0e42719ba81.zip gdb-992c7d700f99002ed455b0588488e0e42719ba81.tar.gz gdb-992c7d700f99002ed455b0588488e0e42719ba81.tar.bz2 |
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.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 23 | ||||
-rw-r--r-- | gdb/config.in | 3 | ||||
-rwxr-xr-x | gdb/configure | 2 | ||||
-rw-r--r-- | gdb/configure.ac | 2 | ||||
-rw-r--r-- | gdb/cp-support.c | 146 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 11 | ||||
-rw-r--r-- | gdb/main.c | 25 |
8 files changed, 214 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8e0de8a..84563c3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,28 @@ 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> + * utils.h (resource_limit_kind): New enum. (can_dump_core): New declaration. (warn_cant_dump_core): Likewise. diff --git a/gdb/config.in b/gdb/config.in index cd4ce92..8585b49 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -366,6 +366,9 @@ /* Define to 1 if you have the `sigaction' function. */ #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. */ #undef HAVE_SIGNAL_H diff --git a/gdb/configure b/gdb/configure index 05ebace..a4c0a8c 100755 --- a/gdb/configure +++ b/gdb/configure @@ -10507,7 +10507,7 @@ for ac_func in canonicalize_file_name realpath getrusage getuid getgid \ sigaction sigprocmask sigsetmask socketpair \ ttrace wborder wresize setlocale iconvlist libiconvlist btowc \ setrlimit getrlimit posix_madvise waitpid lstat \ - ptrace64 + ptrace64 sigaltstack do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/gdb/configure.ac b/gdb/configure.ac index 138fc85..a2ac15f 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1328,7 +1328,7 @@ AC_CHECK_FUNCS([canonicalize_file_name realpath getrusage getuid getgid \ sigaction sigprocmask sigsetmask socketpair \ ttrace wborder wresize setlocale iconvlist libiconvlist btowc \ setrlimit getrlimit posix_madvise waitpid lstat \ - ptrace64]) + ptrace64 sigaltstack]) AM_LANGINFO_CODESET GDB_AC_COMMON diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 350451a..a8ea6fc 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -35,6 +35,7 @@ #include "expression.h" #include "value.h" #include "cp-abi.h" +#include <signal.h> #include "safe-ctype.h" @@ -1482,12 +1483,142 @@ cp_lookup_rtti_type (const char *name, struct block *block) 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. */ char * 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". */ @@ -1562,4 +1693,17 @@ _initialize_cp_support (void) Usage: info vtbl EXPRESSION\n\ Evaluate EXPRESSION and display the virtual function table for the\n\ 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 } diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index afe9867..b686271 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,6 +1,11 @@ 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> + + * gdb.texinfo (Maintenance Commands): Document new "maint demangler-warning" command and new "maint set/show demangler-warning" option. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a990d6b..8588f73 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -33236,6 +33236,17 @@ Expand symbol tables. If @var{regexp} is specified, only expand symbol tables for file 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 @item maint cplus first_component @var{name} Print the first C@t{++} class/namespace component of @var{name}. @@ -45,6 +45,7 @@ #include "filenames.h" #include "filestuff.h" +#include <signal.h> /* The selected interpreter. This will be used as a set command variable, so it should always be malloc'ed - since @@ -288,6 +289,27 @@ get_init_files (const char **system_gdbinit, *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 non-zero return status. */ @@ -785,6 +807,9 @@ captured_main (void *data) 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 control of the console via the deprecated_init_ui_hook (). */ gdb_init (gdb_program_name); |