2012-02-28 2 views
0

여러 스레드로 실행중인 프로세스에 대한 스택 추적을 얻으려고하고 있는데, 주 ​​스레드에 대한 스택 추적을 얻을 수 있습니다. 하지만 다른 스레드 (동일한 프로세스에 속함)에도 불구하고 적절한 threadIds를 사용했지만 모든 스레드에 대해 동일한 스택 추적을 얻고 있습니다 (주 스레드와 동일). 나는 그 스레드에 대한 올바른 추적이 아니라고 확신합니다.프로세스에서 실행중인 모든 스레드에 대해 스택 추적을 얻는 방법은 무엇입니까?

다음 코드는 무엇이 잘못되었는지 전혀 모른다. 어떤 생각이라도 있으면 알려주세요. 고마워.

내 pExPtrs가 null인데 예외로 이것을 호출하지 않습니다.

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

답변

0

스레드 스냅 숏 핸들은 스레드 핸들과 다릅니다. 스냅 샷 핸들의 Suspend/ResumeThread 호출이 올바르지 않습니다. 그렇지 않은 경우 위험 할 수 있습니다. SuspendThread 스레드입니까?). StackWalk64와 함께 사용할 수있는 핸들을 얻으려면 스레드 ID가있는 OpenThread가 필요합니다.

마찬가지로 GET_CURRENT_CONTEXT가 현재 스레드에서 작동한다고 가정하면 올바르지 않습니다. 그것은 hnd에서 작동하는 경우 다시 작동하지 않습니다, 그것은 스레드 핸들이 아니기 때문에 다시 작동하지 않습니다.

+0

스레드 핸들을 얻는 데 사용한 방법이 올바르지 않습니다. 그리고 당신이 맞습니다, 이제 모든 스레드를 반복하고 스택 추적을 얻을 수 있습니다. 매우 감사합니다.. – thanga

관련 문제