繁体   English   中英

如何获取进程中运行的所有线程的stacktrace?

[英]How to get stacktrace for all threads running in a process?

我试图获取运行有多个线程的进程的堆栈跟踪,我能够获取主线程的堆栈跟踪。 但是对于其他线程(属于同一进程),即使我使用了正确的threadIds,我对于所有线程(与主线程相同)也得到相同的stacktrace。 我确信这些不是该线程的正确跟踪。

以下是代码,我不知道出了什么问题。 如果您有任何想法,请告诉我。 谢谢..

我的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 ;
        }
    }
  }

线程快照的句柄与线程快照的句柄不同。 在快照句柄上调用Suspend / ResumeThread是错误的(如果不是这样,则可能很危险,如果您将此线程SuspendThread呢?)。 您需要使用带有线程ID的OpenThread来获取可与StackWalk64一起使用的句柄。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM