1 /*-------------------------------------------------------------------------
4 * Automatic crash dump creation for PostgreSQL on Windows
6 * The crashdump feature traps unhandled win32 exceptions produced by the
7 * backend, and tries to produce a Windows MiniDump crash
8 * dump for later debugging and analysis. The machine performing the dump
9 * doesn't need any special debugging tools; the user only needs to send
10 * the dump to somebody who has the same version of PostgreSQL and has debugging
13 * crashdump module originally by Craig Ringer <ringerc@ringerc.id.au>
17 * This *won't* work in hard OOM situations or stack overflows.
19 * For those, it'd be necessary to take a much more complicated approach where
20 * the handler switches to a new stack (if it can) and forks a helper process
23 * POSSIBLE FUTURE WORK
24 * ====================
25 * For bonus points, the crash dump format permits embedding of user-supplied
26 * data. If there's anything else that should always be supplied with a crash
27 * dump (postgresql.conf? Last few lines of a log file?), it could potentially
28 * be added, though at the cost of a greater chance of the crash dump failing.
31 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
34 * src/backend/port/win32/crashdump.c
36 *-------------------------------------------------------------------------
41 #define WIN32_LEAN_AND_MEAN
44 * Some versions of the MS SDK contain "typedef enum { ... } ;" which the MS
45 * compiler quite sanely complains about. Well done, Microsoft.
46 * This pragma disables the warning just while we include the header.
47 * The pragma is known to work with all (as at the time of writing) supported
52 #pragma warning(disable : 4091)
60 * Much of the following code is based on CodeProject and MSDN examples,
62 * http://www.codeproject.com/KB/debug/postmortemdebug_standalone1.aspx
64 * Useful MSDN articles:
66 * http://msdn.microsoft.com/en-us/library/ff805116(v=VS.85).aspx
67 * http://msdn.microsoft.com/en-us/library/ms679294(VS.85).aspx
69 * Other useful articles on working with minidumps:
70 * http://www.debuginfo.com/articles/effminidumps.html
73 typedef BOOL (WINAPI * MINIDUMPWRITEDUMP) (HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
74 CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
75 CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
76 CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
81 * This function is the exception handler passed to SetUnhandledExceptionFilter.
82 * It's invoked only if there's an unhandled exception. The handler will use
83 * dbghelp.dll to generate a crash dump, then resume the normal unhandled
84 * exception process, which will generally exit with an error message from
87 * This function is run under the unhandled exception handler, effectively
88 * in a crash context, so it should be careful with memory and avoid using
89 * any PostgreSQL functions.
92 crashDumpHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
95 * We only write crash dumps if the "crashdumps" directory within the
96 * postgres data directory exists.
98 DWORD attribs = GetFileAttributesA("crashdumps");
100 if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
102 /* 'crashdumps' exists and is a directory. Try to write a dump' */
104 MINIDUMPWRITEDUMP pDump = NULL;
105 MINIDUMP_TYPE dumpType;
106 char dumpPath[_MAX_PATH];
107 HANDLE selfProcHandle = GetCurrentProcess();
108 DWORD selfPid = GetProcessId(selfProcHandle);
111 struct _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
113 ExInfo.ThreadId = GetCurrentThreadId();
114 ExInfo.ExceptionPointers = pExceptionInfo;
115 ExInfo.ClientPointers = FALSE;
117 /* Load the dbghelp.dll library and functions */
118 hDll = LoadLibrary("dbghelp.dll");
121 write_stderr("could not load dbghelp.dll, cannot write crash dump\n");
122 return EXCEPTION_CONTINUE_SEARCH;
125 pDump = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump");
129 write_stderr("could not load required functions in dbghelp.dll, cannot write crash dump\n");
130 return EXCEPTION_CONTINUE_SEARCH;
134 * Dump as much as we can, except shared memory, code segments, and
135 * memory mapped files. Exactly what we can dump depends on the
136 * version of dbghelp.dll, see:
137 * http://msdn.microsoft.com/en-us/library/ms680519(v=VS.85).aspx
139 dumpType = MiniDumpNormal | MiniDumpWithHandleData |
140 MiniDumpWithDataSegs;
142 if (GetProcAddress(hDll, "EnumDirTree") != NULL)
144 /* If this function exists, we have version 5.2 or newer */
145 dumpType |= MiniDumpWithIndirectlyReferencedMemory |
146 MiniDumpWithPrivateReadWriteMemory;
149 systemTicks = GetTickCount();
150 snprintf(dumpPath, _MAX_PATH,
151 "crashdumps\\postgres-pid%0i-%0i.mdmp",
152 (int) selfPid, (int) systemTicks);
153 dumpPath[_MAX_PATH - 1] = '\0';
155 dumpFile = CreateFile(dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE,
156 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
158 if (dumpFile == INVALID_HANDLE_VALUE)
160 write_stderr("could not open crash dump file \"%s\" for writing: error code %lu\n",
161 dumpPath, GetLastError());
162 return EXCEPTION_CONTINUE_SEARCH;
165 if ((*pDump) (selfProcHandle, selfPid, dumpFile, dumpType, &ExInfo,
167 write_stderr("wrote crash dump to file \"%s\"\n", dumpPath);
169 write_stderr("could not write crash dump to file \"%s\": error code %lu\n",
170 dumpPath, GetLastError());
172 CloseHandle(dumpFile);
175 return EXCEPTION_CONTINUE_SEARCH;
180 pgwin32_install_crashdump_handler(void)
182 SetUnhandledExceptionFilter(crashDumpHandler);