Click to See Complete Forum and Search --> : dumping stack for all threads


Bornish
September 4th, 2004, 10:05 AM
Aloha!
I'm in a bit of a jam... any hints will be greatly appreciated.
Description:
There's this multithreaded process which throws an exception. In the exception handler, am trying to dump the stack for all the threads in the process. For the thread generating the exception is a piece of cake, and I figured will be almost as easy for the other threads:
Step 1 - get the context of each thread using GetThreadContext() API
Step 2 - get TIB (Thread Information Block) of the thread in question
Step 3 - dump from stack's top until stack's base
Unexpected result:
I believed that when switching the thread's context for yielding the execution to a different thread, SegFs member of the CONTEXT structure must have a different value from one thread to another, in order to have FS:[18h] pointing to a different TIB structure. It seems I was wrong!
Questions:
- Is the following function retrieving the TIB of the calling thread?
static tagXTIB* GetTIB()
{
tagXTIB* pTib;
__asm
{
MOV EAX , FS:[18h]
MOV pTib , EAX
}
return pTib;
}...where tagXTIB is defined as:
typedef struct tagXTIB
{
PEXCEPTION_REGISTRATION_RECORD pvExcept; //00h Head of exception record list
PVOID pvStackUserTop; //04 Top of user stack
PVOID pvStackUserBase; //08h Base of user stack
union
{
struct //Win95 fields
{
WORD pvTDB; //0Ch
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
struct _tib *ptibSelf; //18h Linear address of TIB structure
union
{
struct //Win95 fields
{
WORD TIBFlags; //1Ch
WORD Win16MutexCount; //1Eh
DWORD DebugContext; //20h
DWORD pCurrentPriority; //24h
DWORD pvQueue; //28h Message Queue
} WIN95;
struct //WinNT fields
{
DWORD unknown1; //1Ch
DWORD processID; //20h
DWORD threadID; //24h
DWORD unknown2; //28h
} WINNT;
} TIB_UNION2;
PVOID* pvTLSArray;
union
{
struct //Win95 fields
{
PVOID* pProcess; //30h Pointer to owning process database
} WIN95;
} TIB_UNION3;
} XTIB;
#pragma pack() - Are the pvStackUserTop & pvStackUserBase members of tagXTIB structure the addresses defining the memory interval where the thread's stack is located?

- Do you know any other way of getting these values, besides reading them from the TIB?

- In order to get the address of the TIB for all the other threads of the process (not the calling thread), is it correct to use the SegFs member of the CONTEXT structure filled by a GetThreadContext() call, instead of FS from GetTIB() function?

- Then, why SegFs is equal with FS? Makes no sense to get the TIBs this way, since FS:[18h] will be equal with SegFs:[18h], but TIB should be different for two threads, isn't it?

Conclusions:
My interest is to dump the stack for each thread belonging to the process. Having the stack's top & base addresses, and also the Esp pointer (which seems to be retrieved correctly by the API), I will be able to list the call stack. All registers are looking as valid information, as returned by GetThreadContext() API. I've checked Eip value, too. So, makes me believe that SegFs is also correct. But then, why has the same value with the calling thread's FS? If so, from where to read the TIB of the other threads? Or, at least, how to get the correct location of their stack (because I know for sure that threads are not sharing the stack)?

Many anticipated thanks,

Krishnaa
July 9th, 2006, 09:26 AM
I am not sure if your question is answered already, so excuse me if I am posting in old thread. :)

Here is a good article from Matt Patriek on TIBs, Very similar to what you are trying to do,

MSJ Article on TIBs
http://www.microsoft.com/msj/archive/S2CE.aspx

He also had the sample code (SHOWTIB), see DisplayTIB function, not present in source code downloads (at least I couldnt find it there)
So here is a copy I got from somewhere on web,

tib.h and showtib.cpp

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

Bornish
July 10th, 2006, 05:11 AM
Thanks Krishnaa for your reply! I appreciate your effort of gathering some information about TIBs, but unfortunatelly does not answer my question. Your sample code displays the TIB of each thread from within the threads themselves. What I am looking for is to read from a thread "A" the TIB of a thread "B". I assume it is possible to obtain the address of the TIB of each thread in the process when an exception occurs because most debuggers can.
This is my purpose: to install a "global" hook for a process which catches all exceptions raised by all its threads, and log some info about the state of all threads (not only the one that raised the exception). I have managed to implement everything else (including exe patching used to debug applications which can't be recompiled) but currently my log contains only info about the thread that crashed (i do log only unhandled exceptions, not handled ones) and sometimes that isn't enough to catch a bug.
I have also implemented a function call stack retrieval algorithm that works also in some cases of corrupted stack (a bit better than the one in VS 6.0, and similar to the one in VS 7.1). When exceptions are not handled, my implementation uses some heuristics, trying to skip the bad code and resume execution, which in many cases helps an application to regain control and let the user save data,... etc.
Before I've posted here I have read most of the related articles (also from MSJ) I could find and tested many sample source code, but unfortunatelly I couldn't find an answer until today, after more than 2 years since it all started.

Regards,

Krishnaa
July 10th, 2006, 05:54 AM
Ohh...

Are those other threads suspended before using GetThreadContext() ?

Bornish
July 10th, 2006, 06:20 AM
Ohh...

Are those other threads suspended before using GetThreadContext() ?
Yes, but FS register contains the address of the TIB for the calling thread, so: __asm
{
mov EAX, FS:[18h]
mov [pTIB], EAX
mov [fsSel], FS
}will not help to obtain the address of the TIB of another thread. In fact, I would be happy enough to get the "top" and "base" address for the stack of each thread when the unhandled exception occurs. Yes, all threads are suspended and other requirements met, but I need to figure out how context switching occurs. Do I have to execute code in Ring 0 to be able to access this kind of information? I don't even know where to start looking into this matter. uf... :mad:

Krishnaa
July 10th, 2006, 06:32 AM
I am not sure of TIB information, but here is one StackWalker written by Jochen Kalmbach [MVP VC++], It can dump the stack for any thread, of any process.

http://www.codeproject.com/threads/StackWalker.asp

This can at least meet your requirement of dumping the call stack of all threads.

Bornish
July 10th, 2006, 07:36 AM
I am not sure of TIB information, but here is one StackWalker written by Jochen Kalmbach [MVP VC++], It can dump the stack for any thread, of any process.

http://www.codeproject.com/threads/StackWalker.asp

This can at least meet your requirement of dumping the call stack of all threads.Thanks for finding this article for me. The source code is quite well documented, and hope it will work with multiple threads (didn't have time yet to test it in a multithreaded app). I recall having GetThreadContext working just fine for most registers (eax, ecx,...) but returning the same value for FS register of different threads, which confused me in the way TIB are retrieved. I'll go through the StackWalker and figure out what is it doing to get the info about all threads of a process.
Thanks for all your help,

Krishnaa
July 10th, 2006, 07:41 AM
I have tested it, by uncommenting the TestDifferentThread() call in _tmain() function. It works pretty well.
:)

Bornish
July 10th, 2006, 08:43 AM
I have tested it, by uncommenting the TestDifferentThread() call in _tmain() function. It works pretty well.
:) :thumb: Thanks, I will have a look as soon as I get the time. I still wonder why the SegFS returned by GetThreadContext is the same as FS register of the calling thread, for a given handle of a different thread.