Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenexcept.c
Go to the documentation of this file.
00001 /* 00002 * msvcrt.dll exception handling 00003 * 00004 * Copyright 2000 Jon Griffiths 00005 * Copyright 2005 Juan Lang 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 * 00021 * FIXME: Incomplete support for nested exceptions/try block cleanup. 00022 */ 00023 00024 #include <precomp.h> 00025 #include "excpt.h" 00026 #include <wine/exception.h> 00027 00028 void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame); 00029 00030 typedef void (__cdecl *MSVCRT_security_error_handler)(int, void *); 00031 static MSVCRT_security_error_handler security_error_handler; 00032 00033 /* VC++ extensions to Win32 SEH */ 00034 typedef struct _SCOPETABLE 00035 { 00036 int previousTryLevel; 00037 int (*lpfnFilter)(PEXCEPTION_POINTERS); 00038 int (*lpfnHandler)(void); 00039 } SCOPETABLE, *PSCOPETABLE; 00040 00041 typedef struct _MSVCRT_EXCEPTION_FRAME 00042 { 00043 EXCEPTION_REGISTRATION_RECORD *prev; 00044 void (*handler)(PEXCEPTION_RECORD, EXCEPTION_REGISTRATION_RECORD*, 00045 PCONTEXT, PEXCEPTION_RECORD); 00046 PSCOPETABLE scopetable; 00047 int trylevel; 00048 int _ebp; 00049 PEXCEPTION_POINTERS xpointers; 00050 } MSVCRT_EXCEPTION_FRAME; 00051 00052 typedef struct 00053 { 00054 int gs_cookie_offset; 00055 ULONG gs_cookie_xor; 00056 int eh_cookie_offset; 00057 ULONG eh_cookie_xor; 00058 SCOPETABLE entries[1]; 00059 } SCOPETABLE_V4; 00060 00061 #ifdef __i386__ 00062 00063 static const SCOPETABLE_V4 *get_scopetable_v4( MSVCRT_EXCEPTION_FRAME *frame, ULONG_PTR cookie ) 00064 { 00065 return (const SCOPETABLE_V4 *)((ULONG_PTR)frame->scopetable ^ cookie); 00066 } 00067 00068 #if defined(__GNUC__) 00069 static inline void call_finally_block( void *code_block, void *base_ptr ) 00070 { 00071 __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax" 00072 : : "a" (code_block), "g" (base_ptr)); 00073 } 00074 00075 static inline int call_filter( int (*func)(PEXCEPTION_POINTERS), void *arg, void *ebp ) 00076 { 00077 int ret; 00078 __asm__ __volatile__ ("pushl %%ebp; pushl %3; movl %2,%%ebp; call *%%eax; popl %%ebp; popl %%ebp" 00079 : "=a" (ret) 00080 : "0" (func), "r" (ebp), "r" (arg) 00081 : "ecx", "edx", "memory" ); 00082 return ret; 00083 } 00084 static inline int call_unwind_func( int (*func)(void), void *ebp ) 00085 { 00086 int ret; 00087 __asm__ __volatile__ ("pushl %%ebp\n\t" 00088 "pushl %%ebx\n\t" 00089 "pushl %%esi\n\t" 00090 "pushl %%edi\n\t" 00091 "movl %2,%%ebp\n\t" 00092 "call *%0\n\t" 00093 "popl %%edi\n\t" 00094 "popl %%esi\n\t" 00095 "popl %%ebx\n\t" 00096 "popl %%ebp" 00097 : "=a" (ret) 00098 : "0" (func), "r" (ebp) 00099 : "ecx", "edx", "memory" ); 00100 return ret; 00101 } 00102 #elif defined(_MSC_VER) 00103 #pragma warning(push) 00104 #pragma warning(disable:4731) // Don't complain about changing ebp 00105 void __inline call_finally_block( void *code_block, void *base_ptr ) 00106 { 00107 __asm 00108 { 00109 mov eax, code_block 00110 mov ebp, base_ptr 00111 call [eax] 00112 } 00113 } 00114 00115 int __inline call_filter( int (*func)(PEXCEPTION_POINTERS), void *arg, void *_ebp ) 00116 { 00117 int _ret; 00118 __asm 00119 { 00120 push ebp 00121 mov eax, arg 00122 push eax 00123 mov ebp, _ebp 00124 mov eax, func 00125 call [eax] 00126 mov _ret, eax 00127 pop ebp 00128 pop ebp 00129 } 00130 return _ret; 00131 } 00132 int __inline call_unwind_func( int (*func)(void), void *_ebp ) 00133 { 00134 int _ret; 00135 00136 __asm 00137 { 00138 push ebp 00139 push ebx 00140 push esi 00141 push edi 00142 mov ebp, _ebp 00143 call dword ptr [func] 00144 mov _ret, eax 00145 pop edi 00146 pop esi 00147 pop ebx 00148 pop ebp 00149 } 00150 return _ret; 00151 } 00152 #pragma warning(pop) 00153 #endif 00154 00155 static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec, 00156 EXCEPTION_REGISTRATION_RECORD* frame, 00157 PCONTEXT context, 00158 EXCEPTION_REGISTRATION_RECORD** dispatch) 00159 { 00160 if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))) 00161 return ExceptionContinueSearch; 00162 *dispatch = frame; 00163 return ExceptionCollidedUnwind; 00164 } 00165 00166 void msvcrt_local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp ) 00167 { 00168 EXCEPTION_REGISTRATION_RECORD reg; 00169 const SCOPETABLE_V4 *scopetable = get_scopetable_v4( frame, *cookie ); 00170 00171 TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel); 00172 00173 /* Register a handler in case of a nested exception */ 00174 reg.Handler = (PEXCEPTION_ROUTINE)MSVCRT_nested_handler; 00175 reg.Prev = NtCurrentTeb()->NtTib.ExceptionList; 00176 __wine_push_frame(®); 00177 00178 while (frame->trylevel != -2 && frame->trylevel != trylevel) 00179 { 00180 int level = frame->trylevel; 00181 frame->trylevel = scopetable->entries[level].previousTryLevel; 00182 if (!scopetable->entries[level].lpfnFilter) 00183 { 00184 TRACE( "__try block cleanup level %d handler %p ebp %p\n", 00185 level, scopetable->entries[level].lpfnHandler, ebp ); 00186 call_unwind_func( scopetable->entries[level].lpfnHandler, ebp ); 00187 } 00188 } 00189 __wine_pop_frame(®); 00190 TRACE("unwound OK\n"); 00191 } 00192 00193 /********************************************************************* 00194 * _except_handler4_common (MSVCRT.@) 00195 */ 00196 int CDECL _except_handler4_common( ULONG *cookie, void (*check_cookie)(void), 00197 EXCEPTION_RECORD *rec, MSVCRT_EXCEPTION_FRAME *frame, 00198 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) 00199 { 00200 int retval, trylevel; 00201 EXCEPTION_POINTERS exceptPtrs; 00202 const SCOPETABLE_V4 *scope_table = get_scopetable_v4( frame, *cookie ); 00203 00204 TRACE( "exception %x flags=%x at %p handler=%p %p %p cookie=%x scope table=%p cookies=%d/%x,%d/%x\n", 00205 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, 00206 frame->handler, context, dispatcher, *cookie, scope_table, 00207 scope_table->gs_cookie_offset, scope_table->gs_cookie_xor, 00208 scope_table->eh_cookie_offset, scope_table->eh_cookie_xor ); 00209 00210 /* FIXME: no cookie validation yet */ 00211 00212 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) 00213 { 00214 /* Unwinding the current frame */ 00215 msvcrt_local_unwind4( cookie, frame, -2, &frame->_ebp ); 00216 TRACE("unwound current frame, returning ExceptionContinueSearch\n"); 00217 return ExceptionContinueSearch; 00218 } 00219 else 00220 { 00221 /* Hunting for handler */ 00222 exceptPtrs.ExceptionRecord = rec; 00223 exceptPtrs.ContextRecord = context; 00224 *((DWORD *)frame-1) = (DWORD)&exceptPtrs; 00225 trylevel = frame->trylevel; 00226 00227 while (trylevel != -2) 00228 { 00229 TRACE( "level %d prev %d filter %p\n", trylevel, 00230 scope_table->entries[trylevel].previousTryLevel, 00231 scope_table->entries[trylevel].lpfnFilter ); 00232 if (scope_table->entries[trylevel].lpfnFilter) 00233 { 00234 retval = call_filter( scope_table->entries[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp ); 00235 00236 TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ? 00237 "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ? 00238 "EXECUTE_HANDLER" : "CONTINUE_SEARCH"); 00239 00240 if (retval == EXCEPTION_CONTINUE_EXECUTION) 00241 return ExceptionContinueExecution; 00242 00243 if (retval == EXCEPTION_EXECUTE_HANDLER) 00244 { 00245 /* Unwind all higher frames, this one will handle the exception */ 00246 _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame); 00247 msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp ); 00248 00249 /* Set our trylevel to the enclosing block, and call the __finally 00250 * code, which won't return 00251 */ 00252 frame->trylevel = scope_table->entries[trylevel].previousTryLevel; 00253 TRACE("__finally block %p\n",scope_table->entries[trylevel].lpfnHandler); 00254 call_finally_block(scope_table->entries[trylevel].lpfnHandler, &frame->_ebp); 00255 ERR("Returned from __finally block - expect crash!\n"); 00256 } 00257 } 00258 trylevel = scope_table->entries[trylevel].previousTryLevel; 00259 } 00260 } 00261 TRACE("reached -2, returning ExceptionContinueSearch\n"); 00262 return ExceptionContinueSearch; 00263 } 00264 00265 /******************************************************************* 00266 * _local_unwind4 (MSVCRT.@) 00267 */ 00268 void CDECL _local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel ) 00269 { 00270 msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp ); 00271 } 00272 00273 /********************************************************************* 00274 * _seh_longjmp_unwind4 (MSVCRT.@) 00275 */ 00276 void __stdcall _seh_longjmp_unwind4(struct __JUMP_BUFFER *jmp) 00277 { 00278 msvcrt_local_unwind4( (void *)jmp->Cookie, (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, 00279 jmp->TryLevel, (void *)jmp->Ebp ); 00280 } 00281 00282 #endif 00283 00284 /****************************************************************** 00285 * __uncaught_exception 00286 */ 00287 BOOL CDECL __uncaught_exception(void) 00288 { 00289 return FALSE; 00290 } 00291 00292 /* _set_security_error_handler - not exported in native msvcrt, added in msvcr70 */ 00293 MSVCRT_security_error_handler CDECL _set_security_error_handler( 00294 MSVCRT_security_error_handler handler ) 00295 { 00296 MSVCRT_security_error_handler old = security_error_handler; 00297 00298 TRACE("(%p)\n", handler); 00299 00300 security_error_handler = handler; 00301 return old; 00302 } Generated on Sat May 26 2012 04:22:57 for ReactOS by
1.7.6.1
|