r5sdk/r5dev/thirdparty/ea/EAThread/source/pc/eathread_callstack_win32.cpp
Kawe Mazidjatari b3a68ed095 Add EABase, EAThread and DirtySDK to R5sdk
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
2024-04-05 18:29:03 +02:00

144 lines
3.3 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#include <EABase/eabase.h>
#include <eathread/eathread_callstack.h>
#include <eathread/eathread_callstack_context.h>
#include <eathread/eathread_storage.h>
#pragma warning(push, 0)
#include <Windows.h>
#pragma warning(pop)
namespace EA
{
namespace Thread
{
///////////////////////////////////////////////////////////////////////////////
// GetThreadIdFromThreadHandle
//
//
EATHREADLIB_API uint32_t GetThreadIdFromThreadHandle(intptr_t threadId)
{
struct THREAD_BASIC_INFORMATION_WIN32
{
BOOL ExitStatus;
PVOID TebBaseAddress;
DWORD UniqueProcessId;
DWORD UniqueThreadId;
DWORD AffinityMask;
DWORD Priority;
DWORD BasePriority;
};
static HMODULE hKernel32 = NULL;
if (!hKernel32)
hKernel32 = LoadLibraryA("kernel32.dll");
if (hKernel32)
{
typedef DWORD (WINAPI *GetThreadIdFunc)(HANDLE);
static GetThreadIdFunc pGetThreadIdFunc = NULL;
if (!pGetThreadIdFunc)
pGetThreadIdFunc = (GetThreadIdFunc)(uintptr_t)GetProcAddress(hKernel32, "GetThreadId");
if (pGetThreadIdFunc)
return pGetThreadIdFunc((HANDLE)threadId);
}
static HMODULE hNTDLL = NULL;
if (!hNTDLL)
hNTDLL = LoadLibraryA("ntdll.dll");
if (hNTDLL)
{
typedef LONG (WINAPI *NtQueryInformationThreadFunc)(HANDLE, int, PVOID, ULONG, PULONG);
static NtQueryInformationThreadFunc pNtQueryInformationThread = NULL;
if (!pNtQueryInformationThread)
pNtQueryInformationThread = (NtQueryInformationThreadFunc)(uintptr_t)GetProcAddress(hNTDLL, "NtQueryInformationThread");
if (pNtQueryInformationThread)
{
THREAD_BASIC_INFORMATION_WIN32 tbi;
if(pNtQueryInformationThread((HANDLE)threadId, 0, &tbi, sizeof(tbi), NULL) == 0)
return tbi.UniqueThreadId;
}
}
return 0;
}
namespace Internal
{
struct TIBStackInfo
{
uintptr_t StackBase;
uintptr_t StackLimit;
};
static TIBStackInfo GetStackInfo()
{
NT_TIB* pTib;
/**
* Offset 0x18 from the FS segment register gives a pointer to
* the thread information block for the current thread
* https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
*/
__asm {
mov eax, fs:[18h]
mov pTib, eax
}
return { ((uintptr_t)pTib->StackBase), ((uintptr_t)pTib->StackLimit) };
}
} // namespace Internal
///////////////////////////////////////////////////////////////////////////////
// SetStackBase
//
EATHREADLIB_API void SetStackBase(void* /*pStackBase*/)
{
// Nothing to do, as GetStackBase always works on its own.
}
///////////////////////////////////////////////////////////////////////////////
// GetStackBase
//
EATHREADLIB_API void* GetStackBase()
{
Internal::TIBStackInfo info = Internal::GetStackInfo();
return ((void*)info.StackBase);
}
///////////////////////////////////////////////////////////////////////////////
// GetStackLimit
//
EATHREADLIB_API void* GetStackLimit()
{
Internal::TIBStackInfo info = Internal::GetStackInfo();
return ((void*)info.StackLimit);
// Alternative which returns a slightly different answer:
// We return our stack pointer, which is a good approximation of the stack limit of the caller.
// void* pStack = NULL;
// __asm { mov pStack, ESP};
// return pStack;
}
} // namespace Thread
} // namespace EA