public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Andrew Burgess <andrew.burgess@embecosm.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 6/6] gdb: print backtrace for internal error/warning
Date: Thu, 19 Aug 2021 10:49:31 +0100	[thread overview]
Message-ID: <04cfbd78745b617540a7686ba29f940be8a55fcb.1629366146.git.andrew.burgess@embecosm.com> (raw)
In-Reply-To: <cover.1629366146.git.andrew.burgess@embecosm.com>

This commit builds on previous work to allow GDB to print a backtrace
of itself when GDB encounters an internal-error or internal-warning.

There's not many places where we call internal_warning, and I guess in
most cases the user would probably continue their debug session.  And
so, in order to avoid cluttering up the output, by default, printing
of a backtrace is off for internal-warnings.

In contrast, printing of a backtrace is on by default for
internal-errors, as I figure that in most cases hitting an
internal-error is going to be the end of the debug session.

Whether a backtrace is printed or not can be controlled with the new
settings:

  maintenance set internal-error backtrace on|off
  maintenance show internal-error backtrace

  maintenance set internal-warning backtrace on|off
  maintenance show internal-warning backtrace

Here is an example of what an internal-error now looks like with the
backtrace included:

  (gdb) maintenance internal-error blah
  ../../src.dev-3/gdb/maint.c:82: internal-error: blah
  A problem internal to GDB has been detected,
  further debugging may prove unreliable.
  ----- Backtrace -----
  0x5c61ca gdb_internal_backtrace_1
  	../../src.dev-3/gdb/bt-utils.c:123
  0x5c626d _Z22gdb_internal_backtracev
  	../../src.dev-3/gdb/bt-utils.c:165
  0xe33237 internal_vproblem
  	../../src.dev-3/gdb/utils.c:393
  0xe33539 _Z15internal_verrorPKciS0_P13__va_list_tag
  	../../src.dev-3/gdb/utils.c:470
  0x1549652 _Z14internal_errorPKciS0_z
  	../../src.dev-3/gdbsupport/errors.cc:55
  0x9c7982 maintenance_internal_error
  	../../src.dev-3/gdb/maint.c:82
  0x636f57 do_simple_func
  	../../src.dev-3/gdb/cli/cli-decode.c:97
   .... snip, lots more backtrace lines ....
  ---------------------
  ../../src.dev-3/gdb/maint.c:82: internal-error: blah
  A problem internal to GDB has been detected,
  further debugging may prove unreliable.
  Quit this debugging session? (y or n) y

  This is a bug, please report it.  For instructions, see:
  <https://www.gnu.org/software/gdb/bugs/>.

  ../../src.dev-3/gdb/maint.c:82: internal-error: blah
  A problem internal to GDB has been detected,
  further debugging may prove unreliable.
  Create a core file of GDB? (y or n) n

My hope is that this backtrace might make it slightly easier to
diagnose GDB issues if all that is provided is the console output, I
find that we frequently get reports of an assert being hit that is
located in pretty generic code (frame.c, value.c, etc) and it is not
always obvious how we might have arrived at the assert.
---
 gdb/NEWS                                      |   8 ++
 gdb/doc/gdb.texinfo                           |  13 ++
 .../gdb.base/bt-on-error-and-warning.exp      | 118 ++++++++++++++++++
 gdb/testsuite/gdb.base/bt-on-fatal-signal.exp |  36 ------
 gdb/utils.c                                   |  36 +++++-
 5 files changed, 174 insertions(+), 37 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/bt-on-error-and-warning.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index ec3058ea118..2317c5fe25d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -10,6 +10,14 @@ maint show backtrace-on-fatal-signal
   fatal signal.  This only supported on some platforms where the
   backtrace and backtrace_symbols_fd functions are available.
 
+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.
+
 *** Changes in GDB 11
 
 * The 'set disassembler-options' command now supports specifying options
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 58479ef3ed6..5e3e5fd1241 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -39231,6 +39231,19 @@
 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,
diff --git a/gdb/testsuite/gdb.base/bt-on-error-and-warning.exp b/gdb/testsuite/gdb.base/bt-on-error-and-warning.exp
new file mode 100644
index 00000000000..d988cf742b4
--- /dev/null
+++ b/gdb/testsuite/gdb.base/bt-on-error-and-warning.exp
@@ -0,0 +1,118 @@
+# 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}
+    }
+}
diff --git a/gdb/testsuite/gdb.base/bt-on-fatal-signal.exp b/gdb/testsuite/gdb.base/bt-on-fatal-signal.exp
index 1f0d61f00ed..8875d00fdb1 100644
--- a/gdb/testsuite/gdb.base/bt-on-fatal-signal.exp
+++ b/gdb/testsuite/gdb.base/bt-on-fatal-signal.exp
@@ -135,39 +135,3 @@ foreach test_data {{SEGV "Segmentation fault"} \
 	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] }
