summaryrefslogtreecommitdiff
path: root/gdb/windows-nat.c
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2022-12-05 10:56:23 -0700
committerTom Tromey <tromey@adacore.com>2022-12-13 12:51:53 -0700
commitc88afe9cf5d7fb0bd878acb930d79aafcf182505 (patch)
treeaa074a83270492bc86695706e82b322d67ab34b8 /gdb/windows-nat.c
parentc1dc47f53cccf633f3079db25a5b41adaee940a8 (diff)
downloadbinutils-gdb-c88afe9cf5d7fb0bd878acb930d79aafcf182505.tar.gz
Fix control-c handling on Windows
As Hannes pointed out, the Windows target-async patches broke C-c handling there. Looking into this, I found a few oddities, fixed here. First, windows_nat_target::interrupt calls GenerateConsoleCtrlEvent. I think this event can be ignored by the inferior, so it's not a great way to interrupt. Instead, using DebugBreakProcess (or a more complicated thing for Wow64) seems better. Second, windows_nat_target did not implement the pass_ctrlc method. Implementing this lets us remove the special code to call SetConsoleCtrlHandler and instead integrate into gdb's approach to C-c handling. I believe that this should also fix the race that's described in the comment that's being removed. Initially, I thought a simpler version of this patch would work. However, I think what happens is that some other library (I'm not sure what) calls SetConsoleCtrlHandler while gdb is running, and this intercepts and handles C-c -- so that the gdb SIGINT handler is not called. C-break continues to work, presumably because whatever handler is installed ignores it. This patch works around this issue by ensuring that the gdb handler always comes first.
Diffstat (limited to 'gdb/windows-nat.c')
-rw-r--r--gdb/windows-nat.c83
1 files changed, 19 insertions, 64 deletions
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index b3329cd1a0d..dafda4781b9 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -298,6 +298,7 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
std::string pid_to_str (ptid_t) override;
void interrupt () override;
+ void pass_ctrlc () override;
const char *pid_to_exec_file (int pid) override;
@@ -1509,24 +1510,12 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
windows_continue (continue_status, ptid.lwp (), 0);
}
-/* Ctrl-C handler used when the inferior is not run in the same console. The
- handler is in charge of interrupting the inferior using DebugBreakProcess.
- Note that this function is not available prior to Windows XP. In this case
- we emit a warning. */
-static BOOL WINAPI
-ctrl_c_handler (DWORD event_type)
-{
- const int attach_flag = current_inferior ()->attach_flag;
-
- /* Only handle Ctrl-C and Ctrl-Break events. Ignore others. */
- if (event_type != CTRL_C_EVENT && event_type != CTRL_BREAK_EVENT)
- return FALSE;
-
- /* If the inferior and the debugger share the same console, do nothing as
- the inferior has also received the Ctrl-C event. */
- if (!new_console && !attach_flag)
- return TRUE;
+/* Interrupt the inferior. */
+void
+windows_nat_target::interrupt ()
+{
+ DEBUG_EVENTS ("interrupt");
#ifdef __x86_64__
if (windows_process.wow64_process)
{
@@ -1548,19 +1537,24 @@ ctrl_c_handler (DWORD event_type)
windows_process.wow64_dbgbreak,
NULL, 0, NULL);
if (thread)
- CloseHandle (thread);
+ {
+ CloseHandle (thread);
+ return;
+ }
}
}
else
#endif
- {
- if (!DebugBreakProcess (windows_process.handle))
- warning (_("Could not interrupt program. "
- "Press Ctrl-c in the program console."));
- }
+ if (DebugBreakProcess (windows_process.handle))
+ return;
+ warning (_("Could not interrupt program. "
+ "Press Ctrl-c in the program console."));
+}
- /* Return true to tell that Ctrl-C has been handled. */
- return TRUE;
+void
+windows_nat_target::pass_ctrlc ()
+{
+ interrupt ();
}
/* Get the next event from the child. Returns the thread ptid. */
@@ -1840,35 +1834,7 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
while (1)
{
- /* If the user presses Ctrl-c while the debugger is waiting
- for an event, he expects the debugger to interrupt his program
- and to get the prompt back. There are two possible situations:
-
- - The debugger and the program do not share the console, in
- which case the Ctrl-c event only reached the debugger.
- In that case, the ctrl_c handler will take care of interrupting
- the inferior. Note that this case is working starting with
- Windows XP. For Windows 2000, Ctrl-C should be pressed in the
- inferior console.
-
- - The debugger and the program share the same console, in which
- case both debugger and inferior will receive the Ctrl-c event.
- In that case the ctrl_c handler will ignore the event, as the
- Ctrl-c event generated inside the inferior will trigger the
- expected debug event.
-
- FIXME: brobecker/2008-05-20: If the inferior receives the
- signal first and the delay until GDB receives that signal
- is sufficiently long, GDB can sometimes receive the SIGINT
- after we have unblocked the CTRL+C handler. This would
- lead to the debugger stopping prematurely while handling
- the new-thread event that comes with the handling of the SIGINT
- inside the inferior, and then stop again immediately when
- the user tries to resume the execution in the inferior.
- This is a classic race that we should try to fix one day. */
- SetConsoleCtrlHandler (&ctrl_c_handler, TRUE);
ptid_t result = get_windows_debug_event (pid, ourstatus, options);
- SetConsoleCtrlHandler (&ctrl_c_handler, FALSE);
if (result != null_ptid)
{
@@ -2868,17 +2834,6 @@ windows_nat_target::mourn_inferior ()
inf_child_target::mourn_inferior ();
}
-/* Send a SIGINT to the process group. This acts just like the user typed a
- ^C on the controlling terminal. */
-
-void
-windows_nat_target::interrupt ()
-{
- DEBUG_EVENTS ("GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)");
- CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT,
- windows_process.current_event.dwProcessId));
-}
-
/* Helper for windows_xfer_partial that handles memory transfers.
Arguments are like target_xfer_partial. */