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,
|
* 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(®);
|
||||||
|
|
||||||
|
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,
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue