diff --git a/dlls/winecrt0/Makefile.in b/dlls/winecrt0/Makefile.in index 04a39d6bbf5..7f2ea34313c 100644 --- a/dlls/winecrt0/Makefile.in +++ b/dlls/winecrt0/Makefile.in @@ -9,6 +9,7 @@ C_SRCS = \ dll_entry.c \ dll_main.c \ drv_entry.c \ + exception.c \ exe16_entry.c \ exe_entry.c \ exe_main.c \ diff --git a/dlls/winecrt0/exception.c b/dlls/winecrt0/exception.c new file mode 100644 index 00000000000..65b6b415a01 --- /dev/null +++ b/dlls/winecrt0/exception.c @@ -0,0 +1,127 @@ +/* + * Support functions for Wine exception handling + * + * Copyright (c) 1999, 2010 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#include "winternl.h" +#include "wine/exception.h" + +/* wrapper for RtlUnwind since it clobbers registers on Windows */ +void __wine_rtl_unwind( EXCEPTION_REGISTRATION_RECORD* frame, EXCEPTION_RECORD *record, + void (*target)(void) ) +{ +#if defined(__GNUC__) && defined(__i386__) + int dummy1, dummy2, dummy3, dummy4; + __asm__ __volatile__("pushl %%ebp\n\t" + "pushl %%ebx\n\t" + "pushl $0\n\t" + "pushl %3\n\t" + "pushl %2\n\t" + "pushl %1\n\t" + "call *%0\n\t" + "popl %%ebx\n\t" + "popl %%ebp" + : "=a" (dummy1), "=S" (dummy2), "=D" (dummy3), "=c" (dummy4) + : "0" (RtlUnwind), "1" (frame), "2" (target), "3" (record) + : "edx", "memory" ); +#else + RtlUnwind( frame, target, record, 0 ); +#endif + for (;;) target(); +} + +static void DECLSPEC_NORETURN unwind_target(void) +{ + __WINE_FRAME *wine_frame = (__WINE_FRAME *)__wine_get_frame(); + __wine_pop_frame( &wine_frame->frame ); + siglongjmp( wine_frame->jmp, 1 ); +} + +static void DECLSPEC_NORETURN unwind_frame( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame ) +{ + __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; + + /* hack to make GetExceptionCode() work in handler */ + wine_frame->ExceptionCode = record->ExceptionCode; + wine_frame->ExceptionRecord = wine_frame; + + __wine_rtl_unwind( frame, record, unwind_target ); +} + +DWORD __wine_exception_handler( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) +{ + __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; + EXCEPTION_POINTERS ptrs; + + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) + return ExceptionContinueSearch; + + ptrs.ExceptionRecord = record; + ptrs.ContextRecord = context; + switch(wine_frame->u.filter( &ptrs )) + { + case EXCEPTION_CONTINUE_SEARCH: + return ExceptionContinueSearch; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + case EXCEPTION_EXECUTE_HANDLER: + break; + } + unwind_frame( record, frame ); +} + +DWORD __wine_exception_handler_page_fault( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) +{ + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) + return ExceptionContinueSearch; + if (record->ExceptionCode != STATUS_ACCESS_VIOLATION) + return ExceptionContinueSearch; + unwind_frame( record, frame ); +} + +DWORD __wine_exception_handler_all( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) +{ + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) + return ExceptionContinueSearch; + unwind_frame( record, frame ); +} + +DWORD __wine_finally_handler( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) +{ + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) + { + __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; + wine_frame->u.finally_func( FALSE ); + } + return ExceptionContinueSearch; +} diff --git a/include/wine/exception.h b/include/wine/exception.h index 7f013490a80..469083f77e0 100644 --- a/include/wine/exception.h +++ b/include/wine/exception.h @@ -94,6 +94,25 @@ extern "C" { #define siglongjmp(buf,val) longjmp(buf,val) #endif +extern void __wine_rtl_unwind( EXCEPTION_REGISTRATION_RECORD* frame, EXCEPTION_RECORD *record, + void (*target)(void) ) DECLSPEC_HIDDEN DECLSPEC_NORETURN; +extern DWORD __wine_exception_handler( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN; +extern DWORD __wine_exception_handler_page_fault( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN; +extern DWORD __wine_exception_handler_all( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN; +extern DWORD __wine_finally_handler( EXCEPTION_RECORD *record, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN; + #define __TRY \ do { __WINE_FRAME __f; \ int __first = 1; \ @@ -246,116 +265,6 @@ static inline EXCEPTION_REGISTRATION_RECORD *__wine_get_frame(void) extern void __wine_enter_vm86( CONTEXT *context ); -#ifndef USE_COMPILER_EXCEPTIONS - -NTSYSAPI void WINAPI RtlUnwind(PVOID,PVOID,PEXCEPTION_RECORD,PVOID); - -static inline void DECLSPEC_NORETURN __wine_unwind_target(void) -{ - __WINE_FRAME *wine_frame = (__WINE_FRAME *)__wine_get_frame(); - __wine_pop_frame( &wine_frame->frame ); - siglongjmp( wine_frame->jmp, 1 ); -} - -/* wrapper for RtlUnwind since it clobbers registers on Windows */ -static inline void DECLSPEC_NORETURN __wine_rtl_unwind( EXCEPTION_REGISTRATION_RECORD* frame, - EXCEPTION_RECORD *record, - void (*target)(void) ) -{ -#if defined(__GNUC__) && defined(__i386__) - int dummy1, dummy2, dummy3, dummy4; - __asm__ __volatile__("pushl %%ebp\n\t" - "pushl %%ebx\n\t" - "pushl $0\n\t" - "pushl %3\n\t" - "pushl %2\n\t" - "pushl %1\n\t" - "call *%0\n\t" - "popl %%ebx\n\t" - "popl %%ebp" - : "=a" (dummy1), "=S" (dummy2), "=D" (dummy3), "=c" (dummy4) - : "0" (RtlUnwind), "1" (frame), "2" (target), "3" (record) - : "edx", "memory" ); -#else - RtlUnwind( frame, target, record, 0 ); -#endif - for (;;) target(); -} - -static inline void DECLSPEC_NORETURN __wine_unwind_frame( EXCEPTION_RECORD *record, - EXCEPTION_REGISTRATION_RECORD *frame ) -{ - __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; - - /* hack to make GetExceptionCode() work in handler */ - wine_frame->ExceptionCode = record->ExceptionCode; - wine_frame->ExceptionRecord = wine_frame; - - __wine_rtl_unwind( frame, record, __wine_unwind_target ); -} - -static inline DWORD __wine_exception_handler( EXCEPTION_RECORD *record, - EXCEPTION_REGISTRATION_RECORD *frame, - CONTEXT *context, - EXCEPTION_REGISTRATION_RECORD **pdispatcher ) -{ - __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; - EXCEPTION_POINTERS ptrs; - - if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) - return ExceptionContinueSearch; - - ptrs.ExceptionRecord = record; - ptrs.ContextRecord = context; - switch(wine_frame->u.filter( &ptrs )) - { - case EXCEPTION_CONTINUE_SEARCH: - return ExceptionContinueSearch; - case EXCEPTION_CONTINUE_EXECUTION: - return ExceptionContinueExecution; - case EXCEPTION_EXECUTE_HANDLER: - break; - } - __wine_unwind_frame( record, frame ); -} - -static inline DWORD __wine_exception_handler_page_fault( EXCEPTION_RECORD *record, - EXCEPTION_REGISTRATION_RECORD *frame, - CONTEXT *context, - EXCEPTION_REGISTRATION_RECORD **pdispatcher ) -{ - if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) - return ExceptionContinueSearch; - if (record->ExceptionCode != STATUS_ACCESS_VIOLATION) - return ExceptionContinueSearch; - __wine_unwind_frame( record, frame ); -} - -static inline DWORD __wine_exception_handler_all( EXCEPTION_RECORD *record, - EXCEPTION_REGISTRATION_RECORD *frame, - CONTEXT *context, - EXCEPTION_REGISTRATION_RECORD **pdispatcher ) -{ - if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) - return ExceptionContinueSearch; - __wine_unwind_frame( record, frame ); -} - -static inline DWORD __wine_finally_handler( EXCEPTION_RECORD *record, - EXCEPTION_REGISTRATION_RECORD *frame, - CONTEXT *context, - EXCEPTION_REGISTRATION_RECORD **pdispatcher ) -{ - if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) - { - __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; - wine_frame->u.finally_func( FALSE ); - } - return ExceptionContinueSearch; -} - -#endif /* USE_COMPILER_EXCEPTIONS */ - #ifdef __cplusplus } #endif