Index: windows-nat.c =================================================================== --- windows-nat.c (.../branches/gdb/FSF/current/gdb/windows-nat.c) (revision 146347) +++ windows-nat.c (.../trunk/gdb/gdb-head/gdb/windows-nat.c) (revision 146347) @@ -162,6 +162,14 @@ static int debug_memory = 0; /* show ta static int debug_exceptions = 0; /* show target exceptions */ static int useshell = 0; /* use shell for subprocesses */ +/* Set to non-zero if kernel32.dll provides the DebugBreakProcess + function (see the check_for_DebugBreakProcess function). */ +static int has_DebugBreakProcess = 0; + +/* If has_DebugBreakProcess is non-zero then it contains the address of the + kernel32.dll DebugBreakProcess function. */ +static BOOL WINAPI (*kernel32_DebugBreakProcess) (HANDLE); + /* This vector maps GDB's idea of a register's number into an offset in the windows exception context vector. @@ -211,6 +219,28 @@ windows_set_context_register_offsets (co mappings = offsets; } +/* Check if system DLL kernel32.dll contains the DebugBreakProcess function. + If this is the case then set has_DebugBreakProcess to 1 and store the + address of the function in kernel32_DebugBreakProcess. Note that + DebugBreakProcess should be available starting with Windows XP. It gives + a convenient way to propagate a Ctrl-C event from GDB to the inferior when + they are running in separate consoles (see windows_wait). This is the case + when we attach to a process or new-console is set to 1. */ +static void +check_for_DebugBreakProcess () +{ + HMODULE kernel32_module_handle; + + kernel32_module_handle = LoadLibrary ("kernel32.dll"); + if (kernel32_module_handle) + { + kernel32_DebugBreakProcess = + (void *) GetProcAddress (kernel32_module_handle, "DebugBreakProcess"); + if (kernel32_DebugBreakProcess != NULL) + has_DebugBreakProcess = 1; + } +} + static void check (BOOL ok, const char *file, int line) { @@ -1258,9 +1295,39 @@ windows_resume (struct target_ops *ops, windows_continue (continue_status, ptid_get_tid (ptid)); } +/* 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. */ +BOOL WINAPI +ctrl_c_handler (DWORD event_type) +{ + const int attach_flag = current_inferior ()->attach_flag; + + /* Only handle Ctrl-C event. Ignore others. */ + if (event_type != CTRL_C_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; + + if (has_DebugBreakProcess) + kernel32_DebugBreakProcess (current_process_handle); + else + warning (_("\ +Cannot interrupt program on this version of Windows.\n\ +Press Ctrl-c in the program console.")); + + /* Return true to tell that Ctrl-C has been handled. */ + return TRUE; +} + /* Get the next event from the child. Return 1 if the event requires handling by WFI (or whatever). */ + static int get_windows_debug_event (struct target_ops *ops, int pid, struct target_waitstatus *ourstatus) @@ -1465,23 +1532,36 @@ windows_wait (struct target_ops *ops, while (1) { int retval; - - /* Ignore CTRL+C signals while waiting for a debug event. - FIXME: brobecker/2008-05-20: When the user presses CTRL+C while - the inferior is running, both the inferior and GDB receive the - associated signal. 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 to stop - 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, and it would be nice - to find a better solution to that problem. But in the meantime, - the current approach already greatly mitigate this issue. */ - SetConsoleCtrlHandler (NULL, TRUE); + + /* 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); retval = get_windows_debug_event (ops, pid, ourstatus); - SetConsoleCtrlHandler (NULL, FALSE); + SetConsoleCtrlHandler (&ctrl_c_handler, FALSE); if (retval) return ptid_build (current_event.dwProcessId, 0, retval); @@ -2164,6 +2251,8 @@ _initialize_windows_nat (void) add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1); + check_for_DebugBreakProcess (); + #ifdef __CYGWIN__ add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\ Set use of shell to start subprocess."), _("\