1 /***************************************************************************
2 Try to display interesting crash dump
3
4 copyright : (C) 2007 by mean, (C) 2007 Gruntster
5 email : fixounet@free.fr
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16 #include <windows.h>
17 #include <excpt.h>
18
19 #include "ADM_crashdump.h"
20 #include <stdio.h>
21 #include <string>
22 #include <imagehlp.h>
23 #include <cxxabi.h>
24
25
26 static LONG WINAPI ExceptionFilter(struct _EXCEPTION_POINTERS *exceptionInfo);
27 static ADM_saveFunction *mysaveFunction = NULL;
28 static ADM_fatalFunction *myFatalFunction = NULL;
29
30
31 /**
32 * \fn installSigHandler
33 * \brief add hook to catch exception (null pointers etc...)
34 */
installSigHandler(void)35 void installSigHandler(void)
36 {
37 SetUnhandledExceptionFilter(ExceptionFilter);
38 }
39 /**
40 * \fn uninstallSigHandler
41 * \brief
42 */
uninstallSigHandler(void)43 void uninstallSigHandler(void)
44 {
45
46 }
47
48
49 /**
50 *
51 * @param save
52 * @param fatal
53 */
ADM_setCrashHook(ADM_saveFunction * save,ADM_fatalFunction * fatal,ADM_sigIntFunction * ignored)54 void ADM_setCrashHook(ADM_saveFunction *save, ADM_fatalFunction *fatal,ADM_sigIntFunction *ignored)
55 {
56 mysaveFunction = save;
57 myFatalFunction = fatal;
58 }
shortModuleName(const char * module)59 std::string shortModuleName(const char *module)
60 {
61 std::string s=std::string(module);
62 std::size_t last=s.find_last_of('\\');
63 if(last==std::string::npos)
64 return s;
65 return s.substr(last+1);
66 }
67 /**
68 *
69 * @param moduleName
70 * @param functionName
71 * @param frameAddress
72 * @param frameOffset
73 * @return
74 */
PrintFunction(const char * moduleName,const char * functionName,DWORD_PTR frameAddress,DWORD_PTR frameOffset)75 static std::string PrintFunction(const char *moduleName, const char *functionName, DWORD_PTR frameAddress, DWORD_PTR frameOffset)
76 {
77 std::string s;
78 int status;
79
80 if (functionName)
81 {
82 std::string cxaFunction=std::string("_");
83 cxaFunction+=std::string(functionName);
84 char *demangledName = __cxxabiv1::__cxa_demangle(cxaFunction.c_str(), NULL, NULL, &status);
85 if (status == 0)
86 s+=std::string(demangledName);
87 else
88 s+=std::string(functionName);
89
90 if (demangledName)
91 free(demangledName);
92 }
93 else
94 s=std::string("unknown function");
95
96 // if (frameOffset)
97 // s+=std::string(" <+0x%X>", frameOffset);
98
99 if (moduleName)
100 s+=std::string(" [")+shortModuleName(moduleName)+std::string("] ");
101 else
102 s+=std::string(" [unknown module]");
103 s+=std::string("\n");
104 return s;
105 }
106 /**
107 *
108 * @param process
109 * @param frameAddress
110 * @return
111 */
DumpFrame(void * process,DWORD_PTR frameAddress)112 static std::string DumpFrame(void *process, DWORD_PTR frameAddress)
113 {
114 std::string s;
115 const int functionLength = 255;
116 IMAGEHLP_SYMBOL *symbol = (IMAGEHLP_SYMBOL*)malloc(sizeof(IMAGEHLP_SYMBOL) + functionLength);
117 DWORD_PTR moduleBase = SymGetModuleBase(process, frameAddress);
118 const char *moduleName = NULL, *functionName = NULL;
119 DWORD_PTR displacement;
120 char moduleFilename[MAX_PATH];
121
122 symbol->SizeOfStruct = (sizeof(*symbol)) + functionLength;
123 symbol->MaxNameLength = functionLength - 1;
124
125 if (moduleBase && GetModuleFileName((HINSTANCE)moduleBase, moduleFilename, MAX_PATH))
126 moduleName = moduleFilename;
127
128 if (SymGetSymFromAddr(process, frameAddress, &displacement, symbol))
129 functionName = symbol->Name;
130
131 s+=PrintFunction(moduleName, functionName, frameAddress, displacement);
132
133 free(symbol);
134 return s;
135 }
136 /**
137 *
138 * @param processId
139 * @param exceptionRec
140 * @param contextRecord
141 * @return
142 */
DumpExceptionInfo(void * processId,struct _EXCEPTION_RECORD * exceptionRec,struct _CONTEXT * contextRecord)143 static std::string DumpExceptionInfo(void *processId, struct _EXCEPTION_RECORD *exceptionRec, struct _CONTEXT *contextRecord)
144 {
145 std::string s;
146 #ifdef _WIN64
147 printf("RAX: %08X RBX: %08X RCX: %08X RDX: %08X RSI: %08X RDI: %08X RSP: %08X RBP: %08X\n", contextRecord->Rax, contextRecord->Rbx, contextRecord->Rcx, contextRecord->Rdx, contextRecord->Rsi, contextRecord->Rdi, contextRecord->Rsp, contextRecord->Rbp);
148 printf("R8: %08X R9: %08X R10: %08X R11: %08X R12: %08X R13: %08X R14: %08X R15: %08X\n", contextRecord->R8, contextRecord->R9, contextRecord->R10, contextRecord->R11, contextRecord->R12, contextRecord->R13, contextRecord->R14, contextRecord->R15);
149 printf("RIP: %08X EFlags: %08X\n\n", contextRecord->Rip, contextRecord->EFlags);
150 #else
151 //s+=std::string("EAX: %08X EBX: %08X ECX: %08X EDX: %08X ESI: %08X\n", contextRecord->Eax, contextRecord->Ebx, contextRecord->Ecx, contextRecord->Edx, contextRecord->Esi);
152 //s+=std::string("EDI: %08X ESP: %08X EBP: %08X EIP: %08X EFlags: %08X\n\n", contextRecord->Edi, contextRecord->Esp, contextRecord->Ebp, contextRecord->Eip, contextRecord->EFlags);
153 #endif
154
155
156 switch (exceptionRec->ExceptionCode)
157 {
158 case EXCEPTION_ACCESS_VIOLATION:
159 s+=std::string("EXCEPTION_ACCESS_VIOLATION");
160 break;
161 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
162 s+=std::string("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
163 break;
164 case EXCEPTION_BREAKPOINT:
165 s+=std::string("EXCEPTION_BREAKPOINT");
166 break;
167 case EXCEPTION_DATATYPE_MISALIGNMENT:
168 s+=std::string("EXCEPTION_DATATYPE_MISALIGNMENT");
169 break;
170 case EXCEPTION_FLT_DENORMAL_OPERAND:
171 s+=std::string("EXCEPTION_FLT_DENORMAL_OPERAND");
172 break;
173 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
174 s+=std::string("EXCEPTION_FLT_DIVIDE_BY_ZERO");
175 break;
176 case EXCEPTION_FLT_INEXACT_RESULT:
177 s+=std::string("EXCEPTION_FLT_INEXACT_RESULT");
178 break;
179 case EXCEPTION_FLT_INVALID_OPERATION:
180 s+=std::string("EXCEPTION_FLT_INVALID_OPERATION");
181 break;
182 case EXCEPTION_FLT_OVERFLOW:
183 s+=std::string("EXCEPTION_FLT_OVERFLOW");
184 break;
185 case EXCEPTION_FLT_STACK_CHECK:
186 s+=std::string("EXCEPTION_FLT_STACK_CHECK");
187 break;
188 case EXCEPTION_FLT_UNDERFLOW:
189 printf("EXCEPTION_FLT_UNDERFLOW");
190 break;
191 case EXCEPTION_ILLEGAL_INSTRUCTION:
192 s+=std::string("EXCEPTION_ILLEGAL_INSTRUCTION");
193 break;
194 case EXCEPTION_IN_PAGE_ERROR:
195 s+=std::string("EXCEPTION_IN_PAGE_ERROR");
196 break;
197 case EXCEPTION_INT_DIVIDE_BY_ZERO:
198 s+=std::string("EXCEPTION_INT_DIVIDE_BY_ZERO");
199 break;
200 case EXCEPTION_INT_OVERFLOW:
201 s+=std::string("EXCEPTION_INT_OVERFLOW");
202 break;
203 case EXCEPTION_INVALID_DISPOSITION:
204 s+=std::string("EXCEPTION_INVALID_DISPOSITION");
205 break;
206 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
207 s+=std::string("EXCEPTION_NONCONTINUABLE_EXCEPTION");
208 break;
209 case EXCEPTION_PRIV_INSTRUCTION:
210 s+=std::string("EXCEPTION_PRIV_INSTRUCTION");
211 break;
212 case EXCEPTION_SINGLE_STEP:
213 s+=std::string("EXCEPTION_SINGLE_STEP");
214 break;
215 case EXCEPTION_STACK_OVERFLOW:
216 s+=std::string("EXCEPTION_STACK_OVERFLOW");
217 break;
218 default:
219 s+=std::string("UNKNOWN");
220 }
221 s+=std::string("\n");
222 //s+=std::string(" (%08X)\n", exceptionRec->ExceptionCode);
223 //s+=std::string("Exception Flags: %08X\n", exceptionRec->ExceptionFlags);
224
225
226 #ifdef _WIN64
227 #define REGISTER_RECORD Rip
228 #else
229 #define REGISTER_RECORD Eip
230 #endif
231 s+=DumpFrame(processId, contextRecord->REGISTER_RECORD);
232 printf(s.c_str());
233 fflush(stdout);
234 return s;
235 }
236 /**
237 *
238 * @param processId
239 * @return
240 */
DumpBackTrace(void * processId)241 std::string DumpBackTrace(void *processId)
242 {
243 std::string s;
244 typedef VOID NTAPI RtlCaptureContext_(PCONTEXT ContextRecord);
245
246 HANDLE process = GetCurrentProcess();
247 HANDLE thread = GetCurrentThread();
248 HINSTANCE hinstLib = LoadLibrary("kernel32.dll");
249 RtlCaptureContext_* contextFunc = (RtlCaptureContext_*)GetProcAddress(hinstLib, "RtlCaptureContext");
250 STACKFRAME frame;
251 CONTEXT context;
252 int limit = 70;
253 DWORD machineType;
254
255 memset(&frame, 0, sizeof(STACKFRAME));
256 memset(&context, 0, sizeof(CONTEXT));
257
258 context.ContextFlags = CONTEXT_FULL;
259 contextFunc(&context);
260
261 #if _WIN64
262 machineType = IMAGE_FILE_MACHINE_AMD64;
263
264 frame.AddrPC.Offset = context.Rip;
265 frame.AddrStack.Offset = context.Rsp;
266 frame.AddrFrame.Offset = context.Rbp;
267 #else
268 machineType = IMAGE_FILE_MACHINE_I386;
269
270 frame.AddrPC.Offset = context.Eip;
271 frame.AddrStack.Offset = context.Esp;
272 frame.AddrFrame.Offset = context.Ebp;
273 #endif
274
275 frame.AddrPC.Mode = AddrModeFlat;
276 frame.AddrStack.Mode = AddrModeFlat;
277 frame.AddrFrame.Mode = AddrModeFlat;
278
279
280
281 while (StackWalk(machineType, process, thread, &frame, &context, 0, SymFunctionTableAccess, SymGetModuleBase, 0))
282 {
283 if (limit-- == 0)
284 break;
285 s+=DumpFrame(process, frame.AddrPC.Offset);
286 }
287 return s;
288 }
289 /**
290 *
291 * @param exceptionRecord
292 * @param contextRecord
293 */
HandleException(const char * message,struct _EXCEPTION_RECORD * exceptionRecord,struct _CONTEXT * contextRecord)294 void HandleException(const char *message,struct _EXCEPTION_RECORD *exceptionRecord, struct _CONTEXT *contextRecord)
295 {
296 std::string s;
297 fflush(stderr);
298 fflush(stdout);
299
300 static int running = 0;
301
302 if (running)
303 exit(1);
304
305 running = 1;
306
307 if (mysaveFunction)
308 mysaveFunction();
309
310
311
312 void *process = GetCurrentProcess();
313
314 SymInitialize(process, NULL, TRUE);
315
316 if (exceptionRecord != NULL && contextRecord != NULL)
317 {
318 s+=DumpExceptionInfo(process, exceptionRecord, contextRecord);
319 }
320 fflush(stderr);
321 fflush(stdout);
322
323 s+=DumpBackTrace(process);
324 fflush(stderr);
325 fflush(stdout);
326
327 const char *title;
328 if(!message) title="Crash";
329 else title=message;
330 if (myFatalFunction)
331 myFatalFunction(title, s.c_str());
332 SymCleanup(process);
333 fflush(stderr);
334 fflush(stdout);
335 exit(1);
336 }
337 /**
338 *
339 * @param exceptionRecord
340 * @param establisherFrame
341 * @param contextRecord
342 * @param dispatcherContext
343 * @return
344 */
ExceptionHandler(struct _EXCEPTION_RECORD * exceptionRecord,void * establisherFrame,struct _CONTEXT * contextRecord,void * dispatcherContext)345 EXCEPTION_DISPOSITION ExceptionHandler(struct _EXCEPTION_RECORD *exceptionRecord, void *establisherFrame, struct _CONTEXT *contextRecord, void *dispatcherContext)
346 {
347 HandleException("ExceptionHandler",exceptionRecord, contextRecord);
348 }
349 /**
350 *
351 * @param exceptionInfo
352 * @return
353 */
ExceptionFilter(struct _EXCEPTION_POINTERS * exceptionInfo)354 LONG WINAPI ExceptionFilter(struct _EXCEPTION_POINTERS *exceptionInfo)
355 {
356 HandleException("ExceptionFilter",exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord);
357 return EXCEPTION_CONTINUE_SEARCH;
358 }
359 /**
360 *
361 * @param pExceptionInfo
362 * @return
363 */
TopLevelExceptionHandler(struct _EXCEPTION_POINTERS * exceptionInfo)364 LONG WINAPI TopLevelExceptionHandler(struct _EXCEPTION_POINTERS *exceptionInfo)
365 {
366 HandleException("TopLevelExceptionHandler",exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord);
367 return EXCEPTION_CONTINUE_SEARCH;
368 }
369
370 /**
371 *
372 * @param info
373 * @param lineno
374 * @param file
375 */
ADM_backTrack(const char * info,int lineno,const char * file)376 void ADM_backTrack(const char *info, int lineno, const char *file)
377 {
378 char title[2048]={0};
379 snprintf(title,2000,"%s at line %d, file %s\n",info,lineno,file);
380 HandleException(title,NULL, NULL);
381 }
382