Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

676 lines
18 KiB

/*++
Copyright (c) 2002 Microsoft Corporation
Module Name:
tls.cpp
Abstract:
WinDbg Extension Api
Author:
Deon Brewis (deonb) 2-Jun-2002
Environment:
User Mode.
Kernel Mode.
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <time.h>
#define TLS_ALL -2
#define TLS_CURRENT -1
// #define TLS_DBG
#ifdef TLS_DBG
#define trace dprintf
#else
#define trace __noop
#endif
EXTERN_C BOOL GetTeb32FromWowTeb(ULONG64 Teb, PULONG64 pTeb32); // implemented in peb.c
EXTERN_C BOOL GetPeb32FromWowTeb(ULONG64 Teb, PULONG64 pPeb32); // implemented in peb.c
BOOLEAN TestBit (
IN PRTL_BITMAP BitMapHeader,
IN ULONG BitNumber
)
{
PCHAR ByteAddress;
ULONG ShiftCount;
ASSERT(BitNumber < BitMapHeader->SizeOfBitMap);
ByteAddress = (PCHAR)BitMapHeader->Buffer + (BitNumber >> 3);
ShiftCount = BitNumber & 0x7;
return (BOOLEAN)((*ByteAddress >> ShiftCount) & 1);
}
ULONG64 GetPebForTarget()
{
ULONG64 pebAddress;
ULONG64 peb;
pebAddress = GetExpression("@$peb");
ULONG64 tebAddress;
tebAddress = GetExpression("@$teb");
if (tebAddress)
{
if (TargetMachine == IMAGE_FILE_MACHINE_IA64 && tebAddress)
{
ULONG64 Peb32=0;
if (GetPeb32FromWowTeb(tebAddress, &Peb32) && Peb32)
{
trace("Wow64 PEB32 at %lx\n", Peb32);
pebAddress = Peb32;
}
}
}
if (pebAddress)
{
trace( "PEB at %p\n", pebAddress );
peb = IsPtr64() ? pebAddress : (ULONG64)(LONG64)(LONG)pebAddress;
}
else
{
trace( "PEB NULL...\n" );
peb = 0;
}
return peb;
}
ULONG64 GetTebForTarget(ULONG64 ulThread)
{
trace("GetTebForTarget %p\n", ulThread);
ULONG64 tebAddress;
ULONG64 teb;
if (TLS_ALL == ulThread)
{
return 0;
}
if (TLS_CURRENT == ulThread)
{
tebAddress = GetExpression("@$teb");
}
else
{
tebAddress = ulThread; // GetTebForThread!!
}
if ( tebAddress )
{
if (TargetMachine == IMAGE_FILE_MACHINE_IA64 && tebAddress)
{
ULONG64 Teb32=0;
if (GetTeb32FromWowTeb(tebAddress, &Teb32) && Teb32)
{
trace("Wow64 TEB32 at %p\n", Teb32);
tebAddress = Teb32;
trace("\n\nWow64 ");
}
}
trace( "TEB at %p\n", tebAddress);
}
else
{
trace( "TEB NULL...\n" );
teb = 0;
}
if (tebAddress)
{
teb = IsPtr64() ? tebAddress : (ULONG64)(LONG64)(LONG)tebAddress;
}
else
{
teb = 0;
}
return teb;
}
// Function: HrReadPRtlBitmap
//
// Arguments: Address [in] Location of RTL BITMAP
// pRtlBitmap [out] RTL Bitmap. Free with LocalFree / not
HRESULT HrReadPRtlBitmap(IN ULONG64 pAddress, OUT PRTL_BITMAP *ppRtlBitmap)
{
HRESULT hr = S_OK;
if (!pAddress || !ppRtlBitmap)
{
return E_INVALIDARG;
}
ULONG64 Address;
if (!ReadPointer(pAddress, &Address))
{
*ppRtlBitmap = NULL;
return E_FAIL;
}
DWORD dwPtrSize;
if (IsPtr64())
{
dwPtrSize = sizeof(DWORD64);
}
else
{
dwPtrSize = sizeof(DWORD);
}
ULONG SizeOfBitMap;
if (ReadMemory(Address, &SizeOfBitMap, sizeof(SizeOfBitMap), NULL))
{
*ppRtlBitmap = reinterpret_cast<PRTL_BITMAP>(LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(RTL_BITMAP) + (SizeOfBitMap / 8) ));
if (*ppRtlBitmap)
{
// Create an internal pointer into itself
(*ppRtlBitmap)->Buffer = reinterpret_cast<PULONG>(reinterpret_cast<LPBYTE>(*ppRtlBitmap) + sizeof(RTL_BITMAP));
(*ppRtlBitmap)->SizeOfBitMap = SizeOfBitMap;
ULONG64 pBuffer = NULL;
if (ReadPointer(Address + dwPtrSize, &pBuffer))
{
if (!ReadMemory(pBuffer, (*ppRtlBitmap)->Buffer, SizeOfBitMap / 8, NULL))
{
hr = E_FAIL;
}
}
else
{
hr = E_FAIL;
}
if (FAILED(hr))
{
LocalFree(*ppRtlBitmap);
*ppRtlBitmap = NULL;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
#define return_msg(hr, msg) dprintf(msg); return hr;
//
// Function: DumpTls
//
// Arguments:
// ulSlot [in] Slot id || TLS_ALL for all.
// ulThread [in] Thread id || TLS_CURRENT for current || TLS_ALL for all
//
// Returns: S_OK is succeeded
//
HRESULT
DumpTls (
IN ULONG ulSlot,
IN ULONG64 ulThread,
IN LPCWSTR szThreadDescription
)
{
HRESULT hr;
trace("DUMPTLS: %p %p\n", ulSlot, ulThread);
if ( (TLS_ALL != ulSlot) && (ulSlot > 1088) )
{
return_msg (E_INVALIDARG, "Slot must be 0 to 1088 (or -1 to dump slot 0)\n");
}
ULONG64 Peb = GetPebForTarget();
if (!Peb)
{
return_msg (E_INVALIDARG, "Could not get Peb for target - check your symbols for nt!\n");
}
trace("Peb = %p\n", Peb);
ULONG64 Teb = GetTebForTarget(ulThread);
if (!Teb)
{
return_msg (E_INVALIDARG, "Could not get Teb for target - check your symbols for nt!\n");
}
trace("Teb = %p\n", Teb);
WCHAR szOwnDescription[MAX_PATH];
if ( (TLS_CURRENT == ulThread) && !szThreadDescription)
{
ULONG64 ethread = GetExpression("@$thread");
if (ethread)
{
if (ERROR_SUCCESS == InitTypeRead(ethread, nt!_ETHREAD))
{
ULONG64 Cid_UniqueProcess = GetExpression("@$tpid");
ULONG64 Cid_UniqueThread = GetExpression("@$tid");
if (Cid_UniqueProcess && Cid_UniqueThread)
{
trace("%04x %1p.%1p\n", ulSlot, Cid_UniqueProcess, Cid_UniqueThread);
swprintf(szOwnDescription, L"%I64x.%I64x", Cid_UniqueProcess, Cid_UniqueThread);
szThreadDescription = szOwnDescription;
}
}
}
}
if (TLS_ALL == ulSlot)
{
if (szThreadDescription)
{
dprintf("TLS slots on thread: %S\n", szThreadDescription);
}
else
{
dprintf("TLS slots on thread: %p\n", Teb);
}
}
DWORD dwPtrSize;
if (IsPtr64())
{
dwPtrSize = sizeof(DWORD64);
}
else
{
dwPtrSize = sizeof(DWORD);
}
hr = E_FAIL;
PRTL_BITMAP pTlsBitmap = NULL;
PRTL_BITMAP pTlsExpansionBitmap = NULL;
ULONG TlsBitmap_Offset;
GetFieldOffset("PEB", "TlsBitmap", &TlsBitmap_Offset);
if (TlsBitmap_Offset)
{
ULONG TlsExpansionBitmap_Offset;
GetFieldOffset("PEB", "TlsExpansionBitmap", &TlsExpansionBitmap_Offset);
if (TlsExpansionBitmap_Offset)
{
hr = HrReadPRtlBitmap(Peb + TlsBitmap_Offset, &pTlsBitmap);
if (SUCCEEDED(hr))
{
hr = HrReadPRtlBitmap(Peb + TlsExpansionBitmap_Offset, &pTlsExpansionBitmap);
if (SUCCEEDED(hr))
{
trace("pTlsBitmap: %p\n", pTlsBitmap);
trace("pTlsExpansionBitmap: %p\n", pTlsExpansionBitmap);
}
}
}
}
if (FAILED(hr))
{
LocalFree(pTlsBitmap);
LocalFree(pTlsExpansionBitmap);
return_msg (E_FAIL, "Could not get read TlsBitmap or TlsExpansionBitmap in peb - check your symbols for nt!\n");
}
hr = E_FAIL;
ULONG TlsSlots_Offset;
ULONG TlsExpansionSlots_Offset;
GetFieldOffset("TEB", "TlsSlots", &TlsSlots_Offset);
if (TlsSlots_Offset)
{
GetFieldOffset("TEB", "TlsExpansionSlots", &TlsExpansionSlots_Offset);
if (TlsExpansionSlots_Offset)
{
hr = S_OK;
}
}
if (FAILED(hr))
{
LocalFree(pTlsBitmap);
LocalFree(pTlsExpansionBitmap);
return_msg (E_FAIL, "Could not get read TlsSlots or TlsExpansionSlots in teb - check your symbols for nt!\n");
}
if (TLS_ALL == ulSlot)
{
trace("All slots\n");
LPBYTE arrTlsSlots = new BYTE[dwPtrSize * 1088];
if (arrTlsSlots)
{
hr = E_FAIL;
if (ReadMemory(Teb + TlsSlots_Offset, arrTlsSlots, 64 * dwPtrSize, NULL))
{
ULONG64 pTlsExpansionSlots;
if (ReadPointer(Teb + TlsExpansionSlots_Offset, &pTlsExpansionSlots))
{
hr = S_OK;
if (pTlsExpansionSlots)
{
if (!ReadMemory(pTlsExpansionSlots, arrTlsSlots + (64 * dwPtrSize), 1024, NULL))
{
hr = E_FAIL;
}
}
}
}
if (FAILED(hr))
{
delete[] arrTlsSlots;
LocalFree(pTlsBitmap);
LocalFree(pTlsExpansionBitmap);
return_msg (E_FAIL, "Could not read content of Tls Slots from teb - check your symbols for nt!\n");
}
BOOL bFound = FALSE;
for (int x = 0; x < 1088; x++)
{
if (CheckControlC())
{
delete[] arrTlsSlots;
LocalFree(pTlsBitmap);
LocalFree(pTlsExpansionBitmap);
return FALSE;
}
BOOL bSet = FALSE;
if (x < TLS_MINIMUM_AVAILABLE)
{
if (!TestBit(pTlsBitmap, x))
{
continue;
}
else
{
bFound = TRUE;;
}
}
else
{
if (!TestBit(pTlsExpansionBitmap, x - TLS_MINIMUM_AVAILABLE))
{
continue;
}
else
{
bFound = TRUE;;
}
}
if ( sizeof(DWORD64) == dwPtrSize )
{
dprintf("0x%04x : %p\n", x, reinterpret_cast<DWORD64*>(arrTlsSlots)[x]);
}
else
{
dprintf("0x%04x : %p\n", x, reinterpret_cast<DWORD*>(arrTlsSlots)[x]);
}
}
if (!bFound)
{
dprintf(" No TLS slots have been allocated for this process.\n");
}
delete[] arrTlsSlots;
}
}
else
{
ULONG64 Tls_Location = 0;
if (ulSlot < TLS_MINIMUM_AVAILABLE)
{
Tls_Location = Teb + TlsSlots_Offset + ulSlot * dwPtrSize;
}
else
{
if (ReadPointer(Teb + TlsExpansionSlots_Offset, &Tls_Location))
{
Tls_Location += (ulSlot * dwPtrSize);
}
}
if (!Tls_Location)
{
LocalFree(pTlsBitmap);
LocalFree(pTlsExpansionBitmap);
return_msg (E_FAIL, "Could not read content TlsLocation from teb - check your symbols for nt!\n");
}
ULONG64 Tls_SlotX;
if (ReadPointer(Tls_Location, &Tls_SlotX))
{
if (szThreadDescription)
{
dprintf("%S: %p\n", szThreadDescription, Tls_SlotX);
}
else
{
dprintf("%I64x: %p\n", Teb, szThreadDescription, Tls_SlotX);
}
}
else
{
dprintf("Could not read TLS value from %p - check your symbols for nt!\n", Tls_Location);
}
}
LocalFree(pTlsBitmap);
LocalFree(pTlsExpansionBitmap);
return TRUE;
}
HRESULT DumpThreadsUserMode(ULONG ulSlot)
{
ULONG ulOldThread;
HRESULT hr = g_ExtSystem->GetCurrentThreadId(&ulOldThread);
if (SUCCEEDED(hr))
{
ULONG ulNumThreads;
hr = g_ExtSystem->GetNumberThreads(&ulNumThreads);
if (SUCCEEDED(hr))
{
trace("Threads (current %d): %d\n", ulOldThread, ulNumThreads);
PULONG pIds = new ULONG[ulNumThreads];
if (pIds)
{
PULONG pSysIds = new ULONG[ulNumThreads];
if (pSysIds)
{
hr = g_ExtSystem->GetThreadIdsByIndex(0, ulNumThreads, pIds, pSysIds);
if (SUCCEEDED(hr))
{
if (TLS_ALL != ulSlot)
{
dprintf("Per-thread values for slot 0x%03x:\n", static_cast<DWORD>(ulSlot));
}
for (ULONG x = 0; x < ulNumThreads; x++)
{
hr = g_ExtSystem->SetCurrentThreadId(pIds[x]);
if (SUCCEEDED(hr))
{
ULONG64 Cid_UniqueProcess = GetExpression("@$tpid");
ULONG64 teb;
g_ExtSystem->GetCurrentThreadTeb(&teb);
WCHAR szThreadDescription[MAX_PATH];
swprintf(szThreadDescription, L"%I64x.%1x", Cid_UniqueProcess, pSysIds[x]);
trace("Thread: %d %d %x %x\n", x, pIds[x], pSysIds[x], teb);
DumpTls (ulSlot, teb, szThreadDescription);
}
}
}
delete[] pSysIds;
}
delete[] pIds;
}
}
g_ExtSystem->SetCurrentThreadId(ulOldThread);
}
return S_OK;
}
ULONG
ThreadListCallback (
PFIELD_INFO NextThrd,
PVOID Context
)
{
ULONG ulSlot = static_cast<ULONG>(reinterpret_cast<ULONG_PTR>(Context));
ULONG64 RealThreadBase = NextThrd->address;
if (!IsPtr64())
{
RealThreadBase = (ULONG64) (LONG64) (LONG) RealThreadBase;
}
trace("Reading %p\n", RealThreadBase);
if (InitTypeRead(RealThreadBase, nt!_ETHREAD))
{
dprintf("*** Error in in reading nt!_ETHREAD @ %p\n", RealThreadBase);
return TRUE;
}
ULONG64 Cid_UniqueProcess = ReadField(Cid.UniqueProcess);
ULONG64 Cid_UniqueThread = ReadField(Cid.UniqueThread);
ULONG64 Teb = ReadField(Tcb.Teb);
trace("%04x %1p.%1p %1p\n", ulSlot, Cid_UniqueProcess, Cid_UniqueThread, Teb);
WCHAR szThreadDescription[MAX_PATH];
swprintf(szThreadDescription, L"%I64x.%I64x", Cid_UniqueProcess, Cid_UniqueThread);
DumpTls (ulSlot, Teb, szThreadDescription);
return FALSE;
}
HRESULT DumpThreadsKernelMode(ULONG ulSlot)
{
trace("DumpThreadsKernelMode %p %p\n", ulSlot);
ULONG64 ThreadListHead_Flink = 0;
ULONG64 process = GetExpression("@$proc");
trace("Process is %p\n", process);
GetFieldValue(process, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink", ThreadListHead_Flink);
trace("GetFieldValue returned %p\n", ThreadListHead_Flink);
ULONG64 Next;
if (!ReadPointer(ThreadListHead_Flink, &Next) ||
(Next == ThreadListHead_Flink))
{
trace("Empty\n");
return S_OK;
}
if (TLS_ALL != ulSlot)
{
dprintf("Per-thread values for slot 0x%03x:\n", static_cast<DWORD>(ulSlot));
}
ULONG ulList = ListType("nt!_ETHREAD", ThreadListHead_Flink, 1,
"Tcb.ThreadListEntry.Flink", reinterpret_cast<LPVOID>(static_cast<ULONG_PTR>(ulSlot)), &ThreadListCallback);
trace("ListType returned %x\n",ListType);
return S_OK;
}
DECLARE_API( tls )
{
ULONG64 ulProcess = NULL;
ULONG64 ulThread = NULL;
ULONG64 ul64Slot = NULL;
ULONG ulSlot = NULL;
INIT_API();
BOOL bKernelMode = FALSE;
KDDEBUGGER_DATA64 kdd;
if (GetDebuggerData('GBDK', &kdd, sizeof(kdd)))
{
bKernelMode = TRUE;
}
// Skip past leading spaces
while (*args == ' ')
{
args++;
}
if (!GetExpressionEx(args, &ul64Slot, &args))
{
dprintf("Usage:\n"
"tls <slot> [teb]\n"
" slot: -1 to dump all allocated slots\n"
" {0-1088} to dump specific slot\n"
" teb: <empty> for current thread\n"
" 0 for all threads in this process\n"
" <teb address> (not threadid) to dump for specific thread.\n"
);
return S_OK;
}
ulSlot = static_cast<ULONG>(ul64Slot);
if (ulSlot == -1)
{
ulSlot = TLS_ALL;
}
if (!GetExpressionEx(args, &ulThread, &args))
{
ulThread = TLS_CURRENT;
}
if (0 == ulThread)
{
if (bKernelMode)
{
DumpThreadsKernelMode(ulSlot);
}
else
{
DumpThreadsUserMode(ulSlot);
}
}
else
{
DumpTls (ulSlot, ulThread, NULL);
}
EXIT_API();
return S_OK;
}