Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何为进程中运行的所有线程获取stacktrace?_C++_Winapi_Stack Trace - Fatal编程技术网

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

C++ 如何为进程中运行的所有线程获取stacktrace?,c++,winapi,stack-trace,C++,Winapi,Stack Trace,我试图为运行多线程的进程获取堆栈跟踪,我能够获取主线程的堆栈跟踪。但是对于同一进程的其他线程,即使我使用了正确的ThreadID,我也会得到与主线程相同的所有ThreadsName的堆栈跟踪。我确信这些都不是正确的线索 下面是代码,我不知道出了什么问题。如果你有任何想法,请告诉我。谢谢 我的pExPtrs为null,我不会在异常期间调用它 void DoStackTraces ( LPTSTR szString,DWORD dwSize, EXCEPTION_POINTERS *pExPtrs)

我试图为运行多线程的进程获取堆栈跟踪,我能够获取主线程的堆栈跟踪。但是对于同一进程的其他线程,即使我使用了正确的ThreadID,我也会得到与主线程相同的所有ThreadsName的堆栈跟踪。我确信这些都不是正确的线索

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

我的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打开线程,以获得可用于StackWalk64的句柄


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

你应该提到你正在使用的编译器,并包含一个标记。我用来获取线程句柄的方法是不正确的。您是对的,现在我可以遍历所有线程并获得堆栈跟踪。非常感谢。。