-	}
-    }
-}
diff --git a/gdb/utils.c b/gdb/utils.c
index 143c2eddd70..0ab032e48b2 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -75,6 +75,7 @@
 #include "gdbarch.h"
 #include "cli-out.h"
 #include "gdbsupport/gdb-safe-ctype.h"
+#include "bt-utils.h"
 
 void (*deprecated_error_begin_hook) (void);
 
@@ -304,6 +305,13 @@ struct internal_problem
 
   /* 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
@@ -377,9 +385,13 @@ internal_vproblem (struct internal_problem *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
@@ -449,6 +461,7 @@ internal_vproblem (struct internal_problem *problem,
 
 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
@@ -460,6 +473,7 @@ internal_verror (const char *file, int line, const char *fmt, va_list ap)
 
 static struct internal_problem internal_warning_problem = {
   "internal-warning", true, internal_problem_ask, true, internal_problem_ask,
+  true, false
 };
 
 void
@@ -470,6 +484,7 @@ internal_vwarning (const char *file, int line, const char *fmt, va_list ap)
 
 static struct internal_problem demangler_warning_problem = {
   "demangler-warning", true, internal_problem_ask, false, internal_problem_no,
+  false, false
 };
 
 void
@@ -569,6 +584,25 @@ add_internal_problem_command (struct internal_problem *problem)
 			    set_cmd_list,
 			    show_cmd_list);
     }
+
+  if (problem->user_settable_should_print_backtrace)
+    {
+      set_doc
+	= string_printf (_("Set whether GDB should print a backtrace of "
+			   "GDB when %s is detected."), problem->name);
+      show_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_doc.c_str (),
+			       show_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
-- 
2.25.4


  parent reply	other threads:[~2021-08-19  9:49 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-19  9:49 [PATCH 0/6] Display GDB backtrace for internal errors Andrew Burgess
2021-08-19  9:49 ` [PATCH 1/6] gdb: use bool instead of int in struct internal_problem Andrew Burgess
2021-08-19 18:33   ` Simon Marchi
2021-09-07 14:11     ` Andrew Burgess
2021-08-19  9:49 ` [PATCH 2/6] gdb: make use of std::string in utils.c Andrew Burgess
2021-08-19 18:41   ` Simon Marchi
2021-09-07 14:12     ` Andrew Burgess
2021-08-19  9:49 ` [PATCH 3/6] gdb: Add a dependency between gdb and libbacktrace Andrew Burgess
2021-08-19 18:43   ` Simon Marchi
2021-08-27 17:44     ` Tom Tromey
2021-08-30 20:33       ` Andrew Burgess
2021-08-19  9:49 ` [PATCH 4/6] Copy in libbacktrace from gcc Andrew Burgess
2021-08-27 17:46   ` Tom Tromey
2021-08-30 20:34     ` Andrew Burgess
2021-08-19  9:49 ` [PATCH 5/6] gdb: use libbacktrace to create a better backtrace for fatal signals Andrew Burgess
2021-08-19 18:58   ` Simon Marchi
2021-08-19  9:49 ` Andrew Burgess [this message]
2021-08-19 19:01   ` [PATCH 6/6] gdb: print backtrace for internal error/warning Simon Marchi
2021-08-30 14:16 ` [PATCH 0/6] Display GDB backtrace for internal errors Tom de Vries
2021-08-30 20:35   ` Andrew Burgess
2021-08-31 11:17 ` Florian Weimer
2021-09-28 11:26 ` [PUSHED " Andrew Burgess
2021-09-28 11:26   ` [PUSHED 1/6] top-level configure: setup target_configdirs based on repository Andrew Burgess
2021-09-28 11:26   ` [PUSHED 2/6] gdb: Add a dependency between gdb and libbacktrace Andrew Burgess
2021-09-28 11:26   ` [PUSHED 4/6] src-release.sh: add libbacktrace to GDB_SUPPORT_DIRS Andrew Burgess
2021-09-28 11:26   ` [PUSHED 5/6] gdb: use libbacktrace to create a better backtrace for fatal signals Andrew Burgess
2021-09-28 18:55     ` Pedro Alves
2021-09-29  8:21       ` Andrew Burgess
2021-09-29  3:09     ` Simon Marchi
2021-09-29  9:56       ` Andrew Burgess
2021-09-28 11:26   ` [PUSHED 6/6] gdb: print backtrace for internal error/warning Andrew Burgess
2021-09-28 12:26     ` Eli Zaretskii
2021-09-29  8:34       ` Andrew Burgess
2021-09-28 12:20   ` [PUSHED 3/6] Copy in libbacktrace from gcc Andrew Burgess

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=04cfbd78745b617540a7686ba29f940be8a55fcb.1629366146.git.andrew.burgess@embecosm.com \
    --to=andrew.burgess@embecosm.com \
    --cc=gdb-patches@sourceware.org \
    /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).