Index: win32-nat.c =================================================================== RCS file: /cvs/src/src/gdb/win32-nat.c,v retrieving revision 1.165 diff -u -p -r1.165 win32-nat.c --- win32-nat.c 2 Oct 2008 14:20:07 -0000 1.165 +++ win32-nat.c 2 Oct 2008 22:32:20 -0000 @@ -155,6 +155,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 WINBASEAPI BOOL WINAPI (*kernel32_DebugBreakProcess) (HANDLE); + /* This vector maps GDB's idea of a register's number into an address in the win32 exception context vector. @@ -238,6 +246,29 @@ static const struct xlate_exception {STATUS_FLOAT_DIVIDE_BY_ZERO, TARGET_SIGNAL_FPE}, {-1, -1}}; +/* 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 win32_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 = + GetProcAddress (kernel32_module_handle, "DebugBreakProcess"); + if (kernel32_DebugBreakProcess != NULL) + has_DebugBreakProcess = 1; + } +} + static void check (BOOL ok, const char *file, int line) { @@ -1282,6 +1313,34 @@ win32_resume (ptid_t ptid, int step, enu win32_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) +{ + /* 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 && !current_inferior ()->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). */ @@ -1488,22 +1547,35 @@ win32_wait (ptid_t ptid, struct target_w { 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_win32_debug_event (pid, ourstatus); - SetConsoleCtrlHandler (NULL, FALSE); + SetConsoleCtrlHandler (&ctrl_c_handler, FALSE); if (retval) return ptid_build (current_event.dwProcessId, 0, retval); @@ -2181,6 +2253,8 @@ _initialize_win32_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."), _("\