Figure 1 SHOWTIB
TIB.H
//===========================================================
// File: TIB.H
// Author: Matt Pietrek
// From: Microsoft Systems Journal "Under the Hood", May 1996
//===========================================================
#pragma pack(1)
typedef struct _EXCEPTION_REGISTRATION_RECORD
{
struct _EXCEPTION_REGISTRATION_RECORD * pNext;
FARPROC pfnHandler;
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;
typedef struct _TIB
{
PEXCEPTION_REGISTRATION_RECORD pvExcept; // 00h Head of exception record list
PVOID pvStackUserTop; // 04h Top of user stack
PVOID pvStackUserBase; // 08h Base of user stack
union // 0Ch (NT/Win95 differences)
{
struct // Win95 fields
{
WORD pvTDB; // 0Ch TDB
WORD pvThunkSS; // 0Eh SS selector used for thunking to 16 bits
DWORD unknown1; // 10h
} WIN95;
struct // WinNT fields
{
PVOID SubSystemTib; // 0Ch
ULONG FiberData; // 10h
} WINNT;
} TIB_UNION1;
PVOID pvArbitrary; // 14h Available for application use
struct _tib *ptibSelf; // 18h Linear address of TIB structure
union // 1Ch (NT/Win95 differences)
{
struct // Win95 fields
{
WORD TIBFlags; // 1Ch
WORD Win16MutexCount; // 1Eh
DWORD DebugContext; // 20h
DWORD pCurrentPriority; // 24h
DWORD pvQueue; // 28h Message Queue selector
} WIN95;
struct // WinNT fields
{
DWORD unknown1; // 1Ch
DWORD processID; // 20h
DWORD threadID; // 24h
DWORD unknown2; // 28h
} WINNT;
} TIB_UNION2;
PVOID* pvTLSArray; // 2Ch Thread Local Storage array
union // 30h (NT/Win95 differences)
{
struct // Win95 fields
{
PVOID* pProcess; // 30h Pointer to owning process database
} WIN95;
} TIB_UNION3;
} TIB, *PTIB;
#pragma pack()
SHOWTIB.CPP
//==========================================================================
// File: SHOWTIB.CPP
// Author: Matt Pietrek
// To Build:
// CL /MT SHOWTIB.CPP USER32.LIB (Visual C++)
// BCC32 -tWM SHOWTIB.CPP (Borland C++, TASM32 required)
//==========================================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#pragma hdrstop
#include "tib.h"
#define SHOWTIB_MAX_THREADS 64
CRITICAL_SECTION gDisplayTIB_CritSect;
void DisplayTIB( PSTR pszThreadName )
{
PTIB pTIB;
WORD fsSel;
EnterCriticalSection( &gDisplayTIB_CritSect );
__asm
{
mov EAX, FS:[18h]
mov [pTIB], EAX
mov [fsSel], FS
}
printf( "Contents of thread %s\n", pszThreadName );
printf( " TIB %04X (Address: %08X)\n", fsSel, pTIB );
printf( " SEH chain: %08X\n", pTIB->pvExcept );
printf( " Stack top: %08X\n", pTIB->pvStackUserTop );
printf( " Stack base: %08X\n", pTIB->pvStackUserBase );
printf( " pvArbitray: %08X\n", pTIB->pvArbitrary );
printf( " TLS array *: %08X\n", pTIB->pvTLSArray );
printf( " ----OS Specific fields----\n" );
if ( 0xC0000000 == (GetVersion() & 0xC0000000) ) // Is this Win95 ?
{
printf( " TDB: %04X\n", pTIB->TIB_UNION1.WIN95.pvTDB );
printf( " Thunk SS: %04X\n", pTIB->TIB_UNION1.WIN95.pvThunkSS );
printf( " TIB flags: %04X\n", pTIB->TIB_UNION2.WIN95.TIBFlags );
printf( " Win16Mutex count: %04X\n",
pTI->TIB_UNION2.WIN95.Win16MutexCount );
printf( " DebugContext: %08X\n", pTIB->TIB_UNION2.WIN95.DebugContext );
printf( " Current Priority *: %08X (%u)\n",
pTIB->TIB_UNION2.WIN95.pCurrentPriority,
*(PDWORD)(pTIB->TIB_UNION2.WIN95.pCurrentPriority) );
printf( " Queue: %04X\n", pTIB->TIB_UNION2.WIN95.pvQueue );
printf( " Process *: %08X\n", pTIB->TIB_UNION3.WIN95.pProcess );
}
else if ( 0 == (GetVersion() & 0xC0000000) ) // Is this WinNT?
{
printf(" SubSystem TIB: %08X\n", pTIB->TIB_UNION1.WINNT.SubSystemTib);
printf(" FiberData: %08X\n", pTIB->TIB_UNION1.WINNT.FiberData );
printf(" unknown1: %08X\n", pTIB->TIB_UNION2.WINNT.unknown1);
printf(" process ID: %08X\n", pTIB->TIB_UNION2.WINNT.processID);
printf(" thread ID: %08X\n", pTIB->TIB_UNION2.WINNT.threadID);
printf(" unknown2: %08X\n", pTIB->TIB_UNION2.WINNT.unknown2);
}
else
{
printf(" Unsupported Win32 implementation\n" );
}
printf( "\n" );
LeaveCriticalSection( &gDisplayTIB_CritSect );
}
void MyThreadFunction( void * threadParam )
{
char szThreadName[128];
wsprintf( szThreadName, "%u", threadParam ); // Give the thread a name
// If multiple threads are specified, give'em different priorities
if ( (DWORD)threadParam & 1 )
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST );
DisplayTIB( szThreadName ); // Display the thread's TIB
// Let other threads execute while this thread is still alive. The idea
// here is to try and prevent memory region and selector reuse.
Sleep( 1000 );
}
int main( int argc, char *argv[] )
{
if ( argc < 2 )
{
printf( "Syntax: SHOWTIB [# of threads]\n" );
return 1;
}
InitializeCriticalSection( &gDisplayTIB_CritSect );
unsigned cThreads = atoi( argv[1] );
if ( (cThreads < 1) || (cThreads > SHOWTIB_MAX_THREADS) )
{
printf( "thread count must be > 1 and < %u\n", SHOWTIB_MAX_THREADS );
}
else
{
// Allocate an array to hold the thread handles
HANDLE threadHandles[ SHOWTIB_MAX_THREADS ];
// Create the specified number of threads
for ( unsigned i = 0; i < cThreads; i++ )
threadHandles[i] = (HANDLE)
_beginthread(MyThreadFunction,0,(PVOID)i);
// Wait for all the threads to finish before we exit the program
WaitForMultipleObjects( cThreads, threadHandles, TRUE, INFINITE );
// We don't need the thread handles anymore. Close'em!
for ( i = 0; i < cThreads; i++ )
CloseHandle( threadHandles[i] );
}
DeleteCriticalSection( &gDisplayTIB_CritSect );
return 0;
}