From: Gary Benson <gbenson@redhat.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@broadcom.com>,
Doug Evans <xdje42@gmail.com>,
Eli Zaretskii <eliz@gnu.org>,
Florian Weimer <fw@deneb.enyo.de>,
Mark Kettenis <mark.kettenis@xs4all.nl>,
Pedro Alves <palves@redhat.com>,
Tom Tromey <tromey@redhat.com>
Subject: [PATCH 3/3 v4] Demangler crash handler
Date: Thu, 05 Jun 2014 13:04:00 -0000 [thread overview]
Message-ID: <20140605130358.GD20572@blade.nx> (raw)
In-Reply-To: <20140605130140.GA20572@blade.nx>
This patch 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-05 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-05 Gary Benson <gbenson@redhat.com>
* gdb.texinfo (Maintenance Commands): Document new
"maint set/show catch-demangler-crashes" option.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 903f378..f41ba2f 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/configure b/gdb/configure
index 56c92d3..e23a58f 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/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/main.c b/gdb/main.c
index a9fc378..7031cc3 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -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);
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 91533e8..f4dde70 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -36,6 +36,7 @@
#include "value.h"
#include "cp-abi.h"
#include "language.h"
+#include <signal.h>
#include "safe-ctype.h"
@@ -1505,12 +1506,140 @@ 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 can_dump_core = -1;
+
+ if (can_dump_core == -1)
+ {
+ can_dump_core = check_can_dump_core ();
+
+ if (!can_dump_core)
+ 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 *dmw_msg;
+ struct cleanup *back_to;
+
+ dmw_msg = xstrprintf (_("unable to demangle '%s' "
+ "(demangler failed with signal %d)"),
+ name, crash_signal);
+ back_to = make_cleanup (xfree, dmw_msg);
+
+ if (!can_dump_core)
+ {
+ char *cdc_msg = xstrprintf ("%s:%d: %s: %s",
+ __FILE__, __LINE__,
+ "demangler-warning",
+ dmw_msg);
+
+ make_cleanup (xfree, cdc_msg);
+ warn_cant_dump_core (cdc_msg);
+ }
+
+ demangler_warning (__FILE__, __LINE__, "%s", dmw_msg);
+
+ do_cleanups (back_to);
+
+ error_reported = 1;
+ }
+
+ result = NULL;
+ }
+ }
+#endif
+
+ return result;
}
/* Don't allow just "maintenance cplus". */
@@ -1585,4 +1714,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/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9f7fa18..242117b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33235,6 +33235,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}.
next prev parent reply other threads:[~2014-06-05 13:04 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-06-05 13:01 [PATCH 0/3 " Gary Benson
2014-06-05 13:02 ` [PATCH 1/3 v4] Add new internal problem for demangler warnings Gary Benson
2014-06-05 13:03 ` [PATCH 2/3 v4] Refactor and expose core-dumping functionality Gary Benson
2014-06-05 16:28 ` Doug Evans
2014-06-06 9:09 ` Gary Benson
2014-06-05 13:04 ` Gary Benson [this message]
2014-06-06 18:16 ` [PATCH 3/3 v4] Demangler crash handler Florian Weimer
2014-06-06 19:27 ` Gary Benson
2014-06-06 19:42 ` Florian Weimer
2014-06-06 21:12 ` Andrew Burgess
2014-06-09 9:01 ` Gary Benson
2014-06-09 10:26 ` Andrew Burgess
2014-06-09 11:48 ` Gary Benson
2014-06-05 16:19 ` [PATCH 0/3 " Doug Evans
2014-06-06 9:19 ` Gary Benson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140605130358.GD20572@blade.nx \
--to=gbenson@redhat.com \
--cc=aburgess@broadcom.com \
--cc=eliz@gnu.org \
--cc=fw@deneb.enyo.de \
--cc=gdb-patches@sourceware.org \
--cc=mark.kettenis@xs4all.nl \
--cc=palves@redhat.com \
--cc=tromey@redhat.com \
--cc=xdje42@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).