WIP MachO binutils port assisted by AI I may consider upstreaming this in the future.
0

Configure Feed

Select the types of activity you want to include in your feed.

Sync thread state after infcalls with "set unwind-on-* on" (PR gdb/34148)

Commit 519774805a1 ("Don't pretend infcalls don't set the inferior
running (PR gdb/34082)") removed the special case in proceed that
skipped set_state(THREAD_RUNNING) for infcalls. That fixed
gdb.threads/hand-call-new-thread.exp, but introduced a regression in
gdb.compile/compile.exp:

...
set unwind-on-signal on
(gdb) PASS: gdb.compile/compile.exp: set unwind-on-signal on
compile code *(volatile int *) 0 = 0;
The program being debugged received signal SIGSEGV, Segmentation fault
while in a function called from GDB. GDB has restored the context
to what it was before the call. To change this behavior use
"set unwind-on-signal off". Evaluation of the expression containing
the function (_gdb_expr) will be abandoned.
(gdb) PASS: gdb.compile/compile.exp: compile code segfault second
break 132
Breakpoint 2 at 0x555555555262: file .../compile.c, line 132.
(gdb) continue
Cannot execute this command while the selected thread is running.
(gdb) FAIL: gdb.compile/compile.exp: continue to breakpoint: break-here

The "compile code" command before the FAIL is an infcall under the
hood. That hits SIGSEGV with "set unwind-on-signal on" in effect, so
GDB unwinds and abandons the call. After that, "continue" is rejected
because the thread is still marked THREAD_RUNNING from the proceed
that started the infcall.

When an infcall is unwound due to a signal, timeout, or terminating
exception, call_thread_fsm::should_notify_stop returns false, and so
normal_stop is not called from fetch_inferior_event. normal_stop is
what would normally call finish_thread_state to sync the public thread
state back to THREAD_STOPPED. run_inferior_call has a fallback
finish_thread_state call for that purpose, but it is gated on
stop_stack_dummy == STOP_STACK_DUMMY, which is only true for
successful calls.

Before the commit mentioned above, proceed never marked an infcall's
thread as THREAD_RUNNING, so the missing RUNNING => STOPPED transition
was harmless. The old comment in infcall.c about the
finish_thread_state call claimed "If the infcall does NOT succeed,
normal_stop will have already finished the thread states", but that
was already incorrect for the unwind paths. It just happened to not
matter.

Fix this by dropping the STOP_STACK_DUMMY guard and updating the
comment to describe the actual rule: sync regardless of how the call
ended. The !was_running check is kept since it is there to exclude
the in-cond-eval case, where the thread is meant to stay marked
running. finish_thread_state is idempotent, so the call is harmless
on paths where normal_stop also ran.

Extend gdb.base/unwindonsignal.exp to exercise the "set
unwind-on-signal on" path without having to rely on the "compile code"
feature. Without the fix, the test fails like so:

info threads
Id Target Id Frame
* 1 Thread 0x7ffff7f8f740 (LWP 239019) "unwindonsignal" (running)
(gdb) FAIL: gdb.base/unwindonsignal.exp: thread is stopped
continue
Cannot execute this command while the selected thread is running.
(gdb) FAIL: gdb.base/unwindonsignal.exp: continue until exit at after unwound infcall

Similarly, extend gdb.cp/gdb2495.exp for "set
unwind-on-terminating-exception on", and gdb.base/infcall-timeout.exp
for "set unwind-on-timeout on". Both would fail without the code fix,
too.

With the fix, gdb.compile/compile.exp now passes cleanly.

Tested on x86_64-unknown-linux-gnu.

Approved-By: Andrew Burgess <aburgess@redhat.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34148
Change-Id: Idef0dcd4dd751b501869c58b752f77d4dadb6c72

Pedro Alves (May 26, 2026, 1:42 PM +0100) 4e51e5ab a8740b75

+44 -8
+15 -8
gdb/infcall.c
··· 918 918 current_ui->register_file_handler (); 919 919 } 920 920 921 - /* If the infcall does NOT succeed, normal_stop will have already 922 - finished the thread states. However, on success, normal_stop 923 - defers here, so that we can set back the thread states to what 924 - they were before the call. Note that we must also finish the 925 - state of new threads that might have spawned while the call was 926 - running. The main cases to handle are: 921 + /* Sync the user/frontend thread states from the internal thread 922 + states. proceed marked threads in resume_ptid as THREAD_RUNNING 923 + for this infcall; we must now sync them back, regardless of how 924 + the call ended. For the success path and for the unwind paths 925 + (unwind-on-{signal,timeout,terminating-exception}), 926 + call_thread_fsm::should_notify_stop returns false and normal_stop 927 + is skipped -- this call is the canonical place to do the sync. 928 + For other failure paths normal_stop does run and has already 929 + finished the thread state; finish_thread_state is idempotent, so 930 + calling it again here is harmless. Note that we must also finish 931 + the state of new threads that might have spawned while the call 932 + was running. 933 + 934 + The main cases to handle are: 927 935 928 936 - "(gdb) print foo ()", or any other command that evaluates an 929 937 expression at the prompt. (The thread was marked stopped before.) ··· 934 942 evaluates true and thus we'll present a user-visible stop is 935 943 decided elsewhere. */ 936 944 if (!was_running 937 - && call_thread_ptid == inferior_ptid 938 - && stop_stack_dummy == STOP_STACK_DUMMY) 945 + && call_thread_ptid == inferior_ptid) 939 946 finish_thread_state (call_thread->inf->process_target (), 940 947 user_visible_resume_ptid (0)); 941 948
+13
gdb/testsuite/gdb.base/infcall-timeout.exp
··· 86 86 gdb_test "bt" \ 87 87 ".* function_that_never_returns .*<function called from gdb>.*" 88 88 } 89 + 90 + # After the infcall, the thread should be stopped. Regression 91 + # test for PR gdb/34148. 92 + if {$non_stop} { 93 + # Check the main thread only, in case we have system-spawned 94 + # threads. 95 + set thread_filter "1" 96 + } else { 97 + set thread_filter "" 98 + } 99 + gdb_test "info threads -running $thread_filter" \ 100 + "No threads matched\\." \ 101 + "thread is stopped" 89 102 } 90 103 91 104 foreach_with_prefix target_async { "on" "off" } {
+10
gdb/testsuite/gdb.base/unwindonsignal.exp
··· 86 86 pass $gdb_test_name 87 87 } 88 88 } 89 + 90 + # After the unwound infcall, the thread should be stopped, and a 91 + # subsequent resumption command should be accepted. Regression test 92 + # for PR gdb/34148. 93 + 94 + gdb_test "info threads -running" \ 95 + "No threads matched\\." \ 96 + "thread is stopped" 97 + 98 + gdb_continue_to_end "after unwound infcall"
+6
gdb/testsuite/gdb.cp/gdb2495.exp
··· 64 64 "The program being debugged entered a std::terminate call, .*" \ 65 65 "call a function that raises an exception without a handler." 66 66 67 + # Make sure that the thread is stopped. Regression test for PR 68 + # gdb/34148. 69 + gdb_test "info threads -running" \ 70 + "No threads matched\\." \ 71 + "thread is stopped" 72 + 67 73 # Make sure that after rewinding we are back at the call parent. 68 74 gdb_test "bt" \ 69 75 "#0 main.*" \