Added some exception handling functions.

This commit is contained in:
Jon Griffiths 2001-01-12 20:41:03 +00:00 committed by Alexandre Julliard
parent e884cc2b08
commit 5f308d3cb0
1 changed files with 122 additions and 27 deletions

View File

@ -6,10 +6,10 @@
* See http://www.microsoft.com/msj/0197/exception/exception.htm, * See http://www.microsoft.com/msj/0197/exception/exception.htm,
* but don't believe all of it. * but don't believe all of it.
* *
* FIXME: Incomplete, no support for nested exceptions or try block cleanup. * FIXME: Incomplete support for nested exceptions/try block cleanup.
*/ */
#include <setjmp.h>
#include "ntddk.h" #include "ntddk.h"
#include "wine/exception.h"
#include "thread.h" #include "thread.h"
#include "msvcrt.h" #include "msvcrt.h"
@ -21,28 +21,41 @@ typedef void (*MSVCRT_sig_handler_func)(void);
typedef struct _SCOPETABLE typedef struct _SCOPETABLE
{ {
DWORD previousTryLevel; DWORD previousTryLevel;
int (__cdecl *lpfnFilter)(int, PEXCEPTION_POINTERS); int (__cdecl *lpfnFilter)(PEXCEPTION_POINTERS);
int (__cdecl *lpfnHandler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, int (__cdecl *lpfnHandler)(void);
PCONTEXT, PEXCEPTION_FRAME *);
} SCOPETABLE, *PSCOPETABLE; } SCOPETABLE, *PSCOPETABLE;
typedef struct _MSVCRT_EXCEPTION_REGISTRATION typedef struct _MSVCRT_EXCEPTION_FRAME
{ {
struct _EXCEPTION_REGISTRATION *prev; EXCEPTION_FRAME *prev;
void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
PCONTEXT, PEXCEPTION_RECORD); PCONTEXT, PEXCEPTION_RECORD);
PSCOPETABLE scopetable; PSCOPETABLE scopetable;
int trylevel; DWORD trylevel;
int _ebp; int _ebp;
PEXCEPTION_POINTERS xpointers; PEXCEPTION_POINTERS xpointers;
} MSVCRT_EXCEPTION_REGISTRATION; } MSVCRT_EXCEPTION_FRAME;
typedef struct _EXCEPTION_REGISTRATION #define TRYLEVEL_END 0xff /* End of trylevel list */
#if defined(__GNUC__) && defined(__i386__)
#define CALL_FINALLY_BLOCK(code_block, base_ptr) \
__asm__ __volatile__ ("movl %0,%%eax; movl %1,%%ebp; call *%%eax" \
: : "g" (code_block), "g" (base_ptr))
static DWORD __cdecl MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
struct __EXCEPTION_FRAME *frame,
PCONTEXT context WINE_UNUSED,
struct __EXCEPTION_FRAME **dispatch)
{ {
struct _EXCEPTION_REGISTRATION *prev; if (rec->ExceptionFlags & 0x6)
void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, return ExceptionContinueSearch;
PCONTEXT, PEXCEPTION_RECORD); *dispatch = frame;
} EXCEPTION_REGISTRATION; return ExceptionCollidedUnwind;
}
#endif
/********************************************************************* /*********************************************************************
* _XcptFilter (MSVCRT.@) * _XcptFilter (MSVCRT.@)
@ -75,22 +88,42 @@ __ASM_GLOBAL_FUNC(MSVCRT__EH_prolog,
*/ */
void __cdecl MSVCRT__global_unwind2(PEXCEPTION_FRAME frame) void __cdecl MSVCRT__global_unwind2(PEXCEPTION_FRAME frame)
{ {
#if defined(__GNUC__) && defined(__i386__) TRACE("(%p)\n",frame);
TRACE("(%p)\n",frame); RtlUnwind( frame, 0, 0, 0 );
if (0)
unwind_label: return;
RtlUnwind( frame, &&unwind_label, 0, 0 );
#else
FIXME("(%p) stub\n",frame);
#endif
} }
/******************************************************************* /*******************************************************************
* _local_unwind2 (MSVCRT.@) * _local_unwind2 (MSVCRT.@)
*/ */
void __cdecl MSVCRT__local_unwind2(MSVCRT_EXCEPTION_REGISTRATION *endframe, DWORD nr ) void __cdecl MSVCRT__local_unwind2(MSVCRT_EXCEPTION_FRAME *frame,
DWORD trylevel)
{ {
FIXME("(%p,%ld) stub\n",endframe,nr); MSVCRT_EXCEPTION_FRAME *curframe = frame;
DWORD curtrylevel = 0xfe;
EXCEPTION_FRAME reg;
TRACE("(%p,%ld,%ld)\n",frame, frame->trylevel, trylevel);
/* Register a handler in case of a nested exception */
reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler;
reg.Prev = NtCurrentTeb()->except;
__wine_push_frame(&reg);
while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
{
curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
curframe = frame;
curframe->trylevel = curtrylevel;
if (!frame->scopetable[curtrylevel].lpfnFilter)
{
ERR("__try block cleanup not implemented - expect crash!\n");
/* FIXME: Remove current frame, set ebp, call
* frame->scopetable[curtrylevel].lpfnHandler()
*/
}
}
__wine_pop_frame(&reg);
TRACE("unwound OK\n");
} }
/********************************************************************* /*********************************************************************
@ -98,7 +131,8 @@ void __cdecl MSVCRT__local_unwind2(MSVCRT_EXCEPTION_REGISTRATION *endframe, DWOR
*/ */
int __cdecl MSVCRT__except_handler2(PEXCEPTION_RECORD rec, int __cdecl MSVCRT__except_handler2(PEXCEPTION_RECORD rec,
PEXCEPTION_FRAME frame, PEXCEPTION_FRAME frame,
PCONTEXT context, PEXCEPTION_FRAME *dispatcher) PCONTEXT context,
PEXCEPTION_FRAME *dispatcher)
{ {
FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n", FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
@ -110,12 +144,73 @@ int __cdecl MSVCRT__except_handler2(PEXCEPTION_RECORD rec,
* _except_handler3 (MSVCRT.@) * _except_handler3 (MSVCRT.@)
*/ */
int __cdecl MSVCRT__except_handler3(PEXCEPTION_RECORD rec, int __cdecl MSVCRT__except_handler3(PEXCEPTION_RECORD rec,
MSVCRT_EXCEPTION_REGISTRATION *frame, MSVCRT_EXCEPTION_FRAME *frame,
PCONTEXT context,void *dispatcher) PCONTEXT context,void *dispatcher)
{ {
FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n", #if defined(__GNUC__) && defined(__i386__)
long retval, trylevel;
EXCEPTION_POINTERS exceptPtrs;
PSCOPETABLE pScopeTable;
TRACE("exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
frame->handler, context, dispatcher); frame->handler, context, dispatcher);
__asm__ __volatile__ ("cld");
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
{
/* Unwinding the current frame */
MSVCRT__local_unwind2(frame, TRYLEVEL_END);
return ExceptionContinueSearch;
}
else
{
/* Hunting for handler */
exceptPtrs.ExceptionRecord = rec;
exceptPtrs.ContextRecord = context;
*((DWORD *)frame-1) = (DWORD)&exceptPtrs;
trylevel = frame->trylevel;
pScopeTable = frame->scopetable;
while (trylevel != TRYLEVEL_END)
{
if (pScopeTable[trylevel].lpfnFilter)
{
TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter);
retval = pScopeTable[trylevel].lpfnFilter(&exceptPtrs);
TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
"CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
"EXECUTE_HANDLER" : "CONTINUE_SEARCH");
if (retval == EXCEPTION_CONTINUE_EXECUTION)
return ExceptionContinueExecution;
if (retval == EXCEPTION_EXECUTE_HANDLER)
{
/* Unwind all higher frames, this one will handle the exception */
MSVCRT__global_unwind2((PEXCEPTION_FRAME)frame);
MSVCRT__local_unwind2(frame, trylevel);
/* Set our trylevel to the enclosing block, and call the __finally
* code, which won't return
*/
frame->trylevel = pScopeTable->previousTryLevel;
TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
CALL_FINALLY_BLOCK(pScopeTable[trylevel].lpfnHandler, frame->_ebp);
ERR("Returned from __finally block - expect crash!\n");
}
}
trylevel = pScopeTable->previousTryLevel;
}
}
#else
TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
frame->handler, context, dispatcher);
#endif
return ExceptionContinueSearch; return ExceptionContinueSearch;
} }