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.  On Windows versions prior to Windows XP that do
not support 'DebugBreakProcess' return -1 and set errno 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.
This commit is contained in:
Alain Schneble 2016-10-08 16:52:40 +03:00 committed by Eli Zaretskii
parent 67d14c8222
commit f3eedc7e68
3 changed files with 61 additions and 3 deletions

View file

@ -668,6 +668,16 @@ session and exits. In particular, this will happen if you start
emacs.exe from the Windows shell, then type Ctrl-C into that shell's
window.
---
** 'signal-process' supports SIGTRAP on Windows XP and later.
The 'kill' emulation on Windows now maps SIGTRAP to a call to the
'DebugBreakProcess' API. 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.
This is in contrast to the default action on POSIX Systems, where it
causes the receiving process to terminate with a core dump if no
debugger has been attached to it.
----------------------------------------------------------------------
This file is part of GNU Emacs.

View file

@ -334,6 +334,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
@ -9657,6 +9658,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

View file

@ -69,6 +69,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
+ (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 *);
@ -2497,6 +2499,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)
@ -2510,9 +2515,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;
@ -2555,7 +2560,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;
@ -2651,6 +2660,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)