Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit dcb09b5

Browse files
committed
Support for collecting crash dumps on Windows
Add support for collecting "minidump" style crash dumps on Windows, by setting up an exception handling filter. Crash dumps will be generated in PGDATA/crashdumps if the directory is created (the existance of the directory is used as on/off switch for the generation of the dumps). Craig Ringer and Magnus Hagander
1 parent 7e95337 commit dcb09b5

File tree

5 files changed

+202
-1
lines changed

5 files changed

+202
-1
lines changed

doc/src/sgml/installation.sgml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,22 @@ cc-1020 cc: ERROR File = pqcomm.c, Line = 427
27342734
under <command>CMD.EXE</command>, as the MSYS console has
27352735
buffering issues.
27362736
</para>
2737+
2738+
<sect3>
2739+
<title>Collecting crash dumps on Windows</title>
2740+
2741+
<para>
2742+
If PostgreSQL on Windows crashes, it has the ability to generate
2743+
<productname>minidumps</> that can be used to track down the cause
2744+
for the crash, similar to core dumps on Unix. These dumps can be
2745+
read using the <productname>Windows Debugger Tools</> or using
2746+
<productname>Visual Studio</>. To enable the generation of dumps
2747+
on Windows, create a subdirectory named <filename>crashdumps</filename>
2748+
inside the cluster data directory. The dumps will then be written
2749+
into this directory with a unique name based on the identifier of
2750+
the crashing process and the current time of the crash.
2751+
</para>
2752+
</sect3>
27372753
</sect2>
27382754

27392755
<sect2 id="installation-notes-sco">

src/backend/main/main.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ main(int argc, char *argv[])
8181
*/
8282
argv = save_ps_display_args(argc, argv);
8383

