Cytopia  0.3
A city building simulation game
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Exception.cxx
Go to the documentation of this file.
1 #include "Exception.hxx"
2 #include "LOG.hxx"
3 
4 #include "SDL.h"
5 
6 #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__OpenBSD__) && !defined(__vita__) && !defined(__SWITCH__) && \
7  !defined(__ANDROID__) && !defined(__HAIKU__) && !defined(__EMSCRIPTEN__)
8 
9 #include <execinfo.h>
10 #include <signal.h>
11 
12 static void lwBacktracePrint(void)
13 {
14  void *earray[100];
15  int size = backtrace(earray, 100);
16 
17  char **stack = backtrace_symbols(earray, size);
18 
19  for (int i = 0; i < size; i++)
20  {
21  LOG(LOG_ERROR) << stack[i];
22  }
23 }
24 
25 static void lwCrashHandler(int sig)
26 {
27  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Oops, crashed with signal %d :(", sig);
28  lwBacktracePrint();
29  exit(1);
30 }
31 
32 void systemSetupCrashHandler(void) { signal(SIGSEGV, lwCrashHandler); }
33 
34 #elif defined(_WIN32) && defined(_M_X64)
35 
36 #include <windows.h>
37 #include <imagehlp.h>
38 #include <stdio.h>
39 
40 static const char *lwPrintExceptionName(DWORD exception_code)
41 {
42  switch (exception_code)
43  {
44  case EXCEPTION_ACCESS_VIOLATION:
45  return "Access violation";
46  case EXCEPTION_DATATYPE_MISALIGNMENT:
47  return "Datatype misalignment";
48  case EXCEPTION_BREAKPOINT:
49  return "Breakpoint";
50  case EXCEPTION_SINGLE_STEP:
51  return "Single step";
52  case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
53  return "Array bounds exceeded";
54  case EXCEPTION_FLT_DENORMAL_OPERAND:
55  return "Float denormal operand";
56  case EXCEPTION_FLT_DIVIDE_BY_ZERO:
57  return "Float divide by zero";
58  case EXCEPTION_FLT_INEXACT_RESULT:
59  return "Float inexact result";
60  case EXCEPTION_FLT_INVALID_OPERATION:
61  return "Float invalid operation";
62  case EXCEPTION_FLT_OVERFLOW:
63  return "Float overflow";
64  case EXCEPTION_FLT_STACK_CHECK:
65  return "Float stack check";
66  case EXCEPTION_FLT_UNDERFLOW:
67  return "Float underflow";
68  case EXCEPTION_INT_DIVIDE_BY_ZERO:
69  return "Integer divide by zero";
70  case EXCEPTION_INT_OVERFLOW:
71  return "Integer overflow";
72  case EXCEPTION_PRIV_INSTRUCTION:
73  return "Privileged instruction";
74  case EXCEPTION_IN_PAGE_ERROR:
75  return "In page error";
76  case EXCEPTION_ILLEGAL_INSTRUCTION:
77  return "Illegal instruction";
78  case EXCEPTION_NONCONTINUABLE_EXCEPTION:
79  return "Noncontinuable exception";
80  case EXCEPTION_STACK_OVERFLOW:
81  return "Stack overflow";
82  case EXCEPTION_INVALID_DISPOSITION:
83  return "Invalid disposition";
84  case EXCEPTION_GUARD_PAGE:
85  return "Guard page";
86  case EXCEPTION_INVALID_HANDLE:
87  return "Invalid handle";
88  }
89  return "Unknown exception";
90 }
91 
92 static void lwSystemError(const char *title, const char *text) { MessageBox(NULL, text, title, MB_OK | MB_ICONERROR); }
93 
94 // !!! NOTE !!!
95 // Please change this code with accuracy, it used native microsoft sample from
96 // https://social.msdn.microsoft.com/Forums/vstudio/en-US/f93a211a-9c95-42f0-8581-50314457b729/generating-the-stack-traces-in-the-c-code?forum=vsdebug
97 
98 static void lwPrintStacktrace(LPEXCEPTION_POINTERS e)
99 {
100  PIMAGEHLP_SYMBOL64 pSym;
101  STACKFRAME sf;
102  DWORD64 dwModBase, Disp64;
103  DWORD Disp;
104  BOOL more = FALSE;
105  IMAGEHLP_LINE64 line;
106  const char *filename = NULL;
107  unsigned int linenum = 0;
108  line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
109  int count = 0;
110  char modname[MAX_PATH];
111  pSym = (PIMAGEHLP_SYMBOL64)GlobalAlloc(GMEM_FIXED, 16384);
112  ZeroMemory(&sf, sizeof(sf));
113  sf.AddrPC.Mode = AddrModeFlat;
114  sf.AddrStack.Mode = AddrModeFlat;
115  sf.AddrFrame.Mode = AddrModeFlat;
116  sf.AddrReturn.Mode = AddrModeFlat;
117 
118  PCONTEXT context = e->ContextRecord;
119  DWORD machine_type = 0;
120  sf.AddrPC.Offset = context->Rip;
121  sf.AddrFrame.Offset = context->Rbp;
122  sf.AddrStack.Offset = context->Rsp;
123  machine_type = IMAGE_FILE_MACHINE_AMD64;
124 
125  // Record exception info
126  LOG(LOG_ERROR) << "Exception [" << lwPrintExceptionName(e->ExceptionRecord->ExceptionCode) << "] 0x" << std::hex
127  << (unsigned int)e->ExceptionRecord->ExceptionCode;
128  LOG(LOG_ERROR) << "Exception Address: 0x" << std::hex << e->ExceptionRecord->ExceptionAddress;
129 
130  // Record stacktrace
131  LOG(LOG_ERROR) << "Stacktrace:";
132 
133  while (1)
134  {
135  more = StackWalk(machine_type, GetCurrentProcess(), GetCurrentThread(), &sf, context, NULL, SymFunctionTableAccess64,
136  SymGetModuleBase64, NULL);
137  if (!more || sf.AddrFrame.Offset == 0)
138  {
139  break;
140  }
141  dwModBase = SymGetModuleBase64(GetCurrentProcess(), sf.AddrPC.Offset);
142  if (dwModBase)
143  {
144  GetModuleFileName((HINSTANCE)dwModBase, modname, MAX_PATH);
145  }
146  else
147  {
148  strcpy(modname, "Unknown");
149  }
150 
151  pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
152  pSym->MaxNameLength = MAX_PATH;
153 
154  // unwind callstack
155  if (SymGetSymFromAddr64(GetCurrentProcess(), sf.AddrPC.Offset, &Disp64, pSym))
156  {
157  int filelineinfo_ok = SymGetLineFromAddr64(GetCurrentProcess(), sf.AddrPC.Offset, &Disp, &line);
158  filename = !!filelineinfo_ok ? line.FileName : "UNKNOWN FILE";
159  linenum = !!filelineinfo_ok ? line.LineNumber : 0;
160 
161  // This is the code path taken on VC if debugging syms are found
162  LOG(LOG_ERROR) << count << " " << filename << ":" << linenum << " |" << pSym->Name << "+0x" << Disp << std::hex
163  << (unsigned int)sf.AddrPC.Offset;
164  }
165  else
166  {
167  // This is the code path taken on MinGW, and VC if no debugging syms are found.
168  LOG(LOG_ERROR) << count << " " << modname << "+0x" << std::hex << (unsigned int)sf.AddrPC.Offset;
169  }
170  ++count;
171  }
172  GlobalFree(pSym);
173 }
174 
176 static LONG CALLBACK lwExceptionHandler(LPEXCEPTION_POINTERS e)
177 {
178  // Prologue.
179  LOG(LOG_ERROR) << "Oops, crashed :(";
180 
181  // Initialize IMAGEHLP.DLL.
182  SymInitialize(GetCurrentProcess(), ".", TRUE);
183 
184  lwPrintStacktrace(e);
185 
186  // Unintialize IMAGEHLP.DLL
187  SymCleanup(GetCurrentProcess());
188 
189  // Inform user
190  lwSystemError("Cytopia has crashed :(", "There was an unrecoverable error in Cytopia, which will now close.\n\n"
191  "The piece of code that caused the crash has been saved to log.\n\n"
192  "If you can, please create an issue by going to:\n\n"
193  "https://github.com/CytopiaTeam/Cytopia/issues/new \n\n"
194  "Please attatch log and your map to the issue report.\n\n"
195  "With your help, we can avoid this crash in the future.\n\n"
196  "Thanks!\n\n");
197 
198  // this seems to silently close the application
199  return EXCEPTION_EXECUTE_HANDLER;
200 }
201 
202 void systemSetupCrashHandler() { SetUnhandledExceptionFilter(lwExceptionHandler); }
203 
204 #else // fallback
205 
207 
208 #endif
LOG
Definition: LOG.hxx:32
int
int
Definition: tileData.hxx:57
LOG.hxx
LOG_ERROR
@ LOG_ERROR
Definition: LOG.hxx:28
systemSetupCrashHandler
void systemSetupCrashHandler(void)
install OS crash handler
Definition: Exception.cxx:206
Exception.hxx