diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 320d3326a81..5a3bb952279 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -248,6 +248,10 @@ GDBFLAGS =
GNULIB_PARENT_DIR = ..
include $(GNULIB_PARENT_DIR)/gnulib/Makefile.gnulib.inc
+# For libbacktrace.
+LIBBACKTRACE_INC=@LIBBACKTRACE_INC@
+LIBBACKTRACE_LIB=@LIBBACKTRACE_LIB@
+
SUPPORT = ../gdbsupport
LIBSUPPORT = $(SUPPORT)/libgdbsupport.a
INCSUPPORT = -I$(srcdir)/.. -I..
@@ -614,9 +618,9 @@ INTERNAL_CFLAGS_BASE = \
$(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
- $(INTL_CFLAGS) $(INCGNU) $(INCSUPPORT) $(ENABLE_CFLAGS) \
- $(INTERNAL_CPPFLAGS) $(SRCHIGH_CFLAGS) $(TOP_CFLAGS) $(PTHREAD_CFLAGS) \
- $(DEBUGINFOD_CFLAGS)
+ $(INTL_CFLAGS) $(INCGNU) $(INCSUPPORT) $(LIBBACKTRACE_INC) \
+ $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) $(SRCHIGH_CFLAGS) \
+ $(TOP_CFLAGS) $(PTHREAD_CFLAGS) $(DEBUGINFOD_CFLAGS)
INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
@@ -637,12 +641,12 @@ INTERNAL_LDFLAGS = \
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
$(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
- $(XM_CLIBS) $(GDBTKLIBS) \
+ $(XM_CLIBS) $(GDBTKLIBS) $(LIBBACKTRACE_LIB) \
@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
$(WIN32LIBS) $(LIBGNU) $(LIBGNU_EXTRA_LIBS) $(LIBICONV) \
$(LIBMPFR) $(LIBGMP) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
- $(DEBUGINFOD_LIBS)
+ $(DEBUGINFOD_LIBS) $(LIBBABELTRACE_LIB)
CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(CTF_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) \
$(LIBSUPPORT)
@@ -995,6 +999,7 @@ COMMON_SFILES = \
break-catch-syscall.c \
break-catch-throw.c \
breakpoint.c \
+ bt-utils.c \
btrace.c \
build-id.c \
buildsym-legacy.c \
@@ -1256,6 +1261,7 @@ HFILES_NO_SRCDIR = \
breakpoint.h \
bsd-kvm.h \
bsd-uthread.h \
+ bt-utils.h \
build-id.h \
buildsym-legacy.h \
buildsym.h \
diff --git a/gdb/bt-utils.c b/gdb/bt-utils.c
new file mode 100644
index 00000000000..b5e0a0ed004
--- /dev/null
+++ b/gdb/bt-utils.c
@@ -0,0 +1,170 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#include "defs.h"
+#include "bt-utils.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "top.h"
+#include "cli/cli-decode.h"
+
+/* See bt-utils.h. */
+
+void
+gdb_internal_backtrace_set_cmd (const char *args, int from_tty,
+ cmd_list_element *c)
+{
+ gdb_assert (c->type == set_cmd);
+ gdb_assert (c->var_type == var_boolean);
+ gdb_assert (c->var != nullptr);
+
+#ifndef GDB_PRINT_INTERNAL_BACKTRACE
+ bool *var_ptr = (bool *) c->var;
+
+ if (*var_ptr)
+ {
+ *var_ptr = false;
+ error (_("support for this feature is not compiled into GDB"));
+ }
+#endif
+}
+
+#ifdef GDB_PRINT_INTERNAL_BACKTRACE_USING_LIBBACKTRACE
+
+/* Callback used by libbacktrace if it encounters an error. */
+
+static void
+libbacktrace_error (void *data, const char *errmsg, int errnum)
+{
+ /* A negative errnum indicates no debug info was available, just
+ skip printing a backtrace in this case. */
+ if (errnum < 0)
+ return;
+
+ const auto sig_write = [] (const char *msg) -> void
+ {
+ gdb_stderr->write_async_safe (msg, strlen (msg));
+ };
+
+ sig_write ("error creating backtrace: ");
+ sig_write (errmsg);
+ if (errnum > 0)
+ {
+ char buf[20];
+ snprintf (buf, sizeof (buf), ": %d", errnum);
+ buf[sizeof (buf) - 1] = '\0';
+
+ sig_write (buf);
+ }
+ sig_write ("\n");
+}
+
+/* Callback used by libbacktrace to print a single stack frame. */
+
+static int
+libbacktrace_print (void *data, uintptr_t pc, const char *filename,
+ int lineno, const char *function)
+{
+ const auto sig_write = [] (const char *msg) -> void
+ {
+ gdb_stderr->write_async_safe (msg, strlen (msg));
+ };
+
+ /* Buffer to print addresses and line numbers into. An 8-byte address
+ with '0x' prefix and a null terminator requires 20 characters. This
+ also feels like it should be enough to represent line numbers in most
+ files. We are also careful to ensure we don't overflow this buffer. */
+ char buf[20];
+
+ snprintf (buf, sizeof (buf), "0x%lx ", pc);
+ buf[sizeof (buf) - 1] = '\0';
+ sig_write (buf);
+ sig_write (function == nullptr ? "???" : function);
+ if (filename != nullptr)
+ {
+ sig_write ("\n\t");
+ sig_write (filename);
+ sig_write (":");
+ snprintf (buf, sizeof (buf), "%d", lineno);
+ buf[sizeof (buf) - 1] = '\0';
+ sig_write (buf);
+ }
+ sig_write ("\n");
+
+ return function != nullptr && strcmp (function, "main") == 0;
+}
+
+/* Write a backtrace to GDB's stderr in an async safe manor. This is a
+ backtrace of GDB, not any running inferior, and is to be used when GDB
+ crashes or hits some other error condition. */
+
+static void
+gdb_internal_backtrace_1 ()
+{
+ static struct backtrace_state *state = nullptr;
+
+ if (state == nullptr)
+ state = backtrace_create_state (nullptr, 0, libbacktrace_error, nullptr);
+
+ backtrace_full (state, 0, libbacktrace_print, libbacktrace_error, nullptr);
+}
+
+#elif defined GDB_PRINT_INTERNAL_BACKTRACE_USING_EXECINFO
+
+/* See the comment on previous version of this function. */
+
+static void
+gdb_internal_backtrace_1 ()
+{
+ const auto sig_write = [] (const char *msg) -> void
+ {
+ gdb_stderr->write_async_safe (msg, strlen (msg));
+ };
+
+ /* Allow up to 25 frames of backtrace. */
+ void *buffer[25];
+ int frames = backtrace (buffer, ARRAY_SIZE (buffer));
+
+ backtrace_symbols_fd (buffer, frames, gdb_stderr->fd ());
+ if (frames == ARRAY_SIZE (buffer))
+ sig_write (_("Backtrace might be incomplete.\n"));
+}
+
+#endif
+
+/* See bt-utils.h. */
+
+void
+gdb_internal_backtrace ()
+{
+ if (current_ui == nullptr)
+ return;
+
+ const auto sig_write = [] (const char *msg) -> void
+ {
+ gdb_stderr->write_async_safe (msg, strlen (msg));
+ };
+
+ sig_write (_("----- Backtrace -----\n"));
+
+ if (gdb_stderr->fd () > -1)
+ gdb_internal_backtrace_1 ();
+ else
+ sig_write (_("Backtrace unavailable\n"));
+
+ sig_write ("---------------------\n");
+}
diff --git a/gdb/bt-utils.h b/gdb/bt-utils.h
new file mode 100644
index 00000000000..433aa23614b
--- /dev/null
+++ b/gdb/bt-utils.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+/* Support for printing a backtrace when GDB hits an error. This is not
+ for printing backtraces of the inferior, but backtraces of GDB itself. */
+
+#ifdef HAVE_LIBBACKTRACE
+# include "backtrace.h"
+# include "backtrace-supported.h"
+# if BACKTRACE_SUPPORTED && (! BACKTRACE_USES_MALLOC)
+# define GDB_PRINT_INTERNAL_BACKTRACE
+# define GDB_PRINT_INTERNAL_BACKTRACE_USING_LIBBACKTRACE
+# endif
+#endif
+
+#if defined HAVE_EXECINFO_H \
+ && defined HAVE_EXECINFO_BACKTRACE \
+ && !defined PRINT_BACKTRACE_ON_FATAL_SIGNAL
+# include
+# define GDB_PRINT_INTERNAL_BACKTRACE
+# define GDB_PRINT_INTERNAL_BACKTRACE_USING_EXECINFO
+#endif
+
+/* Define GDB_PRINT_INTERNAL_BACKTRACE_INIT_ON. This is a boolean value
+ that can be used as an initial value for a set/show user setting, where
+ the setting controls printing a GDB internal backtrace.
+
+ If backtrace printing is supported then this will have the value true,
+ but if backtrace printing is not supported then this has the value
+ false. */
+#ifdef GDB_PRINT_INTERNAL_BACKTRACE
+# define GDB_PRINT_INTERNAL_BACKTRACE_INIT_ON true
+#else
+# define GDB_PRINT_INTERNAL_BACKTRACE_INIT_ON false
+#endif
+
+/* Print a backtrace of the current GDB process to the current
+ gdb_stderr. The output is done in a signal async manor, so it is safe
+ to call from signal handlers. */
+
+extern void gdb_internal_backtrace ();
+
+/* A generic function that can be used as the set function for any set
+ command that enables printing of an internal backtrace. Command C must
+ be a boolean set command.
+
+ If GDB doesn't support printing a backtrace, and the user has tried to
+ set the variable associated with command C to true, then the associated
+ variable will be set back to false, and an error thrown.
+
+ If GDB does support printing a backtrace then this function does
+ nothing. */
+
+extern void gdb_internal_backtrace_set_cmd (const char *args, int from_tty,
+ cmd_list_element *c);
diff --git a/gdb/config.in b/gdb/config.in
index af3680c6d95..c61f7a91352 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -228,6 +228,9 @@
/* Define if you have the babeltrace library. */
#undef HAVE_LIBBABELTRACE
+/* Define if libbacktrace is being used. */
+#undef HAVE_LIBBACKTRACE
+
/* Define to 1 if debuginfod is enabled. */
#undef HAVE_LIBDEBUGINFOD
diff --git a/gdb/configure b/gdb/configure
index f0b1af4a6ea..7c8335f2576 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -636,6 +636,8 @@ LIBCTF
LTLIBBABELTRACE
LIBBABELTRACE
HAVE_LIBBABELTRACE
+LIBBACKTRACE_LIB
+LIBBACKTRACE_INC
HAVE_NATIVE_GCORE_HOST
NAT_GENERATED_FILES
XM_CLIBS
@@ -925,6 +927,7 @@ with_tcl
with_tk
with_x
enable_sim
+enable_libbacktrace
with_babeltrace
with_libbabeltrace_prefix
with_libbabeltrace_type
@@ -1601,6 +1604,8 @@ Optional Features:
gcc is used
--enable-ubsan enable undefined behavior sanitizer (auto/yes/no)
--enable-sim link gdb with simulator
+ --enable-libbacktrace use libbacktrace to write a backtrace after a fatal
+ signal.
--enable-libctf Handle .ctf type-info sections [default=yes]
--enable-unit-tests Enable the inclusion of unit tests when compiling
GDB
@@ -18659,6 +18664,33 @@ _ACEOF
fi
+# Setup possible use of libbacktrace.
+# Check whether --enable-libbacktrace was given.
+if test "${enable_libbacktrace+set}" = set; then :
+ enableval=$enable_libbacktrace; case "${enableval}" in
+ yes) enable_libbacktrace=yes ;;
+ no) enable_libbacktrace=no ;;
+ *) as_fn_error $? "bad value ${enableval} for --enable-libbacktrace option" "$LINENO" 5 ;;
+esac
+else
+ enable_libbacktrace=yes
+fi
+
+
+if test "${enable_libbacktrace}" == "yes"; then
+ LIBBACKTRACE_INC="-I$srcdir/../libbacktrace/ -I../libbacktrace/"
+ LIBBACKTRACE_LIB=../libbacktrace/.libs/libbacktrace.a
+
+$as_echo "#define HAVE_LIBBACKTRACE 1" >>confdefs.h
+
+else
+ LIBBACKTRACE_INC=
+ LIBBACKTRACE_LIB=
+fi
+
+
+
+
# Check for babeltrace and babeltrace-ctf
# Check whether --with-babeltrace was given.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 93f11316a14..0d91be59cd6 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2131,6 +2131,29 @@ if test x"${gdb_osabi}" != x ; then
[Define to the default OS ABI for this configuration.])
fi
+# Setup possible use of libbacktrace.
+AC_ARG_ENABLE([libbacktrace],
+[AS_HELP_STRING([--enable-libbacktrace],
+ [use libbacktrace to write a backtrace after a fatal signal.])],
+[case "${enableval}" in
+ yes) enable_libbacktrace=yes ;;
+ no) enable_libbacktrace=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-libbacktrace option) ;;
+esac],
+enable_libbacktrace=yes)
+
+if test "${enable_libbacktrace}" == "yes"; then
+ LIBBACKTRACE_INC="-I$srcdir/../libbacktrace/ -I../libbacktrace/"
+ LIBBACKTRACE_LIB=../libbacktrace/.libs/libbacktrace.a
+ AC_DEFINE(HAVE_LIBBACKTRACE, 1, [Define if libbacktrace is being used.])
+else
+ LIBBACKTRACE_INC=
+ LIBBACKTRACE_LIB=
+fi
+
+AC_SUBST(LIBBACKTRACE_INC)
+AC_SUBST(LIBBACKTRACE_LIB)
+
# Check for babeltrace and babeltrace-ctf
AC_ARG_WITH(babeltrace,
AS_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 9233a3650ac..64c624ce4d7 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -41,15 +41,12 @@
#include "gdbsupport/gdb_select.h"
#include "gdbsupport/gdb-sigmask.h"
#include "async-event.h"
+#include "bt-utils.h"
/* readline include files. */
#include "readline/readline.h"
#include "readline/history.h"
-#ifdef HAVE_EXECINFO_H
-# include
-#endif /* HAVE_EXECINFO_H */
-
/* readline defines this. */
#undef savestring
@@ -102,12 +99,7 @@ int call_stdin_event_handler_again_p;
/* When true GDB will produce a minimal backtrace when a fatal signal is
reached (within GDB code). */
-static bool bt_on_fatal_signal
-#ifdef HAVE_EXECINFO_BACKTRACE
- = true;
-#else
- = false;
-#endif /* HAVE_EXECINFO_BACKTRACE */
+static bool bt_on_fatal_signal = GDB_PRINT_INTERNAL_BACKTRACE_INIT_ON;
/* Implement 'maintenance show backtrace-on-fatal-signal'. */
@@ -118,20 +110,6 @@ show_bt_on_fatal_signal (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("Backtrace on a fatal signal is %s.\n"), value);
}
-/* Implement 'maintenance set backtrace-on-fatal-signal'. */
-
-static void
-set_bt_on_fatal_signal (const char *args, int from_tty, cmd_list_element *c)
-{
-#ifndef HAVE_EXECINFO_BACKTRACE
- if (bt_on_fatal_signal)
- {
- bt_on_fatal_signal = false;
- error (_("support for this feature is not compiled into GDB"));
- }
-#endif
-}
-
/* Signal handling variables. */
/* Each of these is a pointer to a function that the event loop will
invoke if the corresponding signal has received. The real signal
@@ -904,7 +882,7 @@ unblock_signal (int sig)
static void ATTRIBUTE_NORETURN
handle_fatal_signal (int sig)
{
-#ifdef HAVE_EXECINFO_BACKTRACE
+#ifdef GDB_PRINT_INTERNAL_BACKTRACE
const auto sig_write = [] (const char *msg) -> void
{
gdb_stderr->write_async_safe (msg, strlen (msg));
@@ -917,19 +895,8 @@ handle_fatal_signal (int sig)
sig_write (strsignal (sig));
sig_write ("\n");
- /* Allow up to 25 frames of backtrace. */
- void *buffer[25];
- int frames = backtrace (buffer, ARRAY_SIZE (buffer));
- sig_write (_("----- Backtrace -----\n"));
- if (gdb_stderr->fd () > -1)
- {
- backtrace_symbols_fd (buffer, frames, gdb_stderr->fd ());
- if (frames == ARRAY_SIZE (buffer))
- sig_write (_("Backtrace might be incomplete.\n"));
- }
- else
- sig_write (_("Backtrace unavailable\n"));
- sig_write ("---------------------\n");
+ gdb_internal_backtrace ();
+
sig_write (_("A fatal error internal to GDB has been detected, "
"further\ndebugging is not possible. GDB will now "
"terminate.\n\n"));
@@ -944,7 +911,7 @@ handle_fatal_signal (int sig)
gdb_stderr->flush ();
}
-#endif /* HAVE_EXECINF_BACKTRACE */
+#endif
/* If possible arrange for SIG to have its default behaviour (which
should be to terminate the current process), unblock SIG, and reraise
@@ -1449,7 +1416,7 @@ Use \"on\" to enable, \"off\" to disable.\n\
If enabled, GDB will produce a minimal backtrace if it encounters a fatal\n\
signal from within GDB itself. This is a mechanism to help diagnose\n\
crashes within GDB, not a mechanism for debugging inferiors."),
- set_bt_on_fatal_signal,
+ gdb_internal_backtrace_set_cmd,
show_bt_on_fatal_signal,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);