]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Improve attach on Windows
authorPedro Alves <pedro@palves.net>
Wed, 11 Jun 2025 21:05:23 +0000 (22:05 +0100)
committerPedro Alves <pedro@palves.net>
Thu, 2 Apr 2026 12:06:48 +0000 (13:06 +0100)
Unlike most targets, on Windows, when you attach, GDB doesn't print
the current stack frame.  Vis:

On GNU/Linux:

 attach 3340347
 Attaching to program: /home/pedro/gdb/build/gdb/testsuite/outputs/gdb.base/attach/attach, process 3340347
 Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
 Reading symbols from /usr/lib/debug/.build-id/d5/197096f709801829b118af1b7cf6631efa2dcd.debug...
 Reading symbols from /lib64/ld-linux-x86-64.so.2...
 Reading symbols from /usr/lib/debug/.build-id/9c/b53985768bb99f138f48655f7b8bf7e420d13d.debug...
 [Thread debugging using libthread_db enabled]
 Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
 0x00005b3bf29be174 in main () at /home/pedro/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/attach.c:19
 19        while (! should_exit)
 (gdb) PASS: gdb.base/attach.exp: do_attach_tests: attach1, after setting file

On Cygwin:

 (gdb) attach 6692
 Attaching to program: /home/alves/gdb/build-cygwin-testsuite/outputs/gdb.base/attach/attach, process 6692
 [New Thread 6692.0x2e60]
 [New Thread 6692.0x2e9c]
 [New Thread 6692.0xd6c]
 [New Thread 6692.0x137c]
 [New Thread 6692.0x1270]
 (gdb) FAIL: gdb.base/attach.exp: do_attach_tests: attach1, after setting file

On Linux, GDB prints the frame because after the target_attach, GDB
goes back to the event loop, to wait for an initial stop event.  The
stop event arrives, and we process it, which sets the stop_print_frame
global, and then we get to normal_stop, which prints the frame iff
stop_print_frame is set, which it is.

Windows OTOH, is a target_attach_no_wait target, so after
target_attach, there is no going back to event loop.  In
infcmd.c:attach_command, we go straight to attach_post_wait which
takes us to normal_stop.  But this time, nothing set stop_print_frame
to true, so no frame is printed.  Actually, if the global happened to
be true due to an earlier event from debugging a previous inferior,
then we will print the frame.

This patch makes GDB's behavior consistent, by making sure the globals
normal_stop looks at are in a good state in the target_attach_no_wait
path.

With that alone, GDB now prints the frame:

 (gdb) attach 2915
 Attaching to program: /usr/bin/sleep.exe, process 2832
 [New Thread 2832.0x2a68]
 [New Thread 2832.0xb1c]
 [New Thread 2832.0x8ac]
 [Switching to Thread 2832.0x8ac]
 0x00007ffec51d4a71 in ntdll!DbgBreakPoint () from C:/Windows/SYSTEM32/ntdll.dll

This is still not ideal, IMHO, as the current thread is the thread
that Windows injects to attach:

 (gdb) info threads
   Id   Target Id                  Frame
   1    Thread 2832.0x2100 "sleep" 0x00007ffec51d18d7 in ntdll!ZwWaitForMultipleObjects () from C:/Windows/SYSTEM32/ntdll.dll
   2    Thread 2832.0x2a68 "sig"   0x00007ffec51d0e47 in ntdll!ZwReadFile () from C:/Windows/SYSTEM32/ntdll.dll
   3    Thread 2832.0xb1c          0x00007ffec51d49d7 in ntdll!ZwWaitForWorkViaWorkerFactory () from C:/Windows/SYSTEM32/ntdll.dll
 * 4    Thread 2832.0x8ac          0x00007ffec51d4a71 in ntdll!DbgBreakPoint () from C:/Windows/SYSTEM32/ntdll.dll

Automatically switching to the main thread is IMHO more useful.  That
results in very similar output than what we see on Linux:

 attach 5164
 Attaching to program: /home/alves/gdb/build-cygwin-testsuite/outputs/gdb.base/attach/attach, process 5164
 [New Thread 5164.0x87c]
 [New Thread 5164.0x28f0]
 [New Thread 5164.0x376c]
 [New Thread 5164.0x2db4]
 [New Thread 5164.0xce4]
 main () at /home/alves/gdb/src/gdb/testsuite/gdb.base/attach.c:19
 19        while (! should_exit)
 (gdb)

If we do this, then we can simplify gdb.base/attach.exp a bit by
removing a couple Cygwin special cases.

The patch does all that, which results in the following
gdb.base/attach.exp progressions:

 -FAIL: gdb.base/attach.exp: do_attach_tests: attach1, after setting file
 -FAIL: gdb.base/attach.exp: do_attach_tests: attach2, with no file
 -FAIL: gdb.base/attach.exp: do_attach_tests: load file manually, after attach2 (re-read) (got interactive prompt)
 -FAIL: gdb.base/attach.exp: do_attach_tests: attach when process' a.out not in cwd
 -FAIL: gdb.base/attach.exp: do_attach_failure_tests: first attach
 +PASS: gdb.base/attach.exp: do_attach_tests: attach1, after setting file
 +PASS: gdb.base/attach.exp: do_attach_tests: attach2, with no file
 +PASS: gdb.base/attach.exp: do_attach_tests: attach when process' a.out not in cwd
 +PASS: gdb.base/attach.exp: do_attach_failure_tests: first attach

