【问题标题】:How to get thread stack information on Windows?如何在 Windows 上获取线程堆栈信息?
【发布时间】:2010-10-12 19:42:24
【问题描述】:

我通过CreateToolhelp32Snapshot 函数枚举了一个进程中的所有线程。我想获得每个线程的一些基本堆栈信息。更具体地说,我想获取堆栈底部地址,如果可能的话,我想获取当前堆栈顶部地址。基本上这是在 WinDbg 中使用~*k 命令显示的信息。那么如何从线程的ID或者HANDLE中获取堆栈信息呢?

【问题讨论】:

    标签: windows stack windbg


    【解决方案1】:

    (定义见here。)

    获取堆栈边界:

    THREAD_BASIC_INFORMATION basicInfo;
    NT_TIB tib;
    
    // Get TEB address
    NtQueryInformationThread(YOUR_THREAD_HANDLE, ThreadBasicInformation, &basicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL);
    // Read TIB
    NtReadVirtualMemory(YOUR_PROCESS_HANDLE, basicInfo.TebBaseAddress, &tib, sizeof(NT_TIB), NULL);
    // Check tib.StackBase and tib.StackLimit
    

    要获取esp 的值,只需使用GetThreadContext

    【讨论】:

    • 感谢 wj32!我会看看你提供的链接。
    【解决方案2】:

    无需涉及 Windows Driver Kit 的更简单方法如下:

    NT_TIB* tib = (NT_TIB*)__readfsdword(0x18);
    size_t* stackBottom = (size_t*)tib->StackLimit;
    size_t* stackTop = (size_t*)tib->StackBase;
    

    【讨论】:

      【解决方案3】:

      __readfsdword() 仅适用于当前线程。因此,带有 NtQueryInformationThread() 的变体更加灵活。

      添加了一些在 ntdll.h 中遗漏的声明:

      typedef enum _THREADINFOCLASS {
          ThreadBasicInformation = 0,
      } THREADINFOCLASS;
      
      typedef LONG KPRIORITY;
      
      typedef struct _CLIENT_ID {
          HANDLE UniqueProcess;
          HANDLE UniqueThread;
      } CLIENT_ID;
      typedef CLIENT_ID *PCLIENT_ID;
      
      typedef struct _THREAD_BASIC_INFORMATION
      {
        NTSTATUS                ExitStatus;
        PVOID                   TebBaseAddress;
        CLIENT_ID               ClientId;
        KAFFINITY               AffinityMask;
        KPRIORITY               Priority;
        KPRIORITY               BasePriority;
      } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
      

      【讨论】:

        【解决方案4】:

        据我所知,Toolhelp 的工作原理是复制有关堆、模块、进程和线程的基本信息。这不包括包含堆栈底部地址的 TEB 块。我认为您需要使用另一个 API,即调试器引擎 API,它提供 functions to examine the stacks

        【讨论】:

          【解决方案5】:

          这是当前线程(便携式Win32 x86/x64版本)的简单方法:

          #include <intrin.h>
          
          NT_TIB* getTIB() {
          #ifdef _M_IX86
            return (NT_TIB*)__readfsdword(0x18);
          #elif _M_AMD64
            return (NT_TIB*)__readgsqword(0x30);
          #else
          #error unsupported architecture
          #endif
          }
          
            NT_TIB* tib = getTIB();
            void* stackBase = tib->StackBase;
            void* stackLimit = tib->StackLimit;
          

          注意:stackLimit stackBase(随着堆栈向下增长)。

          更多详情请参考Win32 TIB

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-06
            • 1970-01-01
            相关资源
            最近更新 更多