From 2eedeef5be2023a462e16143dacaf52338e9555c Mon Sep 17 00:00:00 2001 From: wizche Date: Thu, 17 Feb 2022 17:24:00 +0100 Subject: [PATCH 1/6] Added custom function table access --- Main/StackWalker/StackWalker.cpp | 29 +++++++++++++++++++++++++++-- Main/StackWalker/StackWalker.h | 16 +++++++++++++++- README.md | 4 +++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 64c0df0..cad1193 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -1097,10 +1097,16 @@ BOOL StackWalker::LoadModules() static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; static LPVOID s_readMemoryFunction_UserData = NULL; +// Similar to the readMemoryFunction one may want to provide its own function table access function +static StackWalker::PFunctionTableAccessRoutine s_functionTableAccessFunction = NULL; +static LPVOID s_functionTableAccessFunction_UserData = NULL; + BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT* context, PReadProcessMemoryRoutine readMemoryFunction, - LPVOID pUserData) + LPVOID pUserData, + PFunctionTableAccessRoutine functionTableAccessFunction, + LPVOID s_functionTableAccessFunction_UserData) { CONTEXT c; CallstackEntry csEntry; @@ -1122,6 +1128,8 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, s_readMemoryFunction = readMemoryFunction; s_readMemoryFunction_UserData = pUserData; + s_functionTableAccessFunction = functionTableAccessFunction; + s_functionTableAccessFunction_UserData = pUserData; if (context == NULL) { @@ -1215,7 +1223,7 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, // deeper frame could not be found. // CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386! if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, - this->m_sw->pSFTA, this->m_sw->pSGMB, NULL)) + myFunctionTableAccessFunction, this->m_sw->pSGMB, NULL)) { // INFO: "StackWalk64" does not set "GetLastError"... this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); @@ -1392,6 +1400,15 @@ BOOL StackWalker::ShowObject(LPVOID pObject) return TRUE; }; +PVOID __stdcall StackWalker::myFunctionTableAccessFunction(HANDLE hProcess, + DWORD64 AddrBase){ + if(s_functionTableAccessFunction == NULL){ + return SymFunctionTableAccess64(hProcess, AddrBase); + } else { + return s_functionTableAccessFunction(hProcess, AddrBase, s_functionTableAccessFunction_UserData); + } +} + BOOL __stdcall StackWalker::myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, @@ -1538,3 +1555,11 @@ void StackWalker::OnOutput(LPCSTR buffer) { OutputDebugStringA(buffer); } + +PVOID StackWalker::MySymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) { + PVOID addr = SymFunctionTableAccess64(hProcess, AddrBase); + DWORD64 ImageBase; + UNWIND_HISTORY_TABLE HistoryTable; + addr = RtlLookupFunctionEntry(AddrBase, &ImageBase, &HistoryTable); + return addr; +} diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index 1fba754..72f360e 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -42,6 +42,7 @@ #pragma once #include +#include // special defines for VC5/6 (if no actual PSDK is installed): #if _MSC_VER < 1300 @@ -129,13 +130,21 @@ class StackWalker LPVOID pUserData // optional data, which was passed in "ShowCallstack" ); + typedef PVOID(__stdcall* PFunctionTableAccessRoutine)( + HANDLE hProcess, + DWORD64 AddrBase, + 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 + LPVOID pUserData = NULL, // optional to identify some data in the 'readMemoryFunction'-callback + PFunctionTableAccessRoutine functionTableAccessFunction = NULL, + LPVOID s_functionTableAccessFunction_UserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback ); BOOL ShowObject(LPVOID pObject); @@ -204,7 +213,12 @@ class StackWalker DWORD nSize, LPDWORD lpNumberOfBytesRead); + static PVOID __stdcall myFunctionTableAccessFunction( + HANDLE hProcess, + DWORD64 AddrBase); + friend StackWalkerInternal; + static PVOID MySymFunctionTableAccess64(HANDLE ahProcess, DWORD64 AddrBase); }; // class StackWalker // The "ugly" assembler-implementation is needed for systems before XP diff --git a/README.md b/README.md index 46a9096..5651f20 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ The goal for this project was the following: * Support of x86, x64 and IA64 architecture * Default output to debugger-output window (but can be customized) * Support of user-provided read-memory-function +* Support of user-provided read-function-table * Support of the widest range of development-IDEs (VC5-VC8) * Most portable solution to walk the callstack @@ -157,7 +158,8 @@ class StackWalker { public: BOOL ShowCallstack(HANDLE hThread = GetCurrentThread(), CONTEXT *context = NULL, - PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pUserData = NULL); + PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pUserData = NULL, + PFunctionTableAccessRoutine functionTableAccessFunction = NULL, LPVOID s_functionTableAccessFunction_UserData = NULL); }; ``` From c7e910a4dd8a81881174127d464952ce4ecbb24f Mon Sep 17 00:00:00 2001 From: wizche Date: Thu, 17 Feb 2022 17:31:35 +0100 Subject: [PATCH 2/6] Removed not needed symbol resolution --- Main/StackWalker/StackWalker.cpp | 16 +++++----------- Main/StackWalker/StackWalker.h | 4 ++-- README.md | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index cad1193..4eb24c4 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -261,7 +261,6 @@ class StackWalkerInternal m_hDbhHelp = NULL; pSC = NULL; m_hProcess = hProcess; - pSFTA = NULL; pSGLFA = NULL; pSGMB = NULL; pSGMI = NULL; @@ -368,7 +367,6 @@ class StackWalkerInternal pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions"); pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions"); - pSFTA = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64"); pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64"); pSGMB = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64"); pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64"); @@ -377,7 +375,7 @@ class StackWalkerInternal pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64"); pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath"); - if (pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL || + if (pSC == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL || pSLM == NULL) { @@ -467,10 +465,6 @@ class StackWalkerInternal typedef BOOL(__stdcall* tSC)(IN HANDLE hProcess); tSC pSC; - // SymFunctionTableAccess64() - typedef PVOID(__stdcall* tSFTA)(HANDLE hProcess, DWORD64 AddrBase); - tSFTA pSFTA; - // SymGetLineFromAddr64() typedef BOOL(__stdcall* tSGLFA)(IN HANDLE hProcess, IN DWORD64 dwAddr, @@ -1104,9 +1098,9 @@ static LPVOID s_functionTableAccessFunction_UserData = NULL; BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT* context, PReadProcessMemoryRoutine readMemoryFunction, - LPVOID pUserData, + LPVOID pReadMemoryFunction_userData, PFunctionTableAccessRoutine functionTableAccessFunction, - LPVOID s_functionTableAccessFunction_UserData) + LPVOID pFunctionTableAccessFunction_UserData) { CONTEXT c; CallstackEntry csEntry; @@ -1127,9 +1121,9 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, } s_readMemoryFunction = readMemoryFunction; - s_readMemoryFunction_UserData = pUserData; + s_readMemoryFunction_UserData = pReadMemoryFunction_userData; s_functionTableAccessFunction = functionTableAccessFunction; - s_functionTableAccessFunction_UserData = pUserData; + s_functionTableAccessFunction_UserData = pFunctionTableAccessFunction_UserData; if (context == NULL) { diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index 72f360e..50cf83a 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -142,9 +142,9 @@ class StackWalker HANDLE hThread = GetCurrentThread(), const CONTEXT* context = NULL, PReadProcessMemoryRoutine readMemoryFunction = NULL, - LPVOID pUserData = NULL, // optional to identify some data in the 'readMemoryFunction'-callback + LPVOID pReadMemoryFunction_userData = NULL, // optional to identify some data in the 'readMemoryFunction'-callback PFunctionTableAccessRoutine functionTableAccessFunction = NULL, - LPVOID s_functionTableAccessFunction_UserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback + LPVOID pFunctionTableAccessFunction_UserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback ); BOOL ShowObject(LPVOID pObject); diff --git a/README.md b/README.md index 5651f20..83796af 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ class StackWalker public: BOOL ShowCallstack(HANDLE hThread = GetCurrentThread(), CONTEXT *context = NULL, PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pUserData = NULL, - PFunctionTableAccessRoutine functionTableAccessFunction = NULL, LPVOID s_functionTableAccessFunction_UserData = NULL); + PFunctionTableAccessRoutine functionTableAccessFunction = NULL, LPVOID pfunctionTableAccessFunction_UserData = NULL); }; ``` From 5644d9f78ab4101e7d9f76206ead5fb3af716050 Mon Sep 17 00:00:00 2001 From: wizche Date: Thu, 17 Feb 2022 17:32:32 +0100 Subject: [PATCH 3/6] doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83796af..c060e59 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ class StackWalker { public: BOOL ShowCallstack(HANDLE hThread = GetCurrentThread(), CONTEXT *context = NULL, - PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pUserData = NULL, + PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pReadMemoryFunction_userData = NULL, PFunctionTableAccessRoutine functionTableAccessFunction = NULL, LPVOID pfunctionTableAccessFunction_UserData = NULL); }; ``` From 226708c52283b57fb72c049346775d0c72ca1603 Mon Sep 17 00:00:00 2001 From: wizche Date: Thu, 17 Feb 2022 19:17:34 +0100 Subject: [PATCH 4/6] Removed tests leftovers --- Main/StackWalker/StackWalker.cpp | 10 +--------- Main/StackWalker/StackWalker.h | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 4eb24c4..880466b 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -1548,12 +1548,4 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser void StackWalker::OnOutput(LPCSTR buffer) { OutputDebugStringA(buffer); -} - -PVOID StackWalker::MySymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) { - PVOID addr = SymFunctionTableAccess64(hProcess, AddrBase); - DWORD64 ImageBase; - UNWIND_HISTORY_TABLE HistoryTable; - addr = RtlLookupFunctionEntry(AddrBase, &ImageBase, &HistoryTable); - return addr; -} +} \ No newline at end of file diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index 50cf83a..ca8ff30 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -218,7 +218,6 @@ class StackWalker DWORD64 AddrBase); friend StackWalkerInternal; - static PVOID MySymFunctionTableAccess64(HANDLE ahProcess, DWORD64 AddrBase); }; // class StackWalker // The "ugly" assembler-implementation is needed for systems before XP From 5e0cb060e8bf7a1cbd36f310459409c1cba7442a Mon Sep 17 00:00:00 2001 From: wizche Date: Thu, 17 Feb 2022 22:02:54 +0100 Subject: [PATCH 5/6] Fixing missing import and probably breaking everything else --- Main/StackWalker/StackWalker.cpp | 1 + Main/StackWalker/StackWalker.h | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 880466b..09a1b60 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -91,6 +91,7 @@ #include #pragma comment(lib, "version.lib") // for "VerQueryValue" +#pragma comment(lib, "dbghelp.lib") #pragma warning(disable : 4826) #if _MSC_VER >= 1900 diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index ca8ff30..47f28ae 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -213,9 +213,8 @@ class StackWalker DWORD nSize, LPDWORD lpNumberOfBytesRead); - static PVOID __stdcall myFunctionTableAccessFunction( - HANDLE hProcess, - DWORD64 AddrBase); + static PVOID __stdcall myFunctionTableAccessFunction(HANDLE hProcess, + DWORD64 AddrBase); friend StackWalkerInternal; }; // class StackWalker From 61c84044088bd5db11935599df9e24873b92fff8 Mon Sep 17 00:00:00 2001 From: wizche Date: Wed, 2 Mar 2022 21:25:02 +0000 Subject: [PATCH 6/6] Allow to specify get module base callback --- Main/StackWalker/StackWalker.cpp | 22 +++++++++++++++++++--- Main/StackWalker/StackWalker.h | 12 ++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Main/StackWalker/StackWalker.cpp b/Main/StackWalker/StackWalker.cpp index 09a1b60..d0bb477 100644 --- a/Main/StackWalker/StackWalker.cpp +++ b/Main/StackWalker/StackWalker.cpp @@ -881,7 +881,7 @@ extern "C" void** __cdecl __current_exception_context(); static PCONTEXT get_current_exception_context() { PCONTEXT * pctx = NULL; -#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900 +#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900 LPSTR ptd = (LPSTR)_getptd(); if (ptd) pctx = (PCONTEXT *)(ptd + (sizeof(void*) == 4 ? 0x8C : 0xF8)); @@ -1096,12 +1096,18 @@ static LPVOID s_readMemoryFunction_UserData = NU static StackWalker::PFunctionTableAccessRoutine s_functionTableAccessFunction = NULL; static LPVOID s_functionTableAccessFunction_UserData = NULL; +// Similar to the readMemoryFunction one may want to provide its own function table access function +static StackWalker::PGetModuleBase s_getModuleBaseFunction = NULL; +static LPVOID s_getModuleBaseFunction_UserData = NULL; + BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT* context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pReadMemoryFunction_userData, PFunctionTableAccessRoutine functionTableAccessFunction, - LPVOID pFunctionTableAccessFunction_UserData) + LPVOID pFunctionTableAccessFunction_UserData, + PGetModuleBase getModuleBaseFunction, + LPVOID pGetModuleBaseFunction_UserData) { CONTEXT c; CallstackEntry csEntry; @@ -1125,6 +1131,8 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, s_readMemoryFunction_UserData = pReadMemoryFunction_userData; s_functionTableAccessFunction = functionTableAccessFunction; s_functionTableAccessFunction_UserData = pFunctionTableAccessFunction_UserData; + s_getModuleBaseFunction = getModuleBaseFunction; + s_getModuleBaseFunction_UserData = pGetModuleBaseFunction_UserData; if (context == NULL) { @@ -1218,7 +1226,7 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, // deeper frame could not be found. // CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386! if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, - myFunctionTableAccessFunction, this->m_sw->pSGMB, NULL)) + myFunctionTableAccessFunction, myGetModuleBaseFunction, NULL)) { // INFO: "StackWalk64" does not set "GetLastError"... this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); @@ -1404,6 +1412,14 @@ PVOID __stdcall StackWalker::myFunctionTableAccessFunction(HANDLE hProcess, } } +DWORD64 __stdcall StackWalker::myGetModuleBaseFunction(HANDLE hProcess, DWORD64 dwAddr){ + if(s_getModuleBaseFunction == NULL){ + return SymGetModuleBase64(hProcess, dwAddr); + } else { + return s_getModuleBaseFunction(hProcess, dwAddr, s_getModuleBaseFunction_UserData); + } +} + BOOL __stdcall StackWalker::myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, diff --git a/Main/StackWalker/StackWalker.h b/Main/StackWalker/StackWalker.h index 47f28ae..fc7d84e 100644 --- a/Main/StackWalker/StackWalker.h +++ b/Main/StackWalker/StackWalker.h @@ -136,6 +136,10 @@ class StackWalker LPVOID pUserData // optional data, which was passed in "ShowCallstack" ); + typedef DWORD64(__stdcall* PGetModuleBase)(IN HANDLE hProcess, + IN DWORD64 dwAddr, + LPVOID pUserData); + BOOL LoadModules(); BOOL ShowCallstack( @@ -144,8 +148,10 @@ class StackWalker PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pReadMemoryFunction_userData = NULL, // optional to identify some data in the 'readMemoryFunction'-callback PFunctionTableAccessRoutine functionTableAccessFunction = NULL, - LPVOID pFunctionTableAccessFunction_UserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback - ); + LPVOID pFunctionTableAccessFunction_UserData = NULL, // optional to identify some data in the 'readMemoryFunction'-callback + PGetModuleBase getModuleBaseFunction = NULL, + LPVOID pGetModuleBaseFunction_UserData = NULL + ); BOOL ShowObject(LPVOID pObject); @@ -216,6 +222,8 @@ class StackWalker static PVOID __stdcall myFunctionTableAccessFunction(HANDLE hProcess, DWORD64 AddrBase); + static DWORD64 __stdcall myGetModuleBaseFunction(HANDLE hProcess, DWORD64 dwAddr); + friend StackWalkerInternal; }; // class StackWalker