Skip to content

Commit 5332051

Browse files
Merge pull request #42 from remittor-pr/fix_cpp_exp
Fix stack trace info for C++ exceptions
2 parents 4161d09 + f10743f commit 5332051

5 files changed

Lines changed: 177 additions & 70 deletions

File tree

Main/StackWalker/StackWalker.cpp

Lines changed: 108 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,14 @@
8888
#include <stdlib.h>
8989
#include <tchar.h>
9090
#include <windows.h>
91+
#include <new>
92+
9193
#pragma comment(lib, "version.lib") // for "VerQueryValue"
94+
9295
#pragma warning(disable : 4826)
96+
#if _MSC_VER >= 1900
97+
#pragma warning(disable : 4091) // For fix unnamed enums from DbgHelp.h
98+
#endif
9399

94100

95101
// If VC7 and later, then use the shipped 'dbghelp.h'-file
@@ -249,13 +255,12 @@ static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
249255
class StackWalkerInternal
250256
{
251257
public:
252-
StackWalkerInternal(StackWalker* parent, HANDLE hProcess)
258+
StackWalkerInternal(StackWalker* parent, HANDLE hProcess, PCONTEXT ctx)
253259
{
254260
m_parent = parent;
255261
m_hDbhHelp = NULL;
256262
pSC = NULL;
257263
m_hProcess = hProcess;
258-
m_szSymPath = NULL;
259264
pSFTA = NULL;
260265
pSGLFA = NULL;
261266
pSGMB = NULL;
@@ -268,7 +273,11 @@ class StackWalkerInternal
268273
pSW = NULL;
269274
pUDSN = NULL;
270275
pSGSP = NULL;
276+
m_ctx.ContextFlags = 0;
277+
if (ctx != NULL)
278+
m_ctx = *ctx;
271279
}
280+
272281
~StackWalkerInternal()
273282
{
274283
if (pSC != NULL)
@@ -277,10 +286,8 @@ class StackWalkerInternal
277286
FreeLibrary(m_hDbhHelp);
278287
m_hDbhHelp = NULL;
279288
m_parent = NULL;
280-
if (m_szSymPath != NULL)
281-
free(m_szSymPath);
282-
m_szSymPath = NULL;
283289
}
290+
284291
BOOL Init(LPCSTR szSymPath)
285292
{
286293
if (m_parent == NULL)
@@ -381,9 +388,7 @@ class StackWalkerInternal
381388
}
382389

383390
// SymInitialize
384-
if (szSymPath != NULL)
385-
m_szSymPath = _strdup(szSymPath);
386-
if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
391+
if (this->pSI(m_hProcess, szSymPath, FALSE) == FALSE)
387392
this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
388393

389394
DWORD symOptions = this->pSGO(); // SymGetOptions
@@ -409,12 +414,12 @@ class StackWalkerInternal
409414

410415
StackWalker* m_parent;
411416

417+
CONTEXT m_ctx;
412418
HMODULE m_hDbhHelp;
413419
HANDLE m_hProcess;
414-
LPSTR m_szSymPath;
415420

416421
#pragma pack(push, 8)
417-
typedef struct IMAGEHLP_MODULE64_V3
422+
typedef struct _IMAGEHLP_MODULE64_V3
418423
{
419424
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
420425
DWORD64 BaseOfImage; // base load address of module
@@ -441,9 +446,9 @@ class StackWalkerInternal
441446
// new elements: 17-Dec-2003
442447
BOOL SourceIndexed; // pdb supports source server
443448
BOOL Publics; // contains public symbols
444-
};
449+
} IMAGEHLP_MODULE64_V3, *PIMAGEHLP_MODULE64_V3;
445450

446-
typedef struct IMAGEHLP_MODULE64_V2
451+
typedef struct _IMAGEHLP_MODULE64_V2
447452
{
448453
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
449454
DWORD64 BaseOfImage; // base load address of module
@@ -455,7 +460,7 @@ class StackWalkerInternal
455460
CHAR ModuleName[32]; // module name
456461
CHAR ImageName[256]; // image name
457462
CHAR LoadedImageName[256]; // symbol file name
458-
};
463+
} IMAGEHLP_MODULE64_V2, *PIMAGEHLP_MODULE64_V2;
459464
#pragma pack(pop)
460465

461466
// SymCleanup()
@@ -495,14 +500,14 @@ class StackWalkerInternal
495500
tSGSFA pSGSFA;
496501