84+
/*
85+
* If supported on the current platform, set up a handler to be called if
86+
* the backend/postmaster crashes with a fatal signal or exception.
87+
*/
88+
#ifdef WIN32
89+
pgwin32_install_crashdump_handler();
90+
#endif
91+
8492
/*
8593
* Set up locale information from environment. Note that LC_CTYPE and
8694
* LC_COLLATE will be overridden later from pg_control if we are in an

src/backend/port/win32/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ subdir = src/backend/port/win32
1212
top_builddir = ../../../..
1313
include $(top_builddir)/src/Makefile.global
1414

15-
OBJS = timer.o socket.o signal.o security.o mingwcompat.o
15+
OBJS = timer.o socket.o signal.o security.o mingwcompat.o crashdump.o
1616

1717
include $(top_srcdir)/src/backend/common.mk

src/backend/port/win32/crashdump.c

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* win32_crashdump.c
4+
* Automatic crash dump creation for PostgreSQL on Windows
5+
*
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
11+
* tools.
12+
*
13+
* crashdump module originally by Craig Ringer <ringerc@ringerc.id.au>
14+
*
15+
* LIMITATIONS
16+
* ===========
17+
* This *won't* work in hard OOM situations or stack overflows.
18+
*
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
21+
* to debug it self.
22+
*
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.
29+
*
30+
*
31+
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
32+
*
33+
* IDENTIFICATION
34+
* src/backend/port/win32/crashdump.c
35+
*
36+
*-------------------------------------------------------------------------
37+
*/
38+
39+
#include "postgres.h"
40+
41+
#define WIN32_LEAN_AND_MEAN
42+
#include <windows.h>
43+
#include <string.h>
44+
#include <dbghelp.h>
45+
46+
/*
47+
* Much of the following code is based on CodeProject and MSDN examples,
48+
* particularly
49+
* http://www.codeproject.com/KB/debug/postmortemdebug_standalone1.aspx
50+
*
51+
* Useful MSDN articles:
52+
*
53+
* http://msdn.microsoft.com/en-us/library/ff805116(v=VS.85).aspx
54+
* http://msdn.microsoft.com/en-us/library/ms679294(VS.85).aspx
55+
*
56+
* Other useful articles on working with minidumps:
57+
* http://www.debuginfo.com/articles/effminidumps.html
58+
*/
59+
60+
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
61+
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
62+
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
63+
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
64+
);
65+
66+
67+
/*
68+
* This function is the exception handler passed to SetUnhandledExceptionFilter.
69+
* It's invoked only if there's an unhandled exception. The handler will use
70+
* dbghelp.dll to generate a crash dump, then resume the normal unhandled
71+
* exception process, which will generally exit with an error message from
72+
* the runtime.
73+
*
74+
* This function is run under the unhandled exception handler, effectively
75+
* in a crash context, so it should be careful with memory and avoid using
76+
* any PostgreSQL functions.
77+
*/
78+
static LONG WINAPI
79+
crashDumpHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
80+
{
81+
/*
82+
* We only write crash dumps if the "crashdumps" directory within
83+
* the postgres data directory exists.
84+
*/
85+
DWORD attribs = GetFileAttributesA("crashdumps");
86+
if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY) )
87+
{
88+
/* 'crashdumps' exists and is a directory. Try to write a dump' */
89+
HMODULE hDll = NULL;
90+
MINIDUMPWRITEDUMP pDump = NULL;
91+
MINIDUMP_TYPE dumpType;
92+
char dumpPath[_MAX_PATH];
93+
HANDLE selfProcHandle = GetCurrentProcess();
94+
DWORD selfPid = GetProcessId(selfProcHandle);
95+
HANDLE dumpFile;
96+
DWORD systemTicks;
97+
struct _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
98+
99+
ExInfo.ThreadId = GetCurrentThreadId();
100+
ExInfo.ExceptionPointers = pExceptionInfo;
101+
ExInfo.ClientPointers = FALSE;
102+
103+
/* Load the dbghelp.dll library and functions */
104+
hDll = LoadLibrary("dbghelp.dll");
105+
if (hDll == NULL)
106+
{
107+
write_stderr("could not load dbghelp.dll, cannot write crashdump\n");
108+
return EXCEPTION_CONTINUE_SEARCH;
109+
}
110+
111+
pDump = (MINIDUMPWRITEDUMP)GetProcAddress(hDll, "MiniDumpWriteDump");
112+
113+
if (pDump==NULL)
114+
{
115+
write_stderr("could not load required functions in dbghelp.dll, cannot write crashdump\n");
116+
return EXCEPTION_CONTINUE_SEARCH;
117+
}
118+
119+
/*
120+
* Dump as much as we can, except shared memory, code segments,
121+
* and memory mapped files.
122+
* Exactly what we can dump depends on the version of dbghelp.dll,
123+
* see:
124+
* http://msdn.microsoft.com/en-us/library/ms680519(v=VS.85).aspx
125+
*/
126+
dumpType = MiniDumpNormal | MiniDumpWithHandleData |
127+
MiniDumpWithDataSegs;
128+
129+
if (GetProcAddress(hDll, "EnumDirTree") != NULL)
130+
{
131+
/* If this function exists, we have version 5.2 or newer */
132+
dumpType |= MiniDumpWithIndirectlyReferencedMemory |
133+
MiniDumpWithPrivateReadWriteMemory;
134+
}
135+
if (GetProcAddress(hDll, "SymFromIndex") != NULL)
136+
{
137+
/* If this function exists, we have version 6.2 or newer */
138+
dumpType |= MiniDumpWithThreadInfo;
139+
}
140+
141+
systemTicks = GetTickCount();
142+
snprintf(dumpPath, _MAX_PATH,
143+
"crashdumps\\postgres-pid%0i-%0i.mdmp", selfPid, systemTicks);
144+
dumpPath[_MAX_PATH-1] = '\0';
145+
146+
dumpFile = CreateFile(dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE,
147+
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
148+
NULL);
149+
if (dumpFile==INVALID_HANDLE_VALUE)
150+
{
151+
write_stderr("could not open crash dump file %s for writing: error code %d\n",
152+
dumpPath, GetLastError());
153+
return EXCEPTION_CONTINUE_SEARCH;
154+
}
155+
156+
if ((*pDump)(selfProcHandle, selfPid, dumpFile, dumpType, &ExInfo,
157+
NULL, NULL))
158+
write_stderr("wrote crash dump to %s\n", dumpPath);
159+
else
160+
write_stderr("could not write crash dump to %s: error code %08x\n",
161+
dumpPath, GetLastError());
162+
163+
CloseHandle(dumpFile);
164+
}
165+
166+
return EXCEPTION_CONTINUE_SEARCH;
167+
}
168+
169+
170+
void
171+
pgwin32_install_crashdump_handler(void)
172+
{
173+
SetUnhandledExceptionFilter(crashDumpHandler);
174+
}

src/include/port/win32.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ extern int pgwin32_is_service(void);
303303
/* in backend/port/win32_shmem.c */
304304
extern int pgwin32_ReserveSharedMemoryRegion(HANDLE);
305305

306+
/* in backend/port/win32/crashdump.c */
307+
extern void pgwin32_install_crashdump_handler(void);
308+
306309
/* in port/win32error.c */
307310
extern void _dosmaperr(unsigned long);
308311

0 commit comments

Comments
 (0)