Mercurial > projects > ddmd
diff dbg/CallStackInfo.d @ 70:6bdecc3f4569
Get rid of win32 bindings
author | korDen |
---|---|
date | Sat, 28 Aug 2010 10:51:32 +0400 |
parents | |
children | ef02e2e203c2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbg/CallStackInfo.d Sat Aug 28 10:51:32 2010 +0400 @@ -0,0 +1,257 @@ +/** + A simple runtime crash handler which collects various informations about + the crash such as registers, stack traces, and loaded modules. + + TODO: + * Threading support + * Stack dumps + + Authors: + Jeremie Pelletier + + License: + Public Domain +*/ +module dbg.CallStackInfo; + +import dbg.Debug; +import dbg.image.PE; + +import core.stdc.stdio; +import core.sys.windows.windows; + +class CallStackInfo +{ + this(EXCEPTION_POINTERS* e = null) + { + size_t[16] buff; + size_t[] backtrace = buff[]; + size_t numTraces = 0; + + bool skipFirst = false; + + size_t ip = void, bp = void; + if (e !is null) { + ip = e.ContextRecord.Eip; + bp = e.ContextRecord.Ebp; + + error = _d_translate_se_to_d_exception(e.ExceptionRecord); + append(backtrace, numTraces, ip); + } else { + asm { + mov bp, EBP; + } + } + + while (true) { + ip = cast(size_t)*(cast(void**)bp + 1); + if (ip == 0) break; + + append(backtrace, numTraces, ip); + + bp = cast(size_t)*cast(void**)bp; + } + + frames = new StackFrameInfo[numTraces]; + ResolveStackFrames(backtrace[0..numTraces], frames); + } + + Throwable error; + StackFrameInfo[] frames; + + string toString() { + string text; + + if (error !is null) { + text ~= error.toString() ~ "\n"; + } + + text ~= "Stack trace:\n------------------\n"; + char buffer[128]; + foreach(ref frame; frames) { + with(frame.fileLine) if(line) { + auto len = snprintf(buffer.ptr, buffer.length, "%u", line); + text ~= file ~ ":" ~ buffer[0 .. len] ~ "\r\n"; + } + } + + text ~= '\0'; + + return text; + } + + void dump() { + if (error !is null) { + printf("%.*s\n", error.toString()); + } + + printf("Stack trace:\n------------------\n"); + foreach(ref frame; frames) { + with(frame.fileLine) if (line) { + printf("%.*s:%d\r\n", file, line); + } + } + } + +private: + + struct StackFrameInfo { + size_t va; + string moduleName; + SymbolInfo symbol; + FileLineInfo fileLine; + } + + struct DebugImage { + DebugImage* next; + string moduleName; + size_t baseAddress; + uint rvaOffset; + IExecutableImage exeModule; + ISymbolicDebugInfo debugInfo; + } + + void ResolveStackFrames(size_t[] backtrace, StackFrameInfo[] frames) const { + StackFrameInfo* frame = void; + DebugImage* imageList, image = void; + char[255] buffer = void; + uint len = void; + uint rva = void; + + version(Windows) MEMORY_BASIC_INFORMATION mbi = void; + + foreach(i, va; backtrace) { + frame = &frames[i]; + frame.va = va; + + // mbi.Allocation base is the handle to stack frame's module + VirtualQuery(cast(void*)va, &mbi, MEMORY_BASIC_INFORMATION.sizeof); + if(!mbi.AllocationBase) break; + + image = imageList; + while(image) { + if(image.baseAddress == cast(size_t)mbi.AllocationBase) break; + image = image.next; + } + + if(!image) { + image = new DebugImage; + + with(*image) { + next = imageList; + imageList = image; + baseAddress = cast(size_t)mbi.AllocationBase; + + len = GetModuleFileNameA(cast(HMODULE)baseAddress, buffer.ptr, buffer.length); + moduleName = buffer[0 .. len].idup; + if (len != 0) { + exeModule = new PEImage(moduleName); + rvaOffset = baseAddress + exeModule.codeOffset; + debugInfo = exeModule.debugInfo; + } + } + } + + frame.moduleName = image.moduleName; + + if(!image.debugInfo) continue; + + rva = va - image.rvaOffset; + + with(image.debugInfo) { + frame.symbol = ResolveSymbol(rva); + frame.fileLine = ResolveFileLine(rva); + } + } + + while(imageList) { + image = imageList.next; + delete imageList.debugInfo; + delete imageList.exeModule; + delete imageList; + imageList = image; + } + } +} + +void CrashHandlerInit() { + //SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); + SetErrorMode(0); + SetUnhandledExceptionFilter(&UnhandledExceptionHandler); +} + +enum EXCEPTION_EXECUTE_HANDLER = 1; + +extern(Windows) int UnhandledExceptionHandler(EXCEPTION_POINTERS* e) { + scope CallStackInfo info = new CallStackInfo(e); + info.dump(); + + return EXCEPTION_EXECUTE_HANDLER; +} + +extern (Windows) extern UINT SetErrorMode(UINT); +alias LONG function(EXCEPTION_POINTERS*) PTOP_LEVEL_EXCEPTION_FILTER; +extern (Windows) PTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(PTOP_LEVEL_EXCEPTION_FILTER); + +void append(T)(T[] array, ref size_t index, T value) +{ + size_t capacity = array.length; + assert(capacity >= index); + if (capacity == index) { + if (capacity < 8) { + capacity = 8; + } else { + array.length = capacity * 2; + } + } + + array[index++] = value; +} + +struct EXCEPTION_POINTERS { + EXCEPTION_RECORD* ExceptionRecord; + CONTEXT* ContextRecord; +} + +const size_t EXCEPTION_MAXIMUM_PARAMETERS = 15; + +struct EXCEPTION_RECORD { + DWORD ExceptionCode; + DWORD ExceptionFlags; + EXCEPTION_RECORD* ExceptionRecord; + PVOID ExceptionAddress; + DWORD NumberParameters; + DWORD[EXCEPTION_MAXIMUM_PARAMETERS] ExceptionInformation; +} + +const MAXIMUM_SUPPORTED_EXTENSION = 512; + +struct CONTEXT { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; + BYTE[MAXIMUM_SUPPORTED_EXTENSION] ExtendedRegisters; +} + +extern(C) Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD* exception_record); \ No newline at end of file