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