1 /* 2 * msvcrt C++ exception handling 3 * 4 * Copyright 2000 Jon Griffiths 5 * Copyright 2002 Alexandre Julliard 6 * Copyright 2005 Juan Lang 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 * 22 * NOTES 23 * A good reference is the article "How a C++ compiler implements 24 * exception handling" by Vishal Kochhar, available on 25 * www.thecodeproject.com. 26 */ 27 28 #include "config.h" 29 #include "wine/port.h" 30 31 #ifdef __i386__ 32 33 #include <stdarg.h> 34 35 #include "windef.h" 36 #include "winbase.h" 37 #include "winternl.h" 38 #include "msvcrt.h" 39 #include "wine/exception.h" 40 #include "excpt.h" 41 #include "wine/debug.h" 42 43 #include "cppexcept.h" 44 45 WINE_DEFAULT_DEBUG_CHANNEL(seh); 46 47 48 /* the exception frame used by CxxFrameHandler */ 49 typedef struct __cxx_exception_frame 50 { 51 EXCEPTION_REGISTRATION_RECORD frame; /* the standard exception frame */ 52 int trylevel; 53 DWORD ebp; 54 } cxx_exception_frame; 55 56 /* info about a single catch {} block */ 57 typedef struct __catchblock_info 58 { 59 UINT flags; /* flags (see below) */ 60 const type_info *type_info; /* C++ type caught by this block */ 61 int offset; /* stack offset to copy exception object to */ 62 void * (*handler)(void);/* catch block handler code */ 63 } catchblock_info; 64 #define TYPE_FLAG_CONST 1 65 #define TYPE_FLAG_VOLATILE 2 66 #define TYPE_FLAG_REFERENCE 8 67 68 /* info about a single try {} block */ 69 typedef struct __tryblock_info 70 { 71 int start_level; /* start trylevel of that block */ 72 int end_level; /* end trylevel of that block */ 73 int catch_level; /* initial trylevel of the catch block */ 74 int catchblock_count; /* count of catch blocks in array */ 75 const catchblock_info *catchblock; /* array of catch blocks */ 76 } tryblock_info; 77 78 /* info about the unwind handler for a given trylevel */ 79 typedef struct __unwind_info 80 { 81 int prev; /* prev trylevel unwind handler, to run after this one */ 82 void * (*handler)(void);/* unwind handler */ 83 } unwind_info; 84 85 /* descriptor of all try blocks of a given function */ 86 typedef struct __cxx_function_descr 87 { 88 UINT magic; /* must be CXX_FRAME_MAGIC */ 89 UINT unwind_count; /* number of unwind handlers */ 90 const unwind_info *unwind_table; /* array of unwind handlers */ 91 UINT tryblock_count; /* number of try blocks */ 92 const tryblock_info *tryblock; /* array of try blocks */ 93 UINT ipmap_count; 94 const void *ipmap; 95 const void *expect_list; /* expected exceptions list when magic >= VC7 */ 96 UINT flags; /* flags when magic >= VC8 */ 97 } cxx_function_descr; 98 99 typedef struct 100 { 101 cxx_exception_frame *frame; 102 const cxx_function_descr *descr; 103 EXCEPTION_REGISTRATION_RECORD *nested_frame; 104 } se_translator_ctx; 105 106 typedef struct _SCOPETABLE 107 { 108 int previousTryLevel; 109 int (*lpfnFilter)(PEXCEPTION_POINTERS); 110 void * (*lpfnHandler)(void); 111 } SCOPETABLE, *PSCOPETABLE; 112 113 typedef struct _MSVCRT_EXCEPTION_FRAME 114 { 115 EXCEPTION_REGISTRATION_RECORD *prev; 116 void (*handler)(PEXCEPTION_RECORD, EXCEPTION_REGISTRATION_RECORD*, 117 PCONTEXT, PEXCEPTION_RECORD); 118 PSCOPETABLE scopetable; 119 int trylevel; 120 int _ebp; 121 PEXCEPTION_POINTERS xpointers; 122 } MSVCRT_EXCEPTION_FRAME; 123 124 typedef struct 125 { 126 int gs_cookie_offset; 127 ULONG gs_cookie_xor; 128 int eh_cookie_offset; 129 ULONG eh_cookie_xor; 130 SCOPETABLE entries[1]; 131 } SCOPETABLE_V4; 132 133 #define TRYLEVEL_END (-1) /* End of trylevel list */ 134 135 DWORD CDECL cxx_frame_handler( PEXCEPTION_RECORD rec, cxx_exception_frame* frame, 136 PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch, 137 const cxx_function_descr *descr, 138 EXCEPTION_REGISTRATION_RECORD* nested_frame, int nested_trylevel ) DECLSPEC_HIDDEN; 139 140 /* call a copy constructor */ 141 extern void call_copy_ctor( void *func, void *this, void *src, int has_vbase ); 142 143 __ASM_GLOBAL_FUNC( call_copy_ctor, 144 "pushl %ebp\n\t" 145 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 146 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") 147 "movl %esp, %ebp\n\t" 148 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") 149 "pushl $1\n\t" 150 "movl 12(%ebp), %ecx\n\t" 151 "pushl 16(%ebp)\n\t" 152 "call *8(%ebp)\n\t" 153 "leave\n" 154 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") 155 __ASM_CFI(".cfi_same_value %ebp\n\t") 156 "ret" ); 157 158 /* continue execution to the specified address after exception is caught */ 159 extern void DECLSPEC_NORETURN continue_after_catch( cxx_exception_frame* frame, void *addr ); 160 161 __ASM_GLOBAL_FUNC( continue_after_catch, 162 "movl 4(%esp), %edx\n\t" 163 "movl 8(%esp), %eax\n\t" 164 "movl -4(%edx), %esp\n\t" 165 "leal 12(%edx), %ebp\n\t" 166 "jmp *%eax" ); 167 168 extern void DECLSPEC_NORETURN call_finally_block( void *code_block, void *base_ptr ); 169 170 __ASM_GLOBAL_FUNC( call_finally_block, 171 "movl 8(%esp), %ebp\n\t" 172 "jmp *4(%esp)" ); 173 174 extern int call_filter( int (*func)(PEXCEPTION_POINTERS), void *arg, void *ebp ); 175 176 __ASM_GLOBAL_FUNC( call_filter, 177 "pushl %ebp\n\t" 178 "pushl 12(%esp)\n\t" 179 "movl 20(%esp), %ebp\n\t" 180 "call *12(%esp)\n\t" 181 "popl %ebp\n\t" 182 "popl %ebp\n\t" 183 "ret" ); 184 185 extern void *call_handler( void * (*func)(void), void *ebp ); 186 187 __ASM_GLOBAL_FUNC( call_handler, 188 "pushl %ebp\n\t" 189 "pushl %ebx\n\t" 190 "pushl %esi\n\t" 191 "pushl %edi\n\t" 192 "movl 24(%esp), %ebp\n\t" 193 "call *20(%esp)\n\t" 194 "popl %edi\n\t" 195 "popl %esi\n\t" 196 "popl %ebx\n\t" 197 "popl %ebp\n\t" 198 "ret" ); 199 200 static inline void dump_type( const cxx_type_info *type ) 201 { 202 TRACE( "flags %x type %p %s offsets %d,%d,%d size %d copy ctor %p\n", 203 type->flags, type->type_info, dbgstr_type_info(type->type_info), 204 type->offsets.this_offset, type->offsets.vbase_descr, type->offsets.vbase_offset, 205 type->size, type->copy_ctor ); 206 } 207 208 static void dump_exception_type( const cxx_exception_type *type ) 209 { 210 UINT i; 211 212 TRACE( "flags %x destr %p handler %p type info %p\n", 213 type->flags, type->destructor, type->custom_handler, type->type_info_table ); 214 for (i = 0; i < type->type_info_table->count; i++) 215 { 216 TRACE( " %d: ", i ); 217 dump_type( type->type_info_table->info[i] ); 218 } 219 } 220 221 static void dump_function_descr( const cxx_function_descr *descr ) 222 { 223 UINT i; 224 int j; 225 226 TRACE( "magic %x\n", descr->magic ); 227 TRACE( "unwind table: %p %d\n", descr->unwind_table, descr->unwind_count ); 228 for (i = 0; i < descr->unwind_count; i++) 229 { 230 TRACE( " %d: prev %d func %p\n", i, 231 descr->unwind_table[i].prev, descr->unwind_table[i].handler ); 232 } 233 TRACE( "try table: %p %d\n", descr->tryblock, descr->tryblock_count ); 234 for (i = 0; i < descr->tryblock_count; i++) 235 { 236 TRACE( " %d: start %d end %d catchlevel %d catch %p %d\n", i, 237 descr->tryblock[i].start_level, descr->tryblock[i].end_level, 238 descr->tryblock[i].catch_level, descr->tryblock[i].catchblock, 239 descr->tryblock[i].catchblock_count ); 240 for (j = 0; j < descr->tryblock[i].catchblock_count; j++) 241 { 242 const catchblock_info *ptr = &descr->tryblock[i].catchblock[j]; 243 TRACE( " %d: flags %x offset %d handler %p type %p %s\n", 244 j, ptr->flags, ptr->offset, ptr->handler, 245 ptr->type_info, dbgstr_type_info( ptr->type_info ) ); 246 } 247 } 248 if (descr->magic <= CXX_FRAME_MAGIC_VC6) return; 249 TRACE( "expect list: %p\n", descr->expect_list ); 250 if (descr->magic <= CXX_FRAME_MAGIC_VC7) return; 251 TRACE( "flags: %08x\n", descr->flags ); 252 } 253 254 /* check if the exception type is caught by a given catch block, and return the type that matched */ 255 static const cxx_type_info *find_caught_type( cxx_exception_type *exc_type, 256 const type_info *catch_ti, UINT catch_flags ) 257 { 258 UINT i; 259 260 for (i = 0; i < exc_type->type_info_table->count; i++) 261 { 262 const cxx_type_info *type = exc_type->type_info_table->info[i]; 263 264 if (!catch_ti) return type; /* catch(...) matches any type */ 265 if (catch_ti != type->type_info) 266 { 267 if (strcmp( catch_ti->mangled, type->type_info->mangled )) continue; 268 } 269 /* type is the same, now check the flags */ 270 if ((exc_type->flags & TYPE_FLAG_CONST) && 271 !(catch_flags & TYPE_FLAG_CONST)) continue; 272 if ((exc_type->flags & TYPE_FLAG_VOLATILE) && 273 !(catch_flags & TYPE_FLAG_VOLATILE)) continue; 274 return type; /* it matched */ 275 } 276 return NULL; 277 } 278 279 280 /* copy the exception object where the catch block wants it */ 281 static void copy_exception( void *object, cxx_exception_frame *frame, 282 const catchblock_info *catchblock, const cxx_type_info *type ) 283 { 284 void **dest_ptr; 285 286 if (!catchblock->type_info || !catchblock->type_info->mangled[0]) return; 287 if (!catchblock->offset) return; 288 dest_ptr = (void **)((char *)&frame->ebp + catchblock->offset); 289 290 if (catchblock->flags & TYPE_FLAG_REFERENCE) 291 { 292 *dest_ptr = get_this_pointer( &type->offsets, object ); 293 } 294 else if (type->flags & CLASS_IS_SIMPLE_TYPE) 295 { 296 memmove( dest_ptr, object, type->size ); 297 /* if it is a pointer, adjust it */ 298 if (type->size == sizeof(void *)) *dest_ptr = get_this_pointer( &type->offsets, *dest_ptr ); 299 } 300 else /* copy the object */ 301 { 302 if (type->copy_ctor) 303 call_copy_ctor( type->copy_ctor, dest_ptr, get_this_pointer(&type->offsets,object), 304 (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) ); 305 else 306 memmove( dest_ptr, get_this_pointer(&type->offsets,object), type->size ); 307 } 308 } 309 310 /* unwind the local function up to a given trylevel */ 311 static void cxx_local_unwind( cxx_exception_frame* frame, const cxx_function_descr *descr, int last_level) 312 { 313 void * (*handler)(void); 314 int trylevel = frame->trylevel; 315 316 while (trylevel != last_level) 317 { 318 if (trylevel < 0 || trylevel >= descr->unwind_count) 319 { 320 ERR( "invalid trylevel %d\n", trylevel ); 321 MSVCRT_terminate(); 322 } 323 handler = descr->unwind_table[trylevel].handler; 324 if (handler) 325 { 326 TRACE( "calling unwind handler %p trylevel %d last %d ebp %p\n", 327 handler, trylevel, last_level, &frame->ebp ); 328 call_handler( handler, &frame->ebp ); 329 } 330 trylevel = descr->unwind_table[trylevel].prev; 331 } 332 frame->trylevel = last_level; 333 } 334 335 /* exception frame for nested exceptions in catch block */ 336 struct catch_func_nested_frame 337 { 338 EXCEPTION_REGISTRATION_RECORD frame; /* standard exception frame */ 339 cxx_exception_frame *cxx_frame; /* frame of parent exception */ 340 const cxx_function_descr *descr; /* descriptor of parent exception */ 341 int trylevel; /* current try level */ 342 cxx_frame_info frame_info; 343 }; 344 345 /* handler for exceptions happening while calling a catch function */ 346 static DWORD catch_function_nested_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, 347 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) 348 { 349 struct catch_func_nested_frame *nested_frame = (struct catch_func_nested_frame *)frame; 350 351 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) 352 { 353 __CxxUnregisterExceptionObject(&nested_frame->frame_info, FALSE); 354 return ExceptionContinueSearch; 355 } 356 357 TRACE( "got nested exception in catch function\n" ); 358 359 if(rec->ExceptionCode == CXX_EXCEPTION) 360 { 361 PEXCEPTION_RECORD prev_rec = msvcrt_get_thread_data()->exc_record; 362 363 if((rec->ExceptionInformation[1] == 0 && rec->ExceptionInformation[2] == 0) || 364 (prev_rec->ExceptionCode == CXX_EXCEPTION && 365 rec->ExceptionInformation[1] == prev_rec->ExceptionInformation[1] && 366 rec->ExceptionInformation[2] == prev_rec->ExceptionInformation[2])) 367 { 368 /* exception was rethrown */ 369 *rec = *prev_rec; 370 rec->ExceptionFlags &= ~EH_UNWINDING; 371 if(TRACE_ON(seh)) { 372 TRACE("detect rethrow: exception code: %x\n", rec->ExceptionCode); 373 if(rec->ExceptionCode == CXX_EXCEPTION) 374 TRACE("re-propagate: obj: %lx, type: %lx\n", 375 rec->ExceptionInformation[1], rec->ExceptionInformation[2]); 376 } 377 } 378 else 379 { 380 TRACE("detect threw new exception in catch block\n"); 381 } 382 } 383 384 return cxx_frame_handler( rec, nested_frame->cxx_frame, context, 385 NULL, nested_frame->descr, &nested_frame->frame, 386 nested_frame->trylevel ); 387 } 388 389 /* find and call the appropriate catch block for an exception */ 390 /* returns the address to continue execution to after the catch block was called */ 391 static inline void call_catch_block( PEXCEPTION_RECORD rec, CONTEXT *context, 392 cxx_exception_frame *frame, 393 const cxx_function_descr *descr, int nested_trylevel, 394 EXCEPTION_REGISTRATION_RECORD *catch_frame, 395 cxx_exception_type *info ) 396 { 397 UINT i; 398 int j; 399 void *addr, *object = (void *)rec->ExceptionInformation[1]; 400 struct catch_func_nested_frame nested_frame; 401 int trylevel = frame->trylevel; 402 DWORD save_esp = ((DWORD*)frame)[-1]; 403 thread_data_t *data = msvcrt_get_thread_data(); 404 405 data->processing_throw++; 406 for (i = 0; i < descr->tryblock_count; i++) 407 { 408 const tryblock_info *tryblock = &descr->tryblock[i]; 409 410 /* only handle try blocks inside current catch block */ 411 if (catch_frame && nested_trylevel > tryblock->start_level) continue; 412 413 if (trylevel < tryblock->start_level) continue; 414 if (trylevel > tryblock->end_level) continue; 415 416 /* got a try block */ 417 for (j = 0; j < tryblock->catchblock_count; j++) 418 { 419 const catchblock_info *catchblock = &tryblock->catchblock[j]; 420 if(info) 421 { 422 const cxx_type_info *type = find_caught_type( info, 423 catchblock->type_info, catchblock->flags ); 424 if (!type) continue; 425 426 TRACE( "matched type %p in tryblock %d catchblock %d\n", type, i, j ); 427 428 /* copy the exception to its destination on the stack */ 429 copy_exception( object, frame, catchblock, type ); 430 } 431 else 432 { 433 /* no CXX_EXCEPTION only proceed with a catch(...) block*/ 434 if(catchblock->type_info) 435 continue; 436 TRACE("found catch(...) block\n"); 437 } 438 439 /* Add frame info here so exception is not freed inside RtlUnwind call */ 440 _CreateFrameInfo(&nested_frame.frame_info.frame_info, 441 (void*)rec->ExceptionInformation[1]); 442 443 /* unwind the stack */ 444 RtlUnwind( catch_frame ? catch_frame : &frame->frame, 0, rec, 0 ); 445 cxx_local_unwind( frame, descr, tryblock->start_level ); 446 frame->trylevel = tryblock->end_level + 1; 447 448 nested_frame.frame_info.rec = data->exc_record; 449 nested_frame.frame_info.context = data->ctx_record; 450 data->exc_record = rec; 451 data->ctx_record = context; 452 data->processing_throw--; 453 454 /* call the catch block */ 455 TRACE( "calling catch block %p addr %p ebp %p\n", 456 catchblock, catchblock->handler, &frame->ebp ); 457 458 /* setup an exception block for nested exceptions */ 459 nested_frame.frame.Handler = catch_function_nested_handler; 460 nested_frame.cxx_frame = frame; 461 nested_frame.descr = descr; 462 nested_frame.trylevel = nested_trylevel + 1; 463 464 __wine_push_frame( &nested_frame.frame ); 465 addr = call_handler( catchblock->handler, &frame->ebp ); 466 __wine_pop_frame( &nested_frame.frame ); 467 468 ((DWORD*)frame)[-1] = save_esp; 469 __CxxUnregisterExceptionObject(&nested_frame.frame_info, FALSE); 470 TRACE( "done, continuing at %p\n", addr ); 471 472 continue_after_catch( frame, addr ); 473 } 474 } 475 data->processing_throw--; 476 } 477 478 /********************************************************************* 479 * __CxxExceptionFilter (MSVCRT.@) 480 */ 481 int CDECL __CxxExceptionFilter( PEXCEPTION_POINTERS ptrs, 482 const type_info *ti, int flags, void **copy) 483 { 484 const cxx_type_info *type; 485 PEXCEPTION_RECORD rec; 486 487 TRACE( "%p %p %x %p\n", ptrs, ti, flags, copy ); 488 489 if (!ptrs) return EXCEPTION_CONTINUE_SEARCH; 490 491 /* handle catch(...) */ 492 if (!ti) return EXCEPTION_EXECUTE_HANDLER; 493 494 rec = ptrs->ExceptionRecord; 495 if (rec->ExceptionCode != CXX_EXCEPTION || rec->NumberParameters != 3 || 496 rec->ExceptionInformation[0] < CXX_FRAME_MAGIC_VC6 || 497 rec->ExceptionInformation[0] > CXX_FRAME_MAGIC_VC8) 498 return EXCEPTION_CONTINUE_SEARCH; 499 500 if (rec->ExceptionInformation[1] == 0 && rec->ExceptionInformation[2] == 0) 501 { 502 rec = msvcrt_get_thread_data()->exc_record; 503 if (!rec) return EXCEPTION_CONTINUE_SEARCH; 504 } 505 506 type = find_caught_type( (cxx_exception_type*)rec->ExceptionInformation[2], ti, flags ); 507 if (!type) return EXCEPTION_CONTINUE_SEARCH; 508 509 if (copy) 510 { 511 void *object = (void *)rec->ExceptionInformation[1]; 512 513 if (flags & TYPE_FLAG_REFERENCE) 514 { 515 *copy = get_this_pointer( &type->offsets, object ); 516 } 517 else if (type->flags & CLASS_IS_SIMPLE_TYPE) 518 { 519 memmove( copy, object, type->size ); 520 /* if it is a pointer, adjust it */ 521 if (type->size == sizeof(void*)) *copy = get_this_pointer( &type->offsets, *copy ); 522 } 523 else /* copy the object */ 524 { 525 if (type->copy_ctor) 526 call_copy_ctor( type->copy_ctor, copy, get_this_pointer(&type->offsets,object), 527 (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) ); 528 else 529 memmove( copy, get_this_pointer(&type->offsets,object), type->size ); 530 } 531 } 532 return EXCEPTION_EXECUTE_HANDLER; 533 } 534 535 static LONG CALLBACK se_translation_filter( EXCEPTION_POINTERS *ep, void *c ) 536 { 537 se_translator_ctx *ctx = (se_translator_ctx *)c; 538 EXCEPTION_RECORD *rec = ep->ExceptionRecord; 539 cxx_exception_type *exc_type; 540 541 if (rec->ExceptionCode != CXX_EXCEPTION) 542 { 543 TRACE( "non-c++ exception thrown in SEH handler: %x\n", rec->ExceptionCode ); 544 MSVCRT_terminate(); 545 } 546 547 exc_type = (cxx_exception_type *)rec->ExceptionInformation[2]; 548 call_catch_block( rec, ep->ContextRecord, ctx->frame, ctx->descr, 549 ctx->frame->trylevel, ctx->nested_frame, exc_type ); 550 551 __DestructExceptionObject( rec ); 552 return ExceptionContinueSearch; 553 } 554 555 /********************************************************************* 556 * cxx_frame_handler 557 * 558 * Implementation of __CxxFrameHandler. 559 */ 560 DWORD CDECL cxx_frame_handler( PEXCEPTION_RECORD rec, cxx_exception_frame* frame, 561 PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch, 562 const cxx_function_descr *descr, 563 EXCEPTION_REGISTRATION_RECORD* nested_frame, 564 int nested_trylevel ) 565 { 566 cxx_exception_type *exc_type; 567 568 if (descr->magic < CXX_FRAME_MAGIC_VC6 || descr->magic > CXX_FRAME_MAGIC_VC8) 569 { 570 ERR( "invalid frame magic %x\n", descr->magic ); 571 return ExceptionContinueSearch; 572 } 573 if (descr->magic >= CXX_FRAME_MAGIC_VC8 && 574 (descr->flags & FUNC_DESCR_SYNCHRONOUS) && 575 (rec->ExceptionCode != CXX_EXCEPTION)) 576 return ExceptionContinueSearch; /* handle only c++ exceptions */ 577 578 if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND)) 579 { 580 if (descr->unwind_count && !nested_trylevel) cxx_local_unwind( frame, descr, -1 ); 581 return ExceptionContinueSearch; 582 } 583 if (!descr->tryblock_count) return ExceptionContinueSearch; 584 585 if(rec->ExceptionCode == CXX_EXCEPTION && 586 rec->ExceptionInformation[1] == 0 && rec->ExceptionInformation[2] == 0) 587 { 588 *rec = *msvcrt_get_thread_data()->exc_record; 589 rec->ExceptionFlags &= ~EH_UNWINDING; 590 if(TRACE_ON(seh)) { 591 TRACE("detect rethrow: exception code: %x\n", rec->ExceptionCode); 592 if(rec->ExceptionCode == CXX_EXCEPTION) 593 TRACE("re-propagate: obj: %lx, type: %lx\n", 594 rec->ExceptionInformation[1], rec->ExceptionInformation[2]); 595 } 596 } 597 598 if(rec->ExceptionCode == CXX_EXCEPTION) 599 { 600 exc_type = (cxx_exception_type *)rec->ExceptionInformation[2]; 601 602 if (rec->ExceptionInformation[0] > CXX_FRAME_MAGIC_VC8 && 603 exc_type->custom_handler) 604 { 605 return exc_type->custom_handler( rec, frame, context, dispatch, 606 descr, nested_trylevel, nested_frame, 0 ); 607 } 608 609 if (TRACE_ON(seh)) 610 { 611 TRACE("handling C++ exception rec %p frame %p trylevel %d descr %p nested_frame %p\n", 612 rec, frame, frame->trylevel, descr, nested_frame ); 613 dump_exception_type( exc_type ); 614 dump_function_descr( descr ); 615 } 616 } 617 else 618 { 619 thread_data_t *data = msvcrt_get_thread_data(); 620 621 exc_type = NULL; 622 TRACE("handling C exception code %x rec %p frame %p trylevel %d descr %p nested_frame %p\n", 623 rec->ExceptionCode, rec, frame, frame->trylevel, descr, nested_frame ); 624 625 if (data->se_translator) { 626 EXCEPTION_POINTERS except_ptrs; 627 se_translator_ctx ctx; 628 629 ctx.frame = frame; 630 ctx.descr = descr; 631 ctx.nested_frame = nested_frame; 632 __TRY 633 { 634 except_ptrs.ExceptionRecord = rec; 635 except_ptrs.ContextRecord = context; 636 data->se_translator( rec->ExceptionCode, &except_ptrs ); 637 } 638 __EXCEPT_CTX(se_translation_filter, &ctx) 639 { 640 } 641 __ENDTRY 642 } 643 } 644 645 call_catch_block( rec, context, frame, descr, 646 frame->trylevel, nested_frame, exc_type ); 647 return ExceptionContinueSearch; 648 } 649 650 651 /********************************************************************* 652 * __CxxFrameHandler (MSVCRT.@) 653 */ 654 extern DWORD CDECL __CxxFrameHandler(PEXCEPTION_RECORD rec, EXCEPTION_REGISTRATION_RECORD* frame, 655 PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch); 656 #ifdef _MSC_VER 657 DWORD _declspec(naked) __CxxFrameHandler(PEXCEPTION_RECORD rec, EXCEPTION_REGISTRATION_RECORD* frame, 658 PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch) 659 { 660 __asm 661 { 662 push 0 663 push 0 664 push eax 665 push[esp + 28] 666 push[esp + 28] 667 push[esp + 28] 668 push[esp + 28] 669 call cxx_frame_handler 670 add esp, 28 671 ret 672 } 673 } 674 #else 675 __ASM_GLOBAL_FUNC(__CxxFrameHandler, 676 "pushl $0\n\t" /* nested_trylevel */ 677 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 678 "pushl $0\n\t" /* nested_frame */ 679 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 680 "pushl %eax\n\t" /* descr */ 681 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 682 "pushl 28(%esp)\n\t" /* dispatch */ 683 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 684 "pushl 28(%esp)\n\t" /* context */ 685 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 686 "pushl 28(%esp)\n\t" /* frame */ 687 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 688 "pushl 28(%esp)\n\t" /* rec */ 689 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 690 "call " __ASM_NAME("cxx_frame_handler") "\n\t" 691 "add $28,%esp\n\t" 692 __ASM_CFI(".cfi_adjust_cfa_offset -28\n\t") 693 "ret") 694 #endif 695 696 697 /********************************************************************* 698 * __CxxLongjmpUnwind (MSVCRT.@) 699 * 700 * Callback meant to be used as UnwindFunc for setjmp/longjmp. 701 */ 702 void __stdcall __CxxLongjmpUnwind( const struct MSVCRT___JUMP_BUFFER *buf ) 703 { 704 cxx_exception_frame *frame = (cxx_exception_frame *)buf->Registration; 705 const cxx_function_descr *descr = (const cxx_function_descr *)buf->UnwindData[0]; 706 707 TRACE( "unwinding frame %p descr %p trylevel %ld\n", frame, descr, buf->TryLevel ); 708 cxx_local_unwind( frame, descr, buf->TryLevel ); 709 } 710 711 /********************************************************************* 712 * __CppXcptFilter (MSVCRT.@) 713 */ 714 int CDECL __CppXcptFilter(NTSTATUS ex, PEXCEPTION_POINTERS ptr) 715 { 716 /* only filter c++ exceptions */ 717 if (ex != CXX_EXCEPTION) return EXCEPTION_CONTINUE_SEARCH; 718 return _XcptFilter( ex, ptr ); 719 } 720 721 /********************************************************************* 722 * __CxxDetectRethrow (MSVCRT.@) 723 */ 724 BOOL CDECL __CxxDetectRethrow(PEXCEPTION_POINTERS ptrs) 725 { 726 PEXCEPTION_RECORD rec; 727 728 if (!ptrs) 729 return FALSE; 730 731 rec = ptrs->ExceptionRecord; 732 733 if (rec->ExceptionCode == CXX_EXCEPTION && 734 rec->NumberParameters == 3 && 735 rec->ExceptionInformation[0] == CXX_FRAME_MAGIC_VC6 && 736 rec->ExceptionInformation[2]) 737 { 738 ptrs->ExceptionRecord = msvcrt_get_thread_data()->exc_record; 739 return TRUE; 740 } 741 return (msvcrt_get_thread_data()->exc_record == rec); 742 } 743 744 /********************************************************************* 745 * __CxxQueryExceptionSize (MSVCRT.@) 746 */ 747 unsigned int CDECL __CxxQueryExceptionSize(void) 748 { 749 return sizeof(cxx_exception_type); 750 } 751 752 753 /********************************************************************* 754 * _EH_prolog (MSVCRT.@) 755 */ 756 757 /* Provided for VC++ binary compatibility only */ 758 __ASM_GLOBAL_FUNC(_EH_prolog, 759 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") /* skip ret addr */ 760 "pushl $-1\n\t" 761 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 762 "pushl %eax\n\t" 763 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 764 "pushl %fs:0\n\t" 765 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 766 "movl %esp, %fs:0\n\t" 767 "movl 12(%esp), %eax\n\t" 768 "movl %ebp, 12(%esp)\n\t" 769 "leal 12(%esp), %ebp\n\t" 770 "pushl %eax\n\t" 771 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 772 "ret") 773 774 static const SCOPETABLE_V4 *get_scopetable_v4( MSVCRT_EXCEPTION_FRAME *frame, ULONG_PTR cookie ) 775 { 776 return (const SCOPETABLE_V4 *)((ULONG_PTR)frame->scopetable ^ cookie); 777 } 778 779 static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec, 780 EXCEPTION_REGISTRATION_RECORD* frame, 781 PCONTEXT context, 782 EXCEPTION_REGISTRATION_RECORD** dispatch) 783 { 784 if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))) 785 return ExceptionContinueSearch; 786 *dispatch = frame; 787 return ExceptionCollidedUnwind; 788 } 789 790 static void msvcrt_local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp) 791 { 792 EXCEPTION_REGISTRATION_RECORD reg; 793 794 TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel); 795 796 /* Register a handler in case of a nested exception */ 797 reg.Handler = MSVCRT_nested_handler; 798 reg.Prev = NtCurrentTeb()->Tib.ExceptionList; 799 __wine_push_frame(®); 800 801 while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel) 802 { 803 int level = frame->trylevel; 804 frame->trylevel = frame->scopetable[level].previousTryLevel; 805 if (!frame->scopetable[level].lpfnFilter) 806 { 807 TRACE( "__try block cleanup level %d handler %p ebp %p\n", 808 level, frame->scopetable[level].lpfnHandler, ebp ); 809 call_handler( frame->scopetable[level].lpfnHandler, ebp ); 810 } 811 } 812 __wine_pop_frame(®); 813 TRACE("unwound OK\n"); 814 } 815 816 static void msvcrt_local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp ) 817 { 818 EXCEPTION_REGISTRATION_RECORD reg; 819 const SCOPETABLE_V4 *scopetable = get_scopetable_v4( frame, *cookie ); 820 821 TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel); 822 823 /* Register a handler in case of a nested exception */ 824 reg.Handler = MSVCRT_nested_handler; 825 reg.Prev = NtCurrentTeb()->Tib.ExceptionList; 826 __wine_push_frame(®); 827 828 while (frame->trylevel != -2 && frame->trylevel != trylevel) 829 { 830 int level = frame->trylevel; 831 frame->trylevel = scopetable->entries[level].previousTryLevel; 832 if (!scopetable->entries[level].lpfnFilter) 833 { 834 TRACE( "__try block cleanup level %d handler %p ebp %p\n", 835 level, scopetable->entries[level].lpfnHandler, ebp ); 836 call_handler( scopetable->entries[level].lpfnHandler, ebp ); 837 } 838 } 839 __wine_pop_frame(®); 840 TRACE("unwound OK\n"); 841 } 842 #ifndef __REACTOS__ 843 /******************************************************************* 844 * _local_unwind2 (MSVCRT.@) 845 */ 846 void CDECL _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel) 847 { 848 msvcrt_local_unwind2( frame, trylevel, &frame->_ebp ); 849 } 850 #endif 851 /******************************************************************* 852 * _local_unwind4 (MSVCRT.@) 853 */ 854 void CDECL _local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel ) 855 { 856 msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp ); 857 } 858 859 #ifndef __REACTOS__ 860 /******************************************************************* 861 * _global_unwind2 (MSVCRT.@) 862 */ 863 void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame) 864 { 865 TRACE("(%p)\n",frame); 866 RtlUnwind( frame, 0, 0, 0 ); 867 } 868 #else 869 void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame); 870 #endif 871 872 #ifndef __REACTOS__ 873 /********************************************************************* 874 * _except_handler2 (MSVCRT.@) 875 */ 876 int CDECL _except_handler2(PEXCEPTION_RECORD rec, 877 EXCEPTION_REGISTRATION_RECORD* frame, 878 PCONTEXT context, 879 EXCEPTION_REGISTRATION_RECORD** dispatcher) 880 { 881 FIXME("exception %x flags=%x at %p handler=%p %p %p stub\n", 882 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, 883 frame->Handler, context, dispatcher); 884 return ExceptionContinueSearch; 885 } 886 887 /********************************************************************* 888 * _except_handler3 (MSVCRT.@) 889 */ 890 int CDECL _except_handler3(PEXCEPTION_RECORD rec, 891 MSVCRT_EXCEPTION_FRAME* frame, 892 PCONTEXT context, void* dispatcher) 893 { 894 int retval, trylevel; 895 EXCEPTION_POINTERS exceptPtrs; 896 PSCOPETABLE pScopeTable; 897 898 TRACE("exception %x flags=%x at %p handler=%p %p %p semi-stub\n", 899 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, 900 frame->handler, context, dispatcher); 901 902 #ifdef _MSC_VER 903 __asm{ cld } 904 #else 905 __asm__ __volatile__("cld"); 906 #endif 907 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) 908 { 909 /* Unwinding the current frame */ 910 msvcrt_local_unwind2(frame, TRYLEVEL_END, &frame->_ebp); 911 TRACE("unwound current frame, returning ExceptionContinueSearch\n"); 912 return ExceptionContinueSearch; 913 } 914 else 915 { 916 /* Hunting for handler */ 917 exceptPtrs.ExceptionRecord = rec; 918 exceptPtrs.ContextRecord = context; 919 *((DWORD *)frame-1) = (DWORD)&exceptPtrs; 920 trylevel = frame->trylevel; 921 pScopeTable = frame->scopetable; 922 923 while (trylevel != TRYLEVEL_END) 924 { 925 TRACE( "level %d prev %d filter %p\n", trylevel, pScopeTable[trylevel].previousTryLevel, 926 pScopeTable[trylevel].lpfnFilter ); 927 if (pScopeTable[trylevel].lpfnFilter) 928 { 929 retval = call_filter( pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp ); 930 931 TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ? 932 "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ? 933 "EXECUTE_HANDLER" : "CONTINUE_SEARCH"); 934 935 if (retval == EXCEPTION_CONTINUE_EXECUTION) 936 return ExceptionContinueExecution; 937 938 if (retval == EXCEPTION_EXECUTE_HANDLER) 939 { 940 /* Unwind all higher frames, this one will handle the exception */ 941 _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame); 942 msvcrt_local_unwind2(frame, trylevel, &frame->_ebp); 943 944 /* Set our trylevel to the enclosing block, and call the __finally 945 * code, which won't return 946 */ 947 frame->trylevel = pScopeTable[trylevel].previousTryLevel; 948 TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler); 949 call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp); 950 } 951 } 952 trylevel = pScopeTable[trylevel].previousTryLevel; 953 } 954 } 955 TRACE("reached TRYLEVEL_END, returning ExceptionContinueSearch\n"); 956 return ExceptionContinueSearch; 957 } 958 #endif /* __REACTOS__ */ 959 /********************************************************************* 960 * _except_handler4_common (MSVCRT.@) 961 */ 962 int CDECL _except_handler4_common( ULONG *cookie, void (*check_cookie)(void), 963 EXCEPTION_RECORD *rec, MSVCRT_EXCEPTION_FRAME *frame, 964 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) 965 { 966 int retval, trylevel; 967 EXCEPTION_POINTERS exceptPtrs; 968 const SCOPETABLE_V4 *scope_table = get_scopetable_v4( frame, *cookie ); 969 970 TRACE( "exception %x flags=%x at %p handler=%p %p %p cookie=%x scope table=%p cookies=%d/%x,%d/%x\n", 971 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, 972 frame->handler, context, dispatcher, *cookie, scope_table, 973 scope_table->gs_cookie_offset, scope_table->gs_cookie_xor, 974 scope_table->eh_cookie_offset, scope_table->eh_cookie_xor ); 975 976 /* FIXME: no cookie validation yet */ 977 978 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) 979 { 980 /* Unwinding the current frame */ 981 msvcrt_local_unwind4( cookie, frame, -2, &frame->_ebp ); 982 TRACE("unwound current frame, returning ExceptionContinueSearch\n"); 983 return ExceptionContinueSearch; 984 } 985 else 986 { 987 /* Hunting for handler */ 988 exceptPtrs.ExceptionRecord = rec; 989 exceptPtrs.ContextRecord = context; 990 *((DWORD *)frame-1) = (DWORD)&exceptPtrs; 991 trylevel = frame->trylevel; 992 993 while (trylevel != -2) 994 { 995 TRACE( "level %d prev %d filter %p\n", trylevel, 996 scope_table->entries[trylevel].previousTryLevel, 997 scope_table->entries[trylevel].lpfnFilter ); 998 if (scope_table->entries[trylevel].lpfnFilter) 999 { 1000 retval = call_filter( scope_table->entries[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp ); 1001 1002 TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ? 1003 "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ? 1004 "EXECUTE_HANDLER" : "CONTINUE_SEARCH"); 1005 1006 if (retval == EXCEPTION_CONTINUE_EXECUTION) 1007 return ExceptionContinueExecution; 1008 1009 if (retval == EXCEPTION_EXECUTE_HANDLER) 1010 { 1011 __DestructExceptionObject(rec); 1012 1013 /* Unwind all higher frames, this one will handle the exception */ 1014 _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame); 1015 msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp ); 1016 1017 /* Set our trylevel to the enclosing block, and call the __finally 1018 * code, which won't return 1019 */ 1020 frame->trylevel = scope_table->entries[trylevel].previousTryLevel; 1021 TRACE("__finally block %p\n",scope_table->entries[trylevel].lpfnHandler); 1022 call_finally_block(scope_table->entries[trylevel].lpfnHandler, &frame->_ebp); 1023 } 1024 } 1025 trylevel = scope_table->entries[trylevel].previousTryLevel; 1026 } 1027 } 1028 TRACE("reached -2, returning ExceptionContinueSearch\n"); 1029 return ExceptionContinueSearch; 1030 } 1031 1032 1033 /* 1034 * setjmp/longjmp implementation 1035 */ 1036 1037 #define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */ 1038 typedef void (__stdcall *MSVCRT_unwind_function)(const struct MSVCRT___JUMP_BUFFER *); 1039 1040 /* define an entrypoint for setjmp/setjmp3 that stores the registers in the jmp buf */ 1041 /* and then jumps to the C backend function */ 1042 #define DEFINE_SETJMP_ENTRYPOINT(name) \ 1043 __ASM_GLOBAL_FUNC( name, \ 1044 "movl 4(%esp),%ecx\n\t" /* jmp_buf */ \ 1045 "movl %ebp,0(%ecx)\n\t" /* jmp_buf.Ebp */ \ 1046 "movl %ebx,4(%ecx)\n\t" /* jmp_buf.Ebx */ \ 1047 "movl %edi,8(%ecx)\n\t" /* jmp_buf.Edi */ \ 1048 "movl %esi,12(%ecx)\n\t" /* jmp_buf.Esi */ \ 1049 "movl %esp,16(%ecx)\n\t" /* jmp_buf.Esp */ \ 1050 "movl 0(%esp),%eax\n\t" \ 1051 "movl %eax,20(%ecx)\n\t" /* jmp_buf.Eip */ \ 1052 "jmp " __ASM_NAME("__regs_") # name ) 1053 1054 /******************************************************************* 1055 * _setjmp (MSVCRT.@) 1056 */ 1057 DEFINE_SETJMP_ENTRYPOINT(MSVCRT__setjmp) 1058 int CDECL DECLSPEC_HIDDEN __regs_MSVCRT__setjmp(struct MSVCRT___JUMP_BUFFER *jmp) 1059 { 1060 jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList; 1061 if (jmp->Registration == ~0UL) 1062 jmp->TryLevel = TRYLEVEL_END; 1063 else 1064 jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel; 1065 1066 TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n", 1067 jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration ); 1068 return 0; 1069 } 1070 1071 /******************************************************************* 1072 * _setjmp3 (MSVCRT.@) 1073 */ 1074 DEFINE_SETJMP_ENTRYPOINT( MSVCRT__setjmp3 ) 1075 int WINAPIV DECLSPEC_HIDDEN __regs_MSVCRT__setjmp3(struct MSVCRT___JUMP_BUFFER *jmp, int nb_args, ...) 1076 { 1077 jmp->Cookie = MSVCRT_JMP_MAGIC; 1078 jmp->UnwindFunc = 0; 1079 jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList; 1080 if (jmp->Registration == ~0UL) 1081 { 1082 jmp->TryLevel = TRYLEVEL_END; 1083 } 1084 else 1085 { 1086 int i; 1087 va_list args; 1088 1089 va_start( args, nb_args ); 1090 if (nb_args > 0) jmp->UnwindFunc = va_arg( args, unsigned long ); 1091 if (nb_args > 1) jmp->TryLevel = va_arg( args, unsigned long ); 1092 else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel; 1093 for (i = 0; i < 6 && i < nb_args - 2; i++) 1094 jmp->UnwindData[i] = va_arg( args, unsigned long ); 1095 va_end( args ); 1096 } 1097 1098 TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n", 1099 jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration ); 1100 return 0; 1101 } 1102 1103 /********************************************************************* 1104 * longjmp (MSVCRT.@) 1105 */ 1106 void CDECL MSVCRT_longjmp(struct MSVCRT___JUMP_BUFFER *jmp, int retval) 1107 { 1108 unsigned long cur_frame = 0; 1109 1110 TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx retval=%08x\n", 1111 jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration, retval ); 1112 1113 cur_frame=(unsigned long)NtCurrentTeb()->Tib.ExceptionList; 1114 TRACE("cur_frame=%lx\n",cur_frame); 1115 1116 if (cur_frame != jmp->Registration) 1117 _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)jmp->Registration); 1118 1119 if (jmp->Registration) 1120 { 1121 if (IsBadReadPtr(&jmp->Cookie, sizeof(long)) || jmp->Cookie != MSVCRT_JMP_MAGIC) 1122 { 1123 msvcrt_local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration, 1124 jmp->TryLevel, (void *)jmp->Ebp); 1125 } 1126 else if(jmp->UnwindFunc) 1127 { 1128 MSVCRT_unwind_function unwind_func; 1129 1130 unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc; 1131 unwind_func(jmp); 1132 } 1133 } 1134 1135 if (!retval) 1136 retval = 1; 1137 1138 __wine_longjmp( (__wine_jmp_buf *)jmp, retval ); 1139 } 1140 1141 /********************************************************************* 1142 * _seh_longjmp_unwind (MSVCRT.@) 1143 */ 1144 void __stdcall _seh_longjmp_unwind(struct MSVCRT___JUMP_BUFFER *jmp) 1145 { 1146 msvcrt_local_unwind2( (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, jmp->TryLevel, (void *)jmp->Ebp ); 1147 } 1148 1149 /********************************************************************* 1150 * _seh_longjmp_unwind4 (MSVCRT.@) 1151 */ 1152 void __stdcall _seh_longjmp_unwind4(struct MSVCRT___JUMP_BUFFER *jmp) 1153 { 1154 msvcrt_local_unwind4( (ULONG *)&jmp->Cookie, (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, 1155 jmp->TryLevel, (void *)jmp->Ebp ); 1156 } 1157 1158 /********************************************************************* 1159 * _fpieee_flt (MSVCRT.@) 1160 */ 1161 int __cdecl _fpieee_flt(ULONG exception_code, EXCEPTION_POINTERS *ep, 1162 int (__cdecl *handler)(_FPIEEE_RECORD*)) 1163 { 1164 FLOATING_SAVE_AREA *ctx = &ep->ContextRecord->FloatSave; 1165 _FPIEEE_RECORD rec; 1166 int ret; 1167 1168 TRACE("(%x %p %p)\n", exception_code, ep, handler); 1169 1170 switch(exception_code) { 1171 case STATUS_FLOAT_DIVIDE_BY_ZERO: 1172 case STATUS_FLOAT_INEXACT_RESULT: 1173 case STATUS_FLOAT_INVALID_OPERATION: 1174 case STATUS_FLOAT_OVERFLOW: 1175 case STATUS_FLOAT_UNDERFLOW: 1176 break; 1177 default: 1178 return EXCEPTION_CONTINUE_SEARCH; 1179 } 1180 1181 memset(&rec, 0, sizeof(rec)); 1182 rec.RoundingMode = ctx->ControlWord >> 10; 1183 switch((ctx->ControlWord >> 8) & 0x3) { 1184 case 0: rec.Precision = 2; break; 1185 case 1: rec.Precision = 3; break; 1186 case 2: rec.Precision = 1; break; 1187 case 3: rec.Precision = 0; break; 1188 } 1189 rec.Status.InvalidOperation = ctx->StatusWord & 0x1; 1190 rec.Status.ZeroDivide = ((ctx->StatusWord & 0x4) != 0); 1191 rec.Status.Overflow = ((ctx->StatusWord & 0x8) != 0); 1192 rec.Status.Underflow = ((ctx->StatusWord & 0x10) != 0); 1193 rec.Status.Inexact = ((ctx->StatusWord & 0x20) != 0); 1194 rec.Enable.InvalidOperation = ((ctx->ControlWord & 0x1) == 0); 1195 rec.Enable.ZeroDivide = ((ctx->ControlWord & 0x4) == 0); 1196 rec.Enable.Overflow = ((ctx->ControlWord & 0x8) == 0); 1197 rec.Enable.Underflow = ((ctx->ControlWord & 0x10) == 0); 1198 rec.Enable.Inexact = ((ctx->ControlWord & 0x20) == 0); 1199 rec.Cause.InvalidOperation = rec.Enable.InvalidOperation & rec.Status.InvalidOperation; 1200 rec.Cause.ZeroDivide = rec.Enable.ZeroDivide & rec.Status.ZeroDivide; 1201 rec.Cause.Overflow = rec.Enable.Overflow & rec.Status.Overflow; 1202 rec.Cause.Underflow = rec.Enable.Underflow & rec.Status.Underflow; 1203 rec.Cause.Inexact = rec.Enable.Inexact & rec.Status.Inexact; 1204 1205 TRACE("opcode: %x\n", *(ULONG*)ep->ContextRecord->FloatSave.ErrorOffset); 1206 1207 if(*(WORD*)ctx->ErrorOffset == 0x35dc) { /* fdiv m64fp */ 1208 if(exception_code==STATUS_FLOAT_DIVIDE_BY_ZERO || exception_code==STATUS_FLOAT_INVALID_OPERATION) { 1209 rec.Operand1.OperandValid = 1; 1210 rec.Result.OperandValid = 0; 1211 } else { 1212 rec.Operand1.OperandValid = 0; 1213 rec.Result.OperandValid = 1; 1214 } 1215 rec.Operand2.OperandValid = 1; 1216 rec.Operation = _FpCodeDivide; 1217 rec.Operand1.Format = _FpFormatFp80; 1218 memcpy(&rec.Operand1.Value.Fp80Value, ctx->RegisterArea, sizeof(rec.Operand1.Value.Fp80Value)); 1219 rec.Operand2.Format = _FpFormatFp64; 1220 rec.Operand2.Value.Fp64Value = *(double*)ctx->DataOffset; 1221 rec.Result.Format = _FpFormatFp80; 1222 memcpy(&rec.Result.Value.Fp80Value, ctx->RegisterArea, sizeof(rec.Operand1.Value.Fp80Value)); 1223 1224 ret = handler(&rec); 1225 1226 if(ret == EXCEPTION_CONTINUE_EXECUTION) 1227 memcpy(ctx->RegisterArea, &rec.Result.Value.Fp80Value, sizeof(rec.Operand1.Value.Fp80Value)); 1228 return ret; 1229 } 1230 1231 FIXME("unsupported opcode: %x\n", *(ULONG*)ep->ContextRecord->FloatSave.ErrorOffset); 1232 return EXCEPTION_CONTINUE_SEARCH; 1233 } 1234 1235 #endif /* __i386__ */ 1236