Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Lancelot SIX <Lancelot.Six@amd.com>
To: Andrew Burgess <aburgess@redhat.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH] gdb/python: fix 'exited' event when GDB exits from core file debugging
Date: Thu, 4 Jun 2026 21:11:58 +0100	[thread overview]
Message-ID: <b255ffa8-86e6-4eb4-94c5-5be7b5fe3057@amd.com> (raw)
In-Reply-To: <fce47c4e13bd626b3b3bc074fd51ab1ed23ad0e3.1780591573.git.aburgess@redhat.com>

Hi Andrew,

Thanks for the quick turnaround!

FYI, when applying the patch, git reports:

```
Applying: gdb/python: fix 'exited' event when GDB exits from core file 
debugging
.git/rebase-apply/patch:127: indent with spaces.
             "python print(str(gdb.selected_inferior()))" ""]
.git/rebase-apply/patch:133: indent with spaces.
            set inferior_string $expect_out(1,string)
.git/rebase-apply/patch:134: indent with spaces.
            incr event_count
.git/rebase-apply/patch:135: indent with spaces.
            exp_continue
.git/rebase-apply/patch:139: indent with spaces.
            verbose -log "GDB has now exited"
warning: squelched 7 whitespace errors
warning: 12 lines add whitespace errors.
```

I have tested the patch on top of our downstream ROCgdb, and this fixes 
the issue.

I have one minor comment below, but otherwise the patch itself looks 
good to me.

On 04/06/2026 17:47, Andrew Burgess wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
> 
> 
> 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 <http://www.gnu.org/licenses/>.  */
> +
> +#include <stdlib.h>
> +
> +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 <http://www.gnu.org/licenses/>.
> +
> +# 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
> +    }

I expect you could have GDB create the coredump instead of relying on 
the kernel for this.  This allows this test to run on systems where 
kernel.core_pattern is not set in a way supported by the testsuite:


----
diff --git a/gdb/testsuite/gdb.python/py-inf-exited-at-exit.c 
b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.c
index 708e3eb98ea..f999fdbbf00 100644
--- a/gdb/testsuite/gdb.python/py-inf-exited-at-exit.c
+++ b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.c
@@ -20,8 +20,6 @@
  void
  foo (void)
  {
-  /* With correct ulimit, etc. this should cause a core dump.  */
-  abort ();
  }

  int
diff --git a/gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp 
b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp
index f90974dc894..80543bc6f7c 100644
--- a/gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp
+++ b/gdb/testsuite/gdb.python/py-inf-exited-at-exit.exp
@@ -66,20 +66,27 @@ proc source_py_script_and_exit_checking_event {} {
  # 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"
+    clean_restart $::testfile
+
+    if {![runto_main]} {
         return
      }

+    gdb_breakpoint "foo"
+    gdb_continue_to_breakpoint "stop in foo"
+
+    set corefile "$::binfile.core"
+    gdb_test "generate-core $corefile" "Saved corefile $corefile" \
+           "generate-core"
+
      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\]+"] \
+           "#0  (?:$::hex in )?foo \\(\\) at \[^\r\n\]+" \
+           "#1  (?:$::hex in )?main \\(\\) at \[^\r\n\]+"] \
         "backtrace after loading corefile"

      source_py_script_and_exit_checking_event

----

Best,
Lancelot.

> +
> +    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 <http://www.gnu.org/licenses/>.
> +
> +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
> 


  reply	other threads:[~2026-06-04 20:12 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-04 16:47 Andrew Burgess
2026-06-04 20:11 ` Lancelot SIX [this message]
2026-06-06 17:35   ` Andrew Burgess
2026-06-06 17:32 ` [PATCHv2] " Andrew Burgess
2026-06-09 10:19   ` [PATCHv3] " Andrew Burgess
2026-06-12 14:38     ` Pedro Alves
2026-06-14 21:06       ` Andrew Burgess
2026-06-12 13:49   ` [PATCHv2] " Lancelot SIX

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b255ffa8-86e6-4eb4-94c5-5be7b5fe3057@amd.com \
    --to=lancelot.six@amd.com \
    --cc=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox