From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.31]) by sourceware.org (Postfix) with ESMTPS id 3F3AC3857B94 for ; Mon, 18 Dec 2023 14:41:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3F3AC3857B94 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3F3AC3857B94 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=134.134.136.31 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702910478; cv=none; b=nNP1SY4PreOy9EITVYvz+hENnFuNNd0g6pOjZHDFhtQ2keTArkm30+eVpR86QpYlreZyY8pCzdmT/1oJVOvEqbA2c5IgXd/ZdS4ydCpe7/seH2p4szgUwwat9yZ90SOj8AfCb1M+MHGEWWHPfUDOP4o56wsBOurm7gZcp4SxWi0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702910478; c=relaxed/simple; bh=HgZGq/Od+cnl8Muq9uolpdO02gK/XQZN6nHzl/mIZ30=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=XCaxpxivPud7EemjbcUSxpJODG5EOYmcvFfEi7QBi3H7e+/mQlGNsFwhlUs60cFFLoBcg8T6wKxxBb0ieMa7fzoqt/eYMWwk/yvfgAw8kTW0kkViW01/cPwW0eJBp8oBlYIhzsSt9x8QKJvdHvxujzEH1W2p8OUkmqbfpZehn90= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1702910475; x=1734446475; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=HgZGq/Od+cnl8Muq9uolpdO02gK/XQZN6nHzl/mIZ30=; b=nsCKGXB8Wpi3HPM3UF4gMmmVNgOSD8bHRAxnZdzoJKTyfKc6+wb611cz HB+BoukMj3z4yo7zjrPnyijByNAnSuZSaW9Hm/geL2iXzIVKhWl/9+ffu w9ohwo6tM5FhML6L8IQls+eCKfCEKjPBhxBROQGY07uPmHNAky/l2dECm W4AQSI69JFll2rlHPg3aXjlqUD4ON89vSSwiHUE1w5/at8ToXX8GRT/L3 W5oOfWtCxPxBtzjln4x39HytwPtb5/MVY3LJ3frszxtn4Xp4fNUZVxRV9 9psh8qJpvoc66JJ11fLj1WMibgYsmzqyMYsWXzNNjXT6d423ZkzQLwkus A==; X-IronPort-AV: E=McAfee;i="6600,9927,10928"; a="459840790" X-IronPort-AV: E=Sophos;i="6.04,285,1695711600"; d="scan'208";a="459840790" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2023 06:41:15 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10927"; a="775602966" X-IronPort-AV: E=Sophos;i="6.04,285,1695711600"; d="scan'208";a="775602966" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2023 06:41:13 -0800 From: Tankut Baris Aktemur To: gdb-patches@sourceware.org Subject: [PATCH v4 2/2] gdb: raise and handle NOT_AVAILABLE_ERROR when accessing frame PC Date: Mon, 18 Dec 2023 15:40:43 +0100 Message-Id: <6fb2a95f5999118e30ac972503be4bec35b092ac.1702909611.git.tankut.baris.aktemur@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: This patch can be considered a continuation of commit 4778a5f87d253399083565b4919816f541ebe414 Author: Tom de Vries Date: Tue Apr 21 15:45:57 2020 +0200 [gdb] Fix hang after ext sigkill and commit 47f1aceffa02be4726b854082d7587eb259136e0 Author: Tankut Baris Aktemur Date: Thu May 14 13:59:54 2020 +0200 gdb/infrun: handle already-exited threads when attempting to stop If a process dies before GDB reports the exit error to the user, we may see the "Couldn't get registers: No such process." error message in various places. For instance: (gdb) start ... (gdb) info inferior Num Description Connection Executable * 1 process 31943 1 (native) /tmp/a.out (gdb) shell kill -9 31943 (gdb) maintenance flush register-cache Register cache flushed. Couldn't get registers: No such process. (gdb) info threads Id Target Id Frame * 1 process 31943 "a.out" Couldn't get registers: No such process. (gdb) backtrace Python Exception : Couldn't get registers: No such process. Couldn't get registers: No such process. (gdb) inferior 1 Couldn't get registers: No such process. (gdb) thread [Current thread is 1 (process 31943)] Couldn't get registers: No such process. (gdb) The gdb.threads/killed-outside.exp, gdb.multi/multi-kill.exp, and gdb.multi/multi-exit.exp tests also check related scenarios. To improve the situation, 1. when printing the frame info, catch and process a NOT_AVAILABLE_ERROR. 2. when accessing the target to fetch registers, if the operation fails, raise a NOT_AVAILABLE_ERROR instead of a generic error, so that clients can attempt to recover accordingly. This patch updates the amd64_linux_nat_target and remote_target in this direction. With this patch, we obtain the following behavior: (gdb) start ... (gdb) info inferior Num Description Connection Executable * 1 process 748 1 (native) /tmp/a.out (gdb) shell kill -9 748 (gdb) maintenance flush register-cache Register cache flushed. (gdb) info threads Id Target Id Frame * 1 process 748 "a.out" (gdb) backtrace #0 Backtrace stopped: not enough registers or memory available to unwind further (gdb) inferior 1 [Switching to inferior 1 [process 748] (/tmp/a.out)] [Switching to thread 1 (process 748)] #0 (gdb) thread [Current thread is 1 (process 748)] (gdb) Here is another "before/after" case. Suppose we have two inferiors, each having its own remote target underneath. Before this patch, we get the following output: # Create two inferiors on two remote targets, resume both until # termination. Exit event from one of them is shown first, but the # other also exited -- just not yet shown. (gdb) maint set target-non-stop on (gdb) target remote | gdbserver - ./a.out (gdb) add-inferior -no-connection (gdb) inferior 2 (gdb) target remote | gdbserver - ./a.out (gdb) set schedule-multiple on (gdb) continue ... [Inferior 2 (process 22127) exited normally] (gdb) inferior 1 [Switching to inferior 1 [process 22111] (target:/tmp/a.out)] [Switching to thread 1.1 (Thread 22111.22111)] Could not read registers; remote failure reply 'E01' (gdb) info threads Id Target Id Frame * 1.1 Thread 22111.22111 "a.out" Could not read registers; remote failure reply 'E01' (gdb) backtrace Python Exception : Could not read registers; remote failure reply 'E01' Could not read registers; remote failure reply 'E01' (gdb) thread [Current thread is 1.1 (Thread 22111.22111)] Could not read registers; remote failure reply 'E01' (gdb) With this patch, it becomes: ... [Inferior 1 (process 11759) exited normally] (gdb) inferior 2 [Switching to inferior 2 [process 13440] (target:/path/to/a.out)] [Switching to thread 2.1 (Thread 13440.13440)] #0 in ?? () (gdb) info threads Id Target Id Frame * 2.1 Thread 13440.13440 "a.out" in ?? () (gdb) backtrace #0 in ?? () Backtrace stopped: not enough registers or memory available to unwind further (gdb) thread [Current thread is 2.1 (Thread 13440.13440)] (gdb) Finally, together with its predecessor, this patch also fixes PR gdb/26877. Regression-tested on X86_64-Linux. --- gdb/amd64-linux-nat.c | 5 +- gdb/remote.c | 15 ++-- gdb/stack.c | 33 ++++++- gdb/testsuite/gdb.threads/killed-outside.exp | 8 +- .../gdb.tui/multi-exit-remove-inferior.c | 21 +++++ .../gdb.tui/multi-exit-remove-inferior.exp | 86 +++++++++++++++++++ 6 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 gdb/testsuite/gdb.tui/multi-exit-remove-inferior.c create mode 100644 gdb/testsuite/gdb.tui/multi-exit-remove-inferior.exp diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index f7f9a483def..aa9b10c52d1 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -223,7 +223,10 @@ amd64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) elf_gregset_t regs; if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0) - perror_with_name (_("Couldn't get registers")); + { + std::string msg = perror_string (_("Couldn't get registers")); + throw_error (NOT_AVAILABLE_ERROR, "%s", msg.c_str ()); + } amd64_supply_native_gregset (regcache, ®s, -1); if (regnum != -1) diff --git a/gdb/remote.c b/gdb/remote.c index 84daa8567b6..e17e526411e 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -8760,9 +8760,13 @@ remote_target::fetch_register_using_p (struct regcache *regcache, case PACKET_UNKNOWN: return 0; case PACKET_ERROR: - error (_("Could not fetch register \"%s\"; remote failure reply '%s'"), - gdbarch_register_name (regcache->arch (), reg->regnum), - buf); + { + const char *regname = gdbarch_register_name (regcache->arch (), + reg->regnum); + throw_error (NOT_AVAILABLE_ERROR, + _("Could not fetch register \"%s\"; remote failure " + "reply '%s'"), regname, buf); + } } /* If this register is unfetchable, tell the regcache. */ @@ -8799,8 +8803,9 @@ remote_target::send_g_packet () putpkt (rs->buf); getpkt (&rs->buf); if (packet_check_result (rs->buf) == PACKET_ERROR) - error (_("Could not read registers; remote failure reply '%s'"), - rs->buf.data ()); + throw_error (NOT_AVAILABLE_ERROR, + _("Could not read registers; remote failure reply '%s'"), + rs->buf.data ()); /* We can get out of synch in various cases. If the first character in the buffer is not a hex character, assume that has happened diff --git a/gdb/stack.c b/gdb/stack.c index 20bb85efd19..04478f02ce3 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1098,7 +1098,38 @@ print_frame_info (const frame_print_options &fp_opts, the next frame is a SIGTRAMP_FRAME or a DUMMY_FRAME, then the next frame was not entered as the result of a call, and we want to get the line containing FRAME->pc. */ - symtab_and_line sal = find_frame_sal (frame); + symtab_and_line sal; + try + { + sal = find_frame_sal (frame); + } + catch (const gdb_exception_error &ex) + { + if (ex.error == NOT_AVAILABLE_ERROR) + { + ui_out_emit_tuple tuple_emitter (uiout, "frame"); + + annotate_frame_begin (print_level ? frame_relative_level (frame) : 0, + gdbarch, 0); + + if (print_level) + { + uiout->text ("#"); + uiout->field_fmt_signed (2, ui_left, "level", + frame_relative_level (frame)); + } + + std::string frame_info = "<"; + frame_info += ex.what (); + frame_info += ">"; + uiout->field_string ("func", frame_info.c_str (), + metadata_style.style ()); + uiout->text ("\n"); + annotate_frame_end (); + return; + } + throw; + } location_print = (print_what == LOCATION || print_what == SRC_AND_LOC diff --git a/gdb/testsuite/gdb.threads/killed-outside.exp b/gdb/testsuite/gdb.threads/killed-outside.exp index 003cede78ee..addb6993afd 100644 --- a/gdb/testsuite/gdb.threads/killed-outside.exp +++ b/gdb/testsuite/gdb.threads/killed-outside.exp @@ -37,17 +37,15 @@ remote_exec target "kill -9 ${testpid}" # Give it some time to die. sleep 2 -set regs_msg "(Couldn't get registers|Unable to fetch general registers)" -set no_such_process_msg "$regs_msg: No such process\." +set error_msg "PC register is not available" set killed_msg "Program terminated with signal SIGKILL, Killed\." set no_longer_exists_msg "The program no longer exists\." set not_being_run_msg "The program is not being run\." gdb_test_multiple "continue" "prompt after first continue" { - -re "Continuing\.\r\n$no_such_process_msg\r\n$gdb_prompt " { + -re "Continuing\.\r\n$error_msg\r\n$gdb_prompt " { pass $gdb_test_name - # Saw $no_such_process_msg. The bug condition was triggered, go - # check for it. + # The bug condition was triggered, go check for it. gdb_test_multiple "" "messages" { -re ".*$killed_msg.*$no_longer_exists_msg\r\n" { pass $gdb_test_name diff --git a/gdb/testsuite/gdb.tui/multi-exit-remove-inferior.c b/gdb/testsuite/gdb.tui/multi-exit-remove-inferior.c new file mode 100644 index 00000000000..594408d2e72 --- /dev/null +++ b/gdb/testsuite/gdb.tui/multi-exit-remove-inferior.c @@ -0,0 +1,21 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2020-2023 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 . */ + +int main() { + int a = 42; + return 0; /* break-here */ +} diff --git a/gdb/testsuite/gdb.tui/multi-exit-remove-inferior.exp b/gdb/testsuite/gdb.tui/multi-exit-remove-inferior.exp new file mode 100644 index 00000000000..79f0b453ff4 --- /dev/null +++ b/gdb/testsuite/gdb.tui/multi-exit-remove-inferior.exp @@ -0,0 +1,86 @@ +# Copyright 2020-2023 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 . +# +# This is a regression test for PR gdb/26877. + +tuiterm_env + +standard_testfile + +if {[use_gdb_stub]} { + return 0 +} + +if {[build_executable "failed to prepare" ${testfile} ${srcfile}] == -1} { + return -1 +} + +# Make sure TUI is supported before continuing. +with_test_prefix "initial check" { + Term::clean_restart 24 80 $testfile + if {![Term::enter_tui]} { + unsupported "TUI not supported" + return + } +} + +Term::clean_restart 24 80 $testfile + +# Create a setting with two inferiors, where both are stopped +# at a breakpoint at the end of main. Then resume both. +set bp [gdb_get_line_number "break-here"] +gdb_breakpoint "$bp" + +with_test_prefix "inferior 1" { + gdb_run_cmd + gdb_test "" ".*reakpoint \[^\r\n\]+${srcfile}.*" "run until bp" +} + +with_test_prefix "inferior 2" { + gdb_test "add-inferior -exec [standard_output_file $testfile]" \ + "Added inferior 2.*" "add inferior" + gdb_test "inferior 2" "Switching to inferior 2.*" "switch" + gdb_run_cmd + gdb_test "" ".*reakpoint \[^\r\n\]+${srcfile}.*" "run until bp" +} + +gdb_test_no_output "set schedule-multiple on" +gdb_continue_to_end + +# Find out which inferior is current. It is the inferior that exited. +set exited_inf 1 +gdb_test_multiple "inferior" "current inferior" { + -re -wrap "Current inferior is ($decimal) .*" { + set exited_inf $expect_out(1,string) + pass $gdb_test_name + } +} + +# Switch to the other inferior and remove the exited one. +# Bad GDB used to crash when this is done under TUI. +if {![Term::enter_tui]} { + unsupported "TUI not supported" + return +} + +if {$exited_inf == 1} { + Term::command "inferior 2" +} else { + Term::command "inferior 1" +} + +Term::command "remove-inferiors $exited_inf" +Term::command "info inferior $exited_inf" +Term::check_contents "inferior is removed" "No inferiors." -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928