From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by sourceware.org (Postfix) with ESMTPS id 9A386383302B for ; Wed, 21 Jul 2021 18:09:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9A386383302B 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-x336.google.com with SMTP id x14-20020a7bc20e0000b0290249f2904453so1276514wmi.1 for ; Wed, 21 Jul 2021 11:09:03 -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=v9ff1X9LKERYDz7dc/7PuS7Ov6wUtoRnbI2GMERA9CY=; b=Pn14m9m/+FANBRwT6N/v24QtNqD0BKdT17IkBkRfeJ48kUdQOvk3SwVBeCesugLHqN Bql7JcgIZZ/tbKzLLKM23aktXc06u0JpKwMoN3y48cmirz6gmNCgMOwzYUaj7smYdiHA iQX5vzsXbiIgyhSl4/xPGYGIn+JwKW6XhYLFT1V93JbXensplNqbir3H0+PsiwWdnL1r jZYRicXGrBen88SKmK2cnJf9ZQnzJj2lv9+iWTQ7Wl8DASDelJYByo5ZPEiemE6AC6a6 H2f1XopmCW1+1+xP6+0wFhAtu9n8Y1Wykh+ljZO8HNOEW52IckwYn0hjmx/QdR50LEPP uxsQ== 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=v9ff1X9LKERYDz7dc/7PuS7Ov6wUtoRnbI2GMERA9CY=; b=GYnJ1HZmr9kbOZT/wt6Vy862EbpCqrhL0Rddu3FK9ShWyYh+KJnjweq6/Dij6rXmM2 TS7YGQ3EOXcYrKrUqaWXDjwC2EO/3sOAanxcOFi55CaCv6jrk+KHlQE78Vp0lB2QsgRA QVRrTog0qO7QOudpqXwFuRD/IOufw5TV3ZrQQyCMMUTIoTQ8gLlGDZsNjBbPX0NKU7MM drD0YgIPDW1847FTiWZSmO+z/4VdKVS7j4p64pMDUGARvXfvW7p9zAYRb2xlcL+XX5NB pDODMdP5K0asRwaDbRJ2QwKpodIH/p3yeMSqUw9+7yi6x4VC/5BHTVpmofwzSNsobCfu kgqw== X-Gm-Message-State: AOAM532l+sn6ltpjajTX+Ph+hHrVV3PHvSmEYnxdeMxbL06L/nGu3/zt H/8OrjGLZppkypM/rNsoiBkbbkf4fz2Sog== X-Google-Smtp-Source: ABdhPJyu4UFgV1Ma4WuNOFr0qHAQeRMM5DrwxKEn0wVONo6G1Tt78g1YqLC6/0WP5G6dpo9P0DoD+A== X-Received: by 2002:a05:600c:3b1b:: with SMTP id m27mr6531977wms.35.1626890942298; Wed, 21 Jul 2021 11:09:02 -0700 (PDT) Received: from localhost (host86-134-238-200.range86-134.btcentralplus.com. [86.134.238.200]) by smtp.gmail.com with ESMTPSA id p12sm575976wma.19.2021.07.21.11.09.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Jul 2021 11:09:01 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Subject: [PATCHv2 4/6] gdb: print backtrace on fatal SIGSEGV Date: Wed, 21 Jul 2021 19:08:51 +0100 Message-Id: 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=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP 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: Wed, 21 Jul 2021 18:09:06 -0000 This commit adds a new maintenance feature, the ability to print a (limited) backtrace if GDB dies due to a fatal signal. The backtrace is produced using the backtrace and backtrace_symbols_fd functions which are declared in the execinfo.h header, and both of which are async signal safe. A configure check has been added to check for these features, if they are not available then the new code is not compiled into GDB and the backtrace will not be printed. The motivation for this new feature is to aid in debugging GDB in situations where GDB has crashed at a users site, but the user is reluctant to share core files, possibly due to concerns about what might be in the memory image within the core file. Such a user might be happy to share a simple backtrace that was written to stderr. The production of the backtrace is on by default, but can switched off using the new commands: maintenance set backtrace-on-fatal-signal on|off maintenance show backtrace-on-fatal-signal Right now, I have hooked this feature in to GDB's existing handling of SIGSEGV only, but this will be extended to more signals in a later commit. One additional change I have made in this commit is that, when we decide GDB should terminate due to the fatal signal, we now raise the same fatal signal rather than raising SIGABRT. Currently, this is only effecting our handling of SIGSEGV. So, previously, if GDB hit a SEGV then we would terminate GDB with a SIGABRT. After this commit we will terminate GDB with a SIGSEGV. This feels like an improvement to me, we should still get a core dump, but in many shells, the user will see a more specific message once GDB exits, in bash for example "Segmentation fault" rather than "Aborted". Finally then, here is an example of the output a user would see if GDB should hit an internal SIGSEGV: Fatal signal: Segmentation fault ----- Backtrace ----- ./gdb/gdb[0x8078e6] ./gdb/gdb[0x807b20] /lib64/libpthread.so.0(+0x14b20)[0x7f6648c92b20] /lib64/libc.so.6(__poll+0x4f)[0x7f66484d3a5f] ./gdb/gdb[0x1540f4c] ./gdb/gdb[0x154034a] ./gdb/gdb[0x9b002d] ./gdb/gdb[0x9b014d] ./gdb/gdb[0x9b1aa6] ./gdb/gdb[0x9b1b0c] ./gdb/gdb[0x41756d] /lib64/libc.so.6(__libc_start_main+0xf3)[0x7f66484041a3] ./gdb/gdb[0x41746e] --------------------- A fatal error internal to GDB has been detected, further debugging is not possible. GDB will now terminate. This is a bug, please report it. For instructions, see: . Segmentation fault (core dumped) It is disappointing that backtrace_symbols_fd does not actually map the addresses back to symbols, this appears, in part, to be due to GDB not being built with -rdynamic as the manual page for backtrace_symbols_fd suggests, however, even when I do add -rdynamic to the build of GDB I only see symbols for some addresses. We could potentially look at alternative libraries to provide the backtrace (e.g. libunwind) however, the solution presented here, which is available as part of glibc is probably a good baseline from which we might improve things in future. --- gdb/NEWS | 7 + gdb/config.in | 6 + gdb/configure | 51 +++++++ gdb/configure.ac | 22 +++ gdb/doc/gdb.texinfo | 18 +++ gdb/event-top.c | 140 ++++++++++++++++-- gdb/testsuite/gdb.base/bt-on-fatal-signal.c | 22 +++ gdb/testsuite/gdb.base/bt-on-fatal-signal.exp | 134 +++++++++++++++++ gdb/ui-file.h | 9 ++ 9 files changed, 398 insertions(+), 11 deletions(-) create mode 100644 gdb/testsuite/gdb.base/bt-on-fatal-signal.c create mode 100644 gdb/testsuite/gdb.base/bt-on-fatal-signal.exp diff --git a/gdb/NEWS b/gdb/NEWS index 062249aea98..764558789f3 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,13 @@ *** Changes since GDB 11 +maint set backtrace-on-fatal-signal on|off +maint show backtrace-on-fatal-signal + This setting is 'on' by default. When 'on' GDB will print a limited + backtrace to stderr in the situation where GDB terminates with a + fatal signal. This only supported on some platforms where the + backtrace and backtrace_symbols_fd functions are available. + *** Changes in GDB 11 * The 'set disassembler-options' command now supports specifying options diff --git a/gdb/config.in b/gdb/config.in index 2c30504905b..af3680c6d95 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -162,6 +162,12 @@ /* Define to 1 if your system has the etext variable. */ #undef HAVE_ETEXT +/* Define to 1 if execinfo.h backtrace functions are available. */ +#undef HAVE_EXECINFO_BACKTRACE + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H + /* Define to 1 if you have the `fdwalk' function. */ #undef HAVE_FDWALK diff --git a/gdb/configure b/gdb/configure index 5d89635c043..f0b1af4a6ea 100755 --- a/gdb/configure +++ b/gdb/configure @@ -12315,6 +12315,18 @@ fi done +for ac_header in execinfo.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default" +if test "x$ac_cv_header_execinfo_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXECINFO_H 1 +_ACEOF + +fi + +done + # ------------------------- # # Checks for declarations. # @@ -16484,6 +16496,45 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $found" >&5 $as_echo "$found" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether execinfo.h backtrace is available" >&5 +$as_echo_n "checking whether execinfo.h backtrace is available... " >&6; } +if ${gdb_cv_execinfo_backtrace+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main () +{ + + int f; + void *b[2]; + f = backtrace (b, 2); + backtrace_symbols_fd (b, f, 2); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gdb_cv_execinfo_backtrace=yes +else + gdb_cv_execinfo_backtrace=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_execinfo_backtrace" >&5 +$as_echo "$gdb_cv_execinfo_backtrace" >&6; } +if test "$gdb_cv_execinfo_backtrace" = yes; then + +$as_echo "#define HAVE_EXECINFO_BACKTRACE 1" >>confdefs.h + +fi + if test "${build}" = "${host}" -a "${host}" = "${target}" ; then case ${host_os} in diff --git a/gdb/configure.ac b/gdb/configure.ac index b8c79bcac9a..93f11316a14 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1291,6 +1291,7 @@ AC_CHECK_HEADERS(term.h, [], [], AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([ws2tcpip.h]) +AC_CHECK_HEADERS([execinfo.h]) # ------------------------- # # Checks for declarations. # @@ -1682,6 +1683,27 @@ fi AC_SUBST(RDYNAMIC) AC_MSG_RESULT($found) +AC_CACHE_CHECK( + [whether execinfo.h backtrace is available], + gdb_cv_execinfo_backtrace, + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [ + #include + ], + [ + int f; + void *b[[2]]; + f = backtrace (b, 2); + backtrace_symbols_fd (b, f, 2); + ])], + [gdb_cv_execinfo_backtrace=yes], + [gdb_cv_execinfo_backtrace=no])]) +if test "$gdb_cv_execinfo_backtrace" = yes; then + AC_DEFINE(HAVE_EXECINFO_BACKTRACE, 1, + [Define to 1 if execinfo.h backtrace functions are available.]) +fi + dnl For certain native configurations, we need to check whether thread dnl support can be built in or not. dnl diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 386cef7bd4e..dc8c1a70b52 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -39715,6 +39715,24 @@ @value{GDBN} supports. They are used by the testsuite for exercising the settings infrastructure. +@kindex maint set backtrace-on-fatal-signal +@kindex maint show backtrace-on-fatal-signal +@item maint set backtrace-on-fatal-signal [on|off] +@itemx maint show backtrace-on-fatal-signal +When this setting is @code{on}, if @value{GDBN} itself terminates with +a fatal signal (e.g.@: SIGSEGV), then a limited backtrace will be +printed to stderr. This backtrace can be used to help diagnose +crashes within @value{GDBN} in situations where a user is unable to +share a corefile with the @value{GDBN} developers. + +If the functionality to provide this backtrace is not available for +the platform on which GDB is running then this feature will be +@code{off} by default, and attempting to turn this feature on will +give an error. + +For platforms that do support creating the backtrace this feature is +@code{on} by default. + @kindex maint with @item maint with @var{setting} [@var{value}] [-- @var{command}] Like the @code{with} command, but works with @code{maintenance set} diff --git a/gdb/event-top.c b/gdb/event-top.c index 972b540c8b8..b5dfd43f621 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -46,6 +46,10 @@ #include "readline/readline.h" #include "readline/history.h" +#ifdef HAVE_EXECINFO_H +# include +#endif /* HAVE_EXECINFO_H */ + /* readline defines this. */ #undef savestring @@ -96,6 +100,38 @@ bool exec_done_display_p = false; run again. */ 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 */ + +/* Implement 'maintenance show backtrace-on-fatal-signal'. */ + +static void +show_bt_on_fatal_signal (struct ui_file *file, int from_tty, + struct cmd_list_element *cmd, const char *value) +{ + 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 @@ -846,6 +882,84 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) } +/* Attempt to unblock signal SIG, return true if the signal was unblocked, + otherwise, return false. */ + +static bool +unblock_signal (int sig) +{ +#if HAVE_SIGPROCMASK + sigset_t sigset; + sigemptyset (&sigset); + sigaddset (&sigset, sig); + gdb_sigmask (SIG_UNBLOCK, &sigset, 0); + return true; +#endif + + return false; +} + +/* Called to handle fatal signals. SIG is the signal number. */ + +static void ATTRIBUTE_NORETURN +handle_fatal_signal (int sig) +{ +#ifdef HAVE_EXECINFO_BACKTRACE + const auto sig_write = [] (const char *msg) -> void + { + gdb_stderr->write_async_safe (msg, strlen (msg)); + }; + + if (bt_on_fatal_signal) + { + sig_write ("\n\n"); + sig_write (_("Fatal signal: ")); + sig_write (strsignal (sig)); + sig_write ("\n"); + + /* Allow up to 25 frames of backtrace. */ + void *buffer[25]; + int frames = backtrace (buffer, sizeof(buffer) / sizeof(buffer[0])); + sig_write (_("----- Backtrace -----\n")); + if (gdb_stderr->fd () > -1) + { + backtrace_symbols_fd (buffer, frames, gdb_stderr->fd ()); + if (frames == (sizeof(buffer) / sizeof(buffer[0]))) + sig_write (_("Backtrace might be incomplete.\n")); + } + else + sig_write (_("Backtrace unavailable\n")); + sig_write ("---------------------\n"); + sig_write (_("A fatal error internal to GDB has been detected, " + "further\ndebugging is not possible. GDB will now " + "terminate.\n\n")); + sig_write (_("This is a bug, please report it.")); + if (REPORT_BUGS_TO[0] != '\0') + { + sig_write (_(" For instructions, see:\n")); + sig_write (REPORT_BUGS_TO); + sig_write ("."); + } + sig_write ("\n\n"); + + gdb_stderr->flush (); + } +#endif /* HAVE_EXECINF_BACKTRACE */ + + /* If possible arrange for SIG to have its default behaviour (which + should be to terminate the current process), unblock SIG, and reraise + the signal. This ensures GDB terminates with the expected signal. */ + if (signal (sig, SIG_DFL) != SIG_ERR + && unblock_signal (sig)) + raise (sig); + + /* The above failed, so try to use SIGABRT to terminate GDB. */ +#ifdef SIGABRT + signal (SIGABRT, SIG_DFL); +#endif + abort (); /* ARI: abort */ +} + /* The SIGSEGV handler for this thread, or NULL if there is none. GDB always installs a global SIGSEGV handler, and then lets threads indicate their interest in handling the signal by setting this @@ -887,7 +1001,7 @@ handle_sigsegv (int sig) install_handle_sigsegv (); if (thread_local_segv_handler == nullptr) - abort (); /* ARI: abort */ + handle_fatal_signal (sig); thread_local_segv_handler (sig); } @@ -1160,16 +1274,7 @@ async_sigtstp_handler (gdb_client_data arg) char *prompt = get_prompt (); signal (SIGTSTP, SIG_DFL); -#if HAVE_SIGPROCMASK - { - sigset_t zero; - - sigemptyset (&zero); - gdb_sigmask (SIG_SETMASK, &zero, 0); - } -#elif HAVE_SIGSETMASK - sigsetmask (0); -#endif + unblock_signal (SIGTSTP); raise (SIGTSTP); signal (SIGTSTP, handle_sigtstp); printf_unfiltered ("%s", prompt); @@ -1320,4 +1425,17 @@ Control whether to show event loop-related debug messages."), set_debug_event_loop_command, show_debug_event_loop_command, &setdebuglist, &showdebuglist); + + add_setshow_boolean_cmd ("backtrace-on-fatal-signal", class_maintenance, + &bt_on_fatal_signal, _("\ +Set whether to produce a backtrace if GDB receives a fatal signal."), _("\ +Show whether GDB will produce a backtrace if it receives a fatal signal."), _("\ +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, + show_bt_on_fatal_signal, + &maintenance_set_cmdlist, + &maintenance_show_cmdlist); } diff --git a/gdb/testsuite/gdb.base/bt-on-fatal-signal.c b/gdb/testsuite/gdb.base/bt-on-fatal-signal.c new file mode 100644 index 00000000000..d9d56c3700f --- /dev/null +++ b/gdb/testsuite/gdb.base/bt-on-fatal-signal.c @@ -0,0 +1,22 @@ +/* Copyright 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 . */ + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/bt-on-fatal-signal.exp b/gdb/testsuite/gdb.base/bt-on-fatal-signal.exp new file mode 100644 index 00000000000..7a9f8e45fde --- /dev/null +++ b/gdb/testsuite/gdb.base/bt-on-fatal-signal.exp @@ -0,0 +1,134 @@ +# 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 the 'maint set backtrace-on-fatal-signal' behaviour. Start up +# GDB, turn on backtrace-on-fatal-signal, then send fatal signals to +# GDB and ensure we see the backtrace. + +standard_testfile + +# The logic for sending signals to GDB might now work when using a +# remote host (will the signal go to GDB, or the program that +# established the connection to the remote host?), so just skip this +# test for remote host setups. +if {[is_remote host]} { + untested $testfile + return -1 +} + +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 $testfile + 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 backtrace-on-fatal-signal on" "" { + -re "support for this feature is not compiled into GDB" { + untested $testfile + return -1 + } + -re "$gdb_prompt $" { + pass $gdb_test_name + } +} + +# Now the actual test loop. +foreach test_data {{SEGV "Segmentation fault"}} { + set sig [lindex ${test_data} 0] + set msg [lindex ${test_data} 1] + with_test_prefix ${sig} { + + # Restart GDB. + clean_restart $binfile + + # Capture the pid of GDB. + set testpid [spawn_id_get_pid $gdb_spawn_id] + + # Start the inferior. + runto_main + + # Turn on the backtrace-on-fatal-signal feature. + gdb_test_no_output "maint set backtrace-on-fatal-signal on" + + # Flags for various bits of the output we expect to see, we + # check for these in the gdb_test_multiple below. + set saw_fatal_msg false + set saw_bt_start false + set saw_bt_end false + set internal_error_msg_count 0 + + # Send the fatal signal to GDB. + remote_exec host "kill -${sig} ${testpid}" + + # Scan GDB's output for the backtrace. As the output we get + # here includes the standard "internal error" message, which + # gdb_test_multiple will usually handle, we are forced to make + # extensive use of the "-early" flag here so that all our + # patterns are applied before gdb_test_multiple can check for + # the internal error pattern. + gdb_test_multiple "" "scan for backtrace" { + -early -re "^\r\n" { + exp_continue + } + -early -re "^Fatal signal: ${msg}\r\n" { + set saw_fatal_msg true + exp_continue + } + -early -re "^----- Backtrace -----\r\n" { + set saw_bt_start true + exp_continue + } + -early -re ".+\r\n---------------------\r\n" { + set saw_bt_end true + exp_continue + } + -early -re "^A fatal error internal to GDB has been detected, further\r\n" { + incr internal_error_msg_count + exp_continue + } + -early -re "^debugging is not possible. GDB will now terminate\\.\r\n" { + incr internal_error_msg_count + exp_continue + } + eof { + # Catch the eof case as this indicates that GDB has + # gone away, which in this case, is what we expect to + # happen. + gdb_assert { $saw_fatal_msg } + gdb_assert { $saw_bt_start } + gdb_assert { $saw_bt_end } + gdb_assert { [expr $internal_error_msg_count == 2] } + } + -re "$gdb_prompt $" { + # GDB should terminate, we should never get back to + # the prompt. + fail $gdb_test_name + } + } + + # GDB should be dead and gone by this point, but just to be + # sure, force an exit. + gdb_exit + } +} diff --git a/gdb/ui-file.h b/gdb/ui-file.h index 61509735c68..9593c94e673 100644 --- a/gdb/ui-file.h +++ b/gdb/ui-file.h @@ -83,6 +83,11 @@ class ui_file virtual void flush () {} + + /* If this object has an underlying file descriptor, then return it. + Otherwise, return -1. */ + virtual int fd () const + { return -1; } }; typedef std::unique_ptr ui_file_up; @@ -195,6 +200,10 @@ class stdio_file : public ui_file bool can_emit_style_escape () override; + /* Return the underlying file descriptor. */ + int fd () const override + { return m_fd; } + private: /* Sets the internal stream to FILE, and saves the FILE's file descriptor in M_FD. */ -- 2.25.4