Change-Id: I359bdb25660c9a4d5d873e8771cfd1cd2a54c97b

gdb/infcmd.c
gdb/infrun.c
gdb/infrun.h
gdb/testsuite/gdb.base/attach.exp
gdb/windows-nat.c

index 9fbee5aaba7f4d3831cc01499bedc5bbf06534d3..98b45f884b1e8b0f3a03580b548de8a17ce17c15 100644 (file)
@@ -2956,7 +2956,10 @@ attach_command (const char *args, int from_tty)
       return;
     }
   else
-    attach_post_wait (from_tty, mode);
+    {
+      set_normal_stop_state_just_attached ();
+      attach_post_wait (from_tty, mode);
+    }
 
   disable_commit_resumed.reset_and_commit ();
 }
index 9864b5bbdeca45a0e01e0ed130f763ddaa4504cf..6ca2a505299a2e9add97ebb8807386da6cb4738d 100644 (file)
@@ -407,6 +407,19 @@ static process_stratum_target *target_last_proc_target;
 static ptid_t target_last_wait_ptid;
 static struct target_waitstatus target_last_waitstatus;
 
+/* See infrun.h.  */
+
+void
+set_normal_stop_state_just_attached ()
+{
+  stop_print_frame = true;
+  stopped_by_random_signal = 0;
+
+  target_waitstatus status;
+  status.set_ignore ();
+  set_last_target_status (nullptr, minus_one_ptid, status);
+}
+
 void init_thread_stepping_state (struct thread_info *tss);
 
 static const char follow_fork_mode_child[] = "child";
index 0a7cdadf1faef7b4e2490eb09acfef795dee2a3c..7e2b652e4f1a25d7596a7f1f2b8a0af020558f89 100644 (file)
@@ -428,4 +428,8 @@ private:
    input.  */
 extern void reinstall_readline_callback_handler_cleanup ();
 
+/* Set up state for normal_stop after we just attached, on
+   target_attach_no_wait targets.  */
+extern void set_normal_stop_state_just_attached ();
+
 #endif /* GDB_INFRUN_H */
index c4274994b09a537c0c4df37960df277b03459bcb..bffdfd9b1aa932a10b2890e6b5011b0f21abe2f2 100644 (file)
@@ -159,16 +159,9 @@ proc_with_prefix do_attach_failure_tests {} {
 
     # Verify that we can't double attach to the process.
 
-    set test "first attach"
-    gdb_test_multiple "attach $testpid" "$test" {
-       -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*main.*at .*$srcfile:.*$gdb_prompt $" {
-           pass "$test"
-       }
-       -re "Attaching to program.*`?$escapedbinfile\.exe'?, process $testpid.*\[Switching to thread $testpid\..*\].*$gdb_prompt $" {
-           # Response expected on Cygwin.
-           pass "$test"
-       }
-    }
+    gdb_test "attach $testpid" \
+       "Attaching to program.*`?${escapedbinfile}(\.exe)?'?, process $testpid.*main.*at .*$srcfile:.*" \
+       "first attach"
 
     gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2"
     gdb_test "inferior 2" "Switching to inferior 2.*" "switch to inferior 2"
@@ -252,16 +245,9 @@ proc_with_prefix do_attach_tests {} {
        }
     }
 
-    set test "attach1, after setting file"
-    gdb_test_multiple "attach $testpid" "$test" {
-       -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*main.*at .*$srcfile:.*$gdb_prompt $" {
-           pass "$test"
-       }
-       -re "Attaching to program.*`?$escapedbinfile\.exe'?, process $testpid.*\[Switching to thread $testpid\..*\].*$gdb_prompt $" {
-           # Response expected on Cygwin
-           pass "$test"
-       }
-    }
+    gdb_test "attach $testpid" \
+       "Attaching to program.*`?${escapedbinfile}(\.exe)?'?, process $testpid.*main.*at .*$srcfile:.*" \
+       "attach1, after setting file"
 
     # Verify that we can "see" the variable "should_exit" in the
     # program, and that it is zero.
index 3d1a75d1cc8da13388648b782fd72645bfd098c0..d1328375e554df1be7f6756ac9ffa94e7b5f07a9 100644 (file)
@@ -1412,6 +1412,13 @@ windows_nat_target::attach (const char *args, int from_tty)
 #endif
 
   do_initial_windows_stuff (pid, 1);
+
+  /* The thread that reports the initial breakpoint, and thus ends up
+     as the selected thread when we get here, was injected into the
+     inferior by DebugActiveProcess.  Switch to the main thread, which
+     is normally more useful to the user than the injected thread.  */
+  switch_to_thread (first_thread_of_inferior (current_inferior ()));
+
   target_terminal::ours ();
 }