Skip to content

Commit 9d4a5bd

Browse files
committed
[Windows] Write out minidumps on reception of SIGQUIT
This commit adds the ability to dump core when sending the `SIGQUIT` signal on Windows. The change reads in the current registry setting for local dumps, and attempts to write out to that location before killing the process. See [0] for registry and pathing details. This behavior mimics that of the dumps created by the typical Windows Error Reporting mechanism. [0] https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps
1 parent a9b8cea commit 9d4a5bd

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

configure

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15138,7 +15138,7 @@ fi
1513815138

1513915139
case $host_os in
1514015140
mingw*)
15141-
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -lsecur32 -luserenv -luser32"
15141+
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -lsecur32 -luserenv -luser32 -ldbghelp -lole32 -luuid"
1514215142
;;
1514315143
esac
1514415144
case $host_os in

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false])
7474
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
7575
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
7676
AS_CASE([$host_os],[mingw*], [
77-
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -lsecur32 -luserenv -luser32"
77+
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -lsecur32 -luserenv -luser32 -lwer -ldbghelp"
7878
])
7979
AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])])
8080
AS_CASE([$host_os], [kfreebsd*], [

include/uv/win.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ typedef intptr_t ssize_t;
5757
/* Signals supported by uv_signal and or uv_kill */
5858
#define SIGHUP 1
5959
#define SIGINT 2
60+
#define SIGQUIT 3
6061
#define SIGILL 4
6162
#define SIGABRT_COMPAT 6
6263
#define SIGFPE 8

src/win/process.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "internal.h"
3131
#include "handle-inl.h"
3232
#include "req-inl.h"
33+
#include <dbghelp.h>
34+
#include <shlobj.h>
3335

3436

3537
typedef struct env_var {
@@ -1250,7 +1252,68 @@ static int uv__kill(HANDLE process_handle, int signum) {
12501252
return UV_EINVAL;
12511253
}
12521254

1255+
// Create a dump file for the targeted process, if the registry key
1256+
// `HKLM:Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\DumpFolder`
1257+
// points to a valid folder. The default value if the registry key does not
1258+
// exist is `%LOCALAPPDATA%\CrashDumps`, see [0] for more detail.
1259+
// [0]: https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps
1260+
if (signum == SIGQUIT) {
1261+
// Get process name
1262+
WCHAR basename[MAX_PATH];
1263+
GetModuleBaseNameW(process_handle, NULL, &basename[0], sizeof(basename));
1264+
1265+
// Get PID
1266+
DWORD pid = GetProcessId(process_handle);
1267+
1268+
// Get LocalDumps directory path:
1269+
HKEY registry_key;
1270+
WCHAR dump_folder[MAX_PATH];
1271+
DWORD ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1272+
L"SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps",
1273+
0,
1274+
KEY_QUERY_VALUE,
1275+
&registry_key);
1276+
if (ret == ERROR_SUCCESS) {
1277+
DWORD dump_folder_len = sizeof(dump_folder);
1278+
DWORD key_type = 0;
1279+
ret = RegGetValueW(registry_key,
1280+
NULL,
1281+
L"DumpFolder",
1282+
RRF_RT_ANY,
1283+
&key_type,
1284+
(PVOID) dump_folder,
1285+
&dump_folder_len);
1286+
if (ret != ERROR_SUCCESS) {
1287+
// Default value for `dump_folder` is `%LOCALAPPDATA%\CrashDumps`
1288+
WCHAR * localappdata;
1289+
SHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, NULL, &localappdata);
1290+
swprintf_s(dump_folder, sizeof(dump_folder), L"%ls\\CrashDumps", localappdata);
1291+
CoTaskMemFree(localappdata);
1292+
}
1293+
RegCloseKey(registry_key);
1294+
}
1295+
1296+
// Construct dump filename
1297+
WCHAR dump_name[MAX_PATH];
1298+
swprintf_s(dump_name, sizeof(dump_name), L"%ls\\%ls.%d.dmp", dump_folder, basename, pid);
1299+
1300+
HANDLE hDumpFile = CreateFileW(dump_name, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
1301+
if (hDumpFile != INVALID_HANDLE_VALUE) {
1302+
// Tell wine to dump ELF modules as well
1303+
DWORD sym_options = SymGetOptions();
1304+
SymSetOptions(sym_options | 0x40000000);
1305+
MiniDumpWriteDump(
1306+
process_handle, pid,
1307+
hDumpFile, MiniDumpWithFullMemory,
1308+
NULL, NULL, NULL
1309+
);
1310+
SymSetOptions(sym_options);
1311+
CloseHandle(hDumpFile);
1312+
}
1313+
}
1314+
12531315
switch (signum) {
1316+
case SIGQUIT:
12541317
case SIGTERM:
12551318
case SIGKILL:
12561319
case SIGINT: {

0 commit comments

Comments
 (0)