如何获得在进程中运行的所有线程的堆栈跟踪?
问题描述:
我正在尝试为多线程运行的进程获取堆栈跟踪,我能够获得主线程的堆栈跟踪。但对于其他线程(属于同一进程),即使我使用了正确的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 ;
}
}
}
答
的句柄线程快照不是一回事的句柄线程。在快照句柄上调用Suspend/ResumeThread是不正确的(如果不是这可能是危险的,如果你挂起线程这个线程?)。您需要使用线程ID来获取可以与StackWalk64一起使用的句柄。
同样,假设GET_CURRENT_CONTEXT在当前线程上运行,它将不正确。如果它在hnd上工作,它又不会工作,因为再次,这不是线程句柄。
+0
我用来获取线程句柄的方式不正确。你是正确的,现在我能够遍历所有线程并获得堆栈跟踪。非常感谢.. – thanga 2012-03-12 11:25:14
你应该提到你正在使用什么编译器,并包含一个标签。 – Donotalo 2012-02-28 11:16:33