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-2022, PostgreSQL Global Development Group
34 * src/backend/port/win32/crashdump.c
36 *-------------------------------------------------------------------------
42 * Some versions of the MS SDK contain "typedef enum { ... } ;" which the MS
43 * compiler quite sanely complains about. Well done, Microsoft.
44 * This pragma disables the warning just while we include the header.
45 * The pragma is known to work with all (as at the time of writing) supported
50 #pragma warning(disable : 4091)
58 * Much of the following code is based on CodeProject and MSDN examples,
60 * http://www.codeproject.com/KB/debug/postmortemdebug_standalone1.aspx
62 * Useful MSDN articles:
64 * http://msdn.microsoft.com/en-us/library/ff805116(v=VS.85).aspx
65 * http://msdn.microsoft.com/en-us/library/ms679294(VS.85).aspx
67 * Other useful articles on working with minidumps:
68 * http://www.debuginfo.com/articles/effminidumps.html
71 typedef BOOL (WINAPI
* MINIDUMPWRITEDUMP
) (HANDLE hProcess
, DWORD dwPid
, HANDLE hFile
, MINIDUMP_TYPE DumpType
,
72 CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam
,
73 CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam
,
74 CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
79 * This function is the exception handler passed to SetUnhandledExceptionFilter.
80 * It's invoked only if there's an unhandled exception. The handler will use
81 * dbghelp.dll to generate a crash dump, then resume the normal unhandled
82 * exception process, which will generally exit with an error message from
85 * This function is run under the unhandled exception handler, effectively
86 * in a crash context, so it should be careful with memory and avoid using
87 * any PostgreSQL functions.
90 crashDumpHandler(struct _EXCEPTION_POINTERS
*pExceptionInfo
)
93 * We only write crash dumps if the "crashdumps" directory within the
94 * postgres data directory exists.
96 DWORD attribs
= GetFileAttributesA("crashdumps");
98 if (attribs
!= INVALID_FILE_ATTRIBUTES
&& (attribs
& FILE_ATTRIBUTE_DIRECTORY
))
100 /* 'crashdumps' exists and is a directory. Try to write a dump' */
102 MINIDUMPWRITEDUMP pDump
= NULL
;
103 MINIDUMP_TYPE dumpType
;
104 char dumpPath
[_MAX_PATH
];
105 HANDLE selfProcHandle
= GetCurrentProcess();
106 DWORD selfPid
= GetProcessId(selfProcHandle
);
109 struct _MINIDUMP_EXCEPTION_INFORMATION ExInfo
;
111 ExInfo
.ThreadId
= GetCurrentThreadId();
112 ExInfo
.ExceptionPointers
= pExceptionInfo
;
113 ExInfo
.ClientPointers
= FALSE
;
115 /* Load the dbghelp.dll library and functions */
116 hDll
= LoadLibrary("dbghelp.dll");
119 write_stderr("could not load dbghelp.dll, cannot write crash dump\n");
120 return EXCEPTION_CONTINUE_SEARCH
;
123 pDump
= (MINIDUMPWRITEDUMP
) (pg_funcptr_t
) GetProcAddress(hDll
, "MiniDumpWriteDump");
127 write_stderr("could not load required functions in dbghelp.dll, cannot write crash dump\n");
128 return EXCEPTION_CONTINUE_SEARCH
;
132 * Dump as much as we can, except shared memory, code segments, and
133 * memory mapped files. Exactly what we can dump depends on the
134 * version of dbghelp.dll, see:
135 * http://msdn.microsoft.com/en-us/library/ms680519(v=VS.85).aspx
137 dumpType
= MiniDumpNormal
| MiniDumpWithHandleData
|
138 MiniDumpWithDataSegs
;
140 if (GetProcAddress(hDll
, "EnumDirTree") != NULL
)
142 /* If this function exists, we have version 5.2 or newer */
143 dumpType
|= MiniDumpWithIndirectlyReferencedMemory
|
144 MiniDumpWithPrivateReadWriteMemory
;
147 systemTicks
= GetTickCount();
148 snprintf(dumpPath
, _MAX_PATH
,
149 "crashdumps\\postgres-pid%0i-%0i.mdmp",
150 (int) selfPid
, (int) systemTicks
);
151 dumpPath
[_MAX_PATH
- 1] = '\0';
153 dumpFile
= CreateFile(dumpPath
, GENERIC_WRITE
, FILE_SHARE_WRITE
,
154 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
,
156 if (dumpFile
== INVALID_HANDLE_VALUE
)
158 write_stderr("could not open crash dump file \"%s\" for writing: error code %lu\n",
159 dumpPath
, GetLastError());
160 return EXCEPTION_CONTINUE_SEARCH
;
163 if ((*pDump
) (selfProcHandle
, selfPid
, dumpFile
, dumpType
, &ExInfo
,
165 write_stderr("wrote crash dump to file \"%s\"\n", dumpPath
);
167 write_stderr("could not write crash dump to file \"%s\": error code %lu\n",
168 dumpPath
, GetLastError());
170 CloseHandle(dumpFile
);
173 return EXCEPTION_CONTINUE_SEARCH
;
178 pgwin32_install_crashdump_handler(void)
180 SetUnhandledExceptionFilter(crashDumpHandler
);