Re: Frame-based exception handling problem on Server 2008

Tech-Archive recommends: Fix windows errors by optimizing your registry



Corinna Vinschen wrote:
Ivan Brugiolo [MSFT] wrote:
[...]
To debug debug the issue, start from KeUserExceptionDispatcher.
That's the first function you can set a breakpoint on in user mode.
Then, with good symbols, observer the code that walks the frame-handler
list,
and, check if some Rtl*Validate* function is called.

The example code I sent in my reply to Jeffrey (message-id:
<fpmnif$7i4$1@xxxxxxxxxxxxxxx>) is a self-contained testcase.
[...]
I'm not fluent in debugging the OS DLLs. I can surely look into this
after I have set up and learned how to use windbg.

Ok, I bit the bullet, installed WinDbg, Visual-C++ and the debug symbols
for 2008. I changed the example code to compile under Visual-C++ and
debugged according to your above instructions. The call stack when it's
in the endless loop looks like this:

ntdll!RtlDispatchException+0x67
ntdll!KiUserExceptionDispatcher+0xf
exceptionhandler_example!func+0x22
exceptionhandler_example!main+0x6c
exceptionhandler_example!__tmainCRTStartup+0x1a8
exceptionhandler_example!mainCRTStartup+0xf
kernel32!BaseThreadInitThunk+0xe
ntdll!__RtlUserThreadStart+0x23
ntdll!_RtlUserThreadStart+0x1b

When stepping from KiUserExceptionDispatcher to RtlDispatchException,
there is no call to any Rtl*Validate* function, nor is there a call to
RtlIsValidHandler (which is one function which looks like a likely
candidate). The endless loop occurs as soon as the PC is at
ntdll!RtlDispatchException+0x67.

This is the full assembler code of the entire loop:

ntdll!RtlDispatchException+0x67:
76e80d6d 3b5df8 cmp ebx,dword ptr [ebp-8]
76e80d70 0f829ad1feff jb ntdll!RtlDispatchException+0x19d (76e6df10)
76e80d76 8d4308 lea eax,[ebx+8]
76e80d79 3b45f4 cmp eax,dword ptr [ebp-0Ch]
76e80d7c 0f878ed1feff ja ntdll!RtlDispatchException+0x19d (76e6df10)
76e80d82 f6c303 test bl,3
76e80d85 0f8585d1feff jne ntdll!RtlDispatchException+0x19d (76e6df10)
76e80d8b 8b4304 mov eax,dword ptr [ebx+4]
76e80d8e 3b45f8 cmp eax,dword ptr [ebp-8]
76e80d91 7209 jb ntdll!RtlDispatchException+0x96 (76e80d9c)
76e80d93 3b45f4 cmp eax,dword ptr [ebp-0Ch]
76e80d96 0f8274d1feff jb ntdll!RtlDispatchException+0x19d (76e6df10)
76e80d9c 8b1b mov ebx,dword ptr [ebx]
76e80d9e 3bdf cmp ebx,edi
76e80da0 75cb jne ntdll!RtlDispatchException+0x67 (76e80d6d) [br=1]

That's it. It stays in this loop until the process is stopped. Is that
enough for you to debug this further? I don't know what it's doing in
this loop, sorry.

Below is the code of the example applications changed so that it can be
build with VC++:

=================== SNIP ===================
#include <stdio.h>
#include <windows.h>

//#ifdef __GNUC__
extern DWORD __stdcall RtlUnwind (void *, void *, EXCEPTION_RECORD *, void *);
//#endif

struct _exception_list;

typedef int (*exception_handler_t) (EXCEPTION_RECORD *,
struct _exception_list *,
CONTEXT *,
void *);

typedef struct _exception_list
{
struct _exception_list *prev;
exception_handler_t handler;
} exception_list_t;

typedef struct _cygtls
{
exception_list_t el;
} cygtls_t;

#ifdef __GNUC__
extern exception_list_t *_except_list __asm__ ("%fs:0");
#endif

void
init_exception_handler (cygtls_t *tls, exception_handler_t eh, int do_loop)
{
exception_list_t *_except_list;

tls->el.handler = eh;
if (do_loop)
tls->el.prev = &tls->el; // loop back to itself
else
#ifdef __GNUC__
tls->el.prev = _except_list; // Just point to default handler
_except_list = &tls->el;
#else
{
__asm { mov eax, fs:[0]
mov _except_list, eax }
tls->el.prev = _except_list;
}
_except_list = &tls->el;
__asm { mov eax, _except_list
mov fs:[0], eax }
#endif
}

int
handle_exception (EXCEPTION_RECORD *e, exception_list_t *frame,
CONTEXT *c, void *dummy)
{
fputs ("In exception_handler\n", stderr);
RtlUnwind (frame, (void *) c->Eip, e, 0);
return 0;
}

int
func (int a, int b)
{
return a / b;
}

int
main (int argc, char **argv)
{
cygtls_t _my_tls;
init_exception_handler (&_my_tls, handle_exception, argc <= 1);
fputs ("Before func\n", stderr);
func (1, 0);
fputs ("After func\n", stderr);
return 0;
}
=================== SNAP ===================

Corinna

--
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat
.



Relevant Pages