2 * C++ exception handling (ver. 4)
4 * Copyright 2020 Piotr Caban
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.
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.
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
23 #include "wine/exception.h"
24 #include "wine/debug.h"
25 #include "cppexcept.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
29 #define CXX_EXCEPTION 0xe06d7363
31 static DWORD fls_index
;
45 #define FUNC_DESCR_IS_CATCH 0x01
46 #define FUNC_DESCR_IS_SEPARATED 0x02
47 #define FUNC_DESCR_BBT 0x04
48 #define FUNC_DESCR_UNWIND_MAP 0x08
49 #define FUNC_DESCR_TRYBLOCK_MAP 0x10
50 #define FUNC_DESCR_EHS 0x20
51 #define FUNC_DESCR_NO_EXCEPT 0x40
52 #define FUNC_DESCR_RESERVED 0x80
71 #define CATCHBLOCK_FLAGS 0x01
72 #define CATCHBLOCK_TYPE_INFO 0x02
73 #define CATCHBLOCK_OFFSET 0x04
74 #define CATCHBLOCK_RET_ADDR 0x10
76 #define TYPE_FLAG_CONST 1
77 #define TYPE_FLAG_VOLATILE 2
78 #define TYPE_FLAG_REFERENCE 8
80 #define UNWIND_TYPE_NO_HANDLER 0
81 #define UNWIND_TYPE_DTOR_OBJ 1
82 #define UNWIND_TYPE_DTOR_PTR 2
83 #define UNWIND_TYPE_FRAME 3
90 UINT catchblock_count
;
96 UINT ip_off
; /* relative to start of function or earlier ipmap_info */
102 cxx_frame_info frame_info
;
106 EXCEPTION_RECORD
*prev_rec
;
113 EXCEPTION_RECORD
*seh_rec
;
114 DISPATCHER_CONTEXT
*dispatch
;
115 const cxx_function_descr
*descr
;
119 static UINT
decode_uint(BYTE
**b
)
129 else if ((*p
& 3) == 1)
131 ret
= (p
[0] >> 2) + (p
[1] << 6);
134 else if ((*p
& 7) == 3)
136 ret
= (p
[0] >> 3) + (p
[1] << 5) + (p
[2] << 13);
139 else if ((*p
& 15) == 7)
141 ret
= (p
[0] >> 4) + (p
[1] << 4) + (p
[2] << 12) + (p
[3] << 20);
146 FIXME("not implemented - expect crash\n");
155 static UINT
read_rva(BYTE
**b
)
157 UINT ret
= *(UINT
*)(*b
);
162 static inline void* rva_to_ptr(UINT rva
, ULONG64 base
)
164 return rva
? (void*)(base
+rva
) : NULL
;
167 static void read_unwind_info(BYTE
**b
, unwind_info
*ui
)
171 memset(ui
, 0, sizeof(*ui
));
172 ui
->type
= decode_uint(b
);
173 ui
->prev
= p
- (ui
->type
>> 2);
178 case UNWIND_TYPE_NO_HANDLER
:
180 case UNWIND_TYPE_DTOR_OBJ
:
181 ui
->handler
= read_rva(b
);
182 ui
->object
= decode_uint(b
); /* frame offset to object */
184 case UNWIND_TYPE_DTOR_PTR
:
185 ui
->handler
= read_rva(b
);
186 ui
->object
= decode_uint(b
); /* frame offset to pointer to object */
188 case UNWIND_TYPE_FRAME
:
189 ui
->handler
= read_rva(b
);
194 static void read_tryblock_info(BYTE
**b
, tryblock_info
*ti
, ULONG64 image_base
)
196 BYTE
*count
, *count_end
;
198 ti
->start_level
= decode_uint(b
);
199 ti
->end_level
= decode_uint(b
);
200 ti
->catch_level
= decode_uint(b
);
201 ti
->catchblock
= read_rva(b
);
203 count
= count_end
= rva_to_ptr(ti
->catchblock
, image_base
);
206 ti
->catchblock_count
= decode_uint(&count_end
);
207 ti
->catchblock
+= count_end
- count
;
211 ti
->catchblock_count
= 0;
215 static BOOL
read_catchblock_info(BYTE
**b
, catchblock_info
*ci
)
217 memset(ci
, 0, sizeof(*ci
));
220 if (ci
->header
& ~(CATCHBLOCK_FLAGS
| CATCHBLOCK_TYPE_INFO
| CATCHBLOCK_OFFSET
| CATCHBLOCK_RET_ADDR
))
222 FIXME("unknown header: %x\n", ci
->header
);
225 if (ci
->header
& CATCHBLOCK_FLAGS
) ci
->flags
= decode_uint(b
);
226 if (ci
->header
& CATCHBLOCK_TYPE_INFO
) ci
->type_info
= read_rva(b
);
227 if (ci
->header
& CATCHBLOCK_OFFSET
) ci
->offset
= decode_uint(b
);
228 ci
->handler
= read_rva(b
);
229 if (ci
->header
& CATCHBLOCK_RET_ADDR
) ci
->ret_addr
= decode_uint(b
);
233 static void read_ipmap_info(BYTE
**b
, ipmap_info
*ii
)
235 ii
->ip_off
= decode_uint(b
);
236 ii
->state
= (INT
)decode_uint(b
) - 1;
239 static inline void dump_type(UINT type_rva
, ULONG64 base
)
241 const cxx_type_info
*type
= rva_to_ptr(type_rva
, base
);
243 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n",
244 type
->flags
, type
->type_info
, dbgstr_type_info(rva_to_ptr(type
->type_info
, base
)),
245 type
->offsets
.this_offset
, type
->offsets
.vbase_descr
, type
->offsets
.vbase_offset
,
246 type
->size
, type
->copy_ctor
, rva_to_ptr(type
->copy_ctor
, base
));
249 static void dump_exception_type(const cxx_exception_type
*type
, ULONG64 base
)
251 const cxx_type_info_table
*type_info_table
= rva_to_ptr(type
->type_info_table
, base
);
254 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
255 type
->flags
, type
->destructor
, rva_to_ptr(type
->destructor
, base
),
256 type
->custom_handler
, rva_to_ptr(type
->custom_handler
, base
),
257 type
->type_info_table
, type_info_table
);
258 for (i
= 0; i
< type_info_table
->count
; i
++)
261 dump_type(type_info_table
->info
[i
], base
);
265 static BOOL
validate_cxx_function_descr4(const cxx_function_descr
*descr
, DISPATCHER_CONTEXT
*dispatch
)
267 ULONG64 image_base
= dispatch
->ImageBase
;
268 BYTE
*unwind_map
= rva_to_ptr(descr
->unwind_map
, image_base
);
269 BYTE
*tryblock_map
= rva_to_ptr(descr
->tryblock_map
, image_base
);
270 BYTE
*ip_map
= rva_to_ptr(descr
->ip_map
, image_base
);
274 TRACE("header 0x%x\n", descr
->header
);
275 TRACE("basic block transformations flags: 0x%x\n", descr
->bbt_flags
);
277 TRACE("unwind table: 0x%x(%p) %d\n", descr
->unwind_map
, unwind_map
, descr
->unwind_count
);
278 for (i
= 0; i
< descr
->unwind_count
; i
++)
280 BYTE
*entry
= unwind_map
;
283 read_unwind_info(&unwind_map
, &ui
);
284 if (ui
.prev
< (BYTE
*)rva_to_ptr(descr
->unwind_map
, image_base
)) ui
.prev
= NULL
;
285 TRACE(" %d (%p): type 0x%x prev %p func 0x%x(%p) object 0x%x\n",
286 i
, entry
, ui
.type
, ui
.prev
, ui
.handler
,
287 rva_to_ptr(ui
.handler
, image_base
), ui
.object
);
290 TRACE("try table: 0x%x(%p) %d\n", descr
->tryblock_map
, tryblock_map
, descr
->tryblock_count
);
291 for (i
= 0; i
< descr
->tryblock_count
; i
++)
296 read_tryblock_info(&tryblock_map
, &ti
, image_base
);
297 catchblock
= rva_to_ptr(ti
.catchblock
, image_base
);
298 TRACE(" %d: start %d end %d catchlevel %d catch 0x%x(%p) %d\n",
299 i
, ti
.start_level
, ti
.end_level
, ti
.catch_level
,
300 ti
.catchblock
, catchblock
, ti
.catchblock_count
);
301 for (j
= 0; j
< ti
.catchblock_count
; j
++)
304 if (!read_catchblock_info(&catchblock
, &ci
)) return FALSE
;
305 TRACE(" %d: header 0x%x offset %d handler 0x%x(%p) "
306 "ret addr %x type %x %s\n", j
, ci
.header
, ci
.offset
,
307 ci
.handler
, rva_to_ptr(ci
.handler
, image_base
),
308 ci
.ret_addr
, ci
.type_info
,
309 dbgstr_type_info(rva_to_ptr(ci
.type_info
, image_base
)));
313 TRACE("ipmap: 0x%x(%p) %d\n", descr
->ip_map
, ip_map
, descr
->ip_count
);
314 ip
= rva_to_ptr(dispatch
->FunctionEntry
->BeginAddress
, image_base
);
315 for (i
= 0; i
< descr
->ip_count
; i
++)
319 read_ipmap_info(&ip_map
, &ii
);
321 TRACE(" %d: ip offset 0x%x (%p) state %d\n", i
, ii
.ip_off
, ip
, ii
.state
);
324 TRACE("establisher frame: %x\n", descr
->frame
);
328 static inline int ip_to_state4(BYTE
*ip_map
, UINT count
, DISPATCHER_CONTEXT
*dispatch
, ULONG64 ip
)
335 state_ip
= dispatch
->ImageBase
+ dispatch
->FunctionEntry
->BeginAddress
;
336 for (i
= 0; i
< count
; i
++)
338 read_ipmap_info(&ip_map
, &ii
);
339 state_ip
+= ii
.ip_off
;
340 if (ip
< state_ip
) break;
344 TRACE("state %d\n", ret
);
348 static const cxx_type_info
*find_caught_type(cxx_exception_type
*exc_type
, ULONG64 exc_base
,
349 const type_info
*catch_ti
, UINT catch_flags
)
351 const cxx_type_info_table
*type_info_table
= rva_to_ptr(exc_type
->type_info_table
, exc_base
);
354 for (i
= 0; i
< type_info_table
->count
; i
++)
356 const cxx_type_info
*type
= rva_to_ptr(type_info_table
->info
[i
], exc_base
);
357 const type_info
*ti
= rva_to_ptr(type
->type_info
, exc_base
);
359 if (!catch_ti
) return type
; /* catch(...) matches any type */
362 if (strcmp( catch_ti
->mangled
, ti
->mangled
)) continue;
364 /* type is the same, now check the flags */
365 if ((exc_type
->flags
& TYPE_FLAG_CONST
) &&
366 !(catch_flags
& TYPE_FLAG_CONST
)) continue;
367 if ((exc_type
->flags
& TYPE_FLAG_VOLATILE
) &&
368 !(catch_flags
& TYPE_FLAG_VOLATILE
)) continue;
369 return type
; /* it matched */
374 static inline void copy_exception(void *object
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
375 const catchblock_info
*catchblock
, const cxx_type_info
*type
, ULONG64 exc_base
)
377 const type_info
*catch_ti
= rva_to_ptr(catchblock
->type_info
, dispatch
->ImageBase
);
378 void **dest
= rva_to_ptr(catchblock
->offset
, frame
);
380 if (!catch_ti
|| !catch_ti
->mangled
[0]) return;
381 if (!catchblock
->offset
) return;
383 if (catchblock
->flags
& TYPE_FLAG_REFERENCE
)
385 *dest
= get_this_pointer(&type
->offsets
, object
);
387 else if (type
->flags
& CLASS_IS_SIMPLE_TYPE
)
389 memmove(dest
, object
, type
->size
);
390 /* if it is a pointer, adjust it */
391 if (type
->size
== sizeof(void*)) *dest
= get_this_pointer(&type
->offsets
, *dest
);
393 else /* copy the object */
397 if (type
->flags
& CLASS_HAS_VIRTUAL_BASE_CLASS
)
399 void (__cdecl
*copy_ctor
)(void*, void*, int) =
400 rva_to_ptr(type
->copy_ctor
, exc_base
);
401 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
), 1);
405 void (__cdecl
*copy_ctor
)(void*, void*) =
406 rva_to_ptr(type
->copy_ctor
, exc_base
);
407 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
));
411 memmove(dest
, get_this_pointer(&type
->offsets
,object
), type
->size
);
415 static void cxx_local_unwind4(ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
416 const cxx_function_descr
*descr
, int trylevel
, int last_level
)
418 void (__cdecl
*handler_dtor
)(void *obj
, ULONG64 frame
);
419 BYTE
*unwind_data
, *last
;
426 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
427 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
430 TRACE("current level: %d, last level: %d\n", trylevel
, last_level
);
432 if (trylevel
<-1 || trylevel
>=(int)descr
->unwind_count
)
434 ERR("invalid trylevel %d\n", trylevel
);
438 if (trylevel
<= last_level
) return;
440 unwind_data
= rva_to_ptr(descr
->unwind_map
, dispatch
->ImageBase
);
441 last
= unwind_data
- 1;
442 for (i
= 0; i
< trylevel
; i
++)
444 BYTE
*addr
= unwind_data
;
445 read_unwind_info(&unwind_data
, &ui
);
446 if (i
== last_level
) last
= addr
;
449 while (unwind_data
> last
)
451 read_unwind_info(&unwind_data
, &ui
);
452 unwind_data
= ui
.prev
;
456 handler_dtor
= rva_to_ptr(ui
.handler
, dispatch
->ImageBase
);
457 obj
= rva_to_ptr(ui
.object
, frame
);
458 if(ui
.type
== UNWIND_TYPE_DTOR_PTR
)
460 TRACE("handler: %p object: %p\n", handler_dtor
, obj
);
461 handler_dtor(obj
, frame
);
466 static LONG CALLBACK
cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs
, void *c
)
468 EXCEPTION_RECORD
*rec
= eptrs
->ExceptionRecord
;
469 cxx_catch_ctx
*ctx
= c
;
471 if (rec
->ExceptionCode
== CXX_EXCEPTION
&& !rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
472 return EXCEPTION_EXECUTE_HANDLER
;
474 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->search_state
);
475 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
476 return EXCEPTION_CONTINUE_SEARCH
;
477 if (rec
->ExceptionInformation
[1] == ctx
->prev_rec
->ExceptionInformation
[1])
479 return EXCEPTION_CONTINUE_SEARCH
;
482 static void CALLBACK
cxx_catch_cleanup(BOOL normal
, void *c
)
484 cxx_catch_ctx
*ctx
= c
;
485 __CxxUnregisterExceptionObject(&ctx
->frame_info
, ctx
->rethrow
);
487 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->unwind_state
);
490 static void* WINAPI
call_catch_block4(EXCEPTION_RECORD
*rec
)
492 ULONG64 frame
= rec
->ExceptionInformation
[1];
493 EXCEPTION_RECORD
*prev_rec
= (void*)rec
->ExceptionInformation
[4];
494 EXCEPTION_RECORD
*untrans_rec
= (void*)rec
->ExceptionInformation
[6];
495 CONTEXT
*context
= (void*)rec
->ExceptionInformation
[7];
496 void* (__cdecl
*handler
)(ULONG64 unk
, ULONG64 rbp
) = (void*)rec
->ExceptionInformation
[5];
497 EXCEPTION_POINTERS ep
= { prev_rec
, context
};
499 void *ret_addr
= NULL
;
501 TRACE("calling handler %p\n", handler
);
504 __CxxRegisterExceptionObject(&ep
, &ctx
.frame_info
);
505 ctx
.search_state
= rec
->ExceptionInformation
[2];
506 ctx
.unwind_state
= rec
->ExceptionInformation
[3];
507 ctx
.prev_rec
= prev_rec
;
508 (*__processing_throw())--;
513 ret_addr
= handler(0, frame
);
515 __EXCEPT_CTX(cxx_rethrow_filter
, &ctx
)
517 TRACE("detect rethrow: exception code: %x\n", prev_rec
->ExceptionCode
);
519 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
.search_state
);
523 __DestructExceptionObject(prev_rec
);
524 RaiseException(untrans_rec
->ExceptionCode
, untrans_rec
->ExceptionFlags
,
525 untrans_rec
->NumberParameters
, untrans_rec
->ExceptionInformation
);
529 RaiseException(prev_rec
->ExceptionCode
, prev_rec
->ExceptionFlags
,
530 prev_rec
->NumberParameters
, prev_rec
->ExceptionInformation
);
535 __FINALLY_CTX(cxx_catch_cleanup
, &ctx
)
537 FlsSetValue(fls_index
, (void*)-2);
538 if (rec
->ExceptionInformation
[8]) return (void*)rec
->ExceptionInformation
[8];
542 static inline BOOL
cxx_is_consolidate(const EXCEPTION_RECORD
*rec
)
544 return rec
->ExceptionCode
==STATUS_UNWIND_CONSOLIDATE
&& rec
->NumberParameters
==9 &&
545 rec
->ExceptionInformation
[0]==(ULONG_PTR
)call_catch_block4
;
548 static inline void find_catch_block4(EXCEPTION_RECORD
*rec
, CONTEXT
*context
,
549 EXCEPTION_RECORD
*untrans_rec
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
550 const cxx_function_descr
*descr
, cxx_exception_type
*info
,
551 ULONG64 orig_frame
, int trylevel
)
553 ULONG64 exc_base
= (rec
->NumberParameters
== 4 ? rec
->ExceptionInformation
[3] : 0);
554 int *processing_throw
= __processing_throw();
555 EXCEPTION_RECORD catch_record
;
560 (*processing_throw
)++;
564 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
565 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
567 TRACE("current trylevel: %d\n", trylevel
);
569 tryblock_map
= rva_to_ptr(descr
->tryblock_map
, dispatch
->ImageBase
);
570 for (i
=0; i
<descr
->tryblock_count
; i
++)
572 tryblock_info tryblock
;
575 read_tryblock_info(&tryblock_map
, &tryblock
, dispatch
->ImageBase
);
577 if (trylevel
< tryblock
.start_level
) continue;
578 if (trylevel
> tryblock
.end_level
) continue;
580 /* got a try block */
581 catchblock
= rva_to_ptr(tryblock
.catchblock
, dispatch
->ImageBase
);
582 for (j
=0; j
<tryblock
.catchblock_count
; j
++)
586 read_catchblock_info(&catchblock
, &ci
);
590 const cxx_type_info
*type
= find_caught_type(info
, exc_base
,
591 rva_to_ptr(ci
.type_info
, dispatch
->ImageBase
),
595 TRACE("matched type %p in tryblock %d catchblock %d\n", type
, i
, j
);
597 /* copy the exception to its destination on the stack */
598 copy_exception((void*)rec
->ExceptionInformation
[1],
599 orig_frame
, dispatch
, &ci
, type
, exc_base
);
603 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
606 TRACE("found catch(...) block\n");
609 /* unwind stack and call catch */
610 memset(&catch_record
, 0, sizeof(catch_record
));
611 catch_record
.ExceptionCode
= STATUS_UNWIND_CONSOLIDATE
;
612 catch_record
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
613 catch_record
.NumberParameters
= 9;
614 catch_record
.ExceptionInformation
[0] = (ULONG_PTR
)call_catch_block4
;
615 catch_record
.ExceptionInformation
[1] = orig_frame
;
616 catch_record
.ExceptionInformation
[2] = tryblock
.catch_level
;
617 catch_record
.ExceptionInformation
[3] = tryblock
.start_level
;
618 catch_record
.ExceptionInformation
[4] = (ULONG_PTR
)rec
;
619 catch_record
.ExceptionInformation
[5] =
620 (ULONG_PTR
)rva_to_ptr(ci
.handler
, dispatch
->ImageBase
);
621 catch_record
.ExceptionInformation
[6] = (ULONG_PTR
)untrans_rec
;
622 catch_record
.ExceptionInformation
[7] = (ULONG_PTR
)context
;
624 catch_record
.ExceptionInformation
[8] = (ULONG_PTR
)rva_to_ptr(
625 ci
.ret_addr
+ dispatch
->FunctionEntry
->BeginAddress
, dispatch
->ImageBase
);
626 RtlUnwindEx((void*)frame
, (void*)dispatch
->ControlPc
, &catch_record
, NULL
, &ctx
, NULL
);
630 TRACE("no matching catch block found\n");
631 (*processing_throw
)--;
634 static LONG CALLBACK
se_translation_filter(EXCEPTION_POINTERS
*ep
, void *c
)
636 se_translator_ctx
*ctx
= (se_translator_ctx
*)c
;
637 EXCEPTION_RECORD
*rec
= ep
->ExceptionRecord
;
638 cxx_exception_type
*exc_type
;
640 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
642 TRACE("non-c++ exception thrown in SEH handler: %x\n", rec
->ExceptionCode
);
646 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
647 find_catch_block4(rec
, ep
->ContextRecord
, ctx
->seh_rec
, ctx
->dest_frame
, ctx
->dispatch
,
648 ctx
->descr
, exc_type
, ctx
->orig_frame
, ctx
->trylevel
);
650 __DestructExceptionObject(rec
);
651 return ExceptionContinueSearch
;
654 /* Hacky way to obtain se_translator */
655 static inline _se_translator_function
get_se_translator(void)
657 return __current_exception()[-2];
660 static void check_noexcept( PEXCEPTION_RECORD rec
, const cxx_function_descr
*descr
)
662 if (!(descr
->header
& FUNC_DESCR_IS_CATCH
) &&
663 rec
->ExceptionCode
== CXX_EXCEPTION
&&
664 (descr
->header
& FUNC_DESCR_NO_EXCEPT
))
666 ERR("noexcept function propagating exception\n");
671 static DWORD
cxx_frame_handler4(EXCEPTION_RECORD
*rec
, ULONG64 frame
,
672 CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
,
673 const cxx_function_descr
*descr
, int trylevel
)
675 cxx_exception_type
*exc_type
;
676 ULONG64 orig_frame
= frame
;
678 if (descr
->header
& FUNC_DESCR_IS_CATCH
)
680 TRACE("nested exception detected\n");
681 orig_frame
= *(ULONG64
*)rva_to_ptr(descr
->frame
, frame
);
682 TRACE("setting orig_frame to %lx\n", orig_frame
);
685 if (rec
->ExceptionFlags
& (EH_UNWINDING
|EH_EXIT_UNWIND
))
688 if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && cxx_is_consolidate(rec
))
689 last_level
= rec
->ExceptionInformation
[3];
690 else if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && rec
->ExceptionCode
== STATUS_LONGJUMP
)
691 last_level
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
692 descr
->ip_count
, dispatch
, dispatch
->TargetIp
);
694 cxx_local_unwind4(orig_frame
, dispatch
, descr
, trylevel
, last_level
);
695 return ExceptionContinueSearch
;
697 if (!descr
->tryblock_map
)
699 check_noexcept(rec
, descr
);
700 return ExceptionContinueSearch
;
703 if (rec
->ExceptionCode
== CXX_EXCEPTION
)
705 if (!rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
707 TRACE("rethrow detected.\n");
708 *rec
= *(EXCEPTION_RECORD
*)*__current_exception();
711 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
715 TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec
, frame
, descr
);
716 dump_exception_type(exc_type
, rec
->ExceptionInformation
[3]);
721 _se_translator_function se_translator
= get_se_translator();
724 TRACE("handling C exception code %x rec %p frame %lx descr %p\n",
725 rec
->ExceptionCode
, rec
, frame
, descr
);
728 EXCEPTION_POINTERS except_ptrs
;
729 se_translator_ctx ctx
;
731 ctx
.dest_frame
= frame
;
732 ctx
.orig_frame
= orig_frame
;
734 ctx
.dispatch
= dispatch
;
736 ctx
.trylevel
= trylevel
;
739 except_ptrs
.ExceptionRecord
= rec
;
740 except_ptrs
.ContextRecord
= context
;
741 se_translator(rec
->ExceptionCode
, &except_ptrs
);
743 __EXCEPT_CTX(se_translation_filter
, &ctx
)
750 find_catch_block4(rec
, context
, NULL
, frame
, dispatch
, descr
, exc_type
, orig_frame
, trylevel
);
751 check_noexcept(rec
, descr
);
752 return ExceptionContinueSearch
;
755 EXCEPTION_DISPOSITION __cdecl
__CxxFrameHandler4(EXCEPTION_RECORD
*rec
,
756 ULONG64 frame
, CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
)
758 cxx_function_descr descr
;
759 BYTE
*p
, *count
, *count_end
;
762 TRACE("%p %lx %p %p\n", rec
, frame
, context
, dispatch
);
764 trylevel
= (DWORD_PTR
)FlsGetValue(fls_index
);
765 FlsSetValue(fls_index
, (void*)-2);
767 memset(&descr
, 0, sizeof(descr
));
768 p
= rva_to_ptr(*(UINT
*)dispatch
->HandlerData
, dispatch
->ImageBase
);
771 if ((descr
.header
& FUNC_DESCR_EHS
) &&
772 rec
->ExceptionCode
!= CXX_EXCEPTION
&&
773 !cxx_is_consolidate(rec
) &&
774 rec
->ExceptionCode
!= STATUS_LONGJUMP
)
775 return ExceptionContinueSearch
; /* handle only c++ exceptions */
777 if (descr
.header
& ~(FUNC_DESCR_IS_CATCH
| FUNC_DESCR_UNWIND_MAP
|
778 FUNC_DESCR_TRYBLOCK_MAP
| FUNC_DESCR_EHS
| FUNC_DESCR_NO_EXCEPT
))
780 FIXME("unsupported flags: %x\n", descr
.header
);
781 return ExceptionContinueSearch
;
784 if (descr
.header
& FUNC_DESCR_BBT
) descr
.bbt_flags
= decode_uint(&p
);
785 if (descr
.header
& FUNC_DESCR_UNWIND_MAP
)
787 descr
.unwind_map
= read_rva(&p
);
788 count_end
= count
= rva_to_ptr(descr
.unwind_map
, dispatch
->ImageBase
);
789 descr
.unwind_count
= decode_uint(&count_end
);
790 descr
.unwind_map
+= count_end
- count
;
792 if (descr
.header
& FUNC_DESCR_TRYBLOCK_MAP
)
794 descr
.tryblock_map
= read_rva(&p
);
795 count_end
= count
= rva_to_ptr(descr
.tryblock_map
, dispatch
->ImageBase
);
796 descr
.tryblock_count
= decode_uint(&count_end
);
797 descr
.tryblock_map
+= count_end
- count
;
799 descr
.ip_map
= read_rva(&p
);
800 count_end
= count
= rva_to_ptr(descr
.ip_map
, dispatch
->ImageBase
);
801 descr
.ip_count
= decode_uint(&count_end
);
802 descr
.ip_map
+= count_end
- count
;
803 if (descr
.header
& FUNC_DESCR_IS_CATCH
) descr
.frame
= decode_uint(&p
);
805 if (!validate_cxx_function_descr4(&descr
, dispatch
))
806 return ExceptionContinueSearch
;
808 return cxx_frame_handler4(rec
, frame
, context
, dispatch
, &descr
, trylevel
);
811 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
815 case DLL_PROCESS_ATTACH
:
816 fls_index
= FlsAlloc(NULL
);
817 if (fls_index
== FLS_OUT_OF_INDEXES
)
820 case DLL_THREAD_ATTACH
:
821 FlsSetValue(fls_index
, (void*)-2);
823 case DLL_PROCESS_DETACH
: