From patchwork Mon Mar 30 15:30:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 132459 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 27DBD4B920A5 for ; Mon, 30 Mar 2026 15:31:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 27DBD4B920A5 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=Yb9Tc75U X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org 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 47B024B92088 for ; Mon, 30 Mar 2026 15:31:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 47B024B92088 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 47B024B92088 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774884664; cv=none; b=U6duFxhqTxiI9iXjCcoiiX9ZqMjxT9IvhecnoMOB83pYzilSZ8IHF/2d3xGVOVnDfnDFeBkqmf5AriT9njw5U3wDjnauJbrOxyO/5/SbkXKYVND0ayopwimAog2UrE8HMLxOSQp0WWoQtn3iWNprx9ttfbthkeX1xAxMtsAw0DA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774884664; c=relaxed/simple; bh=s4uTP5pVM1aqdJDnNtOLOdFm1WMu6RtQPIhdy+KhR5k=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=x5OTNoCIA+ypI+5n7tHN+ODNBO9g4TXAZCDTxBJ62nDo1gnOiDcs14h3Y3VcibezRq+RKfGYtUtASgQGA6t7z7De1yetgkxed+JRnFzxxc9NktfNaIpQoZuVR49xLNG2F81FFmHG8AIPJqf964f1tHBlvzTE5gUTxz0RYmXrZt0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 47B024B92088 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774884663; 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: in-reply-to:in-reply-to:references:references; bh=6O6qK4pVesnoV3XAtYKQPBOwPsSjP5foC/yvbRjhymk=; b=Yb9Tc75U+1fPi1jQUFetL7BTwBtA1k8sxSb86l5f2j2aEVRNMtGw3SdDHoavAGIAU76qCu wO/nzXt6YTBycIdaAdFfB6NPTDKZJy8wKO0s2xdWmYfuy0xSwSflIYQffU5hUFeQDGDfoE p3oTIv0ca2HWzgwcLhsONQ+Xz2zFK2E= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-41-9OySQTkkM4W_T30rxyr03w-1; Mon, 30 Mar 2026 11:31:02 -0400 X-MC-Unique: 9OySQTkkM4W_T30rxyr03w-1 X-Mimecast-MFC-AGG-ID: 9OySQTkkM4W_T30rxyr03w_1774884661 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4852cf0318dso51593455e9.3 for ; Mon, 30 Mar 2026 08:31:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774884661; x=1775489461; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=6O6qK4pVesnoV3XAtYKQPBOwPsSjP5foC/yvbRjhymk=; b=tM6FT2J87rMZprtz7hdZ+31YPfXjBpcqFDa3A5CtT2WBSTYg7nOvAxM4ezwcz/d6DG vMQn7S+hPe4gmXwVCDbbouzjs3T5uojenwhwOAbTEq2KM5EgJRijko8WS8O7GNnTpsAN rYFBvnttpsf6YoAItfTqTHu+o7kyNBvJZLTTIZHxtPleENXN4hGHH/nqLTb13LHZNpn5 9FxYUCS1OMVpTuQ2hASAldjskAPMU7AYUEJhXLHW8yj719tP5tr415U3dUFCTFtos1d0 Ntd7zjohMoEkTUfNQ5m8pa1coxZVDnXSSD/4QrzG3tyjtindCnLsv+2W/zOgVcoMCG7A F2cg== X-Gm-Message-State: AOJu0YwV79vmSIE59ra25uRBzBUMslyKOoyr4MnCPTwheOu0wEEHmJLp pbIrSD2UrcmMbdX+vQ/vSWugoZjZOYHEYM8MN3Xy24akCRPRIB88CdTSRnPn0cw7TtoK6v/xwaz QZq1YGGtNmn85D6FA8rVyIPsHhXAUVEn+hj8mX6Z4bdANdH/OXCSeL1rNP1IPAtntYgNAgvNmnW +HYF9C7NFC0XEdyiRJZKpws8oSCAGX2IbdetfXlVXa+iWYijE= X-Gm-Gg: ATEYQzzKxgBtSgKCTC2scpUCZh2JH1VNcXDND9kZn5eZ94EY5acpQtSzMpEe8Qb1tOn /1zrLeNanVyghBHvjLftPBznA3EZEEM/YNusF6IXbctoiJbW3/lrsZgpvIIXHVK8SKG2rlmR83D giG3E5BukzxIT4mbOctzWg/dmf9xqc0rCiTJGOYkNZSIUP9NSTKuEe87yBpCyQ8a7DAlthVEY8F 3wS/rdvTvR9+SLSM+1eUK017SJvtHG0mSc56DqLpDb4P/oPoKm267KgIfUEw9aWZKUAbjFSTxEr xUuEgriozxSPlXQXwk6FUn2Olzp4/HxWSlFpuRejoEi0fOyoQZQz4u52/gKeLSIU9cuAxS60QMd qy7n4qWuTGUydL0iB X-Received: by 2002:a05:600c:c8f:b0:485:5ba3:37d8 with SMTP id 5b1f17b1804b1-48727d59cf4mr222912405e9.5.1774884660498; Mon, 30 Mar 2026 08:31:00 -0700 (PDT) X-Received: by 2002:a05:600c:c8f:b0:485:5ba3:37d8 with SMTP id 5b1f17b1804b1-48727d59cf4mr222911295e9.5.1774884659784; Mon, 30 Mar 2026 08:30:59 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48722be608bsm431810995e9.0.2026.03.30.08.30.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 08:30:59 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 1/3] gdb: delete some unnecessary code from core_target::detach Date: Mon, 30 Mar 2026 16:30:51 +0100 Message-Id: <42209ecb3032e7f55e2113c15613af11056ac8c8.1774884529.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: gKkNJNBlUy_jK3GLVI2SetN_hnC9jtIFroCOviM77NM_1774884661 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org 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~patchwork=sourceware.org@sourceware.org This commit removes some unnecessary code from core_target::detach. When a core_target is created the core BFD (m_core_bfd) is set, and will never be NULL. The m_core_bfd remains set until either core_target::detach or core_target::close is called. The core_target::close function is only called when the refcount of a core_target reaches zero, the core_target::close function deletes the core_target, so we know that after calling core_target::close no other core_target member functions will be called (as the core_target will have been deleted). The core_target::detach function is called as a result of calling target_detach, which is called as a result of either the 'detach' command, or the 'core-file' command (without passing a file name). As a core_target is not shareable (see process_stratum_target::is_shareable), once a core_target is detached, its reference count will reduce to zero, and then it will be closed and deleted. What this means is that there is absolutely no way that a core_target can ever be detached twice, not that such a thing would make much sense, but it cannot happen. Understanding this we can know that when core_target::detach is called m_core_bfd will never be NULL, I've added an assert for this case. Given this assert, if we look at core_target::clear_core, which core_target::detach calls, we can see that exit_inferior will always be called. If we look at exit_inferior (in inferior.c) we see that the last two actions of that function are: /* Clear the register cache and the frame cache. */ registers_changed (); reinit_frame_cache (); Which are also two of the last three actions of core_target::detach. Clearly the calls in core_target::detach are redundant. Just for good measure, if we look in target_detach, from where core_target::detach will have been called, just before the function returns we have: registers_changed_ptid (proc_target, save_pid_ptid); reinit_frame_cache (); The registers_changed_ptid call is slightly more restrictive, only clearing the register cache for the target being detached, but that should be good enough -- I think exit_inferior could probably be changed to call registers_changed_ptid for the inferior that exited, but that's a problem for another day. What this all tells me is that the registers_changed call and the reinit_frame_cache call in core_target::detach are unnecessary, and can be deleted, which is what this patch does. There should be no user visible changes after this commit. --- gdb/corelow.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gdb/corelow.c b/gdb/corelow.c index 954607134f4..216b4e70066 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -1239,6 +1239,13 @@ core_target_open (const char *arg, int from_tty) void core_target::detach (inferior *inf, int from_tty) { + /* The core BFD is set when the core_target is created and attached to + the inferior. It is only cleared during detach or close. After + detaching the core target will be closed and deleted, so detach can + never be called twice. What this means is that detach will never be + called without the core BFD being set. */ + gdb_assert (this->core_bfd () != nullptr); + /* Get rid of the core. Don't rely on core_target::close doing it, because target_detach may be called with core_target's refcount > 1, meaning core_target::close may not be called yet by the @@ -1250,9 +1257,7 @@ core_target::detach (inferior *inf, int from_tty) implementation deletes 'this'. */ inf->unpush_target (this); - /* Clear the register cache and the frame cache. */ - registers_changed (); - reinit_frame_cache (); + /* Inform the user. */ maybe_say_no_core_file_now (from_tty); } From patchwork Mon Mar 30 15:30:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 132460 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 97A684BB591B for ; Mon, 30 Mar 2026 15:32:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 97A684BB591B 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=YNaycvsa X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org 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 48DF04BA2E21 for ; Mon, 30 Mar 2026 15:31:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 48DF04BA2E21 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 48DF04BA2E21 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774884665; cv=none; b=EzD6iZxg9ZdV2DbsOWDcxH/wTZf3zkrgi/kS0ZPfeuFnqtEqwAmZ+xCda+Z7alKyxNEEdGxX6sDxTiCZGCjtxMopH+4eqpBbLPq6EQqC3kq4Oa4dmqFD4Q5bG7eJgTWZHw6Y4H8Grte1iHDLolFfOBpPPkdVo6TJYs5d5c1EmPQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774884665; c=relaxed/simple; bh=/Mge+0gpYuIrKMJdfWT4sUqn6h3tS2J/iPQeoaGtSvM=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=yDlTkNBq/LjPNxpPe1JUtuAeDfobN7Xne0lA+0yFXnCSa9EFkRXTDP1KPCO1YU/Px7HIlQdlIeH+9KRfdHdNHMuuurGI/tVWotrhLEXTBHPimFf4PW349MsCbDGA1YdPosmAWHALjiXnW/cNS3oAMwNhe/BGIcl88KD9Ocj6WnM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 48DF04BA2E21 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774884664; 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: in-reply-to:in-reply-to:references:references; bh=0olojZZkAntzSnzjebRdE6yviZ08NzXesC/I0sn176E=; b=YNaycvsaa+2qlYQITB5tugIdxFftVIpP2lcCpYB/FBI1tQ16pO+vQLV7iBebRLRIFTCTZ2 Lenn/Crc9acAfenJYaKhDpKe0bdxeCpoDMgyyLuR4lV65xhNxE4eJQU52eZqzYOLKZa5HH Y5SOwu95I8bbILp7DU+g0XUqOjqZb60= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-479-1thYuogcOMWnsSNhllEDCg-1; Mon, 30 Mar 2026 11:31:03 -0400 X-MC-Unique: 1thYuogcOMWnsSNhllEDCg-1 X-Mimecast-MFC-AGG-ID: 1thYuogcOMWnsSNhllEDCg_1774884662 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4837bfcfe0dso58571875e9.1 for ; Mon, 30 Mar 2026 08:31:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774884662; x=1775489462; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=0olojZZkAntzSnzjebRdE6yviZ08NzXesC/I0sn176E=; b=QV30q3AfZM6lpWFELYuAdSUsqPMdPoNmdv82ocnG0ehcLej+xrKJDI+4dFX9w8NL8K /yUebzCkWhFw6CmZnAFz9KlrkPYtAZm+ct5+6TFIh154CWQkHlWy2W02F/6oLkz8vv1W eLNP1JWSZs3zOGDm7svQOPMaC84zsx9wHUVVG3nO1cVHjxITmrVlMVFq6rX+BWzRWaa/ fgTc7jy+jBAYxy12hPXC/7ygdCFWOWfBwK7UUshkg+z1aIe84Yk96F0AHWDIwAn6/4lp Ia1byP0LuO/4cgF/lrGEPw5jf2tbMXY5IriZbL2tC9OhRjie/zP6VgRRYS0kdR3YBxgh lO/w== X-Gm-Message-State: AOJu0YzAEbeQDslNKA6Z1MVbwz9zZbzhpOiQgBAhxxD9m/1r1WVfv22C zBn0vEMf3+73w+weRqNF+Kxk6uuUxeWdVGmRcwlKeOv1dovNs/3qUxaXA4P8yw/NrZMAjh9a6PV PW2gI7uqqYLvR0omhHWnynYy/9Obyv9pl21NkUD3PZjZulUiYX04ww6FRpmMIrsGj6IQ8bau3ND vYm7uX6xoLIu93dD+yXg/VMb/IuZHoncf2RsXXy5B0z/caQgE= X-Gm-Gg: ATEYQzz65Ir5gs8Edcy7l58zif9qEF/1WhSx4l/ZhdBHa5TACeWk3216wCD9GptX4I3 XARYBWUO6GTSOO4k2RzzWYZmHtV9KVJ1C4tYztKoV5wLgXZfq6Du5zwP3ZYb6eRqifATCR5sLfk ozgk+qgLjnFHqJGydsC0HaNVCHVdZHpqmxcAF+gG6q2f2PRh+GZrzQLtNOGz/L4IG/SzDMR+rQd 9WjoRA3CztGAgm4j1fOacGl63POK+VwZTJO2Hkxq49IMzmynAiT5vGrD1ZBchDbAXBa/KQstQyg 3f14ZyKtJ27VC9Rt8x6VgdoVkqq9FNnDMfvYUNfB/G+1Mll4LfSYeihC+B320UWajpD+Ew7F7bP dweyHn+pLISO+BMwI X-Received: by 2002:a05:600c:524f:b0:485:4535:73d with SMTP id 5b1f17b1804b1-48727d67a38mr223564065e9.2.1774884661683; Mon, 30 Mar 2026 08:31:01 -0700 (PDT) X-Received: by 2002:a05:600c:524f:b0:485:4535:73d with SMTP id 5b1f17b1804b1-48727d67a38mr223563085e9.2.1774884661032; Mon, 30 Mar 2026 08:31:01 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43cf21e3602sm20302194f8f.4.2026.03.30.08.31.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 08:31:00 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 2/3] gdb: refactor core_target ::close and ::detach functions Date: Mon, 30 Mar 2026 16:30:52 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: JEQJZguMgcFakhpn4ocsxgko2PHLq-xJCZAHK6fmU6g_1774884662 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org 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~patchwork=sourceware.org@sourceware.org This patch refactors the core_target ::close, ::detach, and ::clear_core functions so that the m_core_bfd is not cleared before the core_target is deleted. My motivation for this change is the get_inferior_core_bfd function. This function checks to see if an inferior has a core_target in its target stack, if it does then there is an assert that the core_target's m_core_bfd will not be NULL. Currently, this assert is mostly correct, but during a call to target_detach, the assert stops being true. Calling target_detach will call core_target::detach, which calls core_target::clear_core, which sets m_core_bfd to NULL. The core_target is not unpushed from the inferior's target stack until GDB returns from ::clear_core back to ::detach. This means that, for a short period of time, from the moment m_core_bfd is set to NULL in ::clear_core, until the unpush back in ::detach, the assertion in get_inferior_core_bfd is no longer valid. Within this window we trigger the core_file_changed observer. If any of the observers call get_inferior_core_bfd then the assertion will trigger. Currently, no observer calls get_inferior_core_bfd, the observer just clears some caches. However, in the next commit I'd like to add a new Python event API for when the core file is changed. User code attached to this event can call Inferior.corefile, which is implemented by a call to get_inferior_core_bfd, and in this case the assert will trigger. I could just delete the assertion, but I'd prefer to not do that. I think by restructuring the code we can leave the assertion in place. The first thing to understand is that a core_target is not shareable, see process_stratum_target::is_shareable. This means that a core_target will only appear within a single inferior's target stack. Next there are two ways that a core_target can be removed from an inferior's target stack. First is via target_detach, this is triggered either by the 'detach' command, or by the 'core-file' command without a core filename. In both these cases target_detach is called, which calls core_target::detach, this function unpushes the core_target from the inferior's target stack. As the core_target is not shareable the reference count will return to zero, at which point the core_target will be closed and deleted. The second way that a core_target can be removed from an inferior's target_stack is by direct replacement. If a user loads a different process_stratum_target, e.g. 'target remote ....' then this replaces the core_target in the target_stack. Doing this reduces the core_target's reference count to zero, which causes the target to be closed and deleted. These two approaches differ in that the first calls core_target::detach and then core_target::close, while the second avoids calling ::detach, and immediately calls ::close. My proposal is that we can defer calling the core_file_changed observer until core_target::close. By this point the core_target will have been removed from the inferior's target_stack, and so the assert in get_inferior_core_bfd will still hold. We already call the observer at this point for the process_stratum_target replacement case (e.g. when a user does 'target remote ...' to replace a core file target), this proposal would just mean that we always call the observer at this point, rather than potentially calling it earlier in the detach case. This commit does this change by making a number of changes: * The code to reset m_core_bfd to NULL, and to trigger the core_file_changed observer, is removed from core_target::clear, this only leaves the code relating to exiting and cleaning up after the inferior that was created for inspecting the core file. * To reflect this change of focus, core_target::clear_core is renamed to core_target::exit_core_file_inferior. * In core_target::detach, nothing really needs to change other than calling ::exit_core_file_inferior. I have added an assert that reflects the fact that ::detach cannot be called twice on the same core_target (after the first call the core_target will always be closed and deleted). * In core_target::close the call to ::exit_core_file_inferior needs to be conditional. As discussed above, in the replacement case, ::close can be called without first calling ::detach. But in the target_detach case, ::detach will have already been called, and as a result ::exit_core_file_inferior will have already been called. * Also in core_target::close, we now unconditionally trigger the core_target_changed observer. This commit is a refactor, and there should be no user observable changes. --- gdb/corelow.c | 75 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/gdb/corelow.c b/gdb/corelow.c index 216b4e70066..b4438990a7a 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -286,7 +286,7 @@ class core_target final : public process_stratum_target private: /* per-core data */ /* Get rid of the core inferior. */ - void clear_core (); + void exit_core_file_inferior (); /* The core's section table. Note that these target sections are *not* mapped in the current address spaces' set of target @@ -614,24 +614,23 @@ core_target::build_file_mappings () /* An arbitrary identifier for the core inferior. */ #define CORELOW_PID 1 +/* See class declaration above. */ + void -core_target::clear_core () +core_target::exit_core_file_inferior () { - if (this->core_bfd () != nullptr) - { - switch_to_no_thread (); /* Avoid confusion from thread - stuff. */ - exit_inferior (current_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); - /* Clear out solib state while the bfd is still open. See - comments in clear_solib in solib.c. */ - clear_solib (current_program_space); + /* Avoid confusion from thread stuff. */ + switch_to_no_thread (); - m_core_bfd.reset (nullptr); + exit_inferior (current_inferior ()); - /* Notify that the core file has changed. */ - gdb::observers::core_file_changed.notify (current_inferior ()); - } + /* Clear out solib state while the bfd is still open. See + comments in clear_solib in solib.c. */ + clear_solib (current_program_space); } /* Close the core target. */ @@ -639,11 +638,38 @@ core_target::clear_core () void core_target::close () { - clear_core (); + /* The core BFD is set when the core_target is created and attached to + the inferior. It is never explicitly cleared, instead m_core_bfd will + have its reference count reduced when the core_target is deleted. */ + gdb_assert (this->core_bfd () != nullptr); + + /* If we called ::detach before calling ::close then the inferior will + have already been exited. This will happen if the user clears the + core file with the 'core-file' or 'detach' commands. + + However, if the user just causes the core_target to be unpushed, by + pushing an alternative target, e.g. 'target remote ....', then we will + not call ::detach before calling ::close. + + In the former case we don't want to exit the inferior twice; this is + 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) + exit_core_file_inferior (); /* Core targets are heap-allocated (see core_target_open), so here we delete ourselves. */ delete this; + + /* Notify that the core file has changed. This is intentionally done + after the core_target is deleted as nothing in here depends on the + core_target itself, the core_target has already been removed from the + inferior's target stack by this point. */ + gdb::observers::core_file_changed.notify (current_inferior ()); } /* Look for sections whose names start with `.reg/' so that we can @@ -1240,17 +1266,18 @@ void core_target::detach (inferior *inf, int from_tty) { /* The core BFD is set when the core_target is created and attached to - the inferior. It is only cleared during detach or close. After - detaching the core target will be closed and deleted, so detach can - never be called twice. What this means is that detach will never be - called without the core BFD being set. */ + the inferior. It is never explicitly cleared, instead m_core_bfd will + have its reference count reduced when the core_target is deleted. */ gdb_assert (this->core_bfd () != nullptr); - /* Get rid of the core. Don't rely on core_target::close doing it, - because target_detach may be called with core_target's refcount > 1, - meaning core_target::close may not be called yet by the - unpush_target call below. */ - clear_core (); + /* Similarly, the inferior and thread are created when the core_target is + opened, and are only exited when this function, or ::close are called. + As calling ::close deletes the core_target, then when this function is + called, the inferior will still be live. */ + gdb_assert (inferior_ptid != null_ptid); + + /* Get rid of the core inferior. */ + exit_core_file_inferior (); /* Note that 'this' may be dangling after this call. unpush_target closes the target if the refcount reaches 0, and our close From patchwork Mon Mar 30 15:30:53 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 132461 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 5EC5D4B9208E for ; Mon, 30 Mar 2026 15:33:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5EC5D4B9208E 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=X+v+ST32 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id D53114BA2E39 for ; Mon, 30 Mar 2026 15:31:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D53114BA2E39 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 D53114BA2E39 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774884669; cv=none; b=uvRWe4jvWXU6fLNcjrhmPujNWY3SXAl1jE7LujTRLisPOLZ86/6LvqG6C5OZ3mKC8I/SHVHNoN1A1zlKFgpDhGqGnOGVo04VlKUBGO7+6/RU3l2nwalnk3ggIpc85bM3pWXvQdSKQ+SUBuquKRxXG1VeT+/sGx0ThWdng2Zkcgc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774884669; c=relaxed/simple; bh=R8a9VdkFfzOZeR8hZopNmUSaIld3aTLDCpbsGcDenfk=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=hkqmf1vp63KXETnBK7wXaf8WA+6tMl8SKH95375CGXdhiBVMW19J4ODSJOtiN7JAkcwsXl4fxmkoTVr5z+aTd/snCXdHCqk1o+htCDzLibW2TjQyx4kqAx6S1z0nW/zer+jZa5yFbmmNIfrsv3Uta+54gYa4IjkSMaj4V6YeFy8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D53114BA2E39 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774884668; 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: in-reply-to:in-reply-to:references:references; bh=NqJ4zVXTf60UwDAkrVVP8kYCJ18FXdapxa6+ui6JzpA=; b=X+v+ST32Y1x8q8hZwAX9iynKh2qnpueD5eEyv92vLrmNhfB/Ys1UcYHo1BUozyjvl4WGJk bVoKS6VsXb9fLnBOA3YvVT06gQBQoJL0OWAfefOuRZH95sAgunjass4sL4ap0hj/SbYQXK AzJHVo5/jmGszRA0mFbgcW2FQspce80= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-352-PKkF1BrxNVWQYeLUofz8fg-1; Mon, 30 Mar 2026 11:31:06 -0400 X-MC-Unique: PKkF1BrxNVWQYeLUofz8fg-1 X-Mimecast-MFC-AGG-ID: PKkF1BrxNVWQYeLUofz8fg_1774884665 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-485397788b3so48648075e9.2 for ; Mon, 30 Mar 2026 08:31:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774884665; x=1775489465; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=NqJ4zVXTf60UwDAkrVVP8kYCJ18FXdapxa6+ui6JzpA=; b=CPaZP2Dq5Mj+HAGAV0EWOWhmIAh+cHpIluz0kdHQUEJYB9gyMXiwT7Wlid0KDTvVJF jo9IP95cRKJnoMvT9Qr5KgRwkarz78l/GMhfwdzFgwK4L9UfMaXogpTpdKKTOBI1pv+f OqTiBl5rgTZ+lpbbm0aIN1vaO9P3R11eGWdnsjGC3M1mk0w/ClP8kvNmOdOyhhgQjzpe L+Vy9rludTgm01tFEaEHy1AvL1/Puxwp8P+VrOiWLnKPcAZA69FwFLIjLctVRHL6VWFv Pec+70VrGmdYp4ZtxOzRV+3PCCOmaEfuk2sVF3jJ5tl2LiHgTGA44ayQbw+QPqypjGMn ZKSw== X-Gm-Message-State: AOJu0YxOVHBDeyaPd1M5sk9muJNmXwEr33xmqnuT6zaMKOl4gwVebv3f nQw1zqW86jBJDcvMjhK3uePPcsapLMsjF4XA8XT/6ZKpSuOVjHbKn3VZZia01bYU+lJWEMm+ivK zioSUk48cREJdGAZmwmRH88q3HumOYTwIYTWzCY8O8oU6Sw/3mP36Njx3C1Ys5ZY5+E8BnafV1x 8uIBJo8pg6c/qS1EO4QzvPVZ55QAVOFYHw+pueIrIee3kGkS8= X-Gm-Gg: ATEYQzxz9C3PSx4whhn6upPDrXb3JpXAMxKDrGcdUJGQWg8EXCuk38gG6ksfQgmaDj3 LTE1uU6UbMzWWeOLcxp7d6Cd2WdooWksK8AzlfBygob9HWbXb5V6gOlGkUO6O8O5y6cX883BS9R 0na4XiDyjNxzsASwdG4H6Z4CFfUBbP5KeN6G+0x5mfgJKvcegmr5VvSC+wf3EViIP+LH+bKj+ug hX7s99M5vNnM6VBqIX+cOMqJKXtmsG2wfHBUcofuPaCK7yNXDjf0us2G7C9ViW1Zrb3bVXpqYH6 Zvsl5+wnMAq4ARfRW7AeOAJ/dgOf4rQwT2HXhdoJrBH/wPyBPoA+wk7Lm/URfRb3mioIlxlS/5C OXRmPiEBkEO5BYkO6 X-Received: by 2002:a05:600c:3505:b0:485:4135:5c92 with SMTP id 5b1f17b1804b1-48727c7c6e0mr191528485e9.0.1774884664522; Mon, 30 Mar 2026 08:31:04 -0700 (PDT) X-Received: by 2002:a05:600c:3505:b0:485:4135:5c92 with SMTP id 5b1f17b1804b1-48727c7c6e0mr191527475e9.0.1774884663724; Mon, 30 Mar 2026 08:31:03 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48722c95041sm266116525e9.6.2026.03.30.08.31.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Mar 2026 08:31:02 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 3/3] gdb/python: new events.corefile_changed event Date: Mon, 30 Mar 2026 16:30:53 +0100 Message-Id: <7e010b61a2a9d995765011de53f3036c0b1b2b60.1774884529.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: eGyZw9pBRuFnAhvhQEooNEIK3-3UkVhhfpnVpwYS2wc_1774884665 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H2, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org 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~patchwork=sourceware.org@sourceware.org Add a new Python event registry, events.corefile_changed. This event is emitted each time the corefile within an inferior changes. The event object has a single 'inferior' attribute which is the gdb.Inferior object for which the core file changed. The user can then inspect Inferior.corefile to see details about the new core file, or this will be None if the core file was removed from the inferior. I've updated the existing test to cover this new event. The new test covers both the corefile_changed event, but also monitors the exited event. This ties in to the work done in the previous commit where we use whether the inferior has exited or not as a guard for whether core_target::exit_core_file_inferior should be called. Unloading a core file should result in a single corefile_changed event and a single exited event. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 5 + gdb/doc/python.texi | 11 ++ gdb/python/py-all-events.def | 1 + gdb/python/py-corefile.c | 36 ++++++ gdb/python/py-event-types.def | 5 + gdb/testsuite/gdb.python/py-corefile.exp | 140 ++++++++++++++++++++--- gdb/testsuite/gdb.python/py-corefile.py | 117 +++++++++++++++++++ 7 files changed, 296 insertions(+), 19 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 4cf91053c95..225ce15df16 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -238,6 +238,11 @@ qExecAndArgs a tuple of pairs each representing a single range. Contiguous blocks have only one range. + ** New event registry gdb.events.corefile_changed, which emits a + CorefileChangedEvent whenever the core file associated with an + inferior changes. The event has an 'inferior' attribute which is + the gdb.Inferior in which the core file has changed. + * Guile API ** Procedures 'memory-port-read-buffer-size', diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index e1e983726e8..6c0b3310c7f 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -4147,6 +4147,17 @@ Events In Python filename will have changed, but the symbol filename might still hold its previous value. +@item events.corefile_changed +Emits @code{gdb.CorefileChangedEvent} which indicates that the core +file associated with a @code{gdb.Inferior} has changed, either a new +core file has been loaded, or the existing core file has been +unloaded (@pxref{Core Files In Python}). + +@defvar CorefileChangedEvent.inferior +The @code{gdb.Inferior} in which the corefile has changed +(@pxref{Inferiors In Python}). +@end defvar + @item events.new_progspace This is emitted when @value{GDBN} adds a new program space (@pxref{Progspaces In Python,,Program Spaces In Python}). The event diff --git a/gdb/python/py-all-events.def b/gdb/python/py-all-events.def index 24724038562..3711cf29287 100644 --- a/gdb/python/py-all-events.def +++ b/gdb/python/py-all-events.def @@ -47,3 +47,4 @@ GDB_PY_DEFINE_EVENT(new_progspace) GDB_PY_DEFINE_EVENT(free_progspace) GDB_PY_DEFINE_EVENT(tui_enabled) GDB_PY_DEFINE_EVENT(selected_context) +GDB_PY_DEFINE_EVENT(corefile_changed) diff --git a/gdb/python/py-corefile.c b/gdb/python/py-corefile.c index d35838c7523..4da70d631a4 100644 --- a/gdb/python/py-corefile.c +++ b/gdb/python/py-corefile.c @@ -23,6 +23,7 @@ #include "inferior.h" #include "gdbcore.h" #include "gdbsupport/rsp-low.h" +#include "py-event.h" /* A gdb.Corefile object. */ @@ -320,13 +321,48 @@ cfpy_mapped_files (PyObject *self, PyObject *args) return obj->mapped_files; } +/* Emit a CorefileChangedEvent event to REGISTRY. Return 0 on success, + or a negative value on error. INF is the inferior in which the core + file changed. */ + +static int +emit_corefile_changed_event (eventregistry_object *registry, inferior *inf) +{ + /* If there are no listeners then we are done. */ + if (evregpy_no_listeners_p (gdb_py_events.corefile_changed)) + return 0; + + gdbpy_ref<> event_obj + = create_event_object (&corefile_changed_event_object_type); + if (event_obj == nullptr) + return -1; + + gdbpy_ref inf_obj = inferior_to_inferior_object (inf); + if (inf_obj == nullptr + || evpy_add_attribute (event_obj.get (), "inferior", + inf_obj.get ()) < 0) + return -1; + + return evpy_emit_event (event_obj.get (), registry); +} + /* Callback from gdb::observers::core_file_changed. The core file in PSPACE has been changed. */ static void cfpy_corefile_changed (inferior *inf) { + /* It's safe to do this even if Python is not initialized, but there + should be nothing to clear in that case. */ cfpy_inferior_corefile_data_key.clear (inf); + + if (!gdb_python_initialized) + return; + + gdbpy_enter enter_py; + + if (emit_corefile_changed_event (gdb_py_events.corefile_changed, inf) < 0) + gdbpy_print_stack (); } /* Called when a gdb.Corefile is destroyed. */ diff --git a/gdb/python/py-event-types.def b/gdb/python/py-event-types.def index fe3e0978a55..7dddcc156ec 100644 --- a/gdb/python/py-event-types.def +++ b/gdb/python/py-event-types.def @@ -150,3 +150,8 @@ GDB_PY_DEFINE_EVENT_TYPE (selected_context, "SelectedContextEvent", "GDB user selected context event object", event_object_type); + +GDB_PY_DEFINE_EVENT_TYPE (corefile_changed, + "CorefileChangedEvent", + "GDB corefile changed event", + event_object_type); diff --git a/gdb/testsuite/gdb.python/py-corefile.exp b/gdb/testsuite/gdb.python/py-corefile.exp index ecbff30cf7c..1b7a6458133 100644 --- a/gdb/testsuite/gdb.python/py-corefile.exp +++ b/gdb/testsuite/gdb.python/py-corefile.exp @@ -17,6 +17,7 @@ # support in Python. require isnative +require {!is_remote host} load_lib gdb-python.exp @@ -28,17 +29,93 @@ if {[build_executable "build executable" $testfile $srcfile] == -1} { return } +set remote_python_file \ + [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + set corefile [core_find $binfile] if {$corefile == ""} { unsupported "couldn't create or find corefile" return } +# Helper proc to run the 'core-file' command. Takes optional arguments: +# +# -corefile FILENAME : Load FILENAME as the new core file. If this +# argument is not given then the current core +# file will be unloaded. +# +# -inferior NUM : The inferior in which the corefile is being changed. +# This is used to match the corefile_changed events +# that will be emitted. +# +# -prefix STRING : A test prefix, to make test names unique. +proc core_file_cmd { args } { + parse_some_args { + {corefile ""} + {inferior 1} + {prefix ""} + } + + if { $prefix eq "" } { + if { $corefile eq "" } { + set prefix "unload corefile" + } else { + set prefix "load corefile" + } + } + + with_test_prefix $prefix { + gdb_test "events corefile_changed check" \ + "^No corefile_changed event has been seen\\." \ + "no corefile event has been seen" + + gdb_test "events exited check" \ + "^No exited event has been seen\\." \ + "no exited event has been seen" + + if { $corefile eq "" } { + gdb_test "core-file" "^No core file now\\." "unload current core file" + + gdb_test "events corefile_changed check" \ + "Event 1/1, Inferior $inferior, Corefile None" \ + "expected corefile event has been seen" + + gdb_test "events exited check" \ + "Event 1/1, Inferior $inferior, Exit Code None" \ + "expected exited event has been seen" + } else { + gdb_test "core-file $corefile" ".*" \ + "load core file" + + gdb_test "events corefile_changed check" \ + "Event 1/1, Inferior $inferior, Corefile [string_to_regexp $corefile]" \ + "expected corefile event has been seen" + + gdb_test "events exited check" \ + "^No exited event has been seen\\." \ + "no exited event was emitted" + } + } + + gdb_test_no_output -nopass "events corefile_changed reset" + gdb_test_no_output -nopass "events exited reset" +} + +# A helper proc runs clean_restart passing through ARGS, and then loads the +# test's Python script. +proc clean_restart_and_load_py_script { args } { + clean_restart {*}$args + + # Load the Python script into GDB. + gdb_test "source $::remote_python_file" "^Success" \ + "source python script" +} + # Create a copy of the corefile. set other_corefile [standard_output_file ${testfile}-other.core] remote_exec build "cp $corefile $other_corefile" -clean_restart +clean_restart_and_load_py_script gdb_test_no_output "python inf = gdb.selected_inferior()" \ "capture current inferior" @@ -46,8 +123,7 @@ gdb_test_no_output "python inf = gdb.selected_inferior()" \ gdb_test "python print(inf.corefile)" "^None" \ "Inferior.corefile is None before loading a core file" -gdb_test "core-file $corefile" ".*" \ - "load core file" +core_file_cmd -corefile $corefile set file_re [string_to_regexp $corefile] gdb_test "python print(inf.corefile)" "^" \ @@ -73,7 +149,7 @@ gdb_test "python print(core1.filename)" "^$file_re" \ gdb_test "python print(core1.is_valid())" "^True" \ "Corefile.is_valid() is True while corefile is loaded" -gdb_test "core-file" "^No core file now\\." "unload current core file" +core_file_cmd gdb_test "python print(core1.is_valid())" "^False" \ "Corefile.is_valid() is False after corefile is unloaded" @@ -101,8 +177,7 @@ gdb_test "add-inferior" gdb_test "inferior 2" with_test_prefix "in second inferior" { - gdb_test "core-file $corefile" ".*" \ - "load core file" + core_file_cmd -corefile $corefile -inferior 2 gdb_test "python print(inf.corefile)" "^None" \ "first inferior still has no core file" @@ -128,8 +203,8 @@ gdb_test "python print(core2.filename)" "^$file_re" \ "Corefile.filename attribute works from different progspace" # Load the other corefile into the first inferior. -gdb_test "core $other_corefile" ".*" \ - "load other corefile into inferior 1" +core_file_cmd -corefile $other_corefile \ + -prefix "load other corefile into inferior 1" # Delete the second inferior. We need to switch to the second # inferior and unload its corefile before we can do that. Then, @@ -152,7 +227,7 @@ with_test_prefix "remove second inferior" { "AttributeError.*: 'gdb\\.Corefile' object has no attribute '_my_attribute'" \ "try to read attribute that doesn't exist" - gdb_test "core-file" + core_file_cmd -inferior 2 gdb_test "python print(core2.filename)" \ [multi_line \ @@ -182,18 +257,10 @@ with_test_prefix "remove second inferior" { # mapped_files API. The output from the built-in command, and the # Python command should be identical. with_test_prefix "test mapped files data" { - clean_restart - - set remote_python_file \ - [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] - - # Load the Python script into GDB. - gdb_test "source $remote_python_file" "^Success" \ - "source python script" + clean_restart_and_load_py_script # Load the core file. - gdb_test "core-file $corefile" ".*" \ - "load core file" + core_file_cmd -corefile $corefile # Two files to write the output to. set out_1 [standard_output_file ${gdb_test_file_name}-out-1.txt] @@ -279,3 +346,38 @@ with_test_prefix "test mapped files data" { gdb_test "python regions\[0\] = None" \ "'tuple' object does not support item assignment" } + +# Load a core file. GDB should figure out which file is being debugged. +# Then use 'start' to run this executable, this will replace the core file +# target. At least on Linux, this replacement is done without calling +# target_detach. This test checks that the expected core file changed and +# inferior exited events are still seen. +with_test_prefix "start from corefile" { + if { [gdb_protocol_is_native] } { + clean_restart_and_load_py_script + + # Load the core file. + core_file_cmd -corefile $corefile + + # Check GDB figured out the executable. + gdb_test "info inferiors 1" \ + [multi_line \ + "\[^\r\n\]+[string_to_regexp $binfile]\\s*" \ + "\[^\r\n\]+[string_to_regexp $corefile]\\s*"] \ + "check executable was detected correctly" + + gdb_test "start" \ + "Temporary breakpoint $::decimal, main \\(\\).*" \ + + gdb_test "events corefile_changed check" \ + "Event 1/1, Inferior 1, Corefile None" \ + "expected corefile event has been seen" + + gdb_test "events exited check" \ + "Event 1/1, Inferior 1, Exit Code None" \ + "expected exited event has been seen" + + gdb_test_no_output -nopass "events corefile_changed reset" + gdb_test_no_output -nopass "events exited reset" + } +} diff --git a/gdb/testsuite/gdb.python/py-corefile.py b/gdb/testsuite/gdb.python/py-corefile.py index 43b64085117..1aaf15093ac 100644 --- a/gdb/testsuite/gdb.python/py-corefile.py +++ b/gdb/testsuite/gdb.python/py-corefile.py @@ -196,4 +196,121 @@ class CheckMainExec(gdb.Command): CheckMainExec() +# An 'events' prefix command. +class events_cmd(gdb.Command): + """Information about recent Python events.""" + + def __init__(self): + gdb.Command.__init__(self, "events", gdb.COMMAND_USER, prefix=True) + + +# An 'events corefile_changed' sub-command. +class events_corefile_changed_cmd(gdb.Command): + """Check recent corefile_changed events. + + Requires a single argument either 'check' or 'reset'. With + 'check', print details of every recent corefile_changed event. + With 'reset' clear the list of recent corefile_changed events.""" + + def __init__(self): + gdb.Command.__init__(self, "events corefile_changed", gdb.COMMAND_USER) + self._events = [] + gdb.events.corefile_changed.connect(lambda e: self._corefile_changed_handler(e)) + + def _corefile_changed_handler(self, event): + assert isinstance(event, gdb.CorefileChangedEvent) + inf = event.inferior + assert isinstance(inf, gdb.Inferior) + + corefile = inf.corefile + if corefile is not None: + assert corefile.is_valid() + corefile = corefile.filename + + obj = {"inferior": inf.num, "corefile": corefile} + self._events.append(obj) + + def invoke(self, args, from_tty): + if args == "check": + if len(self._events) == 0: + print("No corefile_changed event has been seen.") + else: + total = len(self._events) + for idx, obj in enumerate(self._events, start=1): + inf_num = obj["inferior"] + corefile = obj["corefile"] + + if corefile is None: + msg = "None" + else: + msg = corefile + + print( + "Event {}/{}, Inferior {}, Corefile {}".format( + idx, total, inf_num, msg + ) + ) + elif args == "reset": + self._events = [] + else: + raise gdb.GdbError("Unknown command args: {}".format(args)) + + +# An 'events exited' sub-command. +class events_exited_cmd(gdb.Command): + """Check recent exited events. + + Requires a single argument either 'check' or 'reset'. With + 'check', print details of every recent corefile_changed event. + With 'reset' clear the list of recent corefile_changed events.""" + + def __init__(self): + gdb.Command.__init__(self, "events exited", gdb.COMMAND_USER) + self._events = [] + gdb.events.exited.connect(lambda e: self._exited_handler(e)) + + def _exited_handler(self, event): + assert isinstance(event, gdb.ExitedEvent) + inf = event.inferior + assert isinstance(inf, gdb.Inferior) + + if hasattr(event, "exit_code"): + assert isinstance(event.exit_code, int) + exit_code = event.exit_code + else: + exit_code = None + + obj = {"inferior": inf.num, "exit_code": exit_code} + self._events.append(obj) + + def invoke(self, args, from_tty): + if args == "check": + if len(self._events) == 0: + print("No exited event has been seen.") + else: + total = len(self._events) + for idx, obj in enumerate(self._events, start=1): + inf_num = obj["inferior"] + exit_code = obj["exit_code"] + + if exit_code is None: + msg = "None" + else: + msg = exit_code + + print( + "Event {}/{}, Inferior {}, Exit Code {}".format( + idx, total, inf_num, msg + ) + ) + elif args == "reset": + self._events = [] + else: + raise gdb.GdbError("Unknown command args: {}".format(args)) + + +events_cmd() +events_corefile_changed_cmd() +events_exited_cmd() + print("Success")