Monday, March 12, 2007

VS Debugger Kung-Fu: Pseudo Variables

In VS2005 while debugging you can view certain variables that are not explicitly defined by your code but defined by the OS enironment. People call them pseudo variables and the official doucmentation is here (msdn) for example here are a couple of the least well known of them:

$user : shows the process token information
$tib : points to the tread information block (TIB) structure (same as FS register)
$vframe : shows you the address of the current stack frame (sometimes in EBP)

From these three the $user is the one that is easiest to grok. It shows you the principal domain\name, the SID, the impersonation level, the priviledges, groups and tells you if the current thread is impersonating. This is very neat except that in a typical VS debugging scenario there is rarely a doubth that you are running as a very priviledged user.

But the one I want to talk about is the $tib one. The Tread information block is a key user-mode structure for windows. Every C or C++ compiler for Windows generates code that uses it. Here is the structure as declared in WinNT.h:
typedef struct _NT_TIB
{
_EXCEPTION_REGISTRATION_RECORD *ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
union {
PVOID FiberData;
DWORD Version;
};
PVOID ArbitraryUserPointer;
struct _NT_TIB *Self;
} NT_TIB;

The TIB is actually the tip of the iceberg; the first part of a larger structure known as the TEB. This structure is so important that in user-mode the FS register always points to it therefore the structure offsets can be used as offsets into the segment pointed to by the FS register. For example, FS:[0] points to the ExceptionList which is the head of structured exception handling chain.

Just bear in mind that each thread has a different TIB so make sure you use the right structure. You can view the current thread structure members by using this incantation on a VS watch window:
(NT_TIB*)$tib

By taking note of the value of the StackBase and StackLimit you can know what is the range of addresses that are normal stack values. Note that StackLimit shows the lowest 'committed' page of the stack. As your program uses more of the thread stack this value will change to lower values. So whenever you a piece of data that you don't recognize you know have a way to find out if it belongs to one of your stacks or belongs to some heap.

For example, for a plain single threaded application it is normal to see the stack base at 0x00130000 which is just 1.1 Mb above the 0 (zero) address, and everybody knows that the default stack size of a win32 thread is 1 Mb, yet you normally see the stack limit being an address closer to the above value than to zero. In fact if you see the stack limit anywhere close 0x00030000 you are having serious stack overflow problems.

Now let's talk about ExceptionList. This member points to the current head of the structured exception chain, an undocumented but well known structure:

typedef struct _EXCEPTION_REGISTRATION_RECORD
{
_EXCEPTION_REGISTRATION_RECORD * pNext;
FARPROC pfnHandler;
} EXCEPTION_REGISTRATION_RECORD


The pNext member (confusingly) points to the previous head of the exception chain while the pfnHandler is the address of function that will be called in case of an exception.

Here is all the code that I am using as reference:

int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{

MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return (int) msg.wParam;
}


In my home computer with a breakpoint in the start of winMain(), (next to the while statement) the stack base is 0x00130000 and the stack limit value is 0x0012d000. The value of ExceptionList is 0x0012ffb0 which is normal and means that the exception record lives very close to the top of the stack. If we dump that memory location we find the exception record:

0x0012FFB0: 0012ffe0 00401f24

Which means that the exception handling routine is at 0x00401f24, which is within our EXE (check the previous blog if you don't know how I know this) and that there is a previous exception record at 0x0012ffe0 also inside the stack (which is a good sanity-check). If we dump that in turn we see:

0x0012FFE0: ffffffff 7c839aa8

And given the 'all ones' value it is obvious there is no previous exception record.

What this all means is that the code in main is executing under two SEH exception frames or in other words it is executing under two nested __try{ }__except( ) blocks. But wait! I don't have SEH in my code?? so how come I have two exception frames? who put them there? why?

By the way (and before we solve the mistery), the method by which these structures are built is a fairly common assembler pattern that you will see a lot when you step thru code and it goes something like this:


PUSH
PUSH FS:[00000000]
MOV DWORD PTR FS:[00000000],ESP


The two push instructions create the new exception registration record in the stack and the mov instruction makes it the new head of the exception chain. So what you just saw was the code that implements the __try part.

Ok, going back to the question the answer is simple: the wWinMain function is not the first function to execute from my EXE; since I compiled with the standard C runtime support, the real entry point to the application is wWinMainCRTStartup(void) which you can find in the VS directories in a file called wwincrt0.c (for VS 2003). If you look at this function you will see that in essense does this:

int wWinMainCRTStartup()
{
int mainret;
//set SEH frame
__try
{
//use win32 API to retrieve the params of winmain
//then call:
mainret = wWinMain(h, NULL, cl, f)
}
__except (_XcptFilter(GetExceptionCode(),
GetExceptionInformation()))
{
mainret = GetExceptionCode();
}
return mainret;
}


This accounts for one SEH frame (the inner one) and the other one is placed by the OS when the thread was created. This outer handler lives as one might expect in kernel32.dll. Ah, one final note about SEH; if you are using C++ try{ }catch{ } they also use SEH under the covers, but of course the inner workings of that are way outside the scope of this post.

So my original point of this post was to show you how to use $tib to find the stack location and to discover the SEH frames that are in scope. The obvious trick here is that if you are debugging strange, magical or just plain wierd behavior on a thread it is not a bad idea to put some breakpoints in the exception handlers and now you know how to find them.

No comments: