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