我通过CreateToolhelp32Snapshot
函数枚举进程中的所有线程。我想获得每个线程的一些基本堆栈信息。更具体地说,我想获得堆栈底部地址,如果可能的话,我想获得当前的堆栈顶部地址。基本上这是在WinDbg中使用~*k
命令显示的信息。那么如何从线程的ID或HANDLE中获取堆栈信息呢?
答案 0 :(得分:9)
(可以找到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
。
答案 1 :(得分:1)
无需涉及Windows驱动程序工具包的更简单方法如下:
NT_TIB* tib = (NT_TIB*)__readfsdword(0x18);
size_t* stackBottom = (size_t*)tib->StackLimit;
size_t* stackTop = (size_t*)tib->StackBase;
答案 2 :(得分:1)
__ 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;
答案 3 :(得分:0)
据我所知,Toolhelp的工作原理是复制堆,模块,进程和线程的基本信息。这不包括包含堆栈底部地址的TEB块。我认为您需要使用另一个API,调试器引擎API,它提供functions to examine the stacks
答案 4 :(得分:0)
这是当前线程(便携式 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。