to open and read source code files, which can be useful if the files
are located over a slow network connection.
+maint set internal-error backtrace on|off
+maint show internal-error backtrace
+maint set internal-warning backtrace on|off
+maint show internal-warning backtrace
+ GDB can now print a backtrace of itself when it encounters either an
+ internal-error, or an internal-warning. This is on by default for
+ internal-error and off by default for internal-warning.
+
* Python API
** New function gdb.add_history(), which takes a gdb.Value object
disabled.
@end table
+@kindex maint set internal-error
+@kindex maint show internal-error
+@kindex maint set internal-warning
+@kindex maint show internal-warning
+@item maint set internal-error backtrace @r{[}on|off@r{]}
+@itemx maint show internal-error backtrace
+@itemx maint set internal-warning backtrace @r{[}on|off@r{]}
+@itemx maint show internal-warning backtrace
+When @value{GDBN} reports an internal problem (error or warning) it is
+possible to have a backtrace of @value{GDBN} printed to stderr. This
+is @samp{on} by default for @code{internal-error} and @samp{off} by
+default for @code{internal-warning}.
+
@kindex maint packet
@item maint packet @var{text}
If @value{GDBN} is talking to an inferior via the serial protocol,
--- /dev/null
+# Copyright 2021 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Test that GDB can print a backtrace when it encounters an internal
+# error or an internal warning, and that this functionality can be
+# switched off.
+
+standard_testfile bt-on-fatal-signal.c
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} {
+ return -1
+}
+
+# Check we can run to main. If this works this time then we just
+# assume that it will work later on (when we repeatedly restart GDB).
+if ![runto_main] then {
+ untested "run to main"
+ return -1
+}
+
+# Check that the backtrace-on-fatal-signal feature is supported. If
+# this target doesn't have the backtrace function available then
+# trying to turn this on will give an error, in which case we just
+# skip this test.
+gdb_test_multiple "maint set internal-error backtrace on" \
+ "check backtrace is supported" {
+ -re "support for this feature is not compiled into GDB" {
+ untested "feature not supported"
+ return -1
+ }
+ -re "$gdb_prompt $" {
+ pass $gdb_test_name
+ }
+}
+
+# MODE should be either 'on' or 'off', while PROBLEM_TYPE should be
+# 'internal-error' or 'internal-warning'. This proc sets the
+# backtrace printing for PROBLEM_TYPE to MODE, then uses 'maint
+# PROBLEM_TYPE foobar' to raise a fake error or warning.
+#
+# We then check that a backtrace either is, or isn't printed, inline
+# with MODE.
+proc run_test {problem_type mode} {
+
+ with_test_prefix "problem=${problem_type}, mode=${mode}" {
+ gdb_test_no_output "maint set ${problem_type} backtrace ${mode}"
+
+ set header_lines 0
+ set bt_lines 0
+
+ gdb_test_multiple "maint ${problem_type} foobar" "scan for backtrace" {
+ -early -re "^\r\n" {
+ exp_continue
+ }
+ -early -re "^maint ${problem_type} foobar\r\n" {
+ exp_continue
+ }
+ -early -re "^\[^\r\n\]+: ${problem_type}: foobar\r\n" {
+ incr header_lines
+ exp_continue
+ }
+ -early -re "^A problem internal to GDB has been detected,\r\n" {
+ incr header_lines
+ exp_continue
+ }
+ -early -re "^further debugging may prove unreliable\\.\r\n" {
+ incr header_lines
+ exp_continue
+ }
+ -early -re "^----- Backtrace -----\r\n" {
+ incr bt_lines
+ exp_continue
+ }
+ -early -re "^\[^-\].+\r\n---------------------\r\n" {
+ incr bt_lines
+ exp_continue
+ }
+ eof {
+ fail ${gdb_test_name}
+ return
+ }
+ -re "$::gdb_prompt $" {
+ pass ${gdb_test_name}
+ }
+ }
+
+ gdb_assert { ${header_lines} == 3 }
+ if { $mode == "on" } {
+ gdb_assert { ${bt_lines} == 2 }
+ } else {
+ gdb_assert { ${bt_lines} == 0 }
+ }
+ }
+}
+
+# For each problem type (error or warning) raise a fake problem using
+# the maintenance commands and check that a backtrace is (or isn't)
+# printed, depending on the user setting.
+foreach problem_type { internal-error internal-warning } {
+ gdb_test_no_output "maint set ${problem_type} corefile no"
+ gdb_test_no_output "maint set ${problem_type} quit no"
+
+ foreach mode { on off } {
+ run_test ${problem_type} ${mode}
+ }
+}
gdb_exit
}
}
-
-# Check that when we get an internal error and choose to dump core, we
-# don't print a backtrace to the console.
-with_test_prefix "internal-error" {
- # Restart GDB.
- clean_restart $binfile
-
- set saw_bt_start false
-
- gdb_test_multiple "maint internal-error foo" "" {
- -early -re "internal-error: foo\r\n" {
- exp_continue
- }
- -early -re "^A problem internal to GDB has been detected,\r\n" {
- exp_continue
- }
- -early -re "^further debugging may prove unreliable\\.\r\n" {
- exp_continue
- }
- -early -re "^Quit this debugging session\\? \\(y or n\\)" {
- send_gdb "y\n"
- exp_continue
- }
- -early -re "^Create a core file of GDB\\? \\(y or n\\)" {
- send_gdb "y\n"
- exp_continue
- }
- -early -re "----- Backtrace -----\r\n" {
- set saw_bt_start true
- exp_continue
- }
- eof {
- gdb_assert { [expr ! $saw_bt_start] }
- }
- }
-}
#include "gdbarch.h"
#include "cli-out.h"
#include "gdbsupport/gdb-safe-ctype.h"
+#include "bt-utils.h"
void (*deprecated_error_begin_hook) (void);
/* Like SHOULD_QUIT, but whether GDB should dump core. */
const char *should_dump_core;
+
+ /* Like USER_SETTABLE_SHOULD_QUIT but for SHOULD_PRINT_BACKTRACE. */
+ bool user_settable_should_print_backtrace;
+
+ /* When this is true GDB will print a backtrace when a problem of this
+ type is encountered. */
+ bool should_print_backtrace;
};
/* Report a problem, internal to GDB, to the user. Once the problem
/* Emit the message unless query will emit it below. */
if (problem->should_quit != internal_problem_ask
|| !confirm
- || !filtered_printing_initialized ())
+ || !filtered_printing_initialized ()
+ || problem->should_print_backtrace)
fprintf_unfiltered (gdb_stderr, "%s\n", reason.c_str ());
+ if (problem->should_print_backtrace)
+ gdb_internal_backtrace ();
+
if (problem->should_quit == internal_problem_ask)
{
/* Default (yes/batch case) is to quit GDB. When in batch mode
static struct internal_problem internal_error_problem = {
"internal-error", true, internal_problem_ask, true, internal_problem_ask,
+ true, GDB_PRINT_INTERNAL_BACKTRACE_INIT_ON
};
void
static struct internal_problem internal_warning_problem = {
"internal-warning", true, internal_problem_ask, true, internal_problem_ask,
+ true, false
};
void
static struct internal_problem demangler_warning_problem = {
"demangler-warning", true, internal_problem_ask, false, internal_problem_no,
+ false, false
};
void
set_cmd_list,
show_cmd_list);
}
+
+ if (problem->user_settable_should_print_backtrace)
+ {
+ std::string set_bt_doc
+ = string_printf (_("Set whether GDB should print a backtrace of "
+ "GDB when %s is detected."), problem->name);
+ std::string show_bt_doc
+ = string_printf (_("Show whether GDB will print a backtrace of "
+ "GDB when %s is detected."), problem->name);
+ add_setshow_boolean_cmd ("backtrace", class_maintenance,
+ &problem->should_print_backtrace,
+ set_bt_doc.c_str (),
+ show_bt_doc.c_str (),
+ NULL, /* help_doc */
+ gdb_internal_backtrace_set_cmd,
+ NULL, /* showfunc */
+ set_cmd_list,
+ show_cmd_list);
+ }
}
/* Return a newly allocated string, containing the PREFIX followed