📄 stackwalker.cpp
字号:
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
#if 1
memset(&Line, 0, sizeof(Line));
#else
Line.Key = NULL;
Line.LineNumber = 0;
Line.FileName = NULL;
Line.Address = 0;
#endif
Line.SizeOfStruct = sizeof(Line);
#if 0
memset(&Module, 0, sizeof(Module));
#else
Module.BaseOfImage = 0;
Module.ImageSize = 0;
Module.TimeDateStamp = 0;
Module.CheckSum = 0;
Module.NumSyms = 0;
Module.SymType = SymNone;
*Module.ModuleName = '\0';
*Module.ImageName = '\0';
*Module.LoadedImageName = '\0';
#endif
Module.SizeOfStruct = sizeof(Module);
for (frameNum = 0; ; ++frameNum )
{
// get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
// if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
// assume that either you are done, or that the stack is so hosed that the next
// deeper frame could not be found.
// CONTEXT need not to be suplied 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) )
{
this->OnDbgHelpErr("StackWalk64", GetLastError(), s.AddrPC.Offset);
break;
}
csEntry.offset = s.AddrPC.Offset;
csEntry.name[0] = 0;
csEntry.undName[0] = 0;
csEntry.undFullName[0] = 0;
csEntry.offsetFromSmybol = 0;
csEntry.offsetFromLine = 0;
csEntry.lineFileName[0] = 0;
csEntry.lineNumber = 0;
csEntry.loadedImageName[0] = 0;
csEntry.moduleName[0] = 0;
csEntry.symTypeString = NULL;
if (s.AddrPC.Offset == s.AddrReturn.Offset)
{
this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
break;
}
if ( s.AddrPC.Offset != 0 )
{
// we seem to have a valid PC
if ((m_pentry = search_entry(s.AddrPC.Offset)) == NULL) /* search if address is already known */
{// address unknown
// show procedure info (SymGetSymFromAddr64())
if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE)
{
// TODO: Mache dies sicher...!
strcpy_s(csEntry.name, pSym->Name);
// UnDecorateSymbolName()
this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY );
this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE );
}
else
{
this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
}
// show line number info, NT5.0-method (SymGetLineFromAddr64())
if (this->m_sw->pSGLFA != NULL )
{ // yes, we have SymGetLineFromAddr64()
if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE)
{
csEntry.lineNumber = Line.LineNumber;
// TODO: Mache dies sicher...!
strcpy_s(csEntry.lineFileName, Line.FileName);
}
else
{
this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
}
} // yes, we have SymGetLineFromAddr64()
// show module info (SymGetModuleInfo64())
if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE)
{ // got module info OK
#if 0 // @@@@ XMEM: not necessary for XMEM
switch ( Module.SymType )
{
case SymNone:
csEntry.symTypeString = "-nosymbols-";
break;
case SymCoff:
csEntry.symTypeString = "COFF";
break;
case SymCv:
csEntry.symTypeString = "CV";
break;
case SymPdb:
csEntry.symTypeString = "PDB";
break;
case SymExport:
csEntry.symTypeString = "-exported-";
break;
case SymDeferred:
csEntry.symTypeString = "-deferred-";
break;
case SymSym:
csEntry.symTypeString = "SYM";
break;
case SymVirtual:
csEntry.symTypeString = "Virtual";
break;
#if API_VERSION_NUMBER >= 9
case SymDia:
csEntry.symTypeString = "DIA";
break;
#endif
default:
//_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );
csEntry.symTypeString = NULL;
break;
}
#endif // /*@@@@ XMEM*/
// TODO: Mache dies sicher...!
strcpy_s(csEntry.moduleName, Module.ModuleName);
// /*@@@@ XMEM*/ csEntry.baseOfImage = Module.BaseOfImage;
// /*@@@@ XMEM*/ strcpy_s(csEntry.loadedImageName, Module.LoadedImageName);
} // got module info OK
else
{
this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
}
}
} // we seem to have a valid PC
else
{
m_pentry = NULL; /* invalid address */
}
CallstackEntryType et = nextEntry;
if (frameNum == 0)
et = firstEntry;
this->OnCallstackEntry(et, csEntry);
if (s.AddrReturn.Offset == 0)
{
this->OnCallstackEntry(lastEntry, csEntry);
SetLastError(ERROR_SUCCESS);
break;
}
} // for ( frameNum )
// /*@@@@ XMEM*/ cleanup:
// /*@@@@ XMEM*/ if (pSym)
// /*@@@@ XMEM*/ free( pSym );
if (context == NULL)
ResumeThread(hThread);
return TRUE;
}
BOOL __stdcall StackWalker::myReadProcMem(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead
)
{
if (s_readMemoryFunction == NULL)
{
SIZE_T st;
BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);
*lpNumberOfBytesRead = (DWORD) st;
//printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
return bRet;
}
else
{
return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData);
}
}
void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
if (fileVersion == 0)
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName);
else
{
DWORD v4 = (DWORD) fileVersion & 0xFFFF;
DWORD v3 = (DWORD) (fileVersion>>16) & 0xFFFF;
DWORD v2 = (DWORD) (fileVersion>>32) & 0xFFFF;
DWORD v1 = (DWORD) (fileVersion>>48) & 0xFFFF;
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
}
OnOutput(buffer);
}
void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
if ( (eType != lastEntry) && (entry.offset != 0) )
{
if (entry.name[0] == 0)
strcpy_s(entry.name, "(function-name not available)");
if (entry.undName[0] != 0)
strcpy_s(entry.name, entry.undName);
if (entry.undFullName[0] != 0)
strcpy_s(entry.name, entry.undFullName);
if (entry.lineFileName[0] == 0)
{
strcpy_s(entry.lineFileName, "(filename not available)");
if (entry.moduleName[0] == 0)
strcpy_s(entry.moduleName, "(module-name not available)");
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
}
else
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);
OnOutput(buffer);
}
}
void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);
OnOutput(buffer);
}
void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
OnOutput(buffer);
// Also display the OS-version
#if _MSC_VER <= 1200
OSVERSIONINFOA ver;
ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
ver.dwOSVersionInfoSize = sizeof(ver);
if (GetVersionExA(&ver) != FALSE)
{
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n",
ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.szCSDVersion);
OnOutput(buffer);
}
#else
OSVERSIONINFOEXA ver;
ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
ver.dwOSVersionInfoSize = sizeof(ver);
if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE)
{
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n",
ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
OnOutput(buffer);
}
#endif
}
void StackWalker::OnOutput(LPCSTR buffer)
{
if (m_pos)
{
// Write to output stream
*m_pos << buffer;
}
else if (m_pwos)
{
// Unicode output stream is ready. Use the output stream.
// Convert ASCII stream to UNICODE stream.
size_t iLen = strlen(buffer) + 1; // Including NULL termination
wchar_t *pBufferW = (wchar_t*)malloc(sizeof(wchar_t)*iLen);
if (pBufferW)
{
for (u32 i = 0; i < iLen; i++)
{
pBufferW[i] = (wchar_t)buffer[i];
}
// Write to output stream
*m_pwos << pBufferW;
// Delete pBufferW
free(pBufferW);
}
}
else
{
// Write to console.
OutputDebugStringA(buffer);
}
}
void StackWalker::OnOutput(LPCWSTR buffer)
{
if (m_pos)
{
// ASCII output stream is ready. Use the output stream.
// Convert UNICODE stream to ASCII stream.
#if UNICODE
u32 iLen = lstrlen(buffer) + 1; // Including NULL termination
#else
u32 iLen = lstrlen((LPCSTR)buffer) + 1; // Including NULL termination
#endif
char *pBufferA = (char*)malloc(sizeof(char)*iLen);
if (pBufferA)
{
for (u32 i = 0; i < iLen; i++)
{
pBufferA[i] = (char)buffer[i];
}
// Write to output stream
*m_pos << pBufferA;
// Delete pBufferA
free(pBufferA);
}
}
else if (m_pwos)
{
// Write to output stream
*m_pwos << buffer;
}
else
{
// Write to console.
OutputDebugStringW(buffer);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -