display stack trace on exceptions
This commit is contained in:
		
							parent
							
								
									050b1a504e
								
							
						
					
					
						commit
						0eceb235ca
					
				|  | @ -94,6 +94,7 @@ | |||
|     <ClInclude Include="third-party\ImGui\imstb_rectpack.h" /> | ||||
|     <ClInclude Include="third-party\ImGui\imstb_textedit.h" /> | ||||
|     <ClInclude Include="third-party\ImGui\imstb_truetype.h" /> | ||||
|     <ClInclude Include="third-party\StackWalker\StackWalker.h" /> | ||||
|     <ClInclude Include="ui\Button.h" /> | ||||
|     <ClInclude Include="ui\Menu.h" /> | ||||
|     <ClInclude Include="utils\DataUtil.h" /> | ||||
|  | @ -153,6 +154,7 @@ | |||
|     <ClCompile Include="third-party\ImGui\imgui_demo.cpp" /> | ||||
|     <ClCompile Include="third-party\ImGui\imgui_draw.cpp" /> | ||||
|     <ClCompile Include="third-party\ImGui\imgui_widgets.cpp" /> | ||||
|     <ClCompile Include="third-party\StackWalker\StackWalker.cpp" /> | ||||
|     <ClCompile Include="ui\Button.cpp" /> | ||||
|     <ClCompile Include="ui\Menu.cpp" /> | ||||
|     <ClCompile Include="utils\DataUtil.cpp" /> | ||||
|  |  | |||
|  | @ -40,6 +40,9 @@ | |||
|     <Filter Include="third-party\ImGui"> | ||||
|       <UniqueIdentifier>{2f24af2d-eba6-4be1-9ac4-fc58aeac6670}</UniqueIdentifier> | ||||
|     </Filter> | ||||
|     <Filter Include="third-party\StackWalker"> | ||||
|       <UniqueIdentifier>{1fec4835-63a1-4612-80b5-828dadf0ac63}</UniqueIdentifier> | ||||
|     </Filter> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="ui\Button.h"> | ||||
|  | @ -327,6 +330,9 @@ | |||
|     <ClInclude Include="imgui\imgui_impl.hpp"> | ||||
|       <Filter>imgui</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="third-party\StackWalker\StackWalker.h"> | ||||
|       <Filter>third-party\StackWalker</Filter> | ||||
|     </ClInclude> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClCompile Include="ui\Button.cpp"> | ||||
|  | @ -500,5 +506,8 @@ | |||
|     <ClCompile Include="imgui\imgui_impl_dx10.cpp"> | ||||
|       <Filter>imgui</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="third-party\StackWalker\StackWalker.cpp"> | ||||
|       <Filter>third-party\StackWalker</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
|  | @ -70,7 +70,6 @@ namespace kiwano | |||
| 
 | ||||
| 	Logger::Logger() | ||||
| 		: enabled_(true) | ||||
| 		, has_console_(false) | ||||
| 		, default_stdout_color_(0) | ||||
| 		, default_stderr_color_(0) | ||||
| 		, output_stream_(std::wcout.rdbuf()) | ||||
|  | @ -81,8 +80,8 @@ namespace kiwano | |||
| 
 | ||||
