2012-02-28 246 views
0

我正在尝试为多线程运行的进程获取堆栈跟踪,我能够获得主线程的堆栈跟踪。但对于其他线程(属于同一进程),即使我使用了正确的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 ; 
     } 
    } 
    } 
+1

你应该提到你正在使用什么编译器,并包含一个标签。 – Donotalo 2012-02-28 11:16:33

回答

0

的句柄线程快照不是一回事的句柄线程。在快照句柄上调用Suspend/ResumeThread是不正确的(如果不是这可能是危险的,如果你挂起线程这个线程?)。您需要使用线程ID来获取可以与StackWalk64一起使用的句柄。

同样,假设GET_CURRENT_CONTEXT在当前线程上运行,它将不正确。如果它在hnd上工作,它又不会工作,因为再次,这不是线程句柄。

+0

我用来获取线程句柄的方式不正确。你是正确的,现在我能够遍历所有线程并获得堆栈跟踪。非常感谢.. – thanga 2012-03-12 11:25:14

相关问题