Cuberite
A lightweight, fast and extensible game server for Minecraft
MiniDumpWriter.h
Go to the documentation of this file.
1 
2 // MiniDumpWriter.h
3 
4 // 32-bit only:
5 // When the server crashes, create a "dump file" containing the callstack of each thread and some variables;
6 // let the user send us that crash file for analysis.
7 
8 // This file MUST NOT be included from anywhere other than main.cpp.
9 
10 
11 
12 
13 
15 enum class MiniDumpFlags
16 {
19 };
20 
21 
22 
23 
24 
25 #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC
26 
27 #include <DbgHelp.h>
28 
29 
30 
31 
32 
33 using MiniDumpWriteDumpFunction = decltype(&MiniDumpWriteDump);
34 
35 static HINSTANCE m_DbgHelp;
36 static MiniDumpWriteDumpFunction s_WriteMiniDump; // The function in dbghlp DLL that creates dump files
37 static wchar_t s_DumpFileName[MAX_PATH]; // Filename of the dump file; hes to be created before the dump handler kicks in
38 static char s_ExceptionStack[128 * 1024]; // Substitute stack, just in case the handler kicks in because of "insufficient stack space"
39 static MINIDUMP_TYPE s_DumpFlags = MiniDumpNormal; // By default dump only the stack and some helpers
40 
41 
42 
43 
44 
47 static LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_ExceptionInfo)
48 {
49  char * newStack = &s_ExceptionStack[sizeof(s_ExceptionStack) - 1];
50  char * oldStack;
51 
52  // Use the substitute stack:
53  _asm
54  {
55  mov oldStack, esp
56  mov esp, newStack
57  }
58 
59  MINIDUMP_EXCEPTION_INFORMATION ExcInformation;
60  ExcInformation.ThreadId = GetCurrentThreadId();
61  ExcInformation.ExceptionPointers = a_ExceptionInfo;
62  ExcInformation.ClientPointers = 0;
63 
64  // Write the dump file:
65  HANDLE dumpFile = CreateFile(s_DumpFileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
66  s_WriteMiniDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, s_DumpFlags, (a_ExceptionInfo) ? &ExcInformation : nullptr, nullptr, nullptr);
67  CloseHandle(dumpFile);
68 
69  // Revert to old stack:
70  _asm
71  {
72  mov esp, oldStack
73  }
74 
75  return 0;
76 }
77 
78 
79 
80 
81 
82 namespace MiniDumpWriter
83 {
84  static void Register()
85  {
86  // Magic code to produce dump-files on Windows if the server crashes:
87 
88  m_DbgHelp = LoadLibrary(L"DBGHELP.DLL");
89  if (m_DbgHelp == INVALID_HANDLE_VALUE)
90  {
91  return;
92  }
93 
94  s_WriteMiniDump = (MiniDumpWriteDumpFunction)GetProcAddress(m_DbgHelp, "MiniDumpWriteDump");
95  if (s_WriteMiniDump != nullptr)
96  {
97  ASSERT(swprintf(s_DumpFileName, ARRAYCOUNT(s_DumpFileName), L"crash_mcs_%x.dmp", GetCurrentProcessId()) > 0);
98  SetUnhandledExceptionFilter(LastChanceExceptionFilter);
99  }
100 
101  // End of dump-file magic
102  }
103 
104  static void AddDumpFlags(const MiniDumpFlags a_Flags)
105  {
106  switch (a_Flags)
107  {
109  {
110  s_DumpFlags = static_cast<MINIDUMP_TYPE>(s_DumpFlags | MINIDUMP_TYPE::MiniDumpWithDataSegs);
111  break;
112  }
114  {
115  s_DumpFlags = static_cast<MINIDUMP_TYPE>(s_DumpFlags | MINIDUMP_TYPE::MiniDumpWithFullMemory);
116  break;
117  }
118  }
119  }
120 
121  static void Unregister()
122  {
123  FreeLibrary(m_DbgHelp);
124  }
125 };
126 
127 #else
128 
129 namespace MiniDumpWriter
130 {
131  static void Register()
132  {
133  }
134 
135  static void AddDumpFlags(const MiniDumpFlags)
136  {
137  }
138 
139  static void Unregister()
140  {
141  }
142 };
143 
144 #endif
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
#define ASSERT(x)
Definition: Globals.h:276
MiniDumpFlags
Flags to control minidump contents on supported platforms.
static void AddDumpFlags(const MiniDumpFlags)
static void Register()
static void Unregister()