497502
// SymInitialize()
498-
typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);
503+
typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN LPCSTR UserSearchPath, IN BOOL fInvadeProcess);
499504
tSI pSI;
500505

501506
// SymLoadModule64()
502507
typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess,
503508
IN HANDLE hFile,
504-
IN PSTR ImageName,
505-
IN PSTR ModuleName,
509+
IN LPCSTR ImageName,
510+
IN LPCSTR ModuleName,
506511
IN DWORD64 BaseOfDll,
507512
IN DWORD SizeOfDll);
508513
tSLM pSLM;
@@ -870,41 +875,102 @@ class StackWalkerInternal
870875
};
871876

872877
// #############################################################
873-
StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
878+
879+
#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
880+
extern "C" void* __cdecl _getptd();
881+
#endif
882+
#if defined(_MSC_VER) && _MSC_VER >= 1900
883+
extern "C" void** __cdecl __current_exception_context();
884+
#endif
885+
886+
static PCONTEXT get_current_exception_context()
874887
{
875-
this->m_options = OptionsAll;
888+
PCONTEXT * pctx = NULL;
889+
#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
890+
LPSTR ptd = (LPSTR)_getptd();
891+
if (ptd)
892+
pctx = (PCONTEXT *)(ptd + (sizeof(void*) == 4 ? 0x8C : 0xF8));
893+
#endif
894+
#if defined(_MSC_VER) && _MSC_VER >= 1900
895+
pctx = (PCONTEXT *)__current_exception_context();
896+
#endif
897+
return pctx ? *pctx : NULL;
898+
}
899+
900+
bool StackWalker::Init(ExceptType extype, int options, LPCSTR szSymPath, DWORD dwProcessId,
901+
HANDLE hProcess, PEXCEPTION_POINTERS exp)
902+
{
903+
PCONTEXT ctx = NULL;
904+
if (extype == AfterCatch)
905+
ctx = get_current_exception_context();
906+
if (extype == AfterExcept && exp)
907+
ctx = exp->ContextRecord;
908+
this->m_options = options;
876909
this->m_modulesLoaded = FALSE;
877-
this->m_hProcess = hProcess;
878-
this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
879-
this->m_dwProcessId = dwProcessId;
880910
this->m_szSymPath = NULL;
881911
this->m_MaxRecursionCount = 1000;
912+
this->m_sw = NULL;
913+
SetTargetProcess(dwProcessId, hProcess);
914+
SetSymPath(szSymPath);
915+
/* MSVC ignore std::nothrow specifier for `new` operator */
916+
LPVOID buf = malloc(sizeof(StackWalkerInternal));
917+
if (!buf)
918+
return false;
919+
memset(buf, 0, sizeof(StackWalkerInternal));
920+
this->m_sw = new(buf) StackWalkerInternal(this, this->m_hProcess, ctx); // placement new
921+
return true;
882922
}
923+
924+
StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
925+
{
926+
Init(NonExcept, OptionsAll, NULL, dwProcessId, hProcess);
927+
}
928+
883929
StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
884930
{
885-
this->m_options = options;
886-
this->m_modulesLoaded = FALSE;
887-
this->m_hProcess = hProcess;
888-
this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
889-
this->m_dwProcessId = dwProcessId;
890-
if (szSymPath != NULL)
891-
{
892-
this->m_szSymPath = _strdup(szSymPath);
893-
this->m_options |= SymBuildPath;
894-
}
895-
else
896-
this->m_szSymPath = NULL;
897-
this->m_MaxRecursionCount = 1000;
931+
Init(NonExcept, options, szSymPath, dwProcessId, hProcess);
932+
}
933+
934+
StackWalker::StackWalker(ExceptType extype, int options, PEXCEPTION_POINTERS exp)
935+
{
936+
Init(extype, options, NULL, GetCurrentProcessId(), GetCurrentProcess(), exp);
898937
}
899938

