Browse files

Issue 1001 - print stack trace (in debug mode) when programs die

  • Loading branch information...
1 parent 34ef4a6 commit e777ed1a5edd8312a661867080e9082e7af5b0e3 @complexmath complexmath committed Mar 23, 2011
Showing with 684 additions and 10 deletions.
  1. +8 −4 posix.mak
  2. +6 −2 src/core/runtime.d
  3. +233 −0 src/core/sys/windows/dbghelp.d
  4. +421 −0 src/core/sys/windows/stacktrace.d
  5. +1 −1 src/core/sys/windows/windows.d
  6. +15 −3 win32.mak
View
12 posix.mak
@@ -27,8 +27,8 @@ IMPDIR=import
MODEL=32
-DFLAGS=-m$(MODEL) -O -release -inline -nofloat -w -d -Isrc -Iimport
-UDFLAGS=-m$(MODEL) -O -release -nofloat -w -d -Isrc -Iimport
+DFLAGS=-m$(MODEL) -O -release -inline -nofloat -w -d -Isrc -Iimport
+UDFLAGS=-m$(MODEL) -O -release -nofloat -w -d -Isrc -Iimport
CFLAGS=-m$(MODEL) -O
@@ -141,6 +141,8 @@ MANIFEST= \
\
src/core/sys/windows/_dll.d \
src/core/sys/windows/_thread.d \
+ src/core/sys/windows/dbghelp.d \
+ src/core/sys/windows/stacktrace.d \
src/core/sys/windows/windows.d \
\
src/gc/gc.d \
@@ -470,6 +472,8 @@ IMPORTS=\
\
$(IMPDIR)/core/sys/windows/_dll.di \
$(IMPDIR)/core/sys/windows/_thread.di \
+ $(IMPDIR)/core/sys/windows/dbghelp.di \
+ $(IMPDIR)/core/sys/windows/stacktrace.di \
$(IMPDIR)/core/sys/windows/windows.di
SRCS=$(addprefix src/,$(addsuffix .d,$(SRC_D_MODULES)))
@@ -483,14 +487,14 @@ $(DOCDIR)/object.html : src/object_.d
$(DOCDIR)/core_%.html : src/core/%.d
$(DMD) -c -d -o- -Isrc -Iimport -Df$@ $(DOCFMT) $<
-
+
$(DOCDIR)/core_sync_%.html : src/core/sync/%.d
$(DMD) -c -d -o- -Isrc -Iimport -Df$@ $(DOCFMT) $<
######################## Header .di file generation ##############################
import: $(IMPORTS)
-
+
$(IMPDIR)/core/%.di : src/core/%.d
$(DMD) -c -d -o- -Isrc -Iimport -Hf$@ $<
View
8 src/core/runtime.d
@@ -58,6 +58,10 @@ private
extern (C) void backtrace_symbols_fd(void**,int,int);
import core.sys.posix.signal; // segv handler
}
+ else version( Windows )
+ {
+ import core.sys.windows.stacktrace;
+ }
// For runModuleUnitTests error reporting.
version( Windows )
@@ -511,8 +515,8 @@ Throwable.TraceInfo defaultTraceHandler( void* ptr = null )
return new DefaultTraceInfo;
}
- else
+ else static if( __traits( compiles, new StackTrace ) )
{
- return null;
+ return new StackTrace;
}
}
View
233 src/core/sys/windows/dbghelp.d
@@ -0,0 +1,233 @@
+/**
+ * ...
+ *
+ * Copyright: Copyright Benjamin Thaut 2010 - 2011.
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors: Benjamin Thaut, Sean Kelly
+ * Source: $(DRUNTIMESRC core/sys/windows/_stacktrace.d)
+ */
+
+/* Copyright Benjamin Thaut 2010 - 2011.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+module core.sys.windows.dbghelp;
+
+
+import core.runtime;
+import core.sys.windows.windows;
+
+
+alias CHAR TCHAR;
+
+/*
+enum ADDRESS_MODE : DWORD
+{
+ AddrMode1616 = 0,
+ AddrMode1632 = 1,
+ AddrModeReal = 2,
+ AddrModeFlat = 3,
+}
+*/
+enum : DWORD
+{
+ SYMOPT_FAIL_CRITICAL_ERRORS = 0x00000200,
+ SYMOPT_LOAD_LINES = 0x00000010,
+}
+
+struct GUID
+{
+ uint Data1;
+ ushort Data2;
+ ushort Data3;
+ ubyte[8] Data4;
+}
+/+
+struct ADDRESS64
+{
+ DWORD64 Offset;
+ WORD Segment;
+ ADDRESS_MODE Mode;
+}
+
+struct KDHELP64
+{
+ DWORD64 Thread;
+ DWORD ThCallbackStack;
+ DWORD ThCallbackBStore;
+ DWORD NextCallback;
+ DWORD FramePointer;
+ DWORD64 KiCallUserMode;
+ DWORD64 KeUserCallbackDispatcher;
+ DWORD64 SystemRangeStart;
+ DWORD64 KiUserExceptionDispatcher;
+ DWORD64[7] Reserved;
+}
+
+struct STACKFRAME64
+{
+ ADDRESS64 AddrPC;
+ ADDRESS64 AddrReturn;
+ ADDRESS64 AddrFrame;
+ ADDRESS64 AddrStack;
+ ADDRESS64 AddrBStore;
+ PVOID FuncTableEntry;
+ DWORD64[4] Params;
+ BOOL Far;
+ BOOL Virtual;
+ DWORD64[3] Reserved;
+ KDHELP64 KdHelp;
+}
++/
+enum : DWORD
+{
+ IMAGE_FILE_MACHINE_I386 = 0x014c,
+ IMGAE_FILE_MACHINE_IA64 = 0x0200,
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664,
+}
+
+struct IMAGEHLP_LINE64
+{
+ DWORD SizeOfStruct;
+ PVOID Key;
+ DWORD LineNumber;
+ PTSTR FileName;
+ DWORD64 Address;
+}
+
+enum SYM_TYPE : int
+{
+ SymNone = 0,
+ SymCoff,
+ SymCv,
+ SymPdb,
+ SymExport,
+ SymDeferred,
+ SymSym,
+ SymDia,
+ SymVirtual,
+ NumSymTypes,
+}
+
+struct IMAGEHLP_MODULE64
+{
+ DWORD SizeOfStruct;
+ DWORD64 BaseOfImage;
+ DWORD ImageSize;
+ DWORD TimeDateStamp;
+ DWORD CheckSum;
+ DWORD NumSyms;
+ SYM_TYPE SymType;
+ TCHAR[32] ModuleName;
+ TCHAR[256] ImageName;
+ TCHAR[256] LoadedImageName;
+ TCHAR[256] LoadedPdbName;
+ DWORD CVSig;
+ TCHAR[MAX_PATH*3] CVData;
+ DWORD PdbSig;
+ GUID PdbSig70;
+ DWORD PdbAge;
+ BOOL PdbUnmatched;
+ BOOL DbgUnmachted;
+ BOOL LineNumbers;
+ BOOL GlobalSymbols;
+ BOOL TypeInfo;
+ BOOL SourceIndexed;
+ BOOL Publics;
+}
+
+struct IMAGEHLP_SYMBOL64
+{
+ DWORD SizeOfStruct;
+ DWORD64 Address;
+ DWORD Size;
+ DWORD Flags;
+ DWORD MaxNameLength;
+ TCHAR[1] Name;
+}
+
+extern(System)
+{
+ typedef BOOL function(HANDLE hProcess, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) ReadProcessMemoryProc64;
+ typedef PVOID function(HANDLE hProcess, DWORD64 AddrBase) FunctionTableAccessProc64;
+ typedef DWORD64 function(HANDLE hProcess, DWORD64 Address) GetModuleBaseProc64;
+ typedef DWORD64 function(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr) TranslateAddressProc64;
+
+ typedef BOOL function(HANDLE hProcess, PCSTR UserSearchPath, bool fInvadeProcess) SymInitializeFunc;
+ typedef BOOL function(HANDLE hProcess) SymCleanupFunc;
+ typedef DWORD function(DWORD SymOptions) SymSetOptionsFunc;
+ typedef DWORD function() SymGetOptionsFunc;
+ typedef PVOID function(HANDLE hProcess, DWORD64 AddrBase) SymFunctionTableAccess64Func;
+ typedef BOOL function(DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, PVOID ContextRecord,
+ ReadProcessMemoryProc64 ReadMemoryRoutine, FunctionTableAccessProc64 FunctoinTableAccess,
+ GetModuleBaseProc64 GetModuleBaseRoutine, TranslateAddressProc64 TranslateAddress) StackWalk64Func;
+ typedef BOOL function(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, IMAGEHLP_LINE64 *line) SymGetLineFromAddr64Func;
+ typedef DWORD64 function(HANDLE hProcess, DWORD64 dwAddr) SymGetModuleBase64Func;
+ typedef BOOL function(HANDLE hProcess, DWORD64 dwAddr, IMAGEHLP_MODULE64 *ModuleInfo) SymGetModuleInfo64Func;
+ typedef BOOL function(HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, IMAGEHLP_SYMBOL64 *Symbol) SymGetSymFromAddr64Func;
+ typedef DWORD function(PCTSTR DecoratedName, PTSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags) UnDecorateSymbolNameFunc;
+ typedef DWORD64 function(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll) SymLoadModule64Func;
+ typedef BOOL function(HANDLE HProcess, PTSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc;
+ typedef BOOL function(HANDLE hProcess, DWORD64 Address) SymUnloadModule64Func;
+}
+
+struct DbgHelp
+{
+ SymInitializeFunc SymInitialize;
+ SymCleanupFunc SymCleanup;
+ StackWalk64Func StackWalk64;
+ SymGetOptionsFunc SymGetOptions;
+ SymSetOptionsFunc SymSetOptions;
+ SymFunctionTableAccess64Func SymFunctionTableAccess64;
+ SymGetLineFromAddr64Func SymGetLineFromAddr64;
+ SymGetModuleBase64Func SymGetModuleBase64;
+ SymGetModuleInfo64Func SymGetModuleInfo64;
+ SymGetSymFromAddr64Func SymGetSymFromAddr64;
+ UnDecorateSymbolNameFunc UnDecorateSymbolName;
+ SymLoadModule64Func SymLoadModule64;
+ SymGetSearchPathFunc SymGetSearchPath;
+ SymUnloadModule64Func SymUnloadModule64;
+
+ static DbgHelp* get()
+ {
+ if( sm_hndl != sm_hndl.init )
+ return &sm_inst;
+ if( auto ptr = Runtime.loadLibrary( "dbghelp.dll" ) )
+ {
+ sm_hndl = cast(HANDLE) ptr;
+
+ sm_inst.SymInitialize = cast(SymInitializeFunc) GetProcAddress(sm_hndl,"SymInitialize");
+ sm_inst.SymCleanup = cast(SymCleanupFunc) GetProcAddress(sm_hndl,"SymCleanup");
+ sm_inst.StackWalk64 = cast(StackWalk64Func) GetProcAddress(sm_hndl,"StackWalk64");
+ sm_inst.SymGetOptions = cast(SymGetOptionsFunc) GetProcAddress(sm_hndl,"SymGetOptions");
+ sm_inst.SymSetOptions = cast(SymSetOptionsFunc) GetProcAddress(sm_hndl,"SymSetOptions");
+ sm_inst.SymFunctionTableAccess64 = cast(SymFunctionTableAccess64Func) GetProcAddress(sm_hndl,"SymFunctionTableAccess64");
+ sm_inst.SymGetLineFromAddr64 = cast(SymGetLineFromAddr64Func) GetProcAddress(sm_hndl,"SymGetLineFromAddr64");
+ sm_inst.SymGetModuleBase64 = cast(SymGetModuleBase64Func) GetProcAddress(sm_hndl,"SymGetModuleBase64");
+ sm_inst.SymGetModuleInfo64 = cast(SymGetModuleInfo64Func) GetProcAddress(sm_hndl,"SymGetModuleInfo64");
+ sm_inst.SymGetSymFromAddr64 = cast(SymGetSymFromAddr64Func) GetProcAddress(sm_hndl,"SymGetSymFromAddr64");
+ sm_inst.SymLoadModule64 = cast(SymLoadModule64Func) GetProcAddress(sm_hndl,"SymLoadModule64");
+ sm_inst.SymGetSearchPath = cast(SymGetSearchPathFunc) GetProcAddress(sm_hndl,"SymGetSearchPath");
+ sm_inst.SymUnloadModule64 = cast(SymUnloadModule64Func) GetProcAddress(sm_hndl,"SymUnloadModule64");
+
+ assert( sm_inst.SymInitialize && sm_inst.SymCleanup && sm_inst.StackWalk64 && sm_inst.SymGetOptions &&
+ sm_inst.SymSetOptions && sm_inst.SymFunctionTableAccess64 && sm_inst.SymGetLineFromAddr64 &&
+ sm_inst.SymGetModuleBase64 && sm_inst.SymGetModuleInfo64 && sm_inst.SymGetSymFromAddr64 &&
+ sm_inst.SymLoadModule64 && sm_inst.SymGetSearchPath && sm_inst.SymUnloadModule64);
+
+ return &sm_inst;
+ }
+ return null;
+ }
+
+ shared static ~this()
+ {
+ if( sm_hndl != sm_hndl.init )
+ Runtime.unloadLibrary( sm_hndl );
+ }
+
+private:
+ __gshared DbgHelp sm_inst;
+ __gshared HANDLE sm_hndl;
+}
View
421 src/core/sys/windows/stacktrace.d
@@ -0,0 +1,421 @@
+/**
+ * ...
+ *
+ * Copyright: Copyright Benjamin Thaut 2010 - 2011.
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors: Benjamin Thaut, Sean Kelly
+ * Source: $(DRUNTIMESRC core/sys/windows/_stacktrace.d)
+ */
+
+/* Copyright Benjamin Thaut 2010 - 2011.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+module core.sys.windows.stacktrace;
+
+
+import core.demangle;
+import core.runtime;
+import core.stdc.stdlib;
+import core.stdc.string;
+import core.sys.windows.dbghelp;
+import core.sys.windows.windows;
+import core.stdc.stdio;
+
+
+extern(Windows)
+{
+ DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR pBuffer, DWORD nSize);
+ void RtlCaptureContext(CONTEXT* ContextRecord);
+
+ typedef LONG function(void*) UnhandeledExceptionFilterFunc;
+ void* SetUnhandledExceptionFilter(void* handler);
+}
+
+
+enum : uint
+{
+ MAX_MODULE_NAME32 = 255,
+ TH32CS_SNAPMODULE = 0x00000008,
+ MAX_NAMELEN = 1024,
+};
+
+
+extern(System)
+{
+ typedef HANDLE function(DWORD dwFlags, DWORD th32ProcessID) CreateToolhelp32SnapshotFunc;
+ typedef BOOL function(HANDLE hSnapshot, MODULEENTRY32 *lpme) Module32FirstFunc;
+ typedef BOOL function(HANDLE hSnapshot, MODULEENTRY32 *lpme) Module32NextFunc;
+}
+
+
+struct MODULEENTRY32
+{
+ DWORD dwSize;
+ DWORD th32ModuleID;
+ DWORD th32ProcessID;
+ DWORD GlblcntUsage;
+ DWORD ProccntUsage;
+ BYTE* modBaseAddr;
+ DWORD modBaseSize;
+ HMODULE hModule;
+ CHAR[MAX_MODULE_NAME32 + 1] szModule;
+ CHAR[MAX_PATH] szExePath;
+}
+
+
+private
+{
+ string generateSearchPath()
+ {
+ __gshared string[3] defaultPathList = ["_NT_SYMBOL_PATH",
+ "_NT_ALTERNATE_SYMBOL_PATH",
+ "SYSTEMROOT"];
+
+ string path;
+ char[MAX_PATH] temp;
+ DWORD len;
+
+ if( (len = GetCurrentDirectoryA( temp.length, temp.ptr )) > 0 )
+ {
+ path ~= temp[0 .. len] ~ ";";
+ }
+ if( (len = GetModuleFileNameA( null,temp.ptr,temp.length )) > 0 )
+ {
+ foreach_reverse( i, ref char e; temp[0 .. len] )
+ {
+ if( e == '\\' || e == '/' || e == ':' )
+ {
+ len -= i;
+ break;
+ }
+ }
+ if( len > 0 )
+ {
+ path ~= temp[0 .. len] ~ ";";
+ }
+ }
+ foreach( e; defaultPathList )
+ {
+ if( (len = GetEnvironmentVariableA( e.ptr, temp.ptr, temp.length )) > 0 )
+ {
+ path ~= temp[0 .. len] ~ ";";
+ }
+ }
+ return path;
+ }
+
+
+ bool loadModules( HANDLE hProcess, DWORD pid )
+ {
+ __gshared string[2] systemDlls = ["kernel32.dll", "tlhelp32.dll"];
+
+ CreateToolhelp32SnapshotFunc CreateToolhelp32Snapshot;
+ Module32FirstFunc Module32First;
+ Module32NextFunc Module32Next;
+ HMODULE dll;
+
+ foreach( e; systemDlls )
+ {
+ if( (dll = cast(HMODULE) Runtime.loadLibrary( e )) is null )
+ continue;
+ CreateToolhelp32Snapshot = cast(CreateToolhelp32SnapshotFunc) GetProcAddress( dll,"CreateToolhelp32Snapshot" );
+ Module32First = cast(Module32FirstFunc) GetProcAddress( dll,"Module32First" );
+ Module32Next = cast(Module32NextFunc) GetProcAddress( dll,"Module32Next" );
+ if( CreateToolhelp32Snapshot !is null && Module32First !is null && Module32Next !is null )
+ break;
+ Runtime.unloadLibrary( dll );
+ dll = null;
+ }
+ if( dll is null )
+ {
+ return false;
+ }
+
+ auto hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
+ if( hSnap == INVALID_HANDLE_VALUE )
+ return false;
+
+ MODULEENTRY32 moduleEntry;
+ moduleEntry.dwSize = MODULEENTRY32.sizeof;
+
+ auto more = cast(bool) Module32First( hSnap, &moduleEntry );
+ int count = 0;
+
+ while( more )
+ {
+ count++;
+ loadModule( hProcess,
+ moduleEntry.szExePath.ptr,
+ moduleEntry.szModule.ptr,
+ cast(DWORD64) moduleEntry.modBaseAddr,
+ moduleEntry.modBaseSize );
+ more = cast(bool) Module32Next( hSnap, &moduleEntry );
+ }
+
+ CloseHandle( hSnap );
+ Runtime.unloadLibrary( dll );
+ return count > 0;
+ }
+
+
+ void loadModule( HANDLE hProcess, PCSTR img, PCSTR mod, DWORD64 baseAddr, DWORD size )
+ {
+ auto dbghelp = DbgHelp.get();
+ DWORD64 moduleAddr = dbghelp.SymLoadModule64( hProcess,
+ HANDLE.init,
+ img,
+ mod,
+ baseAddr,
+ size );
+ if( moduleAddr == 0 )
+ return;
+
+ IMAGEHLP_MODULE64 moduleInfo;
+ moduleInfo.SizeOfStruct = IMAGEHLP_MODULE64.sizeof;
+
+ if( dbghelp.SymGetModuleInfo64( hProcess, moduleAddr, &moduleInfo ) == TRUE )
+ {
+ if( moduleInfo.SymType == SYM_TYPE.SymNone )
+ {
+ dbghelp.SymUnloadModule64( hProcess, moduleAddr );
+ moduleAddr = dbghelp.SymLoadModule64( hProcess,
+ HANDLE.init,
+ img,
+ null,
+ cast(DWORD64) 0,
+ 0 );
+ if( moduleAddr == 0 )
+ return;
+ }
+ }
+ //printf( "Successfully loaded module %s\n", img );
+ }
+
+
+ /+
+ extern(Windows) static LONG unhandeledExceptionFilterHandler(void* info)
+ {
+ printStackTrace();
+ return 0;
+ }
+
+
+ static void printStackTrace()
+ {
+ auto stack = TraceHandler( null );
+ foreach( char[] s; stack )
+ {
+ printf( "%s\n",s );
+ }
+ }
+ +/
+
+
+ __gshared invariant bool initialized;
+}
+
+
+class StackTrace : Throwable.TraceInfo
+{
+public:
+ this()
+ {
+ if( initialized )
+ m_trace = trace();
+ }
+
+
+ int opApply( scope int delegate(ref char[]) dg )
+ {
+ return opApply( (ref size_t, ref char[] buf)
+ {
+ return dg( buf );
+ });
+ }
+
+
+ int opApply( scope int delegate(ref size_t, ref char[]) dg )
+ {
+ int result;
+
+ foreach( i, e; m_trace )
+ {
+ if( (result = dg( i, e )) != 0 )
+ break;
+ }
+ return result;
+ }
+
+
+ override string toString()
+ {
+ string result;
+
+ foreach( e; m_trace )
+ {
+ result ~= e ~ "\n";
+ }
+ return result;
+ }
+
+
+private:
+ char[][] m_trace;
+
+
+ static synchronized char[][] trace()
+ {
+ auto dbghelp = DbgHelp.get();
+ auto hThread = GetCurrentThread();
+ auto hProcess = GetCurrentProcess();
+ STACKFRAME64 stackframe;
+ DWORD imageType;
+ char[][] trace;
+ CONTEXT c;
+
+ c.ContextFlags = CONTEXT_FULL;
+ RtlCaptureContext( &c );
+
+ //x86
+ imageType = IMAGE_FILE_MACHINE_I386;
+ stackframe.AddrPC.Offset = cast(DWORD64) c.Eip;
+ stackframe.AddrPC.Mode = ADDRESS_MODE.AddrModeFlat;
+ stackframe.AddrFrame.Offset = cast(DWORD64) c.Ebp;
+ stackframe.AddrFrame.Mode = ADDRESS_MODE.AddrModeFlat;
+ stackframe.AddrStack.Offset = cast(DWORD64) c.Esp;
+ stackframe.AddrStack.Mode = ADDRESS_MODE.AddrModeFlat;
+
+ auto symbolSize = IMAGEHLP_SYMBOL64.sizeof + MAX_NAMELEN;
+ auto symbol = cast(IMAGEHLP_SYMBOL64*) calloc( symbolSize, 1 );
+
+ symbol.SizeOfStruct = symbolSize;
+ symbol.MaxNameLength = MAX_NAMELEN;
+
+ IMAGEHLP_LINE64 line;
+ line.SizeOfStruct = IMAGEHLP_LINE64.sizeof;
+
+ IMAGEHLP_MODULE64 moduleInfo;
+ moduleInfo.SizeOfStruct = IMAGEHLP_MODULE64.sizeof;
+
+ //printf( "Callstack:\n" );
+ for( int frameNum = 0; ; frameNum++ )
+ {
+ if( dbghelp.StackWalk64( imageType,
+ hProcess,
+ hThread,
+ &stackframe,
+ &c,
+ null,
+ cast(FunctionTableAccessProc64) dbghelp.SymFunctionTableAccess64,
+ cast(GetModuleBaseProc64) dbghelp.SymGetModuleBase64,
+ null) != TRUE )
+ {
+ //printf( "End of Callstack\n" );
+ break;
+ }
+
+ if( stackframe.AddrPC.Offset == stackframe.AddrReturn.Offset )
+ {
+ //printf( "Endless callstack\n" );
+ trace ~= "...".dup;
+ break;
+ }
+
+ if( stackframe.AddrPC.Offset != 0 )
+ {
+ DWORD64 offset;
+
+ if( dbghelp.SymGetSymFromAddr64( hProcess,
+ stackframe.AddrPC.Offset,
+ &offset,
+ symbol ) == TRUE )
+ {
+ DWORD displacement;
+ char[] lineBuf;
+ char[20] temp;
+
+ if( dbghelp.SymGetLineFromAddr64( hProcess, stackframe.AddrPC.Offset, &displacement, &line ) == TRUE )
+ {
+ char[2048] demangleBuf;
+ auto symbolName = (cast(char*) symbol.Name.ptr)[0 .. strlen(symbol.Name.ptr)];
+
+ // displacement bytes from beginning of line
+ trace ~= line.FileName[0 .. strlen( line.FileName )] ~
+ "(" ~ format( temp[], line.LineNumber ) ~ "): " ~
+ demangle( symbolName, demangleBuf );
+ }
+ }
+ else
+ {
+ char[22] temp;
+ auto val = format( temp[], stackframe.AddrPC.Offset, 16 );
+ trace ~= val.dup;
+ }
+ }
+ }
+ free( symbol );
+ return trace;
+ }
+
+
+ // TODO: Remove this in favor of an external conversion.
+ static char[] format( char[] buf, ulong val, uint base = 10 )
+ in
+ {
+ assert( buf.length > 9 );
+ }
+ body
+ {
+ auto p = buf.ptr + buf.length;
+
+ if( base < 11 )
+ {
+ do
+ {
+ *--p = cast(char)(val % base + '0');
+ } while( val /= base );
+ }
+ else if( base < 37 )
+ {
+ do
+ {
+ auto x = val % base;
+ *--p = cast(char)(x < 10 ? x + '0' : (x - 10) + 'A');
+ } while( val /= base );
+ }
+ else
+ {
+ assert( false, "base too large" );
+ }
+ return buf[p - buf.ptr .. $];
+ }
+}
+
+
+shared static this()
+{
+ auto dbghelp = DbgHelp.get();
+
+ if( dbghelp is null )
+ return; // dbghelp.dll not available
+
+ auto hProcess = GetCurrentProcess();
+ auto pid = GetCurrentProcessId();
+ auto symPath = generateSearchPath() ~ 0;
+ auto ret = dbghelp.SymInitialize( hProcess,
+ symPath.ptr,
+ FALSE );
+ assert( ret != FALSE );
+
+ auto symOptions = dbghelp.SymGetOptions();
+ symOptions |= SYMOPT_LOAD_LINES;
+ symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
+ symOptions = dbghelp.SymSetOptions( symOptions );
+
+ if( !loadModules( hProcess, pid ) )
+ {} // for now it's fine if the modules don't load
+ initialized = true;
+ //SetUnhandledExceptionFilter( &unhandeledExceptionFilterHandler );
+}
View
2 src/core/sys/windows/windows.d
@@ -38,7 +38,7 @@ extern (Windows)
alias LPSTR LPTCH, PTCH;
alias LPSTR PTSTR, LPTSTR;
- alias LPCSTR LPCTSTR;
+ alias LPCSTR PCTSTR, LPCTSTR;
alias WCHAR* LPWSTR;
View
18 win32.mak
@@ -120,6 +120,8 @@ MANIFEST= \
\
src\core\sys\windows\_dll.d \
src\core\sys\windows\_thread.d \
+ src\core\sys\windows\dbghelp.d \
+ src\core\sys\windows\stacktrace.d \
src\core\sys\windows\windows.d \
\
src\gc\gc.d \
@@ -245,6 +247,8 @@ SRCS= \
\
src\core\sys\windows\_dll.d \
src\core\sys\windows\_thread.d \
+ src\core\sys\windows\dbghelp.d \
+ src\core\sys\windows\stacktrace.d \
src\core\sys\windows\windows.d \
\
src\core\sync\barrier.d \
@@ -446,6 +450,8 @@ IMPORTS=\
\
$(IMPDIR)\core\sys\windows\_dll.di \
$(IMPDIR)\core\sys\windows\_thread.di \
+ $(IMPDIR)\core\sys\windows\dbghelp.di \
+ $(IMPDIR)\core\sys\windows\stacktrace.di \
$(IMPDIR)\core\sys\windows\windows.di
######################## Doc .html file generation ##############################
@@ -478,7 +484,7 @@ $(DOCDIR)\core_runtime.html : src\core\runtime.d
$(DOCDIR)\core_thread.html : src\core\thread.d
$(DMD) -c -d -o- -Isrc -Iimport -Df$@ $(DOCFMT) $**
-
+
$(DOCDIR)\core_time.html : src\core\time.d
$(DMD) -c -d -o- -Isrc -Iimport -Df$@ $(DOCFMT) $**
@@ -533,7 +539,7 @@ $(IMPDIR)\core\runtime.di : src\core\runtime.d
$(IMPDIR)\core\thread.di : src\core\thread.d
$(DMD) -c -d -o- -Isrc -Iimport -Hf$@ $**
-
+
$(IMPDIR)\core\time.di : src\core\time.d
$(DMD) -c -d -o- -Isrc -Iimport -Hf$@ $**
@@ -740,7 +746,13 @@ $(IMPDIR)\core\sys\windows\_dll.di : src\core\sys\windows\_dll.d
$(IMPDIR)\core\sys\windows\_thread.di : src\core\sys\windows\_thread.d
$(DMD) -c -d -o- -Isrc -Iimport -Hf$@ $**
-
+
+$(IMPDIR)\core\sys\windows\dbghelp.di : src\core\sys\windows\dbghelp.d
+ $(DMD) -c -d -o- -Isrc -Iimport -Hf$@ $**
+
+$(IMPDIR)\core\sys\windows\stacktrace.di : src\core\sys\windows\stacktrace.d
+ $(DMD) -c -d -o- -Isrc -Iimport -Hf$@ $**
+
$(IMPDIR)\core\sys\windows\windows.di : src\core\sys\windows\windows.d
$(DMD) -c -d -o- -Isrc -Iimport -Hf$@ $**

0 comments on commit e777ed1

Please sign in to comment.