我正在尝试为多个线程运行的进程获取堆栈跟踪,我能够获得主线程的堆栈跟踪。但对于其他线程(属于同一进程),即使我使用了正确的threadIds,我也得到了所有线程的相同堆栈跟踪(与主线程相同)。我确信那些线程的跟踪不正确。
以下是代码,我不知道出了什么问题。如果您有任何想法,请告诉我。感谢..
我的pExPtrs为空,我在异常期间没有调用它。
void DoStackTraces ( LPTSTR szString,DWORD dwSize, EXCEPTION_POINTERS *pExPtrs)
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, static_cast<DWORD>(getpid()));
if (h != INVALID_HANDLE_VALUE)
{
THREADENTRY32 te;
te.dwSize = sizeof(te);
if (Thread32First(h, &te)) {
do {
if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) +
sizeof(te.th32OwnerProcessID)) {
if(te.th32OwnerProcessID == static_cast<DWORD>(getpid())) {
std::cout << "Process 0x%04x | Thread 0x%04x\n"
<< te.th32OwnerProcessID << " | " << te.th32ThreadID
<< " Current ProcessID : " << getpid()
<< " dwSize : " << dwSize
<< " pExPtrs : " << pExPtrs
<< std::endl;
HANDLE hnd = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, te.th32ThreadID);
SuspendThread(hnd);
DoStackTraceThread(hnd,szString,dwSize,0);
ResumeThread(hnd);
std::cout << szString << std::endl;
}
}
te.dwSize = sizeof(te);
} while (Thread32Next(h, &te));
}
CloseHandle(h);
}
//HANDLE hThread = GetCurrentThread();
//DoStackTraceThread (hThread, szString,dwSize,pExPtrs);
}
void DoStackTraceThread ( HANDLE hThread, LPTSTR szString ,
DWORD dwSize , EXCEPTION_POINTERS *pExPtrs)
{
if (g_bCsysDontGetProcessCritSec){return;}
sAutoLock al(g_stackTraceMux); // The code probably isn't thread safe.
if (g_cSym.isInstalled() == false) return;
HANDLE hProcess = GetCurrentProcess ( ) ;
// If the symbol engine is not initialized, do it now.
if ( FALSE == g_bSymIsInit )
{
DWORD dwOpts = APFSymGetOptions ( ) ;
// Turn on load lines.
APFSymSetOptions ( dwOpts |
SYMOPT_LOAD_LINES ) ;
if ( FALSE == g_cSym.SymInitialize ( hProcess ,
NULL ,
TRUE ) )
{
std::cerr << "APF ERROR: DiagAssert : Unable to initialize the "
"symbol engine!!!" << std::endl;
}
else
{
g_bSymIsInit = TRUE ;
}
}
// The symbol engine is initialized so do the stack walk.
// The array of addresses.
ADDRVECTOR vAddrs ;
// The thread information.
CONTEXT stCtx ;
CONTEXT *pstCtx ;
GET_CURRENT_CONTEXT(stCtx, CONTEXT_FULL);
{
STACKFRAME64 stFrame ;
DWORD dwMachine ;
ZeroMemory ( &stFrame , sizeof ( STACKFRAME64 ) ) ;
stFrame.AddrPC.Mode = AddrModeFlat ;
if (pExPtrs)
{
pstCtx=pExPtrs->ContextRecord;
}
else {
pstCtx=&stCtx;
}
dwMachine = IMAGE_FILE_MACHINE_I386 ;
if (pExPtrs){
stFrame.AddrPC.Offset = pstCtx->Eip ;
stFrame.AddrStack.Offset = pstCtx->Esp ;
stFrame.AddrFrame.Offset = pstCtx->Ebp ;
}
else {
stFrame.AddrPC.Offset = stCtx.Eip ;
stFrame.AddrStack.Offset = stCtx.Esp ;
stFrame.AddrFrame.Offset = stCtx.Ebp ;
}
stFrame.AddrStack.Mode = AddrModeFlat ;
stFrame.AddrFrame.Mode = AddrModeFlat ;
// Loop for the first 512 stack elements.
for ( DWORD i = 0 ; i < 512 ; i++ )
{
if ( FALSE == StackWalkProc ( dwMachine ,
hProcess ,
hThread ,
&stFrame ,
pstCtx ,
NULL ,
(PFUNCTION_TABLE_ACCESS_ROUTINE64)
APFSymFunctionTableAccess ,
GetModBase ,
NULL ) )
{
break ;
}
// Also check that the address is not zero. Sometimes
// StackWalk returns TRUE with a frame of zero.
if ( 0 != stFrame.AddrPC.Offset )
{
vAddrs.push_back ( stFrame.AddrPC.Offset ) ;
}
}
// Now start converting the addresses.
DWORD64 dwSizeLeft = dwSize ;
DWORD64 dwSymSize ;
TCHAR szSym [ MAX_PATH * 2 ] ;
LPTSTR szCurrPos = szString ;
ADDRVECTOR::iterator loop ;
for ( loop = vAddrs.begin ( ) ;
loop != vAddrs.end ( ) ;
loop++ )
{
dwSymSize = DoConvertAddress ( *loop , szSym ) ;
if ( dwSizeLeft <= dwSymSize )
{
break ;
}
_tcscpy ( szCurrPos , szSym ) ;
szCurrPos += dwSymSize ;
dwSizeLeft -= dwSymSize ;
}
}
}
答案 0 :(得分:0)
线程快照的句柄与线程的句柄不同。在快照句柄上调用Suspend / ResumeThread是不正确的(如果不是它可能是危险的,如果你SuspendThread 这个线程怎么办?)。您需要使用线程ID的OpenThread来获取可与StackWalk64一起使用的句柄。
同样,假设GET_CURRENT_CONTEXT在当前线程上运行它将是不正确的。如果它适用于hnd,它再次无效,因为它不是线程句柄。