Demangler crash handler
authorGary Benson <gbenson@redhat.com>
Thu, 19 Jun 2014 08:13:57 +0000 (09:13 +0100)
committerGary Benson <gbenson@redhat.com>
Thu, 19 Jun 2014 08:13:57 +0000 (09:13 +0100)
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.

gdb/ChangeLog
gdb/config.in
gdb/configure
gdb/configure.ac
gdb/cp-support.c
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/main.c

index 8e0de8ae666189c71b6f1221a275e290dc78c9d4..84563c31c00fd946421af2155ddf08d9f48d12ff 100644 (file)
@@ -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>
 
        * utils.h (resource_limit_kind): New enum.
index cd4ce92d022abdcd11a6cae1c190faa6bf69bc1b..8585b49a99a217748a6345511ec0da7a0886186a 100644 (file)
 /* 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
 
index 05ebace030aed899a3a6d5b7690c50dfa5147faf..a4c0a8ce7f5e30939105b9060c1f77f7cdc14af7 100755 (executable)
@@ -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"
index 138fc8558736b877732f6f45218a2e3b85da4d09..a2ac15f6d74407d06178d355720529897727c38a 100644 (file)
@@ -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
 
index 350451a4675bf1edc634c2e1372bdfdd84ce206f..a8ea6fcbea7d088a13a736b711f8c6b45d63ecae 100644 (file)
@@ -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
 }
index afe98670b3b2bbc6b5f3a30be653625e99e145e1..b686271ac5ce560c8c3ff9f01e3a2025ce5e121a 100644 (file)
@@ -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>
 
        * gdb.texinfo (Maintenance Commands): Document new
index a990d6b271d0a5478f8f8c1b5f16805afaf95af4..8588f732d49e5669d743b43fa45d4ccfeab18118 100644 (file)
@@ -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}.
index 108759dcc33a35451a42f97d52e0ea7309d8140b..0d4d5122f2e4ced9fe399ed4b70fe51b58536914 100644 (file)
@@ -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);
This page took 0.18946 seconds and 4 git commands to generate.