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..
$(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)
# 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)
break-catch-syscall.c \
break-catch-throw.c \
breakpoint.c \
+ bt-utils.c \
btrace.c \
build-id.c \
buildsym-legacy.c \
breakpoint.h \
bsd-kvm.h \
bsd-uthread.h \
+ bt-utils.h \
build-id.h \
buildsym-legacy.h \
buildsym.h \
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#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");
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+/* 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 <execinfo.h>
+# 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);
/* 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
LTLIBBABELTRACE
LIBBABELTRACE
HAVE_LIBBABELTRACE
+LIBBACKTRACE_LIB
+LIBBACKTRACE_INC
HAVE_NATIVE_GCORE_HOST
NAT_GENERATED_FILES
XM_CLIBS
with_tk
with_x
enable_sim
+enable_libbacktrace
with_babeltrace
with_libbabeltrace_prefix
with_libbabeltrace_type
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
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.
[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)]),
#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 <execinfo.h>
-#endif /* HAVE_EXECINFO_H */
-
/* readline defines this. */
#undef savestring
/* 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'. */
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
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));
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"));
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
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);