From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id SVDBALX0dGoiVA4AWB0awg (envelope-from ) for ; Thu, 06 Aug 2026 16:55:17 -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=T0JYOw20; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 0049C1E09B; Thu, 06 Aug 2026 16:55:16 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.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_MSPIKE_H2 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 080191E09B for ; Thu, 06 Aug 2026 16:55:16 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8E4C84BB3BC9 for ; Thu, 6 Aug 2026 20:55:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8E4C84BB3BC9 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=T0JYOw20 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 296EE4BB1C3D for ; Thu, 6 Aug 2026 20:54:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 296EE4BB1C3D 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 296EE4BB1C3D Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1786049654; cv=none; b=Qi1sZLa+wbBIuqz5YU5RTJK5Pm0xswqZttgQOwh5GSAME17DE6WIKBosmcujvBlg5kKmiKTH/Y5Mv+FQ1Ku77EP/Vqd4f6WTKKuj8mzxOlSqJVMoCVYYMS/1dQGOhp0LNURyO8+J5FFu159PvfTjGqQVIugoWnBgxbrmfNetj9g= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1786049654; c=relaxed/simple; bh=HeRwQ4h1eqtBOSNwUMI5BpBNZxFvWMeJ6S2fPJca0v0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=b2JEdftkkYP/XoQyUzBtJLpqm9T5W1lPkuVILeQFrloDrlYZD3g9z9FJvYXR4l3rqkSDsvtV3HrZP5uEAZ+INg447BUSXWzx9TodlAiiaBTaDGuLsH+vTwnBvhvwrDotE2mV9/FZAREj/0SdiyKyAAtt3WDO7A+RicSs9UermIk= 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=T0JYOw20 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 296EE4BB1C3D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1786049653; 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=NNb4u4qdXi/LKYkd+Yjn9hNH1TJLEjwv758Re0/KTgA=; b=T0JYOw20aFsj9WTz+glJkMUHw4euhmiYZtpyt3nxlUrB5lDC+GDlLfcElex067U9Ux54p4 RCPbgoT2zacOZfrh+QgHsFtVv9mvsg8O8NA5Uv4scWhpQ6XrWUK5W3dEx5cXvw9tfpUMAY oi10ktkSScq/8NBCdiCMhmD0gnFlR6Y= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-574-S24oxwzhMY2JY5U54e-OnQ-1; Thu, 06 Aug 2026 16:54:12 -0400 X-MC-Unique: S24oxwzhMY2JY5U54e-OnQ-1 X-Mimecast-MFC-AGG-ID: S24oxwzhMY2JY5U54e-OnQ_1786049651 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-47f7039fa59so2072187f8f.1 for ; Thu, 06 Aug 2026 13:54:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786049651; x=1786654451; 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:content-type; bh=NNb4u4qdXi/LKYkd+Yjn9hNH1TJLEjwv758Re0/KTgA=; b=Wb+QMQgtqIaoiv1Pmq07nCyFCVyVYmWR9cfkzwUcIlnSHdBHS8JvzqxyATebW7AJkt TLhSTqiigBbpW+dfF0dRzLnYuu4hQ6vtWwZyH5xlNEE5ubqa5nuCHRZ5kNy6pdnxhm8t vTPkB2/fFW25qoH8RZUVR7bxkNTQ2TjzMX/LJ8PDCU4b1sMe/c3JrFLqBGhmfHCGkbe2 +dtagUHK5mhOnogjtte76Iq3qYGdZUOSPoKxh2pr9hUBHjAMslcDIYtVvCNqI+hlRG78 63lG5RCTtXrpGwC4x7B/0R4IXjakVJ6qG8ro4Ti4aRnxb0MP02cbTg5ICBSO/H8cw6t8 Zjlg== X-Gm-Message-State: AOJu0YwFEBMI9tOQSRM8xcbU1AZsjdKVfEu4Pd4c9cYxLEXEB2gVSDai RQsMX7eUXwRS/J6/XR+mnTUgDu0Yu5ZIiQ4tHOl0mYJ4p1Ba4QMwdHJFq42i9pk8kJAUXu6L1ET 0OY0VbUO0y02PyiHsFhVJSodsWq89QlZP14yRqzGXdrzu2gge/gvn6ycRlP3MYW6m77lRTKgPPD qEeq0j9nPoBsAajWFER4ofBAQyNo6jofFKJCDKcMpLinj+niM= X-Gm-Gg: AR+sD12iZkpgVH31vRzexBOhKHWrPvgcDSsfxcAbxjkmMAyRLVMFYiY4wWrTXLcL7DT o4A1YHFB3TCfWoWbU+PW+Iwwrt11JndS2VHISIhhGvDF7xkwTJNy7fvwQcg1xnrLVipms9PcjGB BqEhKY00yNSeyffPadzRpiUGl37wuNZcr+KqkGbgAhjgGC7IM/Hpv3LDHuK/6o7S1MYOYIE5VMX Q7O3rXJ53RY+r9FrLMraMiVvq8zfDMciYwP6e14D+x7bqOV+bXDJ8bKUiDMbnumqDmTJsI5lIbI 4upmRQ5J0n1RuvsNJwIpZrCbJtMuCW02mADLKjKGUMMOFzAc5A21FP82zcbguQ89+1LzDLYnj08 6FXke5MmKqHyjmxf+pmAL4Dtg X-Received: by 2002:a05:6000:29d5:b0:47f:6f89:7dae with SMTP id ffacd0b85a97d-47fec4e291dmr22005719f8f.6.1786049651092; Thu, 06 Aug 2026 13:54:11 -0700 (PDT) X-Received: by 2002:a05:6000:29d5:b0:47f:6f89:7dae with SMTP id ffacd0b85a97d-47fec4e291dmr22005676f8f.6.1786049650390; Thu, 06 Aug 2026 13:54:10 -0700 (PDT) Received: from localhost (227.114.208.46.dyn.plus.net. [46.208.114.227]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47ff79a7302sm9448483f8f.1.2026.08.06.13.54.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Aug 2026 13:54:09 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 2/2] gdb: share some thread proceed related code between CLI and MI Date: Thu, 6 Aug 2026 21:54:01 +0100 Message-Id: <55e17e264f17f47680100684c9aa7bd9b88e377c.1786049312.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: 3J5-bYIL3tEWn-90E-tLJjNYHfgBDRZOYoZ8pXml6hk_1786049651 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 I noticed that some code related to proceeding threads could be shared between CLI and MI. This fixes a bug as the CLI code contains a fix that the MI code is missing. In continue_1 (in infcmd.c) we have a loop that iterates over all threads looking for threads that are THREAD_STOPPED and are in an inferior that has_execution. For each thread found we then call: switch_to_thread (&thread); clear_proceed_status (0); proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); In exec_continue (in mi/mi-main.c) we also have a loop over all threads that calls the proceed_thread helper function which skips threads that are not THREAD_STOPPED, does some PID related filtering (more on this later) and then calls the same three functions: switch_to_thread, clear_proceed_status, proceed. The PID filtering mentioned above allows proceed_thread to do two jobs, if the PID is zero then we proceed all threads. If PID is non-zero then we proceed only the threads in the inferior with that PID. You might also have spotted that in continue_1 we checked if the inferior has execution or not. This check was added in commit: commit 5b6d1e4fa4fc6827c7b3f0e99ff120dfa14d65d2 Date: Fri Jan 10 20:06:08 2020 +0000 Multi-target support A matching check was not added into the MI at this point, nor did the commit message mention why such a check was not added. I'm choosing to believe that this was an oversight in the 5b6d1e4fa4fc6827 commit. And this is the bug I mentioned above. If we call `proceed` with a thread that is part of an inferior that does not "has_execution" then the thread will be marked running even though it will never actually be set running. See the early return at the top of `proceed_resume_thread_checked` and the call to set_state in `proceed`. I do worry that there might be a bigger set of bugs here if proceed can set a thread's state to THREAD_RUNNING, but then never actually sets the underlying thread running. But in this case, just having the MI share code with the CLI means that we pick up the fix for this case basically for free. I propose adding a new global helper function `proceed_one_thread`, this will check if the thread is THREAD_STOPPED and is in an inferior which has_execution. If these conditions are met then the three functions mentioned above will be called to proceed the thread. I will then add a second new function `proceed_all_threads`, this will iterate over all threads and call proceed_one_thread. We can then use proceed_all_threads from continue_1, replacing the existing loop. In exec_continue we can move the PID (or rather inferior) check earlier, outside the loop. If we want to resume all threads (the old PID is zero path) then we call proceed_all_threads. If we only want to proceed threads with one PID then we loop over threads in the matching inferior and call proceed_one_thread on each. As the code I am factoring out is all within non_stop only paths I have added `gdb_assert (non_stop);` to each of the new helper functions, this will prevent these functions accidentally being called in the all_stop code path. While moving the two `for (...)` loops I have replaced 'auto' with 'thread_info' for additional type clarity. With the exception of the new has_execution check in the MI path there should be no other user visible changes with this commit. I've added a new test which exposes the missing has_execution check issue. --- gdb/infcmd.c | 62 ++++++++---- gdb/inferior.h | 11 +++ gdb/mi/mi-main.c | 31 ++---- gdb/testsuite/gdb.mi/mi-corefile-and-live.c | 37 +++++++ gdb/testsuite/gdb.mi/mi-corefile-and-live.exp | 97 +++++++++++++++++++ 5 files changed, 195 insertions(+), 43 deletions(-) create mode 100644 gdb/testsuite/gdb.mi/mi-corefile-and-live.c create mode 100644 gdb/testsuite/gdb.mi/mi-corefile-and-live.exp diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 3e943123519..23e93587874 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -722,6 +722,46 @@ ensure_not_running (void) error_is_running (); } +/* See inferior.h. */ + +void +proceed_one_thread (thread_info &thread) +{ + gdb_assert (non_stop); + + if (thread.state () != THREAD_STOPPED) + return; + + if (!thread.inf->has_execution ()) + return; + + switch_to_thread (&thread); + clear_proceed_status (0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); +} + +/* See inferior.h. */ + +void +proceed_all_threads () +{ + gdb_assert (non_stop); + + for (thread_info &thread : all_threads ()) + { + /* We go through all threads individually instead of compressing + into a single target `resume_all' request, because some threads + may be stopped in internal breakpoints/events, or stopped waiting + for its turn in the displaced stepping queue (that is, they are + running from the user's perspective but internally stopped). The + target side has no idea about why the thread is stopped, so a + `resume_all' command would resume too much. If/when GDB gains a + way to tell the target `hold this thread stopped until I say + otherwise', then we can optimize this. */ + proceed_one_thread (thread); + } +} + void continue_1 (bool all_threads_p) { @@ -739,27 +779,7 @@ continue_1 (bool all_threads_p) scoped_disable_commit_resumed disable_commit_resumed ("continue all threads in non-stop"); - for (auto &thread : all_threads ()) - { - /* We go through all threads individually instead of compressing - into a single target `resume_all' request, because some threads - may be stopped in internal breakpoints/events, or stopped waiting - for its turn in the displaced stepping queue (that is, they are - running from the user's perspective but internally stopped). The - target side has no idea about why the thread is stopped, so a - `resume_all' command would resume too much. If/when GDB gains a - way to tell the target `hold this thread stopped until I say - otherwise', then we can optimize this. */ - if (thread.state () != THREAD_STOPPED) - continue; - - if (!thread.inf->has_execution ()) - continue; - - switch_to_thread (&thread); - clear_proceed_status (0); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); - } + proceed_all_threads (); if (current_ui->prompt_state == PROMPT_BLOCKED) { diff --git a/gdb/inferior.h b/gdb/inferior.h index 217741adc07..8255654d9b8 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -227,6 +227,17 @@ extern void registers_info (const char *, bool); extern void continue_1 (bool all_threads_p); +/* For use only when non_stop is true. Proceed all threads in every + inferior. */ + +extern void proceed_all_threads (); + +/* For use only when non_stop is true. If THREAD is stopped, and is in an + inferior that has_execution then switch to THREAD, clear its proceed + status, and proceed the thread. */ + +extern void proceed_one_thread (thread_info &thread); + extern void interrupt_target_1 (bool all_threads); using delete_longjmp_breakpoint_cleanup diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 903c6a5f411..e110b029e1e 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -235,20 +235,6 @@ mi_cmd_exec_jump (const char *args, const char *const *argv, int argc) mi_execute_async_cli_command ("jump", argv, argc); } -static void -proceed_thread (struct thread_info *thread, int pid) -{ - if (thread->state () != THREAD_STOPPED) - return; - - if (pid != 0 && thread->ptid.pid () != pid) - return; - - switch_to_thread (thread); - clear_proceed_status (0); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); -} - static void exec_continue (const char *const *argv, int argc) { @@ -262,24 +248,25 @@ exec_continue (const char *const *argv, int argc) all threads in all inferiors, we need to iterate over threads. - See comment on infcmd.c:proceed_thread_callback for rationale. */ + See comment in infcmd.c:proceed_all_threads for rationale. */ if (current_context->all || current_context->thread_group != -1) { scoped_restore_current_thread restore_thread; scoped_disable_commit_resumed disable_commit_resumed ("MI continue all threads in non-stop"); - int pid = 0; + inferior *inf = nullptr; if (!current_context->all) - { - struct inferior *inf - = find_inferior_id (current_context->thread_group); + inf = find_inferior_id (current_context->thread_group); - pid = inf->pid; + if (inf == nullptr) + proceed_all_threads (); + else + { + for (thread_info &thread : inf->threads ()) + proceed_one_thread (thread); } - for (auto &thread : all_threads ()) - proceed_thread (&thread, pid); disable_commit_resumed.reset_and_commit (); } else diff --git a/gdb/testsuite/gdb.mi/mi-corefile-and-live.c b/gdb/testsuite/gdb.mi/mi-corefile-and-live.c new file mode 100644 index 00000000000..831c7f0de7f --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-corefile-and-live.c @@ -0,0 +1,37 @@ +/* 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 +bar (void) +{ + abort (); +} + +void +foo (void) +{ + bar (); +} + +int +main (int argc, char **argv) +{ + foo (); + return 0; +} diff --git a/gdb/testsuite/gdb.mi/mi-corefile-and-live.exp b/gdb/testsuite/gdb.mi/mi-corefile-and-live.exp new file mode 100644 index 00000000000..a3a57d3c81a --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-corefile-and-live.exp @@ -0,0 +1,97 @@ +# Copyright 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 . + +# In non-stop mode with schedule-multiple turned on, create two +# inferiors, a core target and one other. Then use the command +# '-exec-continue --all'. +# +# The core target threads should not be marked as running by this. + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +require isnative +require allow_multi_inferior_tests + +standard_testfile + +if {[build_executable "build executable" $testfile $srcfile] == -1} { + return +} + +set corefile [core_find $binfile] +if {$corefile == ""} { + untested "unable to create or find corefile" + return +} + +# Start GDB in non-stop and schedule-multiple mode. +save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop on\"" + append GDBFLAGS " -ex \"set schedule-multiple on\"" + mi_clean_restart $::testfile +} + +if {[mi_runto_main] == -1} { + return +} + +# Arrange for inferior 1, our non core file inferior, to stop before +# it hits the abort call. +mi_create_breakpoint "-g i1 foo" \ + "set breakpoint on foo" \ + -inferior 1 + +# Setup inferior 2, this will load the core file. +mi_gdb_test "-add-inferior" \ + [multi_line "=thread-group-added,id=\"i2\"" \ + "~\"\\\[New inferior 2\\\]\\\\n\"" \ + "\~\"Added inferior 2\[^\r\n\]*\\\\n\"" \ + "\\^done,inferior=\"\[^\"\]+\"(?:,connection={.*})?" ] \ + "add inferior 2" + +# Set the executable for inferior 2. +mi_gdb_test "-file-exec-and-symbols --thread-group i2 $::binfile" \ + "\\^done" \ + "set executable of inferior 2" + +# Load the core file into inferior 2. +mi_gdb_test \ + "-target-select --thread-group i2 core $::corefile" \ + [multi_line \ + "=thread-group-started,id=\"i2\",.*" \ + "=thread-created,id=\"2\",group-id=\"i2\"" \ + ".*\\^connected,frame=.*"] \ + "load core file in inferior 2" + +# Check the core file thread is initially shown as stopped. +mi_gdb_test "-thread-info 2" ".*,state=\"stopped\".*" \ + "core file thread is initially stopped" + +# Resume "all" threads. As the core target doesn't support execution +# this should not try to set the core target threads running. +mi_gdb_test "-exec-continue --all" \ + [multi_line \ + "\\^running" \ + "\\*running,thread-id=\"1\""] \ + "resume all" + +# Wait for the non-core target thread to stop. +mi_expect_stop "breakpoint-hit" \ + "foo" ".*" ".*" ".*" {"" "disp=\"keep\""} "w1,i2 stop" + +# Check that the core target thread is still showing as stopped. +mi_gdb_test "-thread-info 2" ".*,state=\"stopped\".*" \ + "core file thread is still stopped" -- 2.25.4