1 /* 2 * msvcrt C++ exception handling 3 * 4 * Copyright 2011 Alexandre Julliard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "config.h" 22 #include "wine/port.h" 23 24 #ifdef __x86_64__ 25 26 #include <stdarg.h> 27 28 #include "ntstatus.h" 29 #define WIN32_NO_STATUS 30 #include "windef.h" 31 #include "winbase.h" 32 #include "winternl.h" 33 #include "msvcrt.h" 34 #include "wine/exception.h" 35 #include "excpt.h" 36 #include "wine/debug.h" 37 38 #include "cppexcept.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(seh); 41 42 typedef struct 43 { 44 int prev; 45 UINT handler; 46 } unwind_info; 47 48 typedef struct 49 { 50 UINT flags; 51 UINT type_info; 52 int offset; 53 UINT handler; 54 UINT frame; 55 } catchblock_info; 56 #define TYPE_FLAG_CONST 1 57 #define TYPE_FLAG_VOLATILE 2 58 #define TYPE_FLAG_REFERENCE 8 59 60 typedef struct 61 { 62 int start_level; 63 int end_level; 64 int catch_level; 65 int catchblock_count; 66 UINT catchblock; 67 } tryblock_info; 68 69 typedef struct 70 { 71 int ip; 72 int state; 73 } ipmap_info; 74 75 typedef struct __cxx_function_descr 76 { 77 UINT magic; 78 UINT unwind_count; 79 UINT unwind_table; 80 UINT tryblock_count; 81 UINT tryblock; 82 UINT ipmap_count; 83 UINT ipmap; 84 UINT unwind_help; 85 UINT expect_list; 86 UINT flags; 87 } cxx_function_descr; 88 89 typedef struct 90 { 91 cxx_frame_info frame_info; 92 BOOL rethrow; 93 } cxx_catch_ctx; 94 95 typedef struct 96 { 97 ULONG64 dest_frame; 98 ULONG64 orig_frame; 99 EXCEPTION_RECORD *seh_rec; 100 DISPATCHER_CONTEXT *dispatch; 101 const cxx_function_descr *descr; 102 } se_translator_ctx; 103 104 static inline void* rva_to_ptr(UINT rva, ULONG64 base) 105 { 106 return rva ? (void*)(base+rva) : NULL; 107 } 108 109 static inline void dump_type(UINT type_rva, ULONG64 base) 110 { 111 const cxx_type_info *type = rva_to_ptr(type_rva, base); 112 113 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n", 114 type->flags, type->type_info, dbgstr_type_info(rva_to_ptr(type->type_info, base)), 115 type->offsets.this_offset, type->offsets.vbase_descr, type->offsets.vbase_offset, 116 type->size, type->copy_ctor, rva_to_ptr(type->copy_ctor, base)); 117 } 118 119 static void dump_exception_type(const cxx_exception_type *type, ULONG64 base) 120 { 121 const cxx_type_info_table *type_info_table = rva_to_ptr(type->type_info_table, base); 122 UINT i; 123 124 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n", 125 type->flags, type->destructor, rva_to_ptr(type->destructor, base), 126 type->custom_handler, rva_to_ptr(type->custom_handler, base), 127 type->type_info_table, type_info_table); 128 for (i = 0; i < type_info_table->count; i++) 129 { 130 TRACE(" %d: ", i); 131 dump_type(type_info_table->info[i], base); 132 } 133 } 134 135 static void dump_function_descr(const cxx_function_descr *descr, ULONG64 image_base) 136 { 137 unwind_info *unwind_table = rva_to_ptr(descr->unwind_table, image_base); 138 tryblock_info *tryblock = rva_to_ptr(descr->tryblock, image_base); 139 ipmap_info *ipmap = rva_to_ptr(descr->ipmap, image_base); 140 UINT i, j; 141 142 TRACE("magic %x\n", descr->magic); 143 TRACE("unwind table: %x(%p) %d\n", descr->unwind_table, unwind_table, descr->unwind_count); 144 for (i=0; i<descr->unwind_count; i++) 145 { 146 TRACE(" %d: prev %d func %x(%p)\n", i, unwind_table[i].prev, 147 unwind_table[i].handler, rva_to_ptr(unwind_table[i].handler, image_base)); 148 } 149 TRACE("try table: %x(%p) %d\n", descr->tryblock, tryblock, descr->tryblock_count); 150 for (i=0; i<descr->tryblock_count; i++) 151 { 152 catchblock_info *catchblock = rva_to_ptr(tryblock[i].catchblock, image_base); 153 154 TRACE(" %d: start %d end %d catchlevel %d catch %x(%p) %d\n", i, 155 tryblock[i].start_level, tryblock[i].end_level, 156 tryblock[i].catch_level, tryblock[i].catchblock, 157 catchblock, tryblock[i].catchblock_count); 158 for (j=0; j<tryblock[i].catchblock_count; j++) 159 { 160 TRACE(" %d: flags %x offset %d handler %x(%p) frame %x type %x %s\n", 161 j, catchblock[j].flags, catchblock[j].offset, catchblock[j].handler, 162 rva_to_ptr(catchblock[j].handler, image_base), catchblock[j].frame, 163 catchblock[j].type_info, 164 dbgstr_type_info(rva_to_ptr(catchblock[j].type_info, image_base))); 165 } 166 } 167 TRACE("ipmap: %x(%p) %d\n", descr->ipmap, ipmap, descr->ipmap_count); 168 for (i=0; i<descr->ipmap_count; i++) 169 { 170 TRACE(" %d: ip %x state %d\n", i, ipmap[i].ip, ipmap[i].state); 171 } 172 TRACE("unwind_help %d\n", descr->unwind_help); 173 if (descr->magic <= CXX_FRAME_MAGIC_VC6) return; 174 TRACE("expect list: %x\n", descr->expect_list); 175 if (descr->magic <= CXX_FRAME_MAGIC_VC7) return; 176 TRACE("flags: %08x\n", descr->flags); 177 } 178 179 static inline int ip_to_state(ipmap_info *ipmap, UINT count, int ip) 180 { 181 UINT low = 0, high = count-1, med; 182 183 while (low < high) { 184 med = low + (high-low)/2; 185 186 if (ipmap[med].ip <= ip && ipmap[med+1].ip > ip) 187 { 188 low = med; 189 break; 190 } 191 if (ipmap[med].ip < ip) low = med+1; 192 else high = med-1; 193 } 194 195 TRACE("%x -> %d\n", ip, ipmap[low].state); 196 return ipmap[low].state; 197 } 198 199 /* check if the exception type is caught by a given catch block, and return the type that matched */ 200 static const cxx_type_info *find_caught_type(cxx_exception_type *exc_type, ULONG64 exc_base, 201 const type_info *catch_ti, UINT catch_flags) 202 { 203 const cxx_type_info_table *type_info_table = rva_to_ptr(exc_type->type_info_table, exc_base); 204 UINT i; 205 206 for (i = 0; i < type_info_table->count; i++) 207 { 208 const cxx_type_info *type = rva_to_ptr(type_info_table->info[i], exc_base); 209 const type_info *ti = rva_to_ptr(type->type_info, exc_base); 210 211 if (!catch_ti) return type; /* catch(...) matches any type */ 212 if (catch_ti != ti) 213 { 214 if (strcmp( catch_ti->mangled, ti->mangled )) continue; 215 } 216 /* type is the same, now check the flags */ 217 if ((exc_type->flags & TYPE_FLAG_CONST) && 218 !(catch_flags & TYPE_FLAG_CONST)) continue; 219 if ((exc_type->flags & TYPE_FLAG_VOLATILE) && 220 !(catch_flags & TYPE_FLAG_VOLATILE)) continue; 221 return type; /* it matched */ 222 } 223 return NULL; 224 } 225 226 static inline void copy_exception(void *object, ULONG64 frame, 227 DISPATCHER_CONTEXT *dispatch, 228 const catchblock_info *catchblock, 229 const cxx_type_info *type, ULONG64 exc_base) 230 { 231 const type_info *catch_ti = rva_to_ptr(catchblock->type_info, dispatch->ImageBase); 232 void **dest = rva_to_ptr(catchblock->offset, frame); 233 234 if (!catch_ti || !catch_ti->mangled[0]) return; 235 if (!catchblock->offset) return; 236 237 if (catchblock->flags & TYPE_FLAG_REFERENCE) 238 { 239 *dest = get_this_pointer(&type->offsets, object); 240 } 241 else if (type->flags & CLASS_IS_SIMPLE_TYPE) 242 { 243 memmove(dest, object, type->size); 244 /* if it is a pointer, adjust it */ 245 if (type->size == sizeof(void*)) *dest = get_this_pointer(&type->offsets, *dest); 246 } 247 else /* copy the object */ 248 { 249 if (type->copy_ctor) 250 { 251 if (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) 252 { 253 void (__cdecl *copy_ctor)(void*, void*, int) = 254 rva_to_ptr(type->copy_ctor, exc_base); 255 copy_ctor(dest, get_this_pointer(&type->offsets, object), 1); 256 } 257 else 258 { 259 void (__cdecl *copy_ctor)(void*, void*) = 260 rva_to_ptr(type->copy_ctor, exc_base); 261 copy_ctor(dest, get_this_pointer(&type->offsets, object)); 262 } 263 } 264 else 265 memmove(dest, get_this_pointer(&type->offsets,object), type->size); 266 } 267 } 268 269 static void cxx_local_unwind(ULONG64 frame, DISPATCHER_CONTEXT *dispatch, 270 const cxx_function_descr *descr, int last_level) 271 { 272 const unwind_info *unwind_table = rva_to_ptr(descr->unwind_table, dispatch->ImageBase); 273 void (__cdecl *handler)(ULONG64 unk, ULONG64 rbp); 274 int *unwind_help = rva_to_ptr(descr->unwind_help, frame); 275 int trylevel; 276 277 if (unwind_help[0] == -2) 278 { 279 trylevel = ip_to_state(rva_to_ptr(descr->ipmap, dispatch->ImageBase), 280 descr->ipmap_count, dispatch->ControlPc-dispatch->ImageBase); 281 } 282 else 283 { 284 trylevel = unwind_help[0]; 285 } 286 287 TRACE("current level: %d, last level: %d\n", trylevel, last_level); 288 while (trylevel > last_level) 289 { 290 if (trylevel<0 || trylevel>=descr->unwind_count) 291 { 292 ERR("invalid trylevel %d\n", trylevel); 293 MSVCRT_terminate(); 294 } 295 handler = rva_to_ptr(unwind_table[trylevel].handler, dispatch->ImageBase); 296 if (handler) 297 { 298 TRACE("handler: %p\n", handler); 299 handler(0, frame); 300 } 301 trylevel = unwind_table[trylevel].prev; 302 } 303 unwind_help[0] = trylevel; 304 } 305 306 static LONG CALLBACK cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs, void *c) 307 { 308 EXCEPTION_RECORD *rec = eptrs->ExceptionRecord; 309 thread_data_t *data = msvcrt_get_thread_data(); 310 cxx_catch_ctx *ctx = c; 311 312 if (rec->ExceptionCode != CXX_EXCEPTION) 313 return EXCEPTION_CONTINUE_SEARCH; 314 if (!rec->ExceptionInformation[1] && !rec->ExceptionInformation[2]) 315 return EXCEPTION_EXECUTE_HANDLER; 316 if (rec->ExceptionInformation[1] == data->exc_record->ExceptionInformation[1]) 317 ctx->rethrow = TRUE; 318 return EXCEPTION_CONTINUE_SEARCH; 319 } 320 321 static void CALLBACK cxx_catch_cleanup(BOOL normal, void *c) 322 { 323 cxx_catch_ctx *ctx = c; 324 __CxxUnregisterExceptionObject(&ctx->frame_info, ctx->rethrow); 325 } 326 327 static void* WINAPI call_catch_block(EXCEPTION_RECORD *rec) 328 { 329 ULONG64 frame = rec->ExceptionInformation[1]; 330 const cxx_function_descr *descr = (void*)rec->ExceptionInformation[2]; 331 EXCEPTION_RECORD *prev_rec = (void*)rec->ExceptionInformation[4]; 332 EXCEPTION_RECORD *untrans_rec = (void*)rec->ExceptionInformation[6]; 333 CONTEXT *context = (void*)rec->ExceptionInformation[7]; 334 void* (__cdecl *handler)(ULONG64 unk, ULONG64 rbp) = (void*)rec->ExceptionInformation[5]; 335 int *unwind_help = rva_to_ptr(descr->unwind_help, frame); 336 EXCEPTION_POINTERS ep = { prev_rec, context }; 337 cxx_catch_ctx ctx; 338 void *ret_addr = NULL; 339 340 TRACE("calling handler %p\n", handler); 341 342 ctx.rethrow = FALSE; 343 __CxxRegisterExceptionObject(&ep, &ctx.frame_info); 344 msvcrt_get_thread_data()->processing_throw--; 345 __TRY 346 { 347 __TRY 348 { 349 ret_addr = handler(0, frame); 350 } 351 __EXCEPT_CTX(cxx_rethrow_filter, &ctx) 352 { 353 TRACE("detect rethrow: exception code: %x\n", prev_rec->ExceptionCode); 354 ctx.rethrow = TRUE; 355 356 if (untrans_rec) 357 { 358 __DestructExceptionObject(prev_rec); 359 RaiseException(untrans_rec->ExceptionCode, untrans_rec->ExceptionFlags, 360 untrans_rec->NumberParameters, untrans_rec->ExceptionInformation); 361 } 362 else 363 { 364 RaiseException(prev_rec->ExceptionCode, prev_rec->ExceptionFlags, 365 prev_rec->NumberParameters, prev_rec->ExceptionInformation); 366 } 367 } 368 __ENDTRY 369 } 370 __FINALLY_CTX(cxx_catch_cleanup, &ctx) 371 372 unwind_help[0] = -2; 373 unwind_help[1] = -1; 374 return ret_addr; 375 } 376 377 static inline BOOL cxx_is_consolidate(const EXCEPTION_RECORD *rec) 378 { 379 return rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==8 && 380 rec->ExceptionInformation[0]==(ULONG_PTR)call_catch_block; 381 } 382 383 static inline void find_catch_block(EXCEPTION_RECORD *rec, CONTEXT *context, 384 EXCEPTION_RECORD *untrans_rec, 385 ULONG64 frame, DISPATCHER_CONTEXT *dispatch, 386 const cxx_function_descr *descr, 387 cxx_exception_type *info, ULONG64 orig_frame) 388 { 389 ULONG64 exc_base = (rec->NumberParameters == 4 ? rec->ExceptionInformation[3] : 0); 390 int trylevel = ip_to_state(rva_to_ptr(descr->ipmap, dispatch->ImageBase), 391 descr->ipmap_count, dispatch->ControlPc-dispatch->ImageBase); 392 thread_data_t *data = msvcrt_get_thread_data(); 393 const tryblock_info *in_catch; 394 EXCEPTION_RECORD catch_record; 395 CONTEXT ctx; 396 UINT i, j; 397 INT *unwind_help; 398 399 data->processing_throw++; 400 for (i=descr->tryblock_count; i>0; i--) 401 { 402 in_catch = rva_to_ptr(descr->tryblock, dispatch->ImageBase); 403 in_catch = &in_catch[i-1]; 404 405 if (trylevel>in_catch->end_level && trylevel<=in_catch->catch_level) 406 break; 407 } 408 if (!i) 409 in_catch = NULL; 410 411 unwind_help = rva_to_ptr(descr->unwind_help, orig_frame); 412 if (trylevel > unwind_help[1]) 413 unwind_help[0] = unwind_help[1] = trylevel; 414 else 415 trylevel = unwind_help[1]; 416 TRACE("current trylevel: %d\n", trylevel); 417 418 for (i=0; i<descr->tryblock_count; i++) 419 { 420 const tryblock_info *tryblock = rva_to_ptr(descr->tryblock, dispatch->ImageBase); 421 tryblock = &tryblock[i]; 422 423 if (trylevel < tryblock->start_level) continue; 424 if (trylevel > tryblock->end_level) continue; 425 426 if (in_catch) 427 { 428 if(tryblock->start_level <= in_catch->end_level) continue; 429 if(tryblock->end_level > in_catch->catch_level) continue; 430 } 431 432 /* got a try block */ 433 for (j=0; j<tryblock->catchblock_count; j++) 434 { 435 const catchblock_info *catchblock = rva_to_ptr(tryblock->catchblock, dispatch->ImageBase); 436 catchblock = &catchblock[j]; 437 438 if (info) 439 { 440 const cxx_type_info *type = find_caught_type(info, exc_base, 441 rva_to_ptr(catchblock->type_info, dispatch->ImageBase), 442 catchblock->flags); 443 if (!type) continue; 444 445 TRACE("matched type %p in tryblock %d catchblock %d\n", type, i, j); 446 447 /* copy the exception to its destination on the stack */ 448 copy_exception((void*)rec->ExceptionInformation[1], 449 orig_frame, dispatch, catchblock, type, exc_base); 450 } 451 else 452 { 453 /* no CXX_EXCEPTION only proceed with a catch(...) block*/ 454 if (catchblock->type_info) 455 continue; 456 TRACE("found catch(...) block\n"); 457 } 458 459 /* unwind stack and call catch */ 460 memset(&catch_record, 0, sizeof(catch_record)); 461 catch_record.ExceptionCode = STATUS_UNWIND_CONSOLIDATE; 462 catch_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 463 catch_record.NumberParameters = 8; 464 catch_record.ExceptionInformation[0] = (ULONG_PTR)call_catch_block; 465 catch_record.ExceptionInformation[1] = orig_frame; 466 catch_record.ExceptionInformation[2] = (ULONG_PTR)descr; 467 catch_record.ExceptionInformation[3] = tryblock->start_level; 468 catch_record.ExceptionInformation[4] = (ULONG_PTR)rec; 469 catch_record.ExceptionInformation[5] = 470 (ULONG_PTR)rva_to_ptr(catchblock->handler, dispatch->ImageBase); 471 catch_record.ExceptionInformation[6] = (ULONG_PTR)untrans_rec; 472 catch_record.ExceptionInformation[7] = (ULONG_PTR)context; 473 RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &ctx, NULL); 474 } 475 } 476 477 TRACE("no matching catch block found\n"); 478 data->processing_throw--; 479 } 480 481 static LONG CALLBACK se_translation_filter(EXCEPTION_POINTERS *ep, void *c) 482 { 483 se_translator_ctx *ctx = (se_translator_ctx *)c; 484 EXCEPTION_RECORD *rec = ep->ExceptionRecord; 485 cxx_exception_type *exc_type; 486 487 if (rec->ExceptionCode != CXX_EXCEPTION) 488 { 489 TRACE("non-c++ exception thrown in SEH handler: %x\n", rec->ExceptionCode); 490 MSVCRT_terminate(); 491 } 492 493 exc_type = (cxx_exception_type *)rec->ExceptionInformation[2]; 494 find_catch_block(rec, ep->ContextRecord, ctx->seh_rec, ctx->dest_frame, ctx->dispatch, 495 ctx->descr, exc_type, ctx->orig_frame); 496 497 __DestructExceptionObject(rec); 498 return ExceptionContinueSearch; 499 } 500 501 static DWORD cxx_frame_handler(EXCEPTION_RECORD *rec, ULONG64 frame, 502 CONTEXT *context, DISPATCHER_CONTEXT *dispatch, 503 const cxx_function_descr *descr) 504 { 505 int trylevel = ip_to_state(rva_to_ptr(descr->ipmap, dispatch->ImageBase), 506 descr->ipmap_count, dispatch->ControlPc-dispatch->ImageBase); 507 cxx_exception_type *exc_type; 508 ULONG64 orig_frame = frame; 509 ULONG64 throw_base; 510 DWORD throw_func_off; 511 void *throw_func; 512 UINT i, j; 513 int unwindlevel = -1; 514 515 if (descr->magic<CXX_FRAME_MAGIC_VC6 || descr->magic>CXX_FRAME_MAGIC_VC8) 516 { 517 FIXME("unhandled frame magic %x\n", descr->magic); 518 return ExceptionContinueSearch; 519 } 520 521 if (descr->magic >= CXX_FRAME_MAGIC_VC8 && 522 (descr->flags & FUNC_DESCR_SYNCHRONOUS) && 523 (rec->ExceptionCode != CXX_EXCEPTION && 524 !cxx_is_consolidate(rec) && 525 rec->ExceptionCode != STATUS_LONGJUMP)) 526 return ExceptionContinueSearch; /* handle only c++ exceptions */ 527 528 /* update orig_frame if it's a nested exception */ 529 throw_func_off = RtlLookupFunctionEntry(dispatch->ControlPc, &throw_base, NULL)->BeginAddress; 530 throw_func = rva_to_ptr(throw_func_off, throw_base); 531 TRACE("reconstructed handler pointer: %p\n", throw_func); 532 for (i=descr->tryblock_count; i>0; i--) 533 { 534 const tryblock_info *tryblock = rva_to_ptr(descr->tryblock, dispatch->ImageBase); 535 tryblock = &tryblock[i-1]; 536 537 if (trylevel>tryblock->end_level && trylevel<=tryblock->catch_level) 538 { 539 for (j=0; j<tryblock->catchblock_count; j++) 540 { 541 const catchblock_info *catchblock = rva_to_ptr(tryblock->catchblock, dispatch->ImageBase); 542 catchblock = &catchblock[j]; 543 544 if (rva_to_ptr(catchblock->handler, dispatch->ImageBase) == throw_func) 545 { 546 TRACE("nested exception detected\n"); 547 unwindlevel = tryblock->end_level; 548 orig_frame = *(ULONG64*)rva_to_ptr(catchblock->frame, frame); 549 TRACE("setting orig_frame to %lx\n", orig_frame); 550 } 551 } 552 } 553 } 554 555 if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND)) 556 { 557 if (rec->ExceptionFlags & EH_TARGET_UNWIND) 558 cxx_local_unwind(orig_frame, dispatch, descr, 559 cxx_is_consolidate(rec) ? rec->ExceptionInformation[3] : trylevel); 560 else 561 cxx_local_unwind(orig_frame, dispatch, descr, unwindlevel); 562 return ExceptionContinueSearch; 563 } 564 if (!descr->tryblock_count) return ExceptionContinueSearch; 565 566 if (rec->ExceptionCode == CXX_EXCEPTION) 567 { 568 exc_type = (cxx_exception_type *)rec->ExceptionInformation[2]; 569 570 if (TRACE_ON(seh)) 571 { 572 TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec, frame, descr); 573 dump_exception_type(exc_type, rec->ExceptionInformation[3]); 574 dump_function_descr(descr, dispatch->ImageBase); 575 } 576 } 577 else 578 { 579 thread_data_t *data = msvcrt_get_thread_data(); 580 581 exc_type = NULL; 582 TRACE("handling C exception code %x rec %p frame %lx descr %p\n", 583 rec->ExceptionCode, rec, frame, descr); 584 585 if (data->se_translator) { 586 EXCEPTION_POINTERS except_ptrs; 587 se_translator_ctx ctx; 588 589 ctx.dest_frame = frame; 590 ctx.orig_frame = orig_frame; 591 ctx.seh_rec = rec; 592 ctx.dispatch = dispatch; 593 ctx.descr = descr; 594 __TRY 595 { 596 except_ptrs.ExceptionRecord = rec; 597 except_ptrs.ContextRecord = context; 598 data->se_translator(rec->ExceptionCode, &except_ptrs); 599 } 600 __EXCEPT_CTX(se_translation_filter, &ctx) 601 { 602 } 603 __ENDTRY 604 } 605 } 606 607 find_catch_block(rec, context, NULL, frame, dispatch, descr, exc_type, orig_frame); 608 return ExceptionContinueSearch; 609 } 610 611 /********************************************************************* 612 * __CxxExceptionFilter (MSVCRT.@) 613 */ 614 int CDECL __CxxExceptionFilter( PEXCEPTION_POINTERS ptrs, 615 const type_info *ti, int flags, void **copy ) 616 { 617 FIXME( "%p %p %x %p: not implemented\n", ptrs, ti, flags, copy ); 618 return EXCEPTION_CONTINUE_SEARCH; 619 } 620 621 /********************************************************************* 622 * __CxxFrameHandler (MSVCRT.@) 623 */ 624 EXCEPTION_DISPOSITION CDECL __CxxFrameHandler( EXCEPTION_RECORD *rec, ULONG64 frame, 625 CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) 626 { 627 TRACE( "%p %lx %p %p\n", rec, frame, context, dispatch ); 628 return cxx_frame_handler( rec, frame, context, dispatch, 629 rva_to_ptr(*(UINT*)dispatch->HandlerData, dispatch->ImageBase) ); 630 } 631 632 633 /********************************************************************* 634 * __CppXcptFilter (MSVCRT.@) 635 */ 636 int CDECL __CppXcptFilter(NTSTATUS ex, PEXCEPTION_POINTERS ptr) 637 { 638 /* only filter c++ exceptions */ 639 if (ex != CXX_EXCEPTION) return EXCEPTION_CONTINUE_SEARCH; 640 return _XcptFilter( ex, ptr ); 641 } 642 643 644 /********************************************************************* 645 * __CxxDetectRethrow (MSVCRT.@) 646 */ 647 BOOL CDECL __CxxDetectRethrow(PEXCEPTION_POINTERS ptrs) 648 { 649 PEXCEPTION_RECORD rec; 650 651 if (!ptrs) 652 return FALSE; 653 654 rec = ptrs->ExceptionRecord; 655 656 if (rec->ExceptionCode == CXX_EXCEPTION && 657 rec->NumberParameters == 4 && 658 rec->ExceptionInformation[0] == CXX_FRAME_MAGIC_VC6 && 659 rec->ExceptionInformation[2]) 660 { 661 ptrs->ExceptionRecord = msvcrt_get_thread_data()->exc_record; 662 return TRUE; 663 } 664 return (msvcrt_get_thread_data()->exc_record == rec); 665 } 666 667 668 /********************************************************************* 669 * __CxxQueryExceptionSize (MSVCRT.@) 670 */ 671 unsigned int CDECL __CxxQueryExceptionSize(void) 672 { 673 return sizeof(cxx_exception_type); 674 } 675 676 677 #ifndef __REACTOS__ 678 /******************************************************************* 679 * _setjmp (MSVCRT.@) 680 */ 681 __ASM_GLOBAL_FUNC( MSVCRT__setjmp, 682 "jmp " __ASM_NAME("__wine_setjmpex") ); 683 #endif 684 685 /******************************************************************* 686 * longjmp (MSVCRT.@) 687 */ 688 void __cdecl MSVCRT_longjmp( struct MSVCRT___JUMP_BUFFER *jmp, int retval ) 689 { 690 EXCEPTION_RECORD rec; 691 692 if (!retval) retval = 1; 693 if (jmp->Frame) 694 { 695 rec.ExceptionCode = STATUS_LONGJUMP; 696 rec.ExceptionFlags = 0; 697 rec.ExceptionRecord = NULL; 698 rec.ExceptionAddress = NULL; 699 rec.NumberParameters = 1; 700 rec.ExceptionInformation[0] = (DWORD_PTR)jmp; 701 RtlUnwind( (void *)jmp->Frame, (void *)jmp->Rip, &rec, IntToPtr(retval) ); 702 } 703 __wine_longjmp( (__wine_jmp_buf *)jmp, retval ); 704 } 705 706 #ifndef __REACTOS__ // different file for ntdll 707 /******************************************************************* 708 * _local_unwind (MSVCRT.@) 709 */ 710 void __cdecl _local_unwind( void *frame, void *target ) 711 { 712 RtlUnwind( frame, target, NULL, 0 ); 713 } 714 #endif /* __REACTOS__ */ 715 716 /********************************************************************* 717 * _fpieee_flt (MSVCRT.@) 718 */ 719 int __cdecl _fpieee_flt(ULONG exception_code, EXCEPTION_POINTERS *ep, 720 int (__cdecl *handler)(_FPIEEE_RECORD*)) 721 { 722 FIXME("(%x %p %p) opcode: %s\n", exception_code, ep, handler, 723 wine_dbgstr_longlong(*(ULONG64*)ep->ContextRecord->Rip)); 724 return EXCEPTION_CONTINUE_SEARCH; 725 } 726 727 #if _MSVCR_VER>=110 && _MSVCR_VER<=120 728 /********************************************************************* 729 * __crtCapturePreviousContext (MSVCR110.@) 730 */ 731 void __cdecl get_prev_context(CONTEXT *ctx, DWORD64 rip) 732 { 733 ULONG64 frame, image_base; 734 RUNTIME_FUNCTION *rf; 735 void *data; 736 737 TRACE("(%p)\n", ctx); 738 739 rf = RtlLookupFunctionEntry(ctx->Rip, &image_base, NULL); 740 if(!rf) { 741 FIXME("RtlLookupFunctionEntry failed\n"); 742 return; 743 } 744 745 RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, ctx->Rip, 746 rf, ctx, &data, &frame, NULL); 747 } 748 749 __ASM_GLOBAL_FUNC( __crtCapturePreviousContext, 750 "movq %rcx,8(%rsp)\n\t" 751 "call " __ASM_NAME("RtlCaptureContext") "\n\t" 752 "movq 8(%rsp),%rcx\n\t" /* context */ 753 "leaq 8(%rsp),%rax\n\t" 754 "movq %rax,0x98(%rcx)\n\t" /* context->Rsp */ 755 "movq (%rsp),%rax\n\t" 756 "movq %rax,0xf8(%rcx)\n\t" /* context->Rip */ 757 "jmp " __ASM_NAME("get_prev_context") ) 758 #endif 759 760 #endif /* __x86_64__ */ 761