900939
StackWalker::~StackWalker()
901940
{
902-
if (m_szSymPath != NULL)
941+
SetSymPath(NULL);
942+
if (m_sw != NULL) {
943+
m_sw->~StackWalkerInternal(); // call the object's destructor
944+
free(m_sw);
945+
}
946+
m_sw = NULL;
947+
}
948+
949+
bool StackWalker::SetSymPath(LPCSTR szSymPath)
950+
{
951+
if (m_szSymPath)
903952
free(m_szSymPath);
904953
m_szSymPath = NULL;
905-
if (this->m_sw != NULL)
906-
delete this->m_sw;
907-
this->m_sw = NULL;
954+
if (szSymPath == NULL)
955+
return true;
956+
m_szSymPath = _strdup(szSymPath);
957+
if (m_szSymPath)
958+
m_options |= SymBuildPath;
959+
return true;
960+
}
961+
962+
bool StackWalker::SetTargetProcess(DWORD dwProcessId, HANDLE hProcess)
963+
{
964+
m_dwProcessId = dwProcessId;
965+
m_hProcess = hProcess;
966+
if (m_sw)
967+
m_sw->m_hProcess = hProcess;
968+
return true;
969+
}
970+
971+
PCONTEXT StackWalker::GetCurrentExceptionContext()
972+
{
973+
return get_current_exception_context();
908974
}
909975

