From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by sourceware.org (Postfix) with ESMTPS id 0DB77383F414 for ; Thu, 19 Aug 2021 09:49:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0DB77383F414 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wm1-x32c.google.com with SMTP id w24so3437469wmi.5 for ; Thu, 19 Aug 2021 02:49:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=p6mgObEEY2vltuRCbjfVFVUR0Z4syjla9bIdDcodAz4=; b=PwGAvzvo6IDiqVkdv+QpONa5YUKi6l+XlDEdcKPs9aewGU4dVG5p7kWCu+haTqHjhk WSgZXkYW/1vn/Wfv11FAhF7aaz8DT0vdrK3vBsKXmdEj0ZO44xBWGiTFtz4ptGnH/cQm c0Y46aIGi5h40d6DYStusHsNZ43VoAsT3Xw8UGY9f6GY3FGt0y65O9VQUqWaB5oQtbuO fupHwPLpnIqeDLtL/4q5ew6vBHUjvK6NnAcKQ0DIi40PLbG9aS12UGrULQbXy+rN9Lcy Jp26+cwUbSGtVoMsWA8P7/i4vNhteMo7qCVWerVcTuWeiThmZ0bBykeK2j7pqYHD8QA+ fJzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=p6mgObEEY2vltuRCbjfVFVUR0Z4syjla9bIdDcodAz4=; b=OHFNf2ku8WFhi1r0IleXnFhBp7BM+F/x9JQW5m6f7iNM11pgQNEIUPCO6V5G9OUNUI 3S+KuJwisQhVDtlW1YyfQYNh61BcP7iBNZ5ZziVumpC54wDhdbpt8X8x1Q4eta8sRMte uPoXzpqaSK1qZ9DMfK3Zi+eJ9Nqj8OoLhxeXnXMbJ9owqdg3RXx8B7Ijpw9WR+MiIr3k 0Rh1E42hIPJogmraWa/xMoopE0aNP/g/KMYDDeOWn79GU2iLYee61RpaqlAf6u8mVqtM MzVHR6psM5418C+Q9T8b+XzgrM07gqMTp1C/y4qTB23Sgqzps5KNTORTt84okiveksiA XW1w== X-Gm-Message-State: AOAM531KZRRyUpqfgVg/hV7b4MNml/aCGFvnR8Oyu+Ac/fCcyQcnyBV2 zdFPkmB5WavW45yr6zreXK1BkWhZaHAadQ== X-Google-Smtp-Source: ABdhPJw1hP+ybzijONB0nioE0Dvl/p0SNWVMyQnX9bHCt2GGUGZiwZFYMAB/M7QYJXemhFBbJTlaAg== X-Received: by 2002:a05:600c:3b9c:: with SMTP id n28mr12527857wms.15.1629366583896; Thu, 19 Aug 2021 02:49:43 -0700 (PDT) Received: from localhost (host86-188-49-44.range86-188.btcentralplus.com. [86.188.49.44]) by smtp.gmail.com with ESMTPSA id k12sm2374294wrd.75.2021.08.19.02.49.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Aug 2021 02:49:43 -0700 (PDT) From: Andrew Burgess 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 Message-Id: <04cfbd78745b617540a7686ba29f940be8a55fcb.1629366146.git.andrew.burgess@embecosm.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-13.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, WEIRD_PORT autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Aug 2021 09:49:58 -0000 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: . ../../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 . + +# 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