| 	void Logger::ResetOutputStream() | ||||
| 	{ | ||||
| 		has_console_ = ::GetConsoleWindow() != nullptr; | ||||
| 		if (has_console_) | ||||
| 		bool has_console = ::GetConsoleWindow() != nullptr; | ||||
| 		if (has_console) | ||||
| 		{ | ||||
| 			default_stdout_color_ = default_stderr_color_ = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||
| 
 | ||||
|  | @ -161,7 +160,7 @@ namespace kiwano | |||
| 
 | ||||
| 	void Logger::Outputf(std::wostream& os, std::wostream& (*color)(std::wostream&), const wchar_t* prompt, const wchar_t* format, va_list args) const | ||||
| 	{ | ||||
| 		if (enabled_ && has_console_) | ||||
| 		if (enabled_) | ||||
| 		{ | ||||
| 			std::wstring output = MakeOutputStringf(prompt, format, args); | ||||
| 
 | ||||
|  |  | |||
|  | @ -115,7 +115,6 @@ namespace kiwano | |||
| 
 | ||||
| 	private: | ||||
| 		bool enabled_; | ||||
| 		bool has_console_; | ||||
| 		WORD default_stdout_color_; | ||||
| 		WORD default_stderr_color_; | ||||
| 
 | ||||
|  | @ -223,7 +222,7 @@ namespace kiwano | |||
| 	template <typename ..._Args> | ||||
| 	void Logger::OutputLine(std::wostream& os, std::wostream& (*color)(std::wostream&), const wchar_t* prompt, _Args&& ... args) const | ||||
| 	{ | ||||
| 		if (enabled_ && has_console_) | ||||
| 		if (enabled_) | ||||
| 		{ | ||||
| 			Output(os, color, prompt, std::forward<_Args>(args)...); | ||||
| 
 | ||||
|  | @ -235,7 +234,7 @@ namespace kiwano | |||
| 	template <typename ..._Args> | ||||
| 	void Logger::Output(std::wostream& os, std::wostream& (*color)(std::wostream&), const wchar_t* prompt, _Args&& ... args) const | ||||
| 	{ | ||||
| 		if (enabled_ && has_console_) | ||||
| 		if (enabled_) | ||||
| 		{ | ||||
| 			std::wstring output = MakeOutputString(prompt, std::forward<_Args>(args)...); | ||||
| 
 | ||||
|  | @ -273,6 +272,12 @@ namespace kiwano | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // Display stack trace on exception
 | ||||
| //
 | ||||
| 
 | ||||
| #include "../third-party/StackWalker/StackWalker.h" | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 	inline void ThrowIfFailed(HRESULT hr) | ||||
|  | @ -281,6 +286,8 @@ namespace kiwano | |||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Fatal error with HRESULT of %08X", hr); | ||||
| 
 | ||||
| 			StackWalker{}.ShowCallstack(); | ||||
| 
 | ||||
| 			static char buffer[1024 + 1]; | ||||
| 			sprintf_s(buffer, "Fatal error with HRESULT of %08X", hr); | ||||
| 			throw std::runtime_error(buffer); | ||||
|  |  | |||
|  | @ -45,47 +45,36 @@ namespace kiwano | |||
| 	{ | ||||
| 		KGE_LOG(L"Creating device resources"); | ||||
| 
 | ||||
| 		HRESULT hr; | ||||
| 
 | ||||
| 		hwnd_ = app->GetWindow()->GetHandle(); | ||||
| 		hr = hwnd_ ? S_OK : E_FAIL; | ||||
| 
 | ||||
| 		if (SUCCEEDED(hr)) | ||||
| 		{ | ||||
| 		ThrowIfFailed(hwnd_ ? S_OK : E_FAIL); | ||||
| 		 | ||||
| 		device_resources_ = nullptr; | ||||
| 			hr = DeviceResources::Create( | ||||
| 		drawing_state_block_ = nullptr; | ||||
| 
 | ||||
| 		ThrowIfFailed( | ||||
| 			DeviceResources::Create( | ||||
| 				&device_resources_, | ||||
| 				hwnd_ | ||||
| 			) | ||||
| 		); | ||||
| 		} | ||||
| 
 | ||||
| 		if (SUCCEEDED(hr)) | ||||
| 		{ | ||||
| 		factory_ = device_resources_->GetD2DFactory(); | ||||
| 		device_context_ = device_resources_->GetD2DDeviceContext(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (SUCCEEDED(hr)) | ||||
| 		{ | ||||
| 			drawing_state_block_ = nullptr; | ||||
| 			hr = factory_->CreateDrawingStateBlock( | ||||
| 		ThrowIfFailed( | ||||
| 			factory_->CreateDrawingStateBlock( | ||||
| 				&drawing_state_block_ | ||||
| 			) | ||||
| 		); | ||||
| 		} | ||||
| 
 | ||||
| 		if (SUCCEEDED(hr)) | ||||
| 		{ | ||||
| 			hr = CreateDeviceResources(); | ||||
| 		} | ||||
| 		ThrowIfFailed( | ||||
| 			CreateDeviceResources() | ||||
| 		); | ||||
| 
 | ||||
| 		if (SUCCEEDED(hr)) | ||||
| 		{ | ||||
| 		output_size_ = app->GetWindow()->GetSize(); | ||||
| 	} | ||||
| 
 | ||||
| 		ThrowIfFailed(hr); | ||||
| 	} | ||||
| 
 | ||||
| 	void Renderer::DestroyComponent() | ||||
| 	{ | ||||
| 		KGE_LOG(L"Destroying device resources"); | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,189 @@ | |||
| /**********************************************************************
 | ||||
|  *  | ||||
|  * StackWalker.h | ||||
|  * | ||||
|  * | ||||
|  * History: | ||||
|  *  2005-07-27   v1    - First public release on http://www.codeproject.com/
 | ||||
|  *  (for additional changes see History in 'StackWalker.cpp'! | ||||
|  * | ||||
|  **********************************************************************/ | ||||
| // #pragma once is supported starting with _MCS_VER 1000, 
 | ||||
| // so we need not to check the version (because we only support _MSC_VER >= 1100)!
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <windows.h> | ||||
| 
 | ||||
| // special defines for VC5/6 (if no actual PSDK is installed):
 | ||||
| #if _MSC_VER < 1300 | ||||
| typedef unsigned __int64 DWORD64, *PDWORD64; | ||||
| #if defined(_WIN64) | ||||
| typedef unsigned __int64 SIZE_T, *PSIZE_T; | ||||
| #else | ||||
| typedef unsigned long SIZE_T, *PSIZE_T; | ||||
| #endif | ||||
| #endif  // _MSC_VER < 1300
 | ||||
| 
 | ||||
| class StackWalkerInternal;  // forward
 | ||||
| class StackWalker | ||||
| { | ||||
| public: | ||||
|   typedef enum StackWalkOptions | ||||
|   { | ||||
|     // No addition info will be retrived 
 | ||||
|     // (only the address is available)
 | ||||
|     RetrieveNone = 0, | ||||
|      | ||||
|     // Try to get the symbol-name
 | ||||
|     RetrieveSymbol = 1, | ||||
|      | ||||
|     // Try to get the line for this symbol
 | ||||
|     RetrieveLine = 2, | ||||
|      | ||||
|     // Try to retrieve the module-infos
 | ||||
|     RetrieveModuleInfo = 4, | ||||
|      | ||||
|     // Also retrieve the version for the DLL/EXE
 | ||||
|     RetrieveFileVersion = 8, | ||||
|      | ||||
|     // Contains all the abouve
 | ||||
|     RetrieveVerbose = 0xF, | ||||
|      | ||||
|     // Generate a "good" symbol-search-path
 | ||||
|     SymBuildPath = 0x10, | ||||
|      | ||||
|     // Also use the public Microsoft-Symbol-Server
 | ||||
|     SymUseSymSrv = 0x20, | ||||
|      | ||||
|     // Contains all the abouve "Sym"-options
 | ||||
|     SymAll = 0x30, | ||||
|      | ||||
|     // Contains all options (default)
 | ||||
|     OptionsAll = 0x3F | ||||
|   } StackWalkOptions; | ||||
| 
 | ||||
|   StackWalker( | ||||
|     int options = OptionsAll, // 'int' is by design, to combine the enum-flags
 | ||||
|     LPCSTR szSymPath = NULL,  | ||||
|     DWORD dwProcessId = GetCurrentProcessId(),  | ||||
|     HANDLE hProcess = GetCurrentProcess() | ||||
|     ); | ||||
|   StackWalker(DWORD dwProcessId, HANDLE hProcess); | ||||
|   virtual ~StackWalker(); | ||||
| 
 | ||||
|   typedef BOOL (__stdcall *PReadProcessMemoryRoutine)( | ||||
|     HANDLE      hProcess, | ||||
|     DWORD64     qwBaseAddress, | ||||
|     PVOID       lpBuffer, | ||||
|     DWORD       nSize, | ||||
|     LPDWORD     lpNumberOfBytesRead, | ||||
|     LPVOID      pUserData  // optional data, which was passed in "ShowCallstack"
 | ||||
|     ); | ||||
| 
 | ||||
|   BOOL LoadModules(); | ||||
| 
 | ||||
|   BOOL ShowCallstack( | ||||
|     HANDLE hThread = GetCurrentThread(),  | ||||
|     const CONTEXT *context = NULL,  | ||||
|     PReadProcessMemoryRoutine readMemoryFunction = NULL, | ||||
|     LPVOID pUserData = NULL  // optional to identify some data in the 'readMemoryFunction'-callback
 | ||||
|     ); | ||||
| 
 | ||||
| #if _MSC_VER >= 1300 | ||||
| // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" 
 | ||||
| // in older compilers in order to use it... starting with VC7 we can declare it as "protected"
 | ||||
| protected: | ||||
| #endif | ||||
| 	enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
 | ||||
| 
 | ||||
| protected: | ||||
|   // Entry for each Callstack-Entry
 | ||||
|   typedef struct CallstackEntry | ||||
|   { | ||||
|     DWORD64 offset;  // if 0, we have no valid entry
 | ||||
|     CHAR name[STACKWALK_MAX_NAMELEN]; | ||||
|     CHAR undName[STACKWALK_MAX_NAMELEN]; | ||||
|     CHAR undFullName[STACKWALK_MAX_NAMELEN]; | ||||
|     DWORD64 offsetFromSmybol; | ||||
|     DWORD offsetFromLine; | ||||
|     DWORD lineNumber; | ||||
|     CHAR lineFileName[STACKWALK_MAX_NAMELEN]; | ||||
|     DWORD symType; | ||||
|     LPCSTR symTypeString; | ||||
|     CHAR moduleName[STACKWALK_MAX_NAMELEN]; | ||||
|     DWORD64 baseOfImage; | ||||
|     CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; | ||||
|   } CallstackEntry; | ||||
| 
 | ||||
|   enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; | ||||
| 
 | ||||
|   virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); | ||||
|   virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion); | ||||
|   virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry); | ||||
|   virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); | ||||
|   virtual void OnOutput(LPCSTR szText); | ||||
| 
 | ||||
|   StackWalkerInternal *m_sw; | ||||
|   HANDLE m_hProcess; | ||||
|   DWORD m_dwProcessId; | ||||
|   BOOL m_modulesLoaded; | ||||
|   LPSTR m_szSymPath; | ||||
| 
 | ||||
|   int m_options; | ||||
| 
 | ||||
|   static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead); | ||||
| 
 | ||||
|   friend StackWalkerInternal; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // The "ugly" assembler-implementation is needed for systems before XP
 | ||||
| // If you have a new PSDK and you only compile for XP and later, then you can use 
 | ||||
| // the "RtlCaptureContext"
 | ||||
| // Currently there is no define which determines the PSDK-Version... 
 | ||||
| // So we just use the compiler-version (and assumes that the PSDK is 
 | ||||
| // the one which was installed by the VS-IDE)
 | ||||
| 
 | ||||
| // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
 | ||||
| //       But I currently use it in x64/IA64 environments...
 | ||||
| //#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
 | ||||
| 
 | ||||
| #if defined(_M_IX86) | ||||
| #ifdef CURRENT_THREAD_VIA_EXCEPTION | ||||
| // TODO: The following is not a "good" implementation, 
 | ||||
| // because the callstack is only valid in the "__except" block...
 | ||||
| #define GET_CURRENT_CONTEXT(c, contextFlags) \ | ||||
|   do { \ | ||||
|     memset(&c, 0, sizeof(CONTEXT)); \ | ||||
|     EXCEPTION_POINTERS *pExp = NULL; \ | ||||
|     __try { \ | ||||
|       throw 0; \ | ||||
|     } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ | ||||
|     if (pExp != NULL) \ | ||||
|       memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ | ||||
|       c.ContextFlags = contextFlags; \ | ||||
|   } while(0); | ||||
| #else | ||||
| // The following should be enough for walking the callstack...
 | ||||
| #define GET_CURRENT_CONTEXT(c, contextFlags) \ | ||||
|   do { \ | ||||
|     memset(&c, 0, sizeof(CONTEXT)); \ | ||||
|     c.ContextFlags = contextFlags; \ | ||||
|     __asm    call x \ | ||||
|     __asm x: pop eax \ | ||||
|     __asm    mov c.Eip, eax \ | ||||
|     __asm    mov c.Ebp, ebp \ | ||||
|     __asm    mov c.Esp, esp \ | ||||
|   } while(0); | ||||
| #endif | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| // The following is defined for x86 (XP and higher), x64 and IA64:
 | ||||
| #define GET_CURRENT_CONTEXT(c, contextFlags) \ | ||||
|   do { \ | ||||
|     memset(&c, 0, sizeof(CONTEXT)); \ | ||||
|     c.ContextFlags = contextFlags; \ | ||||
|     RtlCaptureContext(&c); \ | ||||
| } while(0); | ||||
| #endif | ||||
		Loading…
	
		Reference in New Issue