2012-02-28 98 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

相關問題