1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20
21 #include "porting.h"
22 #include "debug.h"
23 #include "exceptions.h"
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <map>
28 #include <sstream>
29 #include <thread>
30 #include "threading/mutex_auto_lock.h"
31 #include "config.h"
32
33 #ifdef _MSC_VER
34 #include <dbghelp.h>
35 #include "version.h"
36 #include "filesys.h"
37 #endif
38
39 #if USE_CURSES
40 #include "terminal_chat_console.h"
41 #endif
42
43 /*
44 Assert
45 */
46
sanity_check_fn(const char * assertion,const char * file,unsigned int line,const char * function)47 void sanity_check_fn(const char *assertion, const char *file,
48 unsigned int line, const char *function)
49 {
50 #if USE_CURSES
51 g_term_console.stopAndWaitforThread();
52 #endif
53
54 errorstream << std::endl << "In thread " << std::hex
55 << std::this_thread::get_id() << ":" << std::endl;
56 errorstream << file << ":" << line << ": " << function
57 << ": An engine assumption '" << assertion << "' failed." << std::endl;
58
59 abort();
60 }
61
fatal_error_fn(const char * msg,const char * file,unsigned int line,const char * function)62 void fatal_error_fn(const char *msg, const char *file,
63 unsigned int line, const char *function)
64 {
65 #if USE_CURSES
66 g_term_console.stopAndWaitforThread();
67 #endif
68
69 errorstream << std::endl << "In thread " << std::hex
70 << std::this_thread::get_id() << ":" << std::endl;
71 errorstream << file << ":" << line << ": " << function
72 << ": A fatal error occurred: " << msg << std::endl;
73
74 abort();
75 }
76
77 #ifdef _MSC_VER
78
Win32ExceptionCodeToString(DWORD exception_code)79 const char *Win32ExceptionCodeToString(DWORD exception_code)
80 {
81 switch (exception_code) {
82 case EXCEPTION_ACCESS_VIOLATION:
83 return "Access violation";
84 case EXCEPTION_DATATYPE_MISALIGNMENT:
85 return "Misaligned data access";
86 case EXCEPTION_BREAKPOINT:
87 return "Breakpoint reached";
88 case EXCEPTION_SINGLE_STEP:
89 return "Single debug step";
90 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
91 return "Array access out of bounds";
92 case EXCEPTION_FLT_DENORMAL_OPERAND:
93 return "Denormal floating point operand";
94 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
95 return "Floating point division by zero";
96 case EXCEPTION_FLT_INEXACT_RESULT:
97 return "Inaccurate floating point result";
98 case EXCEPTION_FLT_INVALID_OPERATION:
99 return "Invalid floating point operation";
100 case EXCEPTION_FLT_OVERFLOW:
101 return "Floating point exponent overflow";
102 case EXCEPTION_FLT_STACK_CHECK:
103 return "Floating point stack overflow or underflow";
104 case EXCEPTION_FLT_UNDERFLOW:
105 return "Floating point exponent underflow";
106 case EXCEPTION_INT_DIVIDE_BY_ZERO:
107 return "Integer division by zero";
108 case EXCEPTION_INT_OVERFLOW:
109 return "Integer overflow";
110 case EXCEPTION_PRIV_INSTRUCTION:
111 return "Privileged instruction executed";
112 case EXCEPTION_IN_PAGE_ERROR:
113 return "Could not access or load page";
114 case EXCEPTION_ILLEGAL_INSTRUCTION:
115 return "Illegal instruction encountered";
116 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
117 return "Attempted to continue after fatal exception";
118 case EXCEPTION_STACK_OVERFLOW:
119 return "Stack overflow";
120 case EXCEPTION_INVALID_DISPOSITION:
121 return "Invalid disposition returned to the exception dispatcher";
122 case EXCEPTION_GUARD_PAGE:
123 return "Attempted guard page access";
124 case EXCEPTION_INVALID_HANDLE:
125 return "Invalid handle";
126 }
127
128 return "Unknown exception";
129 }
130
Win32ExceptionHandler(struct _EXCEPTION_POINTERS * pExceptInfo)131 long WINAPI Win32ExceptionHandler(struct _EXCEPTION_POINTERS *pExceptInfo)
132 {
133 char buf[512];
134 MINIDUMP_EXCEPTION_INFORMATION mdei;
135 MINIDUMP_USER_STREAM_INFORMATION mdusi;
136 MINIDUMP_USER_STREAM mdus;
137 bool minidump_created = false;
138
139 std::string dumpfile = porting::path_user + DIR_DELIM PROJECT_NAME ".dmp";
140
141 std::string version_str(PROJECT_NAME " ");
142 version_str += g_version_hash;
143
144 HANDLE hFile = CreateFileA(dumpfile.c_str(), GENERIC_WRITE,
145 FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
146 if (hFile == INVALID_HANDLE_VALUE)
147 goto minidump_failed;
148
149 if (SetEndOfFile(hFile) == FALSE)
150 goto minidump_failed;
151
152 mdei.ClientPointers = NULL;
153 mdei.ExceptionPointers = pExceptInfo;
154 mdei.ThreadId = GetCurrentThreadId();
155
156 mdus.Type = CommentStreamA;
157 mdus.BufferSize = version_str.size();
158 mdus.Buffer = (PVOID)version_str.c_str();
159
160 mdusi.UserStreamArray = &mdus;
161 mdusi.UserStreamCount = 1;
162
163 if (MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
164 MiniDumpNormal, &mdei, &mdusi, NULL) == FALSE)
165 goto minidump_failed;
166
167 minidump_created = true;
168
169 minidump_failed:
170
171 CloseHandle(hFile);
172
173 DWORD excode = pExceptInfo->ExceptionRecord->ExceptionCode;
174 _snprintf(buf, sizeof(buf),
175 " >> === FATAL ERROR ===\n"
176 " >> %s (Exception 0x%08X) at 0x%p\n",
177 Win32ExceptionCodeToString(excode), excode,
178 pExceptInfo->ExceptionRecord->ExceptionAddress);
179 dstream << buf;
180
181 if (minidump_created)
182 dstream << " >> Saved dump to " << dumpfile << std::endl;
183 else
184 dstream << " >> Failed to save dump" << std::endl;
185
186 return EXCEPTION_EXECUTE_HANDLER;
187 }
188
189 #endif
190
debug_set_exception_handler()191 void debug_set_exception_handler()
192 {
193 #ifdef _MSC_VER
194 SetUnhandledExceptionFilter(Win32ExceptionHandler);
195 #endif
196 }
197
198