summaryrefslogtreecommitdiff
path: root/rts/win32/veh_excn.c
diff options
context:
space:
mode:
authorTamar Christina <tamar@zhox.com>2017-10-03 13:37:52 -0400
committerBen Gamari <ben@smart-cactus.org>2017-10-03 15:16:27 -0400
commitec9ac20d0964c9f1323105b5a2df24f50d4fe3ef (patch)
tree5e21ede1766511cc09b1eb46e7f571d36f3c34ae /rts/win32/veh_excn.c
parent55001c0c9934de2cf94d3879cea20c0faf73695c (diff)
downloadhaskell-ec9ac20d0964c9f1323105b5a2df24f50d4fe3ef.tar.gz
Add ability to produce crash dumps on Windows
It's often hard to debug things like segfaults on Windows, mostly because gdb isn't always of use and users don't know how to effectively use it. This patch provides a way to create a crash drump by passing `+RTS --generate-crash-dumps` as an option. If any unhandled exception is triggered a dump is made that contains enough information to be able to diagnose things successfully. Currently the created dumps are a bit big because I include all registers, code and threads information. This looks like ``` $ testsuite/tests/rts/derefnull.run/derefnull.exe +RTS --generate-crash-dumps Access violation in generated code when reading 0000000000000000 Crash dump created. Dump written to: E:\msys64\tmp\ghc-20170901-220250-11216-16628.dmp ``` Test Plan: ./validate Reviewers: austin, hvr, bgamari, erikd, simonmar Reviewed By: bgamari, simonmar Subscribers: rwbarton, thomie Differential Revision: https://phabricator.haskell.org/D3912
Diffstat (limited to 'rts/win32/veh_excn.c')
-rw-r--r--rts/win32/veh_excn.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/rts/win32/veh_excn.c b/rts/win32/veh_excn.c
index e45ea2b49c..5105d7676f 100644
--- a/rts/win32/veh_excn.c
+++ b/rts/win32/veh_excn.c
@@ -5,11 +5,18 @@
* Error Handling implementations for windows
*
* ---------------------------------------------------------------------------*/
-
+#define UNICODE 1
#include "Rts.h"
#include "ghcconfig.h"
#include "veh_excn.h"
#include <assert.h>
+#include <stdbool.h>
+#include <wchar.h>
+#include <windows.h>
+#include <stdio.h>
+#include <excpt.h>
+#include <inttypes.h>
+#include <Dbghelp.h>
/////////////////////////////////
// Exception / signal handlers.
@@ -80,11 +87,17 @@
// Registered exception handler
PVOID __hs_handle = NULL;
LPTOP_LEVEL_EXCEPTION_FILTER oldTopFilter = NULL;
+bool crash_dump = false;
+bool filter_called = false;
long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data)
{
+ if (!crash_dump && filter_called)
+ return EXCEPTION_CONTINUE_EXECUTION;
+
long action = EXCEPTION_CONTINUE_SEARCH;
ULONG_PTR what;
+ fprintf (stdout, "\n");
// When the system unwinds the VEH stack after having handled an excn,
// return immediately.
@@ -119,6 +132,7 @@ long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data)
if (EXCEPTION_CONTINUE_EXECUTION == action)
{
fflush(stdout);
+ generateDump (exception_data);
stg_exit(EXIT_FAILURE);
}
}
@@ -128,6 +142,7 @@ long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data)
long WINAPI __hs_exception_filter(struct _EXCEPTION_POINTERS *exception_data)
{
+ filter_called = true;
long result = EXCEPTION_CONTINUE_EXECUTION;
if (oldTopFilter)
{
@@ -137,6 +152,8 @@ long WINAPI __hs_exception_filter(struct _EXCEPTION_POINTERS *exception_data)
return result;
}
+ crash_dump = true;
+
return result;
}
@@ -184,3 +201,42 @@ void __unregister_hs_exception_handler( void )
}
}
+// Generate a crash dump, however in order for these to generate undecorated
+// names we really need to be able to generate PDB files.
+void generateDump (EXCEPTION_POINTERS* pExceptionPointers)
+{
+ if (!RtsFlags.MiscFlags.generate_dump_file)
+ return;
+
+ WCHAR szPath[MAX_PATH];
+ WCHAR szFileName[MAX_PATH];
+ WCHAR const *const szAppName = L"ghc";
+ WCHAR const *const szVersion = L"";
+ DWORD dwBufferSize = MAX_PATH;
+ HANDLE hDumpFile;
+ SYSTEMTIME stLocalTime;
+ MINIDUMP_EXCEPTION_INFORMATION ExpParam;
+
+ GetLocalTime (&stLocalTime);
+ GetTempPathW (dwBufferSize, szPath);
+
+ swprintf (szFileName, MAX_PATH,
+ L"%ls%ls%ls-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
+ szPath, szAppName, szVersion,
+ stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
+ stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
+ GetCurrentProcessId(), GetCurrentThreadId());
+ hDumpFile = CreateFileW (szFileName, GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
+
+ ExpParam.ThreadId = GetCurrentThreadId();
+ ExpParam.ExceptionPointers = pExceptionPointers;
+ ExpParam.ClientPointers = TRUE;
+
+ MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
+ hDumpFile, MiniDumpNormal | MiniDumpWithDataSegs |
+ MiniDumpWithThreadInfo | MiniDumpWithCodeSegs,
+ &ExpParam, NULL, NULL);
+
+ fprintf (stdout, "Crash dump created. Dump written to:\n\t%ls", szFileName);
+}