PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
crashdump.c
Go to the documentation of this file.
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-2017, 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 /*
45  * Some versions of the MS SDK contain "typedef enum { ... } ;" which the MS
46  * compiler quite sanely complains about. Well done, Microsoft.
47  * This pragma disables the warning just while we include the header.
48  * The pragma is known to work with all (as at the time of writing) supported
49  * versions of MSVC.
50  */
51 #ifdef _MSC_VER
52 #pragma warning(push)
53 #pragma warning(disable : 4091)
54 #endif
55 #include <dbghelp.h>
56 #ifdef _MSC_VER
57 #pragma warning(pop)
58 #endif
59 
60 /*
61  * Much of the following code is based on CodeProject and MSDN examples,
62  * particularly
63  * http://www.codeproject.com/KB/debug/postmortemdebug_standalone1.aspx
64  *
65  * Useful MSDN articles:
66  *
67  * http://msdn.microsoft.com/en-us/library/ff805116(v=VS.85).aspx
68  * http://msdn.microsoft.com/en-us/library/ms679294(VS.85).aspx
69  *
70  * Other useful articles on working with minidumps:
71  * http://www.debuginfo.com/articles/effminidumps.html
72  */
73 
74 typedef BOOL (WINAPI * MINIDUMPWRITEDUMP) (HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
75  CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
76  CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
77  CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
78 );
79 
80 
81 /*
82  * This function is the exception handler passed to SetUnhandledExceptionFilter.
83  * It's invoked only if there's an unhandled exception. The handler will use
84  * dbghelp.dll to generate a crash dump, then resume the normal unhandled
85  * exception process, which will generally exit with an error message from
86  * the runtime.
87  *
88  * This function is run under the unhandled exception handler, effectively
89  * in a crash context, so it should be careful with memory and avoid using
90  * any PostgreSQL functions.
91  */
92 static LONG WINAPI
93 crashDumpHandler(struct _EXCEPTION_POINTERS * pExceptionInfo)
94 {
95  /*
96  * We only write crash dumps if the "crashdumps" directory within the
97  * postgres data directory exists.
98  */
99  DWORD attribs = GetFileAttributesA("crashdumps");
100 
101  if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
102  {
103  /* 'crashdumps' exists and is a directory. Try to write a dump' */
104  HMODULE hDll = NULL;
105  MINIDUMPWRITEDUMP pDump = NULL;
106  MINIDUMP_TYPE dumpType;
107  char dumpPath[_MAX_PATH];
108  HANDLE selfProcHandle = GetCurrentProcess();
109  DWORD selfPid = GetProcessId(selfProcHandle);
110  HANDLE dumpFile;
111  DWORD systemTicks;
112  struct _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
113 
114  ExInfo.ThreadId = GetCurrentThreadId();
115  ExInfo.ExceptionPointers = pExceptionInfo;
116  ExInfo.ClientPointers = FALSE;
117 
118  /* Load the dbghelp.dll library and functions */
119  hDll = LoadLibrary("dbghelp.dll");
120  if (hDll == NULL)
121  {
122  write_stderr("could not load dbghelp.dll, cannot write crash dump\n");
123  return EXCEPTION_CONTINUE_SEARCH;
124  }
125 
126  pDump = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump");
127 
128  if (pDump == NULL)
129  {
130  write_stderr("could not load required functions in dbghelp.dll, cannot write crash dump\n");
131  return EXCEPTION_CONTINUE_SEARCH;
132  }
133 
134  /*
135  * Dump as much as we can, except shared memory, code segments, and
136  * memory mapped files. Exactly what we can dump depends on the
137  * version of dbghelp.dll, see:
138  * http://msdn.microsoft.com/en-us/library/ms680519(v=VS.85).aspx
139  */
140  dumpType = MiniDumpNormal | MiniDumpWithHandleData |
141  MiniDumpWithDataSegs;
142 
143  if (GetProcAddress(hDll, "EnumDirTree") != NULL)
144  {
145  /* If this function exists, we have version 5.2 or newer */
146  dumpType |= MiniDumpWithIndirectlyReferencedMemory |
147  MiniDumpWithPrivateReadWriteMemory;
148  }
149 
150  systemTicks = GetTickCount();
151  snprintf(dumpPath, _MAX_PATH,
152  "crashdumps\\postgres-pid%0i-%0i.mdmp",
153  (int) selfPid, (int) systemTicks);
154  dumpPath[_MAX_PATH - 1] = '\0';
155 
156  dumpFile = CreateFile(dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE,
157  NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
158  NULL);
159  if (dumpFile == INVALID_HANDLE_VALUE)
160  {
161  write_stderr("could not open crash dump file \"%s\" for writing: error code %lu\n",
162  dumpPath, GetLastError());
163  return EXCEPTION_CONTINUE_SEARCH;
164  }
165 
166  if ((*pDump) (selfProcHandle, selfPid, dumpFile, dumpType, &ExInfo,
167  NULL, NULL))
168  write_stderr("wrote crash dump to file \"%s\"\n", dumpPath);
169  else
170  write_stderr("could not write crash dump to file \"%s\": error code %lu\n",
171  dumpPath, GetLastError());
172 
173  CloseHandle(dumpFile);
174  }
175 
176  return EXCEPTION_CONTINUE_SEARCH;
177 }
178 
179 
180 void
182 {
183  SetUnhandledExceptionFilter(crashDumpHandler);
184 }
void pgwin32_install_crashdump_handler(void)
Definition: crashdump.c:181
DWORD HANDLE MINIDUMP_TYPE CONST PMINIDUMP_EXCEPTION_INFORMATION CONST PMINIDUMP_USER_STREAM_INFORMATION CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
Definition: crashdump.c:74
DWORD HANDLE MINIDUMP_TYPE DumpType
Definition: crashdump.c:74
#define write_stderr(str)
Definition: parallel.c:182
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static LONG WINAPI crashDumpHandler(struct _EXCEPTION_POINTERS *pExceptionInfo)
Definition: crashdump.c:93
#define FALSE
Definition: c.h:218
DWORD HANDLE MINIDUMP_TYPE CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam
Definition: crashdump.c:74
DWORD HANDLE MINIDUMP_TYPE CONST PMINIDUMP_EXCEPTION_INFORMATION CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam
Definition: crashdump.c:74
DWORD dwPid
Definition: crashdump.c:74
#define NULL
Definition: c.h:226
static void dumpType(Archive *fout, TypeInfo *tyinfo)
Definition: pg_dump.c:9451
DWORD HANDLE hFile
Definition: crashdump.c:74
typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess