📄 stackwalker.cpp
字号:
szSymType = "Virtual";
break;
#if API_VERSION_NUMBER >= 9
case SymDia:
szSymType = "DIA";
break;
#endif
}
}
this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, Module.LoadedImageName, fileVersion);
}
if (szImg != NULL)
free(szImg);
if (szMod != NULL)
free(szMod);
return result;
}
public:
BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)
{
// first try toolhelp32
if (GetModuleListTH32(hProcess, dwProcessId))
return true;
// then try psapi
return GetModuleListPSAPI(hProcess);
}
char m_Data[4096]; // @@@@ XMEM: reserve space with class member, do not allocate dynamically (performance reason)
BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V2 *pModuleInfo)
{
if(this->pSGMI == NULL)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
// First try to use the larger ModuleInfo-Structure
// memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
// pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
// if (this->pSGMI_V3 != NULL)
// {
// if (this->pSGMI_V3(hProcess, baseAddr, pModuleInfo) != FALSE)
// return TRUE;
// // check if the parameter was wrong (size is bad...)
// if (GetLastError() != ERROR_INVALID_PARAMETER)
// return FALSE;
// }
// could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
// /*@@@@ XMEM*/ void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...
// /*@@@@ XMEM*/ if (pData == NULL)
// /*@@@@ XMEM*/ {
// /*@@@@ XMEM*/ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
// /*@@@@ XMEM*/ return FALSE;
// /*@@@@ XMEM*/ }
memcpy(m_Data, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); // @@@@ XMEM
if (this->pSGMI != NULL)
{
if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V2*) m_Data))
{
// only copy as much memory as is reserved...
memcpy(pModuleInfo, m_Data, sizeof(IMAGEHLP_MODULE64_V2)); // @@@@ XMEM
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
// /*@@@@ XMEM*/ free(pData);
return TRUE;
}
// /*@@@@ XMEM*/ free(pData);
return FALSE;
}
// /*@@@@ XMEM*/ free(pData);
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
};
// #############################################################
StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
{
this->m_options = OptionsAll;
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_pwos = NULL;
}
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_pwos = NULL;
}
StackWalker::~StackWalker()
{
if (m_szSymPath != NULL)
free(m_szSymPath);
m_szSymPath = NULL;
if (this->m_sw != NULL)
delete this->m_sw;
this->m_sw = NULL;
}
BOOL StackWalker::LoadModules()
{
if (this->m_sw == NULL)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
if (m_modulesLoaded != FALSE)
return TRUE;
// Build the sym-path:
char *szSymPath = NULL;
if ( (this->m_options & SymBuildPath) != 0)
{
const size_t nSymPathLen = 4096;
szSymPath = (char*) malloc(nSymPathLen);
if (szSymPath == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
szSymPath[0] = 0;
// Now first add the (optional) provided sympath:
if (this->m_szSymPath != NULL)
{
strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);
strcat_s(szSymPath, nSymPathLen, ";");
}
strcat_s(szSymPath, nSymPathLen, ".;");
const size_t nTempLen = 1024;
char szTemp[nTempLen];
// Now add the current directory:
if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
{
szTemp[nTempLen-1] = 0;
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");
}
// Now add the path for the main-module:
if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
{
szTemp[nTempLen-1] = 0;
for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p)
{
// locate the rightmost path separator
if ( (*p == '\\') || (*p == '/') || (*p == ':') )
{
*p = 0;
break;
}
} // for (search for path separator...)
if (strlen(szTemp) > 0)
{
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");
}
}
if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
{
szTemp[nTempLen-1] = 0;
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");
}
if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
{
szTemp[nTempLen-1] = 0;
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");
}
if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
{
szTemp[nTempLen-1] = 0;
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");
// also add the "system32"-directory:
strcat_s(szTemp, nTempLen, "\\system32");
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");
}
if ((this->m_options & SymBuildPath) && (this->m_options & SymUseSymSrv))
{
if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
{
szTemp[nTempLen-1] = 0;
strcat_s(szSymPath, nSymPathLen, "SRV*");
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, "\\websymbols");
strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");
}
else
strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");
}
}
// First Init the whole stuff...
BOOL bRet = this->m_sw->Init(szSymPath);
if (szSymPath != NULL)
free(szSymPath);
szSymPath = NULL;
if (bRet == FALSE)
{
this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);
if (bRet != FALSE)
m_modulesLoaded = TRUE;
return bRet;
}
// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction
// This has to be done due to a problem with the "hProcess"-parameter in x64...
// Because this class is in no case multi-threading-enabled (because of the limitations
// of dbghelp.dll) it is "safe" to use a static-variable
static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;
static LPVOID s_readMemoryFunction_UserData = NULL;
void StackWalker::OstreamRegister( ST_OSTREAMA* pos )
{
m_pos = pos;
m_pwos = NULL;
}
void StackWalker::OstreamRegister( ST_OSTREAMW* pwos )
{
m_pos = NULL;
m_pwos = pwos;
}
BOOL StackWalker::ShowCallstack(const CONTEXT *context, HANDLE hThread, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData)
{
CONTEXT c;
CallstackEntry csEntry;
IMAGEHLP_SYMBOL64 *pSym = NULL;
StackWalkerInternal::IMAGEHLP_MODULE64_V2 Module;
IMAGEHLP_LINE64 Line;
int frameNum;
char tmpSym[sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN]; // @@@@ XMEM: temporary buffer, must be defined here because of dimension parameters
if (m_modulesLoaded == FALSE)
this->LoadModules(); // ignore the result...
if ( (this->m_sw == NULL)
|| (this->m_sw->m_hDbhHelp == NULL)
)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
s_readMemoryFunction = readMemoryFunction;
s_readMemoryFunction_UserData = pUserData;
if (context == NULL)
{
// If no context is provided, capture the context
if (hThread == GetCurrentThread())
{
GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS);
}
else
{
SuspendThread(hThread);
memset(&c, 0, sizeof(CONTEXT));
c.ContextFlags = USED_CONTEXT_FLAGS;
if (GetThreadContext(hThread, &c) == FALSE)
{
ResumeThread(hThread);
return FALSE;
}
}
}
else
c = *context;
// init STACKFRAME for first call
STACKFRAME64 s; // in/out stackframe
memset(&s, 0, sizeof(s));
DWORD imageType;
#ifdef _M_IX86
// normally, call ImageNtHeader() and use machine info from PE header
imageType = IMAGE_FILE_MACHINE_I386;
s.AddrPC.Offset = c.Eip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Ebp;
s.AddrFrame.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Esp;
s.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
imageType = IMAGE_FILE_MACHINE_AMD64;
s.AddrPC.Offset = c.Rip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Rsp;
s.AddrFrame.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Rsp;
s.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
imageType = IMAGE_FILE_MACHINE_IA64;
s.AddrPC.Offset = c.StIIP;
s.AddrPC.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.IntSp;
s.AddrFrame.Mode = AddrModeFlat;
s.AddrBStore.Offset = c.RsBSP;
s.AddrBStore.Mode = AddrModeFlat;
s.AddrStack.Offset = c.IntSp;
s.AddrStack.Mode = AddrModeFlat;
#else
#error "Platform not supported!"
#endif
// /*@@@@ XMEM*/ pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
pSym = (IMAGEHLP_SYMBOL64 *)tmpSym;
// /*@@@@ XMEM*/ if (!pSym)
// /*@@@@ XMEM*/ goto cleanup; // not enough memory...
#if 0
memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
#else
pSym->Address = 0;
pSym->Size = 0;
pSym->Flags = 0;
*pSym->Name = '\0';
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -