From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id WCAsGzmsIWrVgTQAWB0awg (envelope-from ) for ; Thu, 04 Jun 2026 12:47:53 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=AhHuVlXI; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 5EC0F1E062; Thu, 04 Jun 2026 12:47:53 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 5CAE61E062 for ; Thu, 04 Jun 2026 12:47:52 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CDEA94BA23D3 for ; Thu, 4 Jun 2026 16:47:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CDEA94BA23D3 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=AhHuVlXI Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 595154BAD178 for ; Thu, 4 Jun 2026 16:47:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 595154BAD178 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 595154BAD178 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780591632; cv=none; b=NDxraJQK32G7FqOe32pAClOsjKCIhRKCO3j22j/1Oe12KM4tNA6cvOM84rCCh9Jb0QeyNyxLW1fh8TnlJxslZoueIcOAqJzLOdsh5sZynQMQUBtQQYHhnnVxNLStSZcJai7h3kEQdBDEXit3wWHaPO5245N3pMIrVucqqCRqUuw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780591632; c=relaxed/simple; bh=CP/ZYHl1s5wh+OZTUVLcFP8mw86NMA4IvBwq6PGqyK4=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=O9DeX99BDSorv9w9MJCccxqABUkrKYmdHuLnL7Up3WxfuzvPtZMgG36cLzEgXYO8D88L5oMrWrIqdoL+zU3MwiI+9zOmZFsnV3irjEzbBwDSfDdIpCNPEia6fjSjyBpp1RwM0GxxOiX8CK1CS4EaY3Ud+gayxlGLmXhzgUKTZq8= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=AhHuVlXI DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 595154BAD178 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780591632; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4FXIqilCDpuN6vRwc6jpDqlJJ3wQrFLtoQSB9T21s1Q=; b=AhHuVlXIweAJQq61TH+NtBb/szGIheVo3xjUemwr0Co9XfGHEg/DVxWbKP0t2VqbsKJE+Q HwfA7Pu6faAFd29gGQMsIkFEtSaEriBKuVrIYMidQg+9glFGLMzP5ASe3Bpbq0+sbybEVx UgV4lruChLox6Jc3KfElNqIB2CcIJEY= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-563-OrdAdSQ6Mka687ue-UMRsA-1; Thu, 04 Jun 2026 12:47:11 -0400 X-MC-Unique: OrdAdSQ6Mka687ue-UMRsA-1 X-Mimecast-MFC-AGG-ID: OrdAdSQ6Mka687ue-UMRsA_1780591630 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-4601daf4c65so578832f8f.2 for ; Thu, 04 Jun 2026 09:47:10 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780591630; x=1781196430; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=4FXIqilCDpuN6vRwc6jpDqlJJ3wQrFLtoQSB9T21s1Q=; b=FrCdFrDKmfIOxlTEZ6Yal+m6sU2iJeS7aGYl+o8HlhaxFH5ZGw2Zm0f4UDhhKAxff/ e43VoqbZcmph4bswLQdKaD4gaJV8yE8pUc+f2va3yLKKf8XIvTKPLSUdGv24AAxr7lIJ HeuOiFwRBiEYUueFTE1Ib0h8+fArYF32l8/ArnOOPN3K3THR0fFuvWNywCbTgDJka/N/ HbBkcgLmXRSj4fi3pl45fkVnU2BgVSzsYbagEJsBANlIjMpl4Mxx38topGTsNsWExJbb 5sLAxPRc/ZW5q2VSncXR2Z/Z+kyFd+jrK3gu4AshjZPgyB/tD01bIMhUTq0M3/kV0Qfi HLIQ== X-Gm-Message-State: AOJu0YwRmw44BW5dzPmHzzuAmxqzU8c+XGUT1JWL54KGJpQ0HZMVunve 4ezY97RAcBBGA0AuZ7qxXmYaw6wCcLmoKM8Rb5jWwDqqigOqAPTaGNCFDvaZkVSlRdy6mic5Yj/ /KvZEQLPTGTNp2c4MUvKypCHKQ5URu3Y75ewGLCB56vcdUTsTt841IgLJoyGospMnsiXS+I4kI9 UwMABcAdQZr8Hy2hunhlmhjJzIvf1P81taYCh1SSegAIzU5Pk= X-Gm-Gg: Acq92OF1woIur0x8bhTJXAGi2lhi91k9c2ahoP7cGF4/QmxZX+NhPcpHgD7a6x3LWM4 ul585irlAWQIH2h5yM08Lw4h52yRZadxV0WcAegolABy+OJLP+FUt2mos33dMzvH+hNoKDzctXV FHL6cMo9ZvotRwim98gzlnllU0DVXG4Mlu1CPP842t/8ZQxV83/khorlDnVWC7gJOm1OELmodh2 S0otCnHTDtVJ6jdSRGlN0m02uS9q0ImUlycITX4yVjmI2CcUERHQCldH9ZqwkkRQhJz2vvQFxBF tKiZPZQ7IQWZ/IXMawb8HlwLAWxvKmCQfWDZdO6odYtNjYqCVx2VzoHwJAop4jLvZPvylxK2aqq /ABDbEi325WL/lGaeb3E0P55zSA== X-Received: by 2002:a5d:424b:0:b0:45e:ee50:d066 with SMTP id ffacd0b85a97d-4602178307fmr10533804f8f.6.1780591629463; Thu, 04 Jun 2026 09:47:09 -0700 (PDT) X-Received: by 2002:a5d:424b:0:b0:45e:ee50:d066 with SMTP id ffacd0b85a97d-4602178307fmr10533724f8f.6.1780591628816; Thu, 04 Jun 2026 09:47:08 -0700 (PDT) Received: from localhost ([213.31.44.97]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4601f2e4004sm17728405f8f.9.2026.06.04.09.47.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 09:47:08 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Lancelot SIX , Andrew Burgess Subject: [PATCH] gdb/python: fix 'exited' event when GDB exits from core file debugging Date: Thu, 4 Jun 2026 17:47:05 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: sbUimeWOPY5iU6bblLb1I1LPBOSUfKwJ7jbln9j12x8_1780591630 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org This fixes an issue that was reported here: https://inbox.sourceware.org/gdb-patches/v3x4md2dg6rflq35ymzwrmmqf5uaem5exrnlbsp5dmhph2vihy@lq22ncu774yu After commit: commit 3780b9993c973a2b68b496b80eddb820c0932cc0 Date: Fri Mar 27 11:29:07 2026 +0000 gdb: refactor core_target ::close and ::detach functions it was observed that the Python 'exited' event was no longer being emitted when debugging a core file, and then exiting GDB. The problem is that, when GDB is exiting we eventually end up in quit_force (in top.c), which calls kill_or_detach for every inferior. In kill_or_detach we call either target_detach or target_kill, but only for non-core file targets. For core file targets, neither of these is called and kill_or_detach does nothing of interest. After the call to kill_or_detach, we call inferior::pop_all_targets, which calls inferior::pop_all_targets_above the dummy_stratum target, which means popping all targets. In inferior::pop_all_targets_above (in inferior.c), we call switch_to_inferior_no_thread, which ensures the correct inferior is selected, but makes it so that no thread is selected. Switching to no thread sets inferior_ptid to null_ptid. Now popping the core_target calls core_target::close, and within core_target::close we currently check inferior_ptid in order to determine if exit_core_file_inferior has already been called or not. We only call exit_core_file_inferior if inferior_ptid is not null_ptid, so in this case we will not call exit_core_file_inferior. The only other place that exit_core_file_inferior can be called from is core_target::detach, but remember we specifically avoided calling target_detach earlier in kill_or_detach. This means that exit_core_file_inferior ends up never being called. It is exit_core_file_inferior that calls exit_inferior, and it is from here that the Python 'exited' event is emitted. I don't see any reason why kill_or_detach couldn't call target_detach for a core file target, but I don't propose making that change in this commit. The check against inferior_ptid in core_target::close is clearly incorrect, checking this requires that a suitable thread within the inferior be selected, and that is not really a requirement for closing a core_target. Instead, we can just check the inferior::pid field. When we open a core_target we always set inferior::pid, even if we just assign a fake CORELOW_PID value, so checking inferior::pid against zero will tell us if the inferior has already been exited. Fixing this check is enough to resolve the reported bug and ensure that the 'exited' event is always emitted, which is why I don't propose changing kill_or_detach in this commit. An assert in core_target::exit_core_file_inferior has to go too for the same reason, the assert is checking that a thread is currently selected, and as discussed above, this is not always the case. There's a new test which checks that the 'exited' event is emitted for both a core file debug session, and a live inferior debug session. Only the core file case was broken before this commit, but more testing is always a good thing. --- gdb/corelow.c | 13 +-- .../gdb.python/py-inf-exited-at-exit.c | 32 +++++ .../gdb.python/py-inf-exited-at-exit.exp | 110 ++++++++++++++++++ .../gdb.python/py-inf-exited-at-exit.py | 20 ++++ 4 files changed, 167 insertions(+), 8 deletions(-) create mode 100644 gdb/testsuite/gdb.python/py-inf-exited-at-exit.c create mode 100644 gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp create mode 100644 gdb/testsuite/gdb.python/py-inf-exited-at-exit.py diff --git a/gdb/corelow.c b/gdb/corelow.c index 819e7cae6f9..185b8da90de 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -629,10 +629,6 @@ core_target::build_file_mappings () void core_target::exit_core_file_inferior () { - /* Opening a core file ensures that some thread, even if it's just a - "fake" thread, will have been selected. */ - gdb_assert (inferior_ptid != null_ptid); - /* Avoid confusion from thread stuff. */ switch_to_no_thread (); @@ -665,10 +661,11 @@ core_target::close () mostly harmless except it causes two 'exited' events to be emitted in the Python API, which isn't ideal. - As opening a core_target always ensures that some thread is selected, - then we can tell if exit_core_file_inferior has already been called by - checking if no thread is now selected. */ - if (inferior_ptid != null_ptid) + As opening a core_target always ensures that a pid is assigned to the + core file inferior, even if it is the fake CORELOW_PID, then we can + tell if exit_core_file_inferior has already been called by checking if + the inferior has a non-zero pid or not. */ + if (current_inferior ()->pid != 0) exit_core_file_inferior (); /* Core targets are heap-allocated (see core_target_open), so here diff --git a/gdb/testsuite/gdb.python/py-inf-exited-at-exit.c b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.c new file mode 100644 index 00000000000..708e3eb98ea --- /dev/null +++ b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.c @@ -0,0 +1,32 @@ +/* Copyright 2026 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 . */ + +#include + +void +foo (void) +{ + /* With correct ulimit, etc. this should cause a core dump. */ + abort (); +} + +int +main (void) +{ + foo (); + return 0; +} diff --git a/gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp new file mode 100644 index 00000000000..ab415b2c496 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp @@ -0,0 +1,110 @@ +# Copyright (C) 2026 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 . + +# Check that the 'exited' event triggers when GDB exits. Test for +# both live inferiors, and for core files. + +require allow_python_tests + +load_lib gdb-python.exp + +standard_testfile + +if {[build_executable "build executable" $testfile $srcfile] == -1} { + return +} + +set remote_python_file \ + [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + +# Load the Python script for this test. Record the string +# representation of the current inferior. Then exit GDB. Ensure that +# during the exit we see a single Python 'exited' event associated +# with the expected inferior. +proc source_py_script_and_exit_checking_event {} { + gdb_test_no_output "source $::remote_python_file" \ + "load python script" + + set expected_inferior_string \ + [capture_command_output \ + "python print(str(gdb.selected_inferior()))" ""] + + set inferior_string "" + set event_count 0 + gdb_test_multiple "with confirm off -- exit" "exit gdb" { + -re "^EVENT: inferior exited event\\. Inferior is (\[^\r\n\]+)\r\n" { + set inferior_string $expect_out(1,string) + incr event_count + exp_continue + } + + eof { + verbose -log "GDB has now exited" + gdb_assert { $expected_inferior_string eq $inferior_string \ + && $event_count == 1 } $gdb_test_name + } + + -re "^\[^\r\n\]*\r\n" { + exp_continue + } + } +} + +# Create a core file. Start GDB and load the core file. Exit GDB. +# Check that we see an 'exited' event, and that it is associated with +# the correct gdb.Inferior. +proc_with_prefix check_with_corefile {} { + set corefile [core_find $::binfile] + if {$corefile eq ""} { + unsupported "couldn't create or find corefile" + return + } + + clean_restart $::testfile + + gdb_core_cmd $corefile "load corefile" + + gdb_test "bt" \ + [multi_line \ + "#$::decimal (?:$::hex in )?foo \\(\\) at \[^\r\n\]+" \ + "#$::decimal (?:$::hex in )?main \\(\\) at \[^\r\n\]+"] \ + "backtrace after loading corefile" + + source_py_script_and_exit_checking_event +} + +# Start a running inferior. Exit GDB. Check that we see an 'exited' +# event, and that it is associated with the correct gdb.Inferior. +proc_with_prefix check_with_live {} { + clean_restart $::testfile + + if {![runto_main]} { + return + } + + gdb_breakpoint "foo" + gdb_continue_to_breakpoint "stop in foo" + + gdb_test "bt" \ + [multi_line \ + "#0 (?:$::hex in )?foo \\(\\) at \[^\r\n\]+" \ + "#1 (?:$::hex in )?main \\(\\) at \[^\r\n\]+"] \ + "backtrace at breakpoint" + + source_py_script_and_exit_checking_event +} + +check_with_live +check_with_corefile diff --git a/gdb/testsuite/gdb.python/py-inf-exited-at-exit.py b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.py new file mode 100644 index 00000000000..b6fe39e4061 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.py @@ -0,0 +1,20 @@ +# Copyright (C) 2026 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 . + +def exit_event_handler(event): + inf = event.inferior + print("EVENT: inferior exited event. Inferior is " + str(inf)) + +gdb.events.exited.connect(exit_event_handler) base-commit: bd64797371d27c766d551d0bf115d9090f1d0594 -- 2.25.4