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
25 #include "wine/exception.h"
26 #include "wine/debug.h"
27 #include "cppexcept.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
31 #define CXX_EXCEPTION 0xe06d7363
33 static DWORD fls_index
;
47 #define FUNC_DESCR_IS_CATCH 0x01
48 #define FUNC_DESCR_IS_SEPARATED 0x02
49 #define FUNC_DESCR_BBT 0x04
50 #define FUNC_DESCR_UNWIND_MAP 0x08
51 #define FUNC_DESCR_TRYBLOCK_MAP 0x10
52 #define FUNC_DESCR_EHS 0x20
53 #define FUNC_DESCR_NO_EXCEPT 0x40
54 #define FUNC_DESCR_RESERVED 0x80
73 #define CATCHBLOCK_FLAGS 0x01
74 #define CATCHBLOCK_TYPE_INFO 0x02
75 #define CATCHBLOCK_OFFSET 0x04
76 #define CATCHBLOCK_RET_ADDR_MASK 0x30
77 #define CATCHBLOCK_RET_ADDR 0x10
78 #define CATCHBLOCK_TWO_RET_ADDRS 0x20
80 #define TYPE_FLAG_CONST 1
81 #define TYPE_FLAG_VOLATILE 2
82 #define TYPE_FLAG_REFERENCE 8
84 #define UNWIND_TYPE_NO_HANDLER 0
85 #define UNWIND_TYPE_DTOR_OBJ 1
86 #define UNWIND_TYPE_DTOR_PTR 2
87 #define UNWIND_TYPE_FRAME 3
89 #define CONSOLIDATE_UNWIND_PARAMETER_COUNT 10
96 UINT catchblock_count
;
102 UINT ip_off
; /* relative to start of function or earlier ipmap_info */
108 cxx_frame_info frame_info
;
112 EXCEPTION_RECORD
*prev_rec
;
119 EXCEPTION_RECORD
*seh_rec
;
120 DISPATCHER_CONTEXT
*dispatch
;
121 const cxx_function_descr
*descr
;
125 static UINT
decode_uint(BYTE
**b
)
135 else if ((*p
& 3) == 1)
137 ret
= (p
[0] >> 2) + (p
[1] << 6);
140 else if ((*p
& 7) == 3)
142 ret
= (p
[0] >> 3) + (p
[1] << 5) + (p
[2] << 13);
145 else if ((*p
& 15) == 7)
147 ret
= (p
[0] >> 4) + (p
[1] << 4) + (p
[2] << 12) + (p
[3] << 20);
152 FIXME("not implemented - expect crash\n");
161 static UINT
read_rva(BYTE
**b
)
163 UINT ret
= *(UINT
*)(*b
);
168 static inline void* rva_to_ptr(UINT rva
, ULONG64 base
)
170 return rva
? (void*)(base
+rva
) : NULL
;
173 static void read_unwind_info(BYTE
**b
, unwind_info
*ui
)
177 memset(ui
, 0, sizeof(*ui
));
178 ui
->type
= decode_uint(b
);
179 ui
->prev
= p
- (ui
->type
>> 2);
184 case UNWIND_TYPE_NO_HANDLER
:
186 case UNWIND_TYPE_DTOR_OBJ
:
187 ui
->handler
= read_rva(b
);
188 ui
->object
= decode_uint(b
); /* frame offset to object */
190 case UNWIND_TYPE_DTOR_PTR
:
191 ui
->handler
= read_rva(b
);
192 ui
->object
= decode_uint(b
); /* frame offset to pointer to object */
194 case UNWIND_TYPE_FRAME
:
195 ui
->handler
= read_rva(b
);
200 static void read_tryblock_info(BYTE
**b
, tryblock_info
*ti
, ULONG64 image_base
)
202 BYTE
*count
, *count_end
;
204 ti
->start_level
= decode_uint(b
);
205 ti
->end_level
= decode_uint(b
);
206 ti
->catch_level
= decode_uint(b
);
207 ti
->catchblock
= read_rva(b
);
209 count
= count_end
= rva_to_ptr(ti
->catchblock
, image_base
);
212 ti
->catchblock_count
= decode_uint(&count_end
);
213 ti
->catchblock
+= count_end
- count
;
217 ti
->catchblock_count
= 0;
221 static BOOL
read_catchblock_info(BYTE
**b
, catchblock_info
*ci
)
224 memset(ci
, 0, sizeof(*ci
));
227 if (ci
->header
& ~(CATCHBLOCK_FLAGS
| CATCHBLOCK_TYPE_INFO
| CATCHBLOCK_OFFSET
| CATCHBLOCK_RET_ADDR_MASK
))
229 FIXME("unknown header: %x\n", ci
->header
);
232 ret_addr_type
= ci
->header
& CATCHBLOCK_RET_ADDR_MASK
;
233 if (ret_addr_type
== (CATCHBLOCK_RET_ADDR
| CATCHBLOCK_TWO_RET_ADDRS
))
235 FIXME("unsupported ret addr type.\n");
239 if (ci
->header
& CATCHBLOCK_FLAGS
) ci
->flags
= decode_uint(b
);
240 if (ci
->header
& CATCHBLOCK_TYPE_INFO
) ci
->type_info
= read_rva(b
);
241 if (ci
->header
& CATCHBLOCK_OFFSET
) ci
->offset
= decode_uint(b
);
242 ci
->handler
= read_rva(b
);
243 if (ret_addr_type
== CATCHBLOCK_RET_ADDR
|| ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
244 ci
->ret_addr
[0] = decode_uint(b
);
245 if (ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
246 ci
->ret_addr
[1] = decode_uint(b
);
251 static void read_ipmap_info(BYTE
**b
, ipmap_info
*ii
)
253 ii
->ip_off
= decode_uint(b
);
254 ii
->state
= (INT
)decode_uint(b
) - 1;
257 static inline void dump_type(UINT type_rva
, ULONG64 base
)
259 const cxx_type_info
*type
= rva_to_ptr(type_rva
, base
);
261 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n",
262 type
->flags
, type
->type_info
, dbgstr_type_info(rva_to_ptr(type
->type_info
, base
)),
263 type
->offsets
.this_offset
, type
->offsets
.vbase_descr
, type
->offsets
.vbase_offset
,
264 type
->size
, type
->copy_ctor
, rva_to_ptr(type
->copy_ctor
, base
));
267 static void dump_exception_type(const cxx_exception_type
*type
, ULONG64 base
)
269 const cxx_type_info_table
*type_info_table
= rva_to_ptr(type
->type_info_table
, base
);
272 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
273 type
->flags
, type
->destructor
, rva_to_ptr(type
->destructor
, base
),
274 type
->custom_handler
, rva_to_ptr(type
->custom_handler
, base
),
275 type
->type_info_table
, type_info_table
);
276 for (i
= 0; i
< type_info_table
->count
; i
++)
279 dump_type(type_info_table
->info
[i
], base
);
283 static BOOL
validate_cxx_function_descr4(const cxx_function_descr
*descr
, DISPATCHER_CONTEXT
*dispatch
)
285 ULONG64 image_base
= dispatch
->ImageBase
;
286 BYTE
*unwind_map
= rva_to_ptr(descr
->unwind_map
, image_base
);
287 BYTE
*tryblock_map
= rva_to_ptr(descr
->tryblock_map
, image_base
);
288 BYTE
*ip_map
= rva_to_ptr(descr
->ip_map
, image_base
);
292 TRACE("header 0x%x\n", descr
->header
);
293 TRACE("basic block transformations flags: 0x%x\n", descr
->bbt_flags
);
295 TRACE("unwind table: 0x%x(%p) %d\n", descr
->unwind_map
, unwind_map
, descr
->unwind_count
);
296 for (i
= 0; i
< descr
->unwind_count
; i
++)
298 BYTE
*entry
= unwind_map
;
301 read_unwind_info(&unwind_map
, &ui
);
302 if (ui
.prev
< (BYTE
*)rva_to_ptr(descr
->unwind_map
, image_base
)) ui
.prev
= NULL
;
303 TRACE(" %d (%p): type 0x%x prev %p func 0x%x(%p) object 0x%x\n",
304 i
, entry
, ui
.type
, ui
.prev
, ui
.handler
,
305 rva_to_ptr(ui
.handler
, image_base
), ui
.object
);
308 TRACE("try table: 0x%x(%p) %d\n", descr
->tryblock_map
, tryblock_map
, descr
->tryblock_count
);
309 for (i
= 0; i
< descr
->tryblock_count
; i
++)
314 read_tryblock_info(&tryblock_map
, &ti
, image_base
);
315 catchblock
= rva_to_ptr(ti
.catchblock
, image_base
);
316 TRACE(" %d: start %d end %d catchlevel %d catch 0x%x(%p) %d\n",
317 i
, ti
.start_level
, ti
.end_level
, ti
.catch_level
,
318 ti
.catchblock
, catchblock
, ti
.catchblock_count
);
319 for (j
= 0; j
< ti
.catchblock_count
; j
++)
322 if (!read_catchblock_info(&catchblock
, &ci
)) return FALSE
;
323 TRACE(" %d: header 0x%x offset %d handler 0x%x(%p) "
324 "ret addr[0] %#x ret_addr[1] %#x type %#x %s\n", j
, ci
.header
, ci
.offset
,
325 ci
.handler
, rva_to_ptr(ci
.handler
, image_base
),
326 ci
.ret_addr
[0], ci
.ret_addr
[1], ci
.type_info
,
327 dbgstr_type_info(rva_to_ptr(ci
.type_info
, image_base
)));
331 TRACE("ipmap: 0x%x(%p) %d\n", descr
->ip_map
, ip_map
, descr
->ip_count
);
332 ip
= rva_to_ptr(dispatch
->FunctionEntry
->BeginAddress
, image_base
);
333 for (i
= 0; i
< descr
->ip_count
; i
++)
337 read_ipmap_info(&ip_map
, &ii
);
339 TRACE(" %d: ip offset 0x%x (%p) state %d\n", i
, ii
.ip_off
, ip
, ii
.state
);
342 TRACE("establisher frame: %x\n", descr
->frame
);
346 static inline int ip_to_state4(BYTE
*ip_map
, UINT count
, DISPATCHER_CONTEXT
*dispatch
, ULONG64 ip
)
353 state_ip
= dispatch
->ImageBase
+ dispatch
->FunctionEntry
->BeginAddress
;
354 for (i
= 0; i
< count
; i
++)
356 read_ipmap_info(&ip_map
, &ii
);
357 state_ip
+= ii
.ip_off
;
358 if (ip
< state_ip
) break;
362 TRACE("state %d\n", ret
);
366 static const cxx_type_info
*find_caught_type(cxx_exception_type
*exc_type
, ULONG64 exc_base
,
367 const type_info
*catch_ti
, UINT catch_flags
)
369 const cxx_type_info_table
*type_info_table
= rva_to_ptr(exc_type
->type_info_table
, exc_base
);
372 for (i
= 0; i
< type_info_table
->count
; i
++)
374 const cxx_type_info
*type
= rva_to_ptr(type_info_table
->info
[i
], exc_base
);
375 const type_info
*ti
= rva_to_ptr(type
->type_info
, exc_base
);
377 if (!catch_ti
) return type
; /* catch(...) matches any type */
380 if (strcmp( catch_ti
->mangled
, ti
->mangled
)) continue;
382 /* type is the same, now check the flags */
383 if ((exc_type
->flags
& TYPE_FLAG_CONST
) &&
384 !(catch_flags
& TYPE_FLAG_CONST
)) continue;
385 if ((exc_type
->flags
& TYPE_FLAG_VOLATILE
) &&
386 !(catch_flags
& TYPE_FLAG_VOLATILE
)) continue;
387 return type
; /* it matched */
392 static inline void copy_exception(void *object
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
393 const catchblock_info
*catchblock
, const cxx_type_info
*type
, ULONG64 exc_base
)
395 const type_info
*catch_ti
= rva_to_ptr(catchblock
->type_info
, dispatch
->ImageBase
);
396 void **dest
= rva_to_ptr(catchblock
->offset
, frame
);
398 if (!catch_ti
|| !catch_ti
->mangled
[0]) return;
399 if (!catchblock
->offset
) return;
401 if (catchblock
->flags
& TYPE_FLAG_REFERENCE
)
403 *dest
= get_this_pointer(&type
->offsets
, object
);
405 else if (type
->flags
& CLASS_IS_SIMPLE_TYPE
)
407 memmove(dest
, object
, type
->size
);
408 /* if it is a pointer, adjust it */
409 if (type
->size
== sizeof(void*)) *dest
= get_this_pointer(&type
->offsets
, *dest
);
411 else /* copy the object */
415 if (type
->flags
& CLASS_HAS_VIRTUAL_BASE_CLASS
)
417 void (__cdecl
*copy_ctor
)(void*, void*, int) =
418 rva_to_ptr(type
->copy_ctor
, exc_base
);
419 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
), 1);
423 void (__cdecl
*copy_ctor
)(void*, void*) =
424 rva_to_ptr(type
->copy_ctor
, exc_base
);
425 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
));
429 memmove(dest
, get_this_pointer(&type
->offsets
,object
), type
->size
);
433 static void cxx_local_unwind4(ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
434 const cxx_function_descr
*descr
, int trylevel
, int last_level
)
436 void (__cdecl
*handler_dtor
)(void *obj
, ULONG64 frame
);
437 BYTE
*unwind_data
, *last
;
444 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
445 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
448 TRACE("current level: %d, last level: %d\n", trylevel
, last_level
);
450 if (trylevel
<-1 || trylevel
>=(int)descr
->unwind_count
)
452 ERR("invalid trylevel %d\n", trylevel
);
456 if (trylevel
<= last_level
) return;
458 unwind_data
= rva_to_ptr(descr
->unwind_map
, dispatch
->ImageBase
);
459 last
= unwind_data
- 1;
460 for (i
= 0; i
< trylevel
; i
++)
462 BYTE
*addr
= unwind_data
;
463 read_unwind_info(&unwind_data
, &ui
);
464 if (i
== last_level
) last
= addr
;
467 while (unwind_data
> last
)
469 read_unwind_info(&unwind_data
, &ui
);
470 unwind_data
= ui
.prev
;
474 handler_dtor
= rva_to_ptr(ui
.handler
, dispatch
->ImageBase
);
475 obj
= rva_to_ptr(ui
.object
, frame
);
476 if(ui
.type
== UNWIND_TYPE_DTOR_PTR
)
478 TRACE("handler: %p object: %p\n", handler_dtor
, obj
);
479 handler_dtor(obj
, frame
);
484 static LONG CALLBACK
cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs
, void *c
)
486 EXCEPTION_RECORD
*rec
= eptrs
->ExceptionRecord
;
487 cxx_catch_ctx
*ctx
= c
;
489 if (rec
->ExceptionCode
== CXX_EXCEPTION
&& !rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
490 return EXCEPTION_EXECUTE_HANDLER
;
492 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->search_state
);
493 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
494 return EXCEPTION_CONTINUE_SEARCH
;
495 if (rec
->ExceptionInformation
[1] == ctx
->prev_rec
->ExceptionInformation
[1])
497 return EXCEPTION_CONTINUE_SEARCH
;
500 static void CALLBACK
cxx_catch_cleanup(BOOL normal
, void *c
)
502 cxx_catch_ctx
*ctx
= c
;
503 __CxxUnregisterExceptionObject(&ctx
->frame_info
, ctx
->rethrow
);
505 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->unwind_state
);
508 static void* WINAPI
call_catch_block4(EXCEPTION_RECORD
*rec
)
510 ULONG64 frame
= rec
->ExceptionInformation
[1];
511 EXCEPTION_RECORD
*prev_rec
= (void*)rec
->ExceptionInformation
[4];
512 EXCEPTION_RECORD
*untrans_rec
= (void*)rec
->ExceptionInformation
[6];
513 CONTEXT
*context
= (void*)rec
->ExceptionInformation
[7];
514 void* (__cdecl
*handler
)(ULONG64 unk
, ULONG64 rbp
) = (void*)rec
->ExceptionInformation
[5];
515 EXCEPTION_POINTERS ep
= { prev_rec
, context
};
517 void *ret_addr
= NULL
;
519 TRACE("calling handler %p\n", handler
);
522 __CxxRegisterExceptionObject(&ep
, &ctx
.frame_info
);
523 ctx
.search_state
= rec
->ExceptionInformation
[2];
524 ctx
.unwind_state
= rec
->ExceptionInformation
[3];
525 ctx
.prev_rec
= prev_rec
;
526 (*__processing_throw())--;
531 ret_addr
= handler(0, frame
);
533 __EXCEPT_CTX(cxx_rethrow_filter
, &ctx
)
535 TRACE("detect rethrow: exception code: %x\n", prev_rec
->ExceptionCode
);
537 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
.search_state
);
541 __DestructExceptionObject(prev_rec
);
542 RaiseException(untrans_rec
->ExceptionCode
, untrans_rec
->ExceptionFlags
,
543 untrans_rec
->NumberParameters
, untrans_rec
->ExceptionInformation
);
547 RaiseException(prev_rec
->ExceptionCode
, prev_rec
->ExceptionFlags
,
548 prev_rec
->NumberParameters
, prev_rec
->ExceptionInformation
);
553 __FINALLY_CTX(cxx_catch_cleanup
, &ctx
)
555 FlsSetValue(fls_index
, (void*)-2);
556 TRACE("handler returned %p, ret_addr[0] %p, ret_addr[1] %p.\n",
557 ret_addr
, rec
->ExceptionInformation
[8], rec
->ExceptionInformation
[9]);
559 if (rec
->ExceptionInformation
[9])
561 if ((ULONG_PTR
)ret_addr
> 1)
563 ERR("unexpected handler result %p.\n", ret_addr
);
566 return (void*)rec
->ExceptionInformation
[8 + (ULONG_PTR
)ret_addr
];
568 return rec
->ExceptionInformation
[8] ? (void *)rec
->ExceptionInformation
[8] : ret_addr
;
571 static inline BOOL
cxx_is_consolidate(const EXCEPTION_RECORD
*rec
)
573 return rec
->ExceptionCode
== STATUS_UNWIND_CONSOLIDATE
574 && rec
->NumberParameters
== CONSOLIDATE_UNWIND_PARAMETER_COUNT
575 && rec
->ExceptionInformation
[0] == (ULONG_PTR
)call_catch_block4
;
578 static inline void find_catch_block4(EXCEPTION_RECORD
*rec
, CONTEXT
*context
,
579 EXCEPTION_RECORD
*untrans_rec
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
580 const cxx_function_descr
*descr
, cxx_exception_type
*info
,
581 ULONG64 orig_frame
, int trylevel
)
583 ULONG64 exc_base
= (rec
->NumberParameters
== 4 ? rec
->ExceptionInformation
[3] : 0);
584 int *processing_throw
= __processing_throw();
585 EXCEPTION_RECORD catch_record
;
590 (*processing_throw
)++;
594 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
595 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
597 TRACE("current trylevel: %d\n", trylevel
);
599 tryblock_map
= rva_to_ptr(descr
->tryblock_map
, dispatch
->ImageBase
);
600 for (i
=0; i
<descr
->tryblock_count
; i
++)
602 tryblock_info tryblock
;
605 read_tryblock_info(&tryblock_map
, &tryblock
, dispatch
->ImageBase
);
607 if (trylevel
< tryblock
.start_level
) continue;
608 if (trylevel
> tryblock
.end_level
) continue;
610 /* got a try block */
611 catchblock
= rva_to_ptr(tryblock
.catchblock
, dispatch
->ImageBase
);
612 for (j
=0; j
<tryblock
.catchblock_count
; j
++)
616 read_catchblock_info(&catchblock
, &ci
);
620 const cxx_type_info
*type
= find_caught_type(info
, exc_base
,
621 rva_to_ptr(ci
.type_info
, dispatch
->ImageBase
),
625 TRACE("matched type %p in tryblock %d catchblock %d\n", type
, i
, j
);
627 /* copy the exception to its destination on the stack */
628 copy_exception((void*)rec
->ExceptionInformation
[1],
629 orig_frame
, dispatch
, &ci
, type
, exc_base
);
633 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
636 TRACE("found catch(...) block\n");
639 /* unwind stack and call catch */
640 memset(&catch_record
, 0, sizeof(catch_record
));
641 catch_record
.ExceptionCode
= STATUS_UNWIND_CONSOLIDATE
;
642 catch_record
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
643 catch_record
.NumberParameters
= CONSOLIDATE_UNWIND_PARAMETER_COUNT
;
644 catch_record
.ExceptionInformation
[0] = (ULONG_PTR
)call_catch_block4
;
645 catch_record
.ExceptionInformation
[1] = orig_frame
;
646 catch_record
.ExceptionInformation
[2] = tryblock
.catch_level
;
647 catch_record
.ExceptionInformation
[3] = tryblock
.start_level
;
648 catch_record
.ExceptionInformation
[4] = (ULONG_PTR
)rec
;
649 catch_record
.ExceptionInformation
[5] =
650 (ULONG_PTR
)rva_to_ptr(ci
.handler
, dispatch
->ImageBase
);
651 catch_record
.ExceptionInformation
[6] = (ULONG_PTR
)untrans_rec
;
652 catch_record
.ExceptionInformation
[7] = (ULONG_PTR
)context
;
654 catch_record
.ExceptionInformation
[8] = (ULONG_PTR
)rva_to_ptr(
655 ci
.ret_addr
[0] + dispatch
->FunctionEntry
->BeginAddress
, dispatch
->ImageBase
);
657 catch_record
.ExceptionInformation
[9] = (ULONG_PTR
)rva_to_ptr(
658 ci
.ret_addr
[1] + dispatch
->FunctionEntry
->BeginAddress
, dispatch
->ImageBase
);
659 RtlUnwindEx((void*)frame
, (void*)dispatch
->ControlPc
, &catch_record
, NULL
, &ctx
, NULL
);
663 TRACE("no matching catch block found\n");
664 (*processing_throw
)--;
667 static LONG CALLBACK
se_translation_filter(EXCEPTION_POINTERS
*ep
, void *c
)
669 se_translator_ctx
*ctx
= (se_translator_ctx
*)c
;
670 EXCEPTION_RECORD
*rec
= ep
->ExceptionRecord
;
671 cxx_exception_type
*exc_type
;
673 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
675 TRACE("non-c++ exception thrown in SEH handler: %x\n", rec
->ExceptionCode
);
679 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
680 find_catch_block4(rec
, ep
->ContextRecord
, ctx
->seh_rec
, ctx
->dest_frame
, ctx
->dispatch
,
681 ctx
->descr
, exc_type
, ctx
->orig_frame
, ctx
->trylevel
);
683 __DestructExceptionObject(rec
);
684 return ExceptionContinueSearch
;
687 /* Hacky way to obtain se_translator */
688 static inline _se_translator_function
get_se_translator(void)
690 return __current_exception()[-2];
693 static void check_noexcept( PEXCEPTION_RECORD rec
, const cxx_function_descr
*descr
)
695 if (!(descr
->header
& FUNC_DESCR_IS_CATCH
) &&
696 rec
->ExceptionCode
== CXX_EXCEPTION
&&
697 (descr
->header
& FUNC_DESCR_NO_EXCEPT
))
699 ERR("noexcept function propagating exception\n");
704 static DWORD
cxx_frame_handler4(EXCEPTION_RECORD
*rec
, ULONG64 frame
,
705 CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
,
706 const cxx_function_descr
*descr
, int trylevel
)
708 cxx_exception_type
*exc_type
;
709 ULONG64 orig_frame
= frame
;
711 if (descr
->header
& FUNC_DESCR_IS_CATCH
)
713 TRACE("nested exception detected\n");
714 orig_frame
= *(ULONG64
*)rva_to_ptr(descr
->frame
, frame
);
715 TRACE("setting orig_frame to %lx\n", orig_frame
);
718 if (rec
->ExceptionFlags
& (EH_UNWINDING
|EH_EXIT_UNWIND
))
721 if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && cxx_is_consolidate(rec
))
722 last_level
= rec
->ExceptionInformation
[3];
723 else if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && rec
->ExceptionCode
== STATUS_LONGJUMP
)
724 last_level
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
725 descr
->ip_count
, dispatch
, dispatch
->TargetIp
);
727 cxx_local_unwind4(orig_frame
, dispatch
, descr
, trylevel
, last_level
);
728 return ExceptionContinueSearch
;
730 if (!descr
->tryblock_map
)
732 check_noexcept(rec
, descr
);
733 return ExceptionContinueSearch
;
736 if (rec
->ExceptionCode
== CXX_EXCEPTION
)
738 if (!rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
740 TRACE("rethrow detected.\n");
741 *rec
= *(EXCEPTION_RECORD
*)*__current_exception();
744 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
748 TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec
, frame
, descr
);
749 dump_exception_type(exc_type
, rec
->ExceptionInformation
[3]);
754 _se_translator_function se_translator
= get_se_translator();
757 TRACE("handling C exception code %x rec %p frame %lx descr %p\n",
758 rec
->ExceptionCode
, rec
, frame
, descr
);
761 EXCEPTION_POINTERS except_ptrs
;
762 se_translator_ctx ctx
;
764 ctx
.dest_frame
= frame
;
765 ctx
.orig_frame
= orig_frame
;
767 ctx
.dispatch
= dispatch
;
769 ctx
.trylevel
= trylevel
;
772 except_ptrs
.ExceptionRecord
= rec
;
773 except_ptrs
.ContextRecord
= context
;
774 se_translator(rec
->ExceptionCode
, &except_ptrs
);
776 __EXCEPT_CTX(se_translation_filter
, &ctx
)
783 find_catch_block4(rec
, context
, NULL
, frame
, dispatch
, descr
, exc_type
, orig_frame
, trylevel
);
784 check_noexcept(rec
, descr
);
785 return ExceptionContinueSearch
;
788 EXCEPTION_DISPOSITION __cdecl
__CxxFrameHandler4(EXCEPTION_RECORD
*rec
,
789 ULONG64 frame
, CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
)
791 cxx_function_descr descr
;
792 BYTE
*p
, *count
, *count_end
;
795 TRACE("%p %lx %p %p\n", rec
, frame
, context
, dispatch
);
797 trylevel
= (DWORD_PTR
)FlsGetValue(fls_index
);
798 FlsSetValue(fls_index
, (void*)-2);
800 memset(&descr
, 0, sizeof(descr
));
801 p
= rva_to_ptr(*(UINT
*)dispatch
->HandlerData
, dispatch
->ImageBase
);
804 if ((descr
.header
& FUNC_DESCR_EHS
) &&
805 rec
->ExceptionCode
!= CXX_EXCEPTION
&&
806 !cxx_is_consolidate(rec
) &&
807 rec
->ExceptionCode
!= STATUS_LONGJUMP
)
808 return ExceptionContinueSearch
; /* handle only c++ exceptions */
810 if (descr
.header
& ~(FUNC_DESCR_IS_CATCH
| FUNC_DESCR_UNWIND_MAP
|
811 FUNC_DESCR_TRYBLOCK_MAP
| FUNC_DESCR_EHS
| FUNC_DESCR_NO_EXCEPT
))
813 FIXME("unsupported flags: %x\n", descr
.header
);
814 return ExceptionContinueSearch
;
817 if (descr
.header
& FUNC_DESCR_BBT
) descr
.bbt_flags
= decode_uint(&p
);
818 if (descr
.header
& FUNC_DESCR_UNWIND_MAP
)
820 descr
.unwind_map
= read_rva(&p
);
821 count_end
= count
= rva_to_ptr(descr
.unwind_map
, dispatch
->ImageBase
);
822 descr
.unwind_count
= decode_uint(&count_end
);
823 descr
.unwind_map
+= count_end
- count
;
825 if (descr
.header
& FUNC_DESCR_TRYBLOCK_MAP
)
827 descr
.tryblock_map
= read_rva(&p
);
828 count_end
= count
= rva_to_ptr(descr
.tryblock_map
, dispatch
->ImageBase
);
829 descr
.tryblock_count
= decode_uint(&count_end
);
830 descr
.tryblock_map
+= count_end
- count
;
832 descr
.ip_map
= read_rva(&p
);
833 count_end
= count
= rva_to_ptr(descr
.ip_map
, dispatch
->ImageBase
);
834 descr
.ip_count
= decode_uint(&count_end
);
835 descr
.ip_map
+= count_end
- count
;
836 if (descr
.header
& FUNC_DESCR_IS_CATCH
) descr
.frame
= decode_uint(&p
);
838 if (!validate_cxx_function_descr4(&descr
, dispatch
))
839 return ExceptionContinueSearch
;
841 return cxx_frame_handler4(rec
, frame
, context
, dispatch
, &descr
, trylevel
);
844 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
848 case DLL_PROCESS_ATTACH
:
849 fls_index
= FlsAlloc(NULL
);
850 if (fls_index
== FLS_OUT_OF_INDEXES
)
853 case DLL_THREAD_ATTACH
:
854 FlsSetValue(fls_index
, (void*)-2);
856 case DLL_PROCESS_DETACH
: