Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom function table access #51

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 40 additions & 12 deletions Main/StackWalker/StackWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#include <new>

#pragma comment(lib, "version.lib") // for "VerQueryValue"
#pragma comment(lib, "dbghelp.lib")

#pragma warning(disable : 4826)
#if _MSC_VER >= 1900
Expand Down Expand Up @@ -261,7 +262,6 @@ class StackWalkerInternal
m_hDbhHelp = NULL;
pSC = NULL;
m_hProcess = hProcess;
pSFTA = NULL;
pSGLFA = NULL;
pSGMB = NULL;
pSGMI = NULL;
Expand Down Expand Up @@ -368,7 +368,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");
Expand All @@ -377,7 +376,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)
{
Expand Down Expand Up @@ -467,10 +466,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,
Expand Down Expand Up @@ -886,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));
Expand Down Expand Up @@ -1097,10 +1092,22 @@ 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;

// 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 pUserData)
LPVOID pReadMemoryFunction_userData,
PFunctionTableAccessRoutine functionTableAccessFunction,
LPVOID pFunctionTableAccessFunction_UserData,
PGetModuleBase getModuleBaseFunction,
LPVOID pGetModuleBaseFunction_UserData)
{
CONTEXT c;
CallstackEntry csEntry;
Expand All @@ -1121,7 +1128,11 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread,
}

s_readMemoryFunction = readMemoryFunction;
s_readMemoryFunction_UserData = pUserData;
s_readMemoryFunction_UserData = pReadMemoryFunction_userData;
s_functionTableAccessFunction = functionTableAccessFunction;
s_functionTableAccessFunction_UserData = pFunctionTableAccessFunction_UserData;
s_getModuleBaseFunction = getModuleBaseFunction;
s_getModuleBaseFunction_UserData = pGetModuleBaseFunction_UserData;

if (context == NULL)
{
Expand Down Expand Up @@ -1215,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,
this->m_sw->pSFTA, this->m_sw->pSGMB, NULL))
myFunctionTableAccessFunction, myGetModuleBaseFunction, NULL))
{
// INFO: "StackWalk64" does not set "GetLastError"...
this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset);
Expand Down Expand Up @@ -1392,6 +1403,23 @@ 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);
}
}

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,
Expand Down Expand Up @@ -1537,4 +1565,4 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser
void StackWalker::OnOutput(LPCSTR buffer)
{
OutputDebugStringA(buffer);
}
}
24 changes: 22 additions & 2 deletions Main/StackWalker/StackWalker.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#pragma once

#include <windows.h>
#include <DbgHelp.h>

// special defines for VC5/6 (if no actual PSDK is installed):
#if _MSC_VER < 1300
Expand Down Expand Up @@ -129,14 +130,28 @@ 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"
);

typedef DWORD64(__stdcall* PGetModuleBase)(IN HANDLE hProcess,
IN DWORD64 dwAddr,
LPVOID pUserData);

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 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
PGetModuleBase getModuleBaseFunction = NULL,
LPVOID pGetModuleBaseFunction_UserData = NULL
);

BOOL ShowObject(LPVOID pObject);

Expand Down Expand Up @@ -204,6 +219,11 @@ class StackWalker
DWORD nSize,
LPDWORD lpNumberOfBytesRead);

static PVOID __stdcall myFunctionTableAccessFunction(HANDLE hProcess,
DWORD64 AddrBase);

static DWORD64 __stdcall myGetModuleBaseFunction(HANDLE hProcess, DWORD64 dwAddr);

friend StackWalkerInternal;
}; // class StackWalker

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 pReadMemoryFunction_userData = NULL,
PFunctionTableAccessRoutine functionTableAccessFunction = NULL, LPVOID pfunctionTableAccessFunction_UserData = NULL);
};
```

Expand Down