910976
BOOL StackWalker::LoadModules()
@@ -1068,7 +1134,10 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread,
10681134
if (GetThreadId(hThread) == GetCurrentThreadId())
10691135
#endif
10701136
{
1071-
GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
1137+
if (m_sw->m_ctx.ContextFlags != 0)
1138+
c = m_sw->m_ctx; // context taken at Init
1139+
else
1140+
GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
10721141
}
10731142
else
10741143
{

Main/StackWalker/StackWalker.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@
4343

4444
#include <windows.h>
4545

46-
#if _MSC_VER >= 1900
47-
#pragma warning(disable : 4091)
48-
#endif
49-
5046
// special defines for VC5/6 (if no actual PSDK is installed):
5147
#if _MSC_VER < 1300
5248
typedef unsigned __int64 DWORD64, *PDWORD64;
@@ -61,6 +57,13 @@ class StackWalkerInternal; // forward
6157
class StackWalker
6258
{
6359
public:
60+
typedef enum ExceptType
61+
{
62+
NonExcept = 0, // RtlCaptureContext
63+
AfterExcept = 1,
64+
AfterCatch = 2, // get_current_exception_context
65+
} ExceptType;
66+
6467
typedef enum StackWalkOptions
6568
{
6669
// No addition info will be retrieved
@@ -95,13 +98,28 @@ class StackWalker
9598
OptionsAll = 0x3F
9699
} StackWalkOptions;
97100

101+
StackWalker(ExceptType extype, int options = OptionsAll, PEXCEPTION_POINTERS exp = NULL);
102+
98103
StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags
99104
LPCSTR szSymPath = NULL,
100105
DWORD dwProcessId = GetCurrentProcessId(),
101106
HANDLE hProcess = GetCurrentProcess());
107+
102108
StackWalker(DWORD dwProcessId, HANDLE hProcess);
109+
103110
virtual ~StackWalker();
104111

112+
bool SetSymPath(LPCSTR szSymPath);
113+
114+
bool SetTargetProcess(DWORD dwProcessId, HANDLE hProcess);
115+
116+
PCONTEXT GetCurrentExceptionContext();
117+
118+
private:
119+
bool Init(ExceptType extype, int options, LPCSTR szSymPath, DWORD dwProcessId,
120+
HANDLE hProcess, PEXCEPTION_POINTERS exp = NULL);
121+
122+
public:
105123
typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
106124
HANDLE hProcess,
107125
DWORD64 qwBaseAddress,

Main/StackWalker/StackWalker_VC2015.sln

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,24 @@ Global
2020
Release_VC2015-UNICODE|x64 = Release_VC2015-UNICODE|x64
2121
EndGlobalSection
2222
GlobalSection(ProjectConfigurationPlatforms) = postSolution
23-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.ActiveCfg = Debug_VC2015-UNICODE|Itanium
24-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.Build.0 = Debug_VC2015-UNICODE|Itanium
25-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.ActiveCfg = Debug_VC2015-UNICODE|Win32
26-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.Build.0 = Debug_VC2015-UNICODE|Win32
27-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.ActiveCfg = Debug_VC2015-UNICODE|x64
28-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.Build.0 = Debug_VC2015-UNICODE|x64
23+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.ActiveCfg = Debug_VC2015|Itanium
24+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Itanium.Build.0 = Debug_VC2015|Itanium
25+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.ActiveCfg = Debug_VC2015|Win32
26+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|Win32.Build.0 = Debug_VC2015|Win32
27+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.ActiveCfg = Debug_VC2015|x64
28+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015|x64.Build.0 = Debug_VC2015|x64
2929
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Itanium.ActiveCfg = Debug_VC2015-UNICODE|Itanium
3030
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Itanium.Build.0 = Debug_VC2015-UNICODE|Itanium
3131
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Win32.ActiveCfg = Debug_VC2015-UNICODE|Win32
3232
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|Win32.Build.0 = Debug_VC2015-UNICODE|Win32
3333
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|x64.ActiveCfg = Debug_VC2015-UNICODE|x64
3434
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2015-UNICODE|x64.Build.0 = Debug_VC2015-UNICODE|x64
35-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.ActiveCfg = Release_VC2015-UNICODE|Itanium
36-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.Build.0 = Release_VC2015-UNICODE|Itanium
37-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.ActiveCfg = Release_VC2015-UNICODE|Win32
38-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.Build.0 = Release_VC2015-UNICODE|Win32
39-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.ActiveCfg = Release_VC2015-UNICODE|x64
40-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.Build.0 = Release_VC2015-UNICODE|x64
35+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.ActiveCfg = Release_VC2015|Itanium
36+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Itanium.Build.0 = Release_VC2015|Itanium
37+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.ActiveCfg = Release_VC2015|Win32
38+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|Win32.Build.0 = Release_VC2015|Win32
39+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.ActiveCfg = Release_VC2015|x64
40+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015|x64.Build.0 = Release_VC2015|x64
4141
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015-UNICODE|Itanium.ActiveCfg = Release_VC2015-UNICODE|Itanium
4242
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015-UNICODE|Itanium.Build.0 = Release_VC2015-UNICODE|Itanium
4343
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2015-UNICODE|Win32.ActiveCfg = Release_VC2015-UNICODE|Win32

Main/StackWalker/StackWalker_VC2017.sln

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ Global
1616
Release_VC2017-UNICODE|x64 = Release_VC2017-UNICODE|x64
1717
EndGlobalSection
1818
GlobalSection(ProjectConfigurationPlatforms) = postSolution
19-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.ActiveCfg = Debug_VC2017-UNICODE|Win32
20-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.Build.0 = Debug_VC2017-UNICODE|Win32
21-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.ActiveCfg = Debug_VC2017-UNICODE|x64
22-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.Build.0 = Debug_VC2017-UNICODE|x64
19+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.ActiveCfg = Debug_VC2017|Win32
20+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|Win32.Build.0 = Debug_VC2017|Win32
21+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.ActiveCfg = Debug_VC2017|x64
22+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017|x64.Build.0 = Debug_VC2017|x64
2323
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|Win32.ActiveCfg = Debug_VC2017-UNICODE|Win32
2424
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|Win32.Build.0 = Debug_VC2017-UNICODE|Win32
2525
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|x64.ActiveCfg = Debug_VC2017-UNICODE|x64
2626
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Debug_VC2017-UNICODE|x64.Build.0 = Debug_VC2017-UNICODE|x64
27-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.ActiveCfg = Release_VC2017-UNICODE|Win32
28-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.Build.0 = Release_VC2017-UNICODE|Win32
29-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.ActiveCfg = Release_VC2017-UNICODE|x64
30-
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.Build.0 = Release_VC2017-UNICODE|x64
27+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.ActiveCfg = Release_VC2017|Win32
28+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|Win32.Build.0 = Release_VC2017|Win32
29+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.ActiveCfg = Release_VC2017|x64
30+
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017|x64.Build.0 = Release_VC2017|x64
3131
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017-UNICODE|Win32.ActiveCfg = Release_VC2017-UNICODE|Win32
3232
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017-UNICODE|Win32.Build.0 = Release_VC2017-UNICODE|Win32
3333
{89B2BD42-B130-4811-9043-71A8EBC40DE5}.Release_VC2017-UNICODE|x64.ActiveCfg = Release_VC2017-UNICODE|x64
@@ -36,7 +36,4 @@ Global
3636
GlobalSection(SolutionProperties) = preSolution
3737
HideSolutionNode = FALSE
3838
EndGlobalSection
39-
GlobalSection(ExtensibilityGlobals) = postSolution
40-
SolutionGuid = {66CC86C2-413E-467D-AC75-7B4BD9AE3ECD}
41-
EndGlobalSection
4239
EndGlobal

0 commit comments

Comments
 (0)