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; }