From 752594c2b9208132a1a57bd8771d0bef0493071f Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Nov 2020 08:57:57 +0300 Subject: [PATCH 1/7] Fix UNICODE config for VC2015 and VC2017 --- Main/StackWalker/StackWalker_VC2015.sln | 24 ++++++++++++------------ Main/StackWalker/StackWalker_VC2017.sln | 19 ++++++++----------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/Main/StackWalker/StackWalker_VC2015.sln b/Main/StackWalker/StackWalker_VC2015.sln index 60c2806..b40a199 100644 --- a/Main/StackWalker/StackWalker_VC2015.sln +++ b/Main/StackWalker/StackWalker_VC2015.sln @@ -20,24 +20,24 @@ Global Release_VC2015-UNICODE|x64 = Release_VC2015-UNICODE|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.ActiveCfg = Debug_VC2015-UNICODE|Itanium - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.Build.0 = Debug_VC2015-UNICODE|Itanium - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.ActiveCfg = Debug_VC2015-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.Build.0 = Debug_VC2015-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.ActiveCfg = Debug_VC2015-UNICODE|x64 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.Build.0 = Debug_VC2015-UNICODE|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.ActiveCfg = Debug_VC2015|Itanium + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.Build.0 = Debug_VC2015|Itanium + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.ActiveCfg = Debug_VC2015|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.Build.0 = Debug_VC2015|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.ActiveCfg = Debug_VC2015|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.Build.0 = Debug_VC2015|x64 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Itanium.ActiveCfg = Debug_VC2015-UNICODE|Itanium {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Itanium.Build.0 = Debug_VC2015-UNICODE|Itanium {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Win32.ActiveCfg = Debug_VC2015-UNICODE|Win32 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Win32.Build.0 = Debug_VC2015-UNICODE|Win32 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|x64.ActiveCfg = Debug_VC2015-UNICODE|x64 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|x64.Build.0 = Debug_VC2015-UNICODE|x64 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.ActiveCfg = Release_VC2015-UNICODE|Itanium - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.Build.0 = Release_VC2015-UNICODE|Itanium - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.ActiveCfg = Release_VC2015-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.Build.0 = Release_VC2015-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.ActiveCfg = Release_VC2015-UNICODE|x64 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.Build.0 = Release_VC2015-UNICODE|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.ActiveCfg = Release_VC2015|Itanium + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.Build.0 = Release_VC2015|Itanium + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.ActiveCfg = Release_VC2015|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.Build.0 = Release_VC2015|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.ActiveCfg = Release_VC2015|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.Build.0 = Release_VC2015|x64 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015-UNICODE|Itanium.ActiveCfg = Release_VC2015-UNICODE|Itanium {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015-UNICODE|Itanium.Build.0 = Release_VC2015-UNICODE|Itanium {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015-UNICODE|Win32.ActiveCfg = Release_VC2015-UNICODE|Win32 diff --git a/Main/StackWalker/StackWalker_VC2017.sln b/Main/StackWalker/StackWalker_VC2017.sln index 790d550..d359f58 100644 --- a/Main/StackWalker/StackWalker_VC2017.sln +++ b/Main/StackWalker/StackWalker_VC2017.sln @@ -16,18 +16,18 @@ Global Release_VC2017-UNICODE|x64 = Release_VC2017-UNICODE|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.ActiveCfg = Debug_VC2017-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.Build.0 = Debug_VC2017-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.ActiveCfg = Debug_VC2017-UNICODE|x64 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.Build.0 = Debug_VC2017-UNICODE|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.ActiveCfg = Debug_VC2017|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.Build.0 = Debug_VC2017|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.ActiveCfg = Debug_VC2017|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.Build.0 = Debug_VC2017|x64 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|Win32.ActiveCfg = Debug_VC2017-UNICODE|Win32 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|Win32.Build.0 = Debug_VC2017-UNICODE|Win32 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|x64.ActiveCfg = Debug_VC2017-UNICODE|x64 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|x64.Build.0 = Debug_VC2017-UNICODE|x64 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.ActiveCfg = Release_VC2017-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.Build.0 = Release_VC2017-UNICODE|Win32 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.ActiveCfg = Release_VC2017-UNICODE|x64 - {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.Build.0 = Release_VC2017-UNICODE|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.ActiveCfg = Release_VC2017|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.Build.0 = Release_VC2017|Win32 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.ActiveCfg = Release_VC2017|x64 + {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.Build.0 = Release_VC2017|x64 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017-UNICODE|Win32.ActiveCfg = Release_VC2017-UNICODE|Win32 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017-UNICODE|Win32.Build.0 = Release_VC2017-UNICODE|Win32 {89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017-UNICODE|x64.ActiveCfg = Release_VC2017-UNICODE|x64 @@ -36,7 +36,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {66CC86C2-413E-467D-AC75-7B4BD9AE3ECD} - EndGlobalSection EndGlobal From d698822e10d42ef4c44898a2672b9ebc4e0988c2 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Nov 2020 09:31:58 +0300 Subject: [PATCH 2/7] Removed disabling warning 4091 from header file --- Main/StackWalker/StackWalker.cpp | 11 +++++++---- Main/StackWalker/StackWalker.h | 4 ---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 41bd2bf..8490322 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -90,6 +90,9 @@ #include #pragma comment(lib, "version.lib") // for "VerQueryValue" #pragma warning(disable : 4826) +#if _MSC_VER >= 1900 +#pragma warning(disable : 4091) // For fix unnamed enums from DbgHelp.h +#endif // If VC7 and later, then use the shipped 'dbghelp.h'-file @@ -414,7 +417,7 @@ class StackWalkerInternal LPSTR m_szSymPath; #pragma pack(push, 8) - typedef struct IMAGEHLP_MODULE64_V3 + typedef struct _IMAGEHLP_MODULE64_V3 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) DWORD64 BaseOfImage; // base load address of module @@ -441,9 +444,9 @@ class StackWalkerInternal // new elements: 17-Dec-2003 BOOL SourceIndexed; // pdb supports source server BOOL Publics; // contains public symbols - }; + } IMAGEHLP_MODULE64_V3, *PIMAGEHLP_MODULE64_V3; - typedef struct IMAGEHLP_MODULE64_V2 + typedef struct _IMAGEHLP_MODULE64_V2 { DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) DWORD64 BaseOfImage; // base load address of module @@ -455,7 +458,7 @@ class StackWalkerInternal CHAR ModuleName[32]; // module name CHAR ImageName[256]; // image name CHAR LoadedImageName[256]; // symbol file name - }; + } IMAGEHLP_MODULE64_V2, *PIMAGEHLP_MODULE64_V2; #pragma pack(pop) // SymCleanup() diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index 66c8260..c9032eb 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -43,10 +43,6 @@ #include -#if _MSC_VER >= 1900 -#pragma warning(disable : 4091) -#endif - // special defines for VC5/6 (if no actual PSDK is installed): #if _MSC_VER < 1300 typedef unsigned __int64 DWORD64, *PDWORD64; From 81b1424cf5d28d5a2ccd9a4f1df12e74ce4d3fc0 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Nov 2020 12:45:51 +0300 Subject: [PATCH 3/7] Added new methods Init, SetSymPath, SetTargetProcess --- Main/StackWalker/StackWalker.cpp | 77 ++++++++++++++++++-------------- Main/StackWalker/StackWalker.h | 10 +++++ 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 8490322..40fb6d9 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -258,7 +258,6 @@ class StackWalkerInternal m_hDbhHelp = NULL; pSC = NULL; m_hProcess = hProcess; - m_szSymPath = NULL; pSFTA = NULL; pSGLFA = NULL; pSGMB = NULL; @@ -272,6 +271,7 @@ class StackWalkerInternal pUDSN = NULL; pSGSP = NULL; } + ~StackWalkerInternal() { if (pSC != NULL) @@ -280,10 +280,8 @@ class StackWalkerInternal FreeLibrary(m_hDbhHelp); m_hDbhHelp = NULL; m_parent = NULL; - if (m_szSymPath != NULL) - free(m_szSymPath); - m_szSymPath = NULL; } + BOOL Init(LPCSTR szSymPath) { if (m_parent == NULL) @@ -384,9 +382,7 @@ class StackWalkerInternal } // SymInitialize - if (szSymPath != NULL) - m_szSymPath = _strdup(szSymPath); - if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) + if (this->pSI(m_hProcess, szSymPath, FALSE) == FALSE) this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); DWORD symOptions = this->pSGO(); // SymGetOptions @@ -414,7 +410,6 @@ class StackWalkerInternal HMODULE m_hDbhHelp; HANDLE m_hProcess; - LPSTR m_szSymPath; #pragma pack(push, 8) typedef struct _IMAGEHLP_MODULE64_V3 @@ -498,14 +493,14 @@ class StackWalkerInternal tSGSFA pSGSFA; // SymInitialize() - typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess); + typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN LPCSTR UserSearchPath, IN BOOL fInvadeProcess); tSI pSI; // SymLoadModule64() typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess, IN HANDLE hFile, - IN PSTR ImageName, - IN PSTR ModuleName, + IN LPCSTR ImageName, + IN LPCSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll); tSLM pSLM; @@ -873,41 +868,57 @@ class StackWalkerInternal }; // ############################################################# -StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) +bool StackWalker::Init(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) { - this->m_options = OptionsAll; + this->m_options = options; this->m_modulesLoaded = FALSE; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; this->m_szSymPath = NULL; this->m_MaxRecursionCount = 1000; + this->m_sw = NULL; + SetTargetProcess(dwProcessId, hProcess); + SetSymPath(szSymPath); + this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + return true; } + +StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) +{ + Init(OptionsAll, NULL, dwProcessId, hProcess); +} + StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) { - this->m_options = options; - this->m_modulesLoaded = FALSE; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; - if (szSymPath != NULL) - { - this->m_szSymPath = _strdup(szSymPath); - this->m_options |= SymBuildPath; - } - else - this->m_szSymPath = NULL; - this->m_MaxRecursionCount = 1000; + Init(options, szSymPath, dwProcessId, hProcess); } StackWalker::~StackWalker() { - if (m_szSymPath != NULL) + SetSymPath(NULL); + if (m_sw != NULL) + delete m_sw; + m_sw = NULL; +} + +bool StackWalker::SetSymPath(LPCSTR szSymPath) +{ + if (m_szSymPath) free(m_szSymPath); m_szSymPath = NULL; - if (this->m_sw != NULL) - delete this->m_sw; - this->m_sw = NULL; + if (szSymPath == NULL) + return true; + m_szSymPath = _strdup(szSymPath); + if (m_szSymPath) + m_options |= SymBuildPath; + return true; +} + +bool StackWalker::SetTargetProcess(DWORD dwProcessId, HANDLE hProcess) +{ + m_dwProcessId = dwProcessId; + m_hProcess = hProcess; + if (m_sw) + m_sw->m_hProcess = hProcess; + return true; } BOOL StackWalker::LoadModules() diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index c9032eb..3805d2e 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -95,9 +95,19 @@ class StackWalker LPCSTR szSymPath = NULL, DWORD dwProcessId = GetCurrentProcessId(), HANDLE hProcess = GetCurrentProcess()); + StackWalker(DWORD dwProcessId, HANDLE hProcess); + virtual ~StackWalker(); + bool SetSymPath(LPCSTR szSymPath); + + bool SetTargetProcess(DWORD dwProcessId, HANDLE hProcess); + +private: + bool Init(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess); + +public: typedef BOOL(__stdcall* PReadProcessMemoryRoutine)( HANDLE hProcess, DWORD64 qwBaseAddress, From acaf65826b8a58002ede323b86676ca8bb5d8118 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Nov 2020 13:06:49 +0300 Subject: [PATCH 4/7] Replace "new" to "malloc + placement new" Reason: A regular call "new" can throw an std::bad_alloc exception. Using new(std::nothrow) on MSVC is ignored. --- Main/StackWalker/StackWalker.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 40fb6d9..81c6b49 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -88,7 +88,10 @@ #include #include #include +#include + #pragma comment(lib, "version.lib") // for "VerQueryValue" + #pragma warning(disable : 4826) #if _MSC_VER >= 1900 #pragma warning(disable : 4091) // For fix unnamed enums from DbgHelp.h @@ -877,7 +880,12 @@ bool StackWalker::Init(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE this->m_sw = NULL; SetTargetProcess(dwProcessId, hProcess); SetSymPath(szSymPath); - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); + /* MSVC ignore std::nothrow specifier for `new` operator */ + LPVOID buf = malloc(sizeof(StackWalkerInternal)); + if (!buf) + return false; + memset(buf, 0, sizeof(StackWalkerInternal)); + this->m_sw = new(buf) StackWalkerInternal(this, this->m_hProcess); // placement new return true; } @@ -894,8 +902,10 @@ StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDL StackWalker::~StackWalker() { SetSymPath(NULL); - if (m_sw != NULL) - delete m_sw; + if (m_sw != NULL) { + m_sw->~StackWalkerInternal(); // call the object's destructor + free(m_sw); + } m_sw = NULL; } From bf32dbc89230fbce443bb42728238d9af9c0e870 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Nov 2020 15:19:00 +0300 Subject: [PATCH 5/7] Added type of exception handling and use of PTD to get the current exception context Recommended MSVC2005 or newer. --- Main/StackWalker/StackWalker.cpp | 52 ++++++++++++++++++++++++++++---- Main/StackWalker/StackWalker.h | 12 +++++++- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 81c6b49..a14ce0b 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -255,7 +255,7 @@ static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) class StackWalkerInternal { public: - StackWalkerInternal(StackWalker* parent, HANDLE hProcess) + StackWalkerInternal(StackWalker* parent, HANDLE hProcess, PCONTEXT ctx) { m_parent = parent; m_hDbhHelp = NULL; @@ -273,6 +273,9 @@ class StackWalkerInternal pSW = NULL; pUDSN = NULL; pSGSP = NULL; + m_ctx.ContextFlags = 0; + if (ctx != NULL) + m_ctx = *ctx; } ~StackWalkerInternal() @@ -411,6 +414,7 @@ class StackWalkerInternal StackWalker* m_parent; + CONTEXT m_ctx; HMODULE m_hDbhHelp; HANDLE m_hProcess; @@ -871,8 +875,36 @@ class StackWalkerInternal }; // ############################################################# -bool StackWalker::Init(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) + +#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900 +extern "C" void* __cdecl _getptd(); +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1900 +extern "C" void** __cdecl __current_exception_context(); +#endif + +static PCONTEXT get_current_exception_context() { + PCONTEXT * pctx = NULL; +#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900 + LPSTR ptd = (LPSTR)_getptd(); + if (ptd) + pctx = (PCONTEXT *)(ptd + (sizeof(void*) == 4 ? 0x8C : 0xF8)); +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1900 + pctx = (PCONTEXT *)__current_exception_context(); +#endif + return pctx ? *pctx : NULL; +} + +bool StackWalker::Init(ExceptType extype, int options, LPCSTR szSymPath, DWORD dwProcessId, + HANDLE hProcess, PEXCEPTION_POINTERS exp) +{ + PCONTEXT ctx = NULL; + if (extype == AfterCatch) + ctx = get_current_exception_context(); + if (extype == AfterExcept && exp) + ctx = exp->ContextRecord; this->m_options = options; this->m_modulesLoaded = FALSE; this->m_szSymPath = NULL; @@ -885,18 +917,23 @@ bool StackWalker::Init(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE if (!buf) return false; memset(buf, 0, sizeof(StackWalkerInternal)); - this->m_sw = new(buf) StackWalkerInternal(this, this->m_hProcess); // placement new + this->m_sw = new(buf) StackWalkerInternal(this, this->m_hProcess, ctx); // placement new return true; } StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) { - Init(OptionsAll, NULL, dwProcessId, hProcess); + Init(NonExcept, OptionsAll, NULL, dwProcessId, hProcess); } StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) { - Init(options, szSymPath, dwProcessId, hProcess); + Init(NonExcept, options, szSymPath, dwProcessId, hProcess); +} + +StackWalker::StackWalker(ExceptType extype, int options, PEXCEPTION_POINTERS exp) +{ + Init(extype, options, NULL, GetCurrentProcessId(), GetCurrentProcess(), exp); } StackWalker::~StackWalker() @@ -1092,7 +1129,10 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, if (GetThreadId(hThread) == GetCurrentThreadId()) #endif { - GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS); + if (m_sw->m_ctx.ContextFlags != 0) + c = m_sw->m_ctx; // context taken at Init + else + GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS); } else { diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index 3805d2e..5570b5d 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -57,6 +57,13 @@ class StackWalkerInternal; // forward class StackWalker { public: + typedef enum ExceptType + { + NonExcept = 0, // RtlCaptureContext + AfterExcept = 1, + AfterCatch = 2, // get_current_exception_context + } ExceptType; + typedef enum StackWalkOptions { // No addition info will be retrieved @@ -91,6 +98,8 @@ class StackWalker OptionsAll = 0x3F } StackWalkOptions; + StackWalker(ExceptType extype, int options, PEXCEPTION_POINTERS exp = NULL); + StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags LPCSTR szSymPath = NULL, DWORD dwProcessId = GetCurrentProcessId(), @@ -105,7 +114,8 @@ class StackWalker bool SetTargetProcess(DWORD dwProcessId, HANDLE hProcess); private: - bool Init(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess); + bool Init(ExceptType extype, int options, LPCSTR szSymPath, DWORD dwProcessId, + HANDLE hProcess, PEXCEPTION_POINTERS exp = NULL); public: typedef BOOL(__stdcall* PReadProcessMemoryRoutine)( From 68e9994cfdd4239dc273c672e84beb6cce17d3f5 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Nov 2020 15:57:26 +0300 Subject: [PATCH 6/7] Added new method GetCurrentExceptionContext --- Main/StackWalker/StackWalker.cpp | 5 +++++ Main/StackWalker/StackWalker.h | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index a14ce0b..fe12547 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -968,6 +968,11 @@ bool StackWalker::SetTargetProcess(DWORD dwProcessId, HANDLE hProcess) return true; } +PCONTEXT StackWalker::GetCurrentExceptionContext() +{ + return get_current_exception_context(); +} + BOOL StackWalker::LoadModules() { if (this->m_sw == NULL) diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index 5570b5d..1fba754 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -98,7 +98,7 @@ class StackWalker OptionsAll = 0x3F } StackWalkOptions; - StackWalker(ExceptType extype, int options, PEXCEPTION_POINTERS exp = NULL); + StackWalker(ExceptType extype, int options = OptionsAll, PEXCEPTION_POINTERS exp = NULL); StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags LPCSTR szSymPath = NULL, @@ -113,6 +113,8 @@ class StackWalker bool SetTargetProcess(DWORD dwProcessId, HANDLE hProcess); + PCONTEXT GetCurrentExceptionContext(); + private: bool Init(ExceptType extype, int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess, PEXCEPTION_POINTERS exp = NULL); From f10743f85a3bfa3f06b1b786927bcf6a5ac178e9 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Nov 2020 17:37:32 +0300 Subject: [PATCH 7/7] Added info about C++ exception handler to README.md --- README.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a9052ee..46a9096 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,8 @@ class StackWalker protected: 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); + DWORD result, LPCSTR symType, LPCSTR pdbName, + ULONGLONG fileVersion); virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry); virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); }; @@ -140,9 +141,12 @@ public: LPCSTR szSymPath = NULL, DWORD dwProcessId = GetCurrentProcessId(), HANDLE hProcess = GetCurrentProcess()); - // Just for other processes with - // default-values for options and symPath + + // Just for other processes with default-values for options and symPath StackWalker(DWORD dwProcessId, HANDLE hProcess); + + // For showing stack trace after __except or catch + StackWalker(ExceptType extype, int options = OptionsAll, PEXCEPTION_POINTERS exp = NULL); }; ``` @@ -159,7 +163,7 @@ public: ### Displaying the callstack of an exception -With this `StackWalker` you can also display the callstack inside an exception handler. You only need to write a filter-function which does the stack-walking: +With this `StackWalker` you can also display the callstack inside an structured exception handler. You only need to write a filter-function which does the stack-walking: ```c++ // The exception filter function: @@ -180,6 +184,25 @@ __except (ExpFilter(GetExceptionInformation(), GetExceptionCode())) } ``` +Display the callstack inside an C++ exception handler (two ways): +```c++ +// This is how to catch an exception: +try +{ + // do some ugly stuff... +} +catch (std::exception & ex) +{ + StackWalker sw; + sw.ShowCallstack(GetCurrentThread(), sw.GetCurrentExceptionContext()); +} +catch (...) +{ + StackWalker sw(StackWalker::AfterCatch); + sw.ShowCallstack(); +} +``` + ## Points of Interest ### Context and callstack