Added some exception handling functions.
This commit is contained in:
parent
e884cc2b08
commit
5f308d3cb0
|
@ -6,10 +6,10 @@
|
|||
* See http://www.microsoft.com/msj/0197/exception/exception.htm,
|
||||
* 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 "wine/exception.h"
|
||||
#include "thread.h"
|
||||
#include "msvcrt.h"
|
||||
|
||||
|
@ -21,28 +21,41 @@ typedef void (*MSVCRT_sig_handler_func)(void);
|
|||
typedef struct _SCOPETABLE
|
||||
{
|
||||
DWORD previousTryLevel;
|
||||
int (__cdecl *lpfnFilter)(int, PEXCEPTION_POINTERS);
|
||||
int (__cdecl *lpfnHandler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
|
||||
PCONTEXT, PEXCEPTION_FRAME *);
|
||||
int (__cdecl *lpfnFilter)(PEXCEPTION_POINTERS);
|
||||
int (__cdecl *lpfnHandler)(void);
|
||||
} 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,
|
||||
PCONTEXT, PEXCEPTION_RECORD);
|
||||
PSCOPETABLE scopetable;
|
||||
int trylevel;
|
||||
DWORD trylevel;
|
||||
int _ebp;
|
||||
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;
|
||||
void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
|
||||
PCONTEXT, PEXCEPTION_RECORD);
|
||||
} EXCEPTION_REGISTRATION;
|
||||
if (rec->ExceptionFlags & 0x6)
|
||||
return ExceptionContinueSearch;
|
||||
*dispatch = frame;
|
||||
return ExceptionCollidedUnwind;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _XcptFilter (MSVCRT.@)
|
||||
|
@ -75,22 +88,42 @@ __ASM_GLOBAL_FUNC(MSVCRT__EH_prolog,
|
|||
*/
|
||||
void __cdecl MSVCRT__global_unwind2(PEXCEPTION_FRAME frame)
|
||||
{
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
TRACE("(%p)\n",frame);
|
||||
if (0)
|
||||
unwind_label: return;
|
||||
RtlUnwind( frame, &&unwind_label, 0, 0 );
|
||||
#else
|
||||
FIXME("(%p) stub\n",frame);
|
||||
#endif
|
||||
RtlUnwind( frame, 0, 0, 0 );
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* _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(®);
|
||||
|
||||
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(®);
|
||||
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,
|
||||
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",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
||||
|
@ -110,12 +144,73 @@ int __cdecl MSVCRT__except_handler2(PEXCEPTION_RECORD rec,
|
|||
* _except_handler3 (MSVCRT.@)
|
||||
*/
|
||||
int __cdecl MSVCRT__except_handler3(PEXCEPTION_RECORD rec,
|
||||
MSVCRT_EXCEPTION_REGISTRATION *frame,
|
||||
MSVCRT_EXCEPTION_FRAME *frame,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue