From ecf00b52957bb0bf15735180a67cc9ce7027ff19 Mon Sep 17 00:00:00 2001 From: Alain Schneble Date: Thu, 25 Aug 2016 21:31:48 +0200 Subject: [PATCH] Support SIGTRAP in kill emulation on Windows * src/w32proc.c (sys_kill): Translate SIGTRAP signal into a call to DebugBreakProcess to cause a breakpoint exception to occur in the specified process. Windows versions prior to Windows XP that do not support DebugBreakProcess return -1 and errno set to ENOTSUP (as opposed to EINVAL before this change). * src/w32proc.c: Add typedef for DebugBreakProcess function pointer and global variable to track state of run-time dynamic linking of this function. * etc/NEWS: Add entry to document that 'signal-process' now supports SIGTRAP. --- etc/NEWS | 8 ++++++++ src/w32.c | 3 +++ src/w32proc.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 494a091..3d055fc 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -599,6 +599,14 @@ still apply.) Previously, on MS-Windows this function converted slash characters in file names into backslashes. It no longer does that. +--- +** 'signal-process' supports SIGTRAP on Windows XP and later. +The 'kill' emulation on Windows now maps SIGTRAP to a call to Win32 +'DebugBreakProcess'. This causes the receiving process to break +execution and return control to the debugger. If no debugger is +attached to the receiving process, the call is typically ignored by +the receiving process. + * Installation Changes in Emacs 25.1 diff --git a/src/w32.c b/src/w32.c index 1db3426..355e7ca 100644 --- a/src/w32.c +++ b/src/w32.c @@ -330,6 +330,7 @@ static BOOL g_b_init_set_named_security_info_a; static BOOL g_b_init_get_adapters_info; BOOL g_b_init_compare_string_w; +BOOL g_b_init_debug_break_process; /* BEGIN: Wrapper functions around OpenProcessToken @@ -9636,6 +9637,7 @@ globals_of_w32 (void) g_b_init_get_process_working_set_size = 0; g_b_init_global_memory_status = 0; g_b_init_global_memory_status_ex = 0; + g_b_init_debug_break_process = 0; g_b_init_equal_sid = 0; g_b_init_copy_sid = 0; g_b_init_get_length_sid = 0; @@ -9653,6 +9655,7 @@ globals_of_w32 (void) g_b_init_set_named_security_info_a = 0; g_b_init_get_adapters_info = 0; g_b_init_compare_string_w = 0; + g_b_init_debug_break_process = 0; num_of_processors = 0; /* The following sets a handler for shutdown notifications for console apps. This actually applies to Emacs in both console and diff --git a/src/w32proc.c b/src/w32proc.c index 11a121f..bb637bc 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -66,6 +66,8 @@ along with GNU Emacs. If not, see . */ + (filedata).file_base)) extern BOOL g_b_init_compare_string_w; +extern BOOL g_b_init_debug_break_process; + int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, struct timespec *, void *); @@ -2494,6 +2496,9 @@ find_child_console (HWND hwnd, LPARAM arg) return TRUE; } +typedef BOOL (WINAPI * DebugBreakProcess_Proc) ( + HANDLE hProcess); + /* Emulate 'kill', but only for other processes. */ int sys_kill (pid_t pid, int sig) @@ -2507,9 +2512,9 @@ sys_kill (pid_t pid, int sig) if (pid < 0) pid = -pid; - /* Only handle signals that will result in the process dying */ + /* Only handle signals that can be mapped to a similar behavior on Windows */ if (sig != 0 - && sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP) + && sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP && sig != SIGTRAP) { errno = EINVAL; return -1; @@ -2552,7 +2557,11 @@ sys_kill (pid_t pid, int sig) close the selected frame, which does not necessarily terminates Emacs. But then we are not supposed to call sys_kill with our own PID. */ - proc_hand = OpenProcess (PROCESS_TERMINATE, 0, pid); + + DWORD desiredAccess = + (sig == SIGTRAP) ? PROCESS_ALL_ACCESS : PROCESS_TERMINATE; + + proc_hand = OpenProcess (desiredAccess, 0, pid); if (proc_hand == NULL) { errno = EPERM; @@ -2648,6 +2657,43 @@ sys_kill (pid_t pid, int sig) rc = -1; } } + else if (sig == SIGTRAP) + { + static DebugBreakProcess_Proc s_pfn_Debug_Break_Process = NULL; + + if (g_b_init_debug_break_process == 0) + { + g_b_init_debug_break_process = 1; + s_pfn_Debug_Break_Process = (DebugBreakProcess_Proc) + GetProcAddress (GetModuleHandle ("kernel32.dll"), + "DebugBreakProcess"); + } + + if (s_pfn_Debug_Break_Process == NULL) + { + errno = ENOTSUP; + rc = -1; + } + else if (!s_pfn_Debug_Break_Process (proc_hand)) + { + DWORD err = GetLastError (); + + DebPrint (("sys_kill.DebugBreakProcess return %d " + "for pid %lu\n", err, pid)); + + switch (err) + { + case ERROR_ACCESS_DENIED: + errno = EPERM; + break; + default: + errno = EINVAL; + break; + } + + rc = -1; + } + } else { if (NILP (Vw32_start_process_share_console) && cp && cp->hwnd) -- 2.8.1.windows.1