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 #if defined(__x86_64__) && _MSVCR_VER>=140
28 #include "wine/exception.h"
29 #include "wine/debug.h"
30 #include "cppexcept.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
35 #define CXX_EXCEPTION 0xe06d7363
37 static DWORD fls_index
;
51 #define FUNC_DESCR_IS_CATCH 0x01
52 #define FUNC_DESCR_IS_SEPARATED 0x02
53 #define FUNC_DESCR_BBT 0x04
54 #define FUNC_DESCR_UNWIND_MAP 0x08
55 #define FUNC_DESCR_TRYBLOCK_MAP 0x10
56 #define FUNC_DESCR_EHS 0x20
57 #define FUNC_DESCR_NO_EXCEPT 0x40
58 #define FUNC_DESCR_RESERVED 0x80
77 #define CATCHBLOCK_FLAGS 0x01
78 #define CATCHBLOCK_TYPE_INFO 0x02
79 #define CATCHBLOCK_OFFSET 0x04
80 #define CATCHBLOCK_SEPARATED 0x08
81 #define CATCHBLOCK_RET_ADDR_MASK 0x30
82 #define CATCHBLOCK_RET_ADDR 0x10
83 #define CATCHBLOCK_TWO_RET_ADDRS 0x20
85 #define TYPE_FLAG_CONST 1
86 #define TYPE_FLAG_VOLATILE 2
87 #define TYPE_FLAG_REFERENCE 8
89 #define UNWIND_TYPE_NO_HANDLER 0
90 #define UNWIND_TYPE_DTOR_OBJ 1
91 #define UNWIND_TYPE_DTOR_PTR 2
92 #define UNWIND_TYPE_FRAME 3
94 #define CONSOLIDATE_UNWIND_PARAMETER_COUNT 10
101 UINT catchblock_count
;
107 UINT ip_off
; /* relative to start of function or earlier ipmap_info */
113 cxx_frame_info frame_info
;
117 EXCEPTION_RECORD
*prev_rec
;
124 EXCEPTION_RECORD
*seh_rec
;
125 DISPATCHER_CONTEXT
*dispatch
;
126 const cxx_function_descr
*descr
;
130 static UINT
decode_uint(BYTE
**b
)
140 else if ((*p
& 3) == 1)
142 ret
= (p
[0] >> 2) + (p
[1] << 6);
145 else if ((*p
& 7) == 3)
147 ret
= (p
[0] >> 3) + (p
[1] << 5) + (p
[2] << 13);
150 else if ((*p
& 15) == 7)
152 ret
= (p
[0] >> 4) + (p
[1] << 4) + (p
[2] << 12) + (p
[3] << 20);
157 FIXME("not implemented - expect crash\n");
166 static UINT
read_rva(BYTE
**b
)
168 UINT ret
= *(UINT
*)(*b
);
173 static inline void* rva_to_ptr(UINT rva
, ULONG64 base
)
175 return rva
? (void*)(base
+rva
) : NULL
;
178 static void read_unwind_info(BYTE
**b
, unwind_info
*ui
)
182 memset(ui
, 0, sizeof(*ui
));
183 ui
->type
= decode_uint(b
);
184 ui
->prev
= p
- (ui
->type
>> 2);
189 case UNWIND_TYPE_NO_HANDLER
:
191 case UNWIND_TYPE_DTOR_OBJ
:
192 ui
->handler
= read_rva(b
);
193 ui
->object
= decode_uint(b
); /* frame offset to object */
195 case UNWIND_TYPE_DTOR_PTR
:
196 ui
->handler
= read_rva(b
);
197 ui
->object
= decode_uint(b
); /* frame offset to pointer to object */
199 case UNWIND_TYPE_FRAME
:
200 ui
->handler
= read_rva(b
);
205 static void read_tryblock_info(BYTE
**b
, tryblock_info
*ti
, ULONG64 image_base
)
207 BYTE
*count
, *count_end
;
209 ti
->start_level
= decode_uint(b
);
210 ti
->end_level
= decode_uint(b
);
211 ti
->catch_level
= decode_uint(b
);
212 ti
->catchblock
= read_rva(b
);
214 count
= count_end
= rva_to_ptr(ti
->catchblock
, image_base
);
217 ti
->catchblock_count
= decode_uint(&count_end
);
218 ti
->catchblock
+= count_end
- count
;
222 ti
->catchblock_count
= 0;
226 static BOOL
read_catchblock_info(BYTE
**b
, catchblock_info
*ci
, DWORD func_rva
)
229 memset(ci
, 0, sizeof(*ci
));
232 if (ci
->header
& ~(CATCHBLOCK_FLAGS
| CATCHBLOCK_TYPE_INFO
| CATCHBLOCK_OFFSET
|
233 CATCHBLOCK_SEPARATED
| CATCHBLOCK_RET_ADDR_MASK
))
235 FIXME("unknown header: %x\n", ci
->header
);
238 ret_addr_type
= ci
->header
& CATCHBLOCK_RET_ADDR_MASK
;
239 if (ret_addr_type
== (CATCHBLOCK_RET_ADDR
| CATCHBLOCK_TWO_RET_ADDRS
))
241 FIXME("unsupported ret addr type.\n");
245 if (ci
->header
& CATCHBLOCK_FLAGS
) ci
->flags
= decode_uint(b
);
246 if (ci
->header
& CATCHBLOCK_TYPE_INFO
) ci
->type_info
= read_rva(b
);
247 if (ci
->header
& CATCHBLOCK_OFFSET
) ci
->offset
= decode_uint(b
);
248 ci
->handler
= read_rva(b
);
249 if (ci
->header
& CATCHBLOCK_SEPARATED
)
251 if (ret_addr_type
== CATCHBLOCK_RET_ADDR
|| ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
252 ci
->ret_addr
[0] = read_rva(b
);
253 if (ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
254 ci
->ret_addr
[1] = read_rva(b
);
258 if (ret_addr_type
== CATCHBLOCK_RET_ADDR
|| ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
259 ci
->ret_addr
[0] = decode_uint(b
) + func_rva
;
260 if (ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
261 ci
->ret_addr
[1] = decode_uint(b
) + func_rva
;
267 static void read_ipmap_info(BYTE
**b
, ipmap_info
*ii
)
269 ii
->ip_off
= decode_uint(b
);
270 ii
->state
= (INT
)decode_uint(b
) - 1;
273 static inline void dump_type(UINT type_rva
, ULONG64 base
)
275 const cxx_type_info
*type
= rva_to_ptr(type_rva
, base
);
277 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n",
278 type
->flags
, type
->type_info
, dbgstr_type_info(rva_to_ptr(type
->type_info
, base
)),
279 type
->offsets
.this_offset
, type
->offsets
.vbase_descr
, type
->offsets
.vbase_offset
,
280 type
->size
, type
->copy_ctor
, rva_to_ptr(type
->copy_ctor
, base
));
283 static void dump_exception_type(const cxx_exception_type
*type
, ULONG64 base
)
285 const cxx_type_info_table
*type_info_table
= rva_to_ptr(type
->type_info_table
, base
);
288 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
289 type
->flags
, type
->destructor
, rva_to_ptr(type
->destructor
, base
),
290 type
->custom_handler
, rva_to_ptr(type
->custom_handler
, base
),
291 type
->type_info_table
, type_info_table
);
292 for (i
= 0; i
< type_info_table
->count
; i
++)
295 dump_type(type_info_table
->info
[i
], base
);
299 static BOOL
validate_cxx_function_descr4(const cxx_function_descr
*descr
, DISPATCHER_CONTEXT
*dispatch
)
301 ULONG64 image_base
= dispatch
->ImageBase
;
302 BYTE
*unwind_map
= rva_to_ptr(descr
->unwind_map
, image_base
);
303 BYTE
*tryblock_map
= rva_to_ptr(descr
->tryblock_map
, image_base
);
304 BYTE
*ip_map
= rva_to_ptr(descr
->ip_map
, image_base
);
308 TRACE("header 0x%x\n", descr
->header
);
309 TRACE("basic block transformations flags: 0x%x\n", descr
->bbt_flags
);
311 TRACE("unwind table: 0x%x(%p) %d\n", descr
->unwind_map
, unwind_map
, descr
->unwind_count
);
312 for (i
= 0; i
< descr
->unwind_count
; i
++)
314 BYTE
*entry
= unwind_map
;
317 read_unwind_info(&unwind_map
, &ui
);
318 if (ui
.prev
< (BYTE
*)rva_to_ptr(descr
->unwind_map
, image_base
)) ui
.prev
= NULL
;
319 TRACE(" %d (%p): type 0x%x prev %p func 0x%x(%p) object 0x%x\n",
320 i
, entry
, ui
.type
, ui
.prev
, ui
.handler
,
321 rva_to_ptr(ui
.handler
, image_base
), ui
.object
);
324 TRACE("try table: 0x%x(%p) %d\n", descr
->tryblock_map
, tryblock_map
, descr
->tryblock_count
);
325 for (i
= 0; i
< descr
->tryblock_count
; i
++)
330 read_tryblock_info(&tryblock_map
, &ti
, image_base
);
331 catchblock
= rva_to_ptr(ti
.catchblock
, image_base
);
332 TRACE(" %d: start %d end %d catchlevel %d catch 0x%x(%p) %d\n",
333 i
, ti
.start_level
, ti
.end_level
, ti
.catch_level
,
334 ti
.catchblock
, catchblock
, ti
.catchblock_count
);
335 for (j
= 0; j
< ti
.catchblock_count
; j
++)
338 if (!read_catchblock_info(&catchblock
, &ci
,
339 dispatch
->FunctionEntry
->BeginAddress
)) return FALSE
;
340 TRACE(" %d: header 0x%x offset %d handler 0x%x(%p) "
341 "ret addr[0] %#x ret_addr[1] %#x type %#x %s\n", j
, ci
.header
, ci
.offset
,
342 ci
.handler
, rva_to_ptr(ci
.handler
, image_base
),
343 ci
.ret_addr
[0], ci
.ret_addr
[1], ci
.type_info
,
344 dbgstr_type_info(rva_to_ptr(ci
.type_info
, image_base
)));
348 TRACE("ipmap: 0x%x(%p) %d\n", descr
->ip_map
, ip_map
, descr
->ip_count
);
349 ip
= rva_to_ptr(dispatch
->FunctionEntry
->BeginAddress
, image_base
);
350 for (i
= 0; i
< descr
->ip_count
; i
++)
354 read_ipmap_info(&ip_map
, &ii
);
356 TRACE(" %d: ip offset 0x%x (%p) state %d\n", i
, ii
.ip_off
, ip
, ii
.state
);
359 TRACE("establisher frame: %x\n", descr
->frame
);
363 static inline int ip_to_state4(BYTE
*ip_map
, UINT count
, DISPATCHER_CONTEXT
*dispatch
, ULONG64 ip
)
370 state_ip
= dispatch
->ImageBase
+ dispatch
->FunctionEntry
->BeginAddress
;
371 for (i
= 0; i
< count
; i
++)
373 read_ipmap_info(&ip_map
, &ii
);
374 state_ip
+= ii
.ip_off
;
375 if (ip
< state_ip
) break;
379 TRACE("state %d\n", ret
);
383 static const cxx_type_info
*find_caught_type(cxx_exception_type
*exc_type
, ULONG64 exc_base
,
384 const type_info
*catch_ti
, UINT catch_flags
)
386 const cxx_type_info_table
*type_info_table
= rva_to_ptr(exc_type
->type_info_table
, exc_base
);
389 for (i
= 0; i
< type_info_table
->count
; i
++)
391 const cxx_type_info
*type
= rva_to_ptr(type_info_table
->info
[i
], exc_base
);
392 const type_info
*ti
= rva_to_ptr(type
->type_info
, exc_base
);
394 if (!catch_ti
) return type
; /* catch(...) matches any type */
397 if (strcmp( catch_ti
->mangled
, ti
->mangled
)) continue;
399 /* type is the same, now check the flags */
400 if ((exc_type
->flags
& TYPE_FLAG_CONST
) &&
401 !(catch_flags
& TYPE_FLAG_CONST
)) continue;
402 if ((exc_type
->flags
& TYPE_FLAG_VOLATILE
) &&
403 !(catch_flags
& TYPE_FLAG_VOLATILE
)) continue;
404 return type
; /* it matched */
409 static inline void copy_exception(void *object
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
410 const catchblock_info
*catchblock
, const cxx_type_info
*type
, ULONG64 exc_base
)
412 const type_info
*catch_ti
= rva_to_ptr(catchblock
->type_info
, dispatch
->ImageBase
);
413 void **dest
= rva_to_ptr(catchblock
->offset
, frame
);
415 if (!catch_ti
|| !catch_ti
->mangled
[0]) return;
416 if (!catchblock
->offset
) return;
418 if (catchblock
->flags
& TYPE_FLAG_REFERENCE
)
420 *dest
= get_this_pointer(&type
->offsets
, object
);
422 else if (type
->flags
& CLASS_IS_SIMPLE_TYPE
)
424 memmove(dest
, object
, type
->size
);
425 /* if it is a pointer, adjust it */
426 if (type
->size
== sizeof(void*)) *dest
= get_this_pointer(&type
->offsets
, *dest
);
428 else /* copy the object */
432 if (type
->flags
& CLASS_HAS_VIRTUAL_BASE_CLASS
)
434 void (__cdecl
*copy_ctor
)(void*, void*, int) =
435 rva_to_ptr(type
->copy_ctor
, exc_base
);
436 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
), 1);
440 void (__cdecl
*copy_ctor
)(void*, void*) =
441 rva_to_ptr(type
->copy_ctor
, exc_base
);
442 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
));
446 memmove(dest
, get_this_pointer(&type
->offsets
,object
), type
->size
);
450 static void cxx_local_unwind4(ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
451 const cxx_function_descr
*descr
, int trylevel
, int last_level
)
453 void (__cdecl
*handler_dtor
)(void *obj
, ULONG64 frame
);
454 BYTE
*unwind_data
, *last
;
461 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
462 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
465 TRACE("current level: %d, last level: %d\n", trylevel
, last_level
);
467 if (trylevel
<-1 || trylevel
>=(int)descr
->unwind_count
)
469 ERR("invalid trylevel %d\n", trylevel
);
473 if (trylevel
<= last_level
) return;
475 unwind_data
= rva_to_ptr(descr
->unwind_map
, dispatch
->ImageBase
);
476 last
= unwind_data
- 1;
477 for (i
= 0; i
< trylevel
; i
++)
479 BYTE
*addr
= unwind_data
;
480 read_unwind_info(&unwind_data
, &ui
);
481 if (i
== last_level
) last
= addr
;
484 while (unwind_data
> last
)
486 read_unwind_info(&unwind_data
, &ui
);
487 unwind_data
= ui
.prev
;
491 handler_dtor
= rva_to_ptr(ui
.handler
, dispatch
->ImageBase
);
492 obj
= rva_to_ptr(ui
.object
, frame
);
493 if(ui
.type
== UNWIND_TYPE_DTOR_PTR
)
495 TRACE("handler: %p object: %p\n", handler_dtor
, obj
);
496 handler_dtor(obj
, frame
);
501 static LONG CALLBACK
cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs
, void *c
)
503 EXCEPTION_RECORD
*rec
= eptrs
->ExceptionRecord
;
504 cxx_catch_ctx
*ctx
= c
;
506 if (rec
->ExceptionCode
== CXX_EXCEPTION
&& !rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
507 return EXCEPTION_EXECUTE_HANDLER
;
509 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->search_state
);
510 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
511 return EXCEPTION_CONTINUE_SEARCH
;
512 if (rec
->ExceptionInformation
[1] == ctx
->prev_rec
->ExceptionInformation
[1])
514 return EXCEPTION_CONTINUE_SEARCH
;
517 static void CALLBACK
cxx_catch_cleanup(BOOL normal
, void *c
)
519 cxx_catch_ctx
*ctx
= c
;
520 __CxxUnregisterExceptionObject(&ctx
->frame_info
, ctx
->rethrow
);
522 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->unwind_state
);
525 static void* WINAPI
call_catch_block4(EXCEPTION_RECORD
*rec
)
527 ULONG64 frame
= rec
->ExceptionInformation
[1];
528 EXCEPTION_RECORD
*prev_rec
= (void*)rec
->ExceptionInformation
[4];
529 EXCEPTION_RECORD
*untrans_rec
= (void*)rec
->ExceptionInformation
[6];
530 CONTEXT
*context
= (void*)rec
->ExceptionInformation
[7];
531 void* (__cdecl
*handler
)(ULONG64 unk
, ULONG64 rbp
) = (void*)rec
->ExceptionInformation
[5];
532 EXCEPTION_POINTERS ep
= { prev_rec
, context
};
534 void *ret_addr
= NULL
;
536 TRACE("calling handler %p\n", handler
);
539 __CxxRegisterExceptionObject(&ep
, &ctx
.frame_info
);
540 ctx
.search_state
= rec
->ExceptionInformation
[2];
541 ctx
.unwind_state
= rec
->ExceptionInformation
[3];
542 ctx
.prev_rec
= prev_rec
;
543 (*__processing_throw())--;
548 ret_addr
= handler(0, frame
);
550 __EXCEPT_CTX(cxx_rethrow_filter
, &ctx
)
552 TRACE("detect rethrow: exception code: %lx\n", prev_rec
->ExceptionCode
);
554 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
.search_state
);
558 __DestructExceptionObject(prev_rec
);
559 RaiseException(untrans_rec
->ExceptionCode
, untrans_rec
->ExceptionFlags
,
560 untrans_rec
->NumberParameters
, untrans_rec
->ExceptionInformation
);
564 RaiseException(prev_rec
->ExceptionCode
, prev_rec
->ExceptionFlags
,
565 prev_rec
->NumberParameters
, prev_rec
->ExceptionInformation
);
570 __FINALLY_CTX(cxx_catch_cleanup
, &ctx
)
572 FlsSetValue(fls_index
, (void*)-2);
573 TRACE("handler returned %p, ret_addr[0] %#Ix, ret_addr[1] %#Ix.\n",
574 ret_addr
, rec
->ExceptionInformation
[8], rec
->ExceptionInformation
[9]);
576 if (rec
->ExceptionInformation
[9])
578 if ((ULONG_PTR
)ret_addr
> 1)
580 ERR("unexpected handler result %p.\n", ret_addr
);
583 return (void*)rec
->ExceptionInformation
[8 + (ULONG_PTR
)ret_addr
];
585 return rec
->ExceptionInformation
[8] ? (void *)rec
->ExceptionInformation
[8] : ret_addr
;
588 static inline BOOL
cxx_is_consolidate(const EXCEPTION_RECORD
*rec
)
590 return rec
->ExceptionCode
== STATUS_UNWIND_CONSOLIDATE
591 && rec
->NumberParameters
== CONSOLIDATE_UNWIND_PARAMETER_COUNT
592 && rec
->ExceptionInformation
[0] == (ULONG_PTR
)call_catch_block4
;
595 static inline void find_catch_block4(EXCEPTION_RECORD
*rec
, CONTEXT
*context
,
596 EXCEPTION_RECORD
*untrans_rec
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
597 const cxx_function_descr
*descr
, cxx_exception_type
*info
,
598 ULONG64 orig_frame
, int trylevel
)
600 ULONG64 exc_base
= (rec
->NumberParameters
== 4 ? rec
->ExceptionInformation
[3] : 0);
601 int *processing_throw
= __processing_throw();
602 EXCEPTION_RECORD catch_record
;
607 (*processing_throw
)++;
611 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
612 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
614 TRACE("current trylevel: %d\n", trylevel
);
616 tryblock_map
= rva_to_ptr(descr
->tryblock_map
, dispatch
->ImageBase
);
617 for (i
=0; i
<descr
->tryblock_count
; i
++)
619 tryblock_info tryblock
;
622 read_tryblock_info(&tryblock_map
, &tryblock
, dispatch
->ImageBase
);
624 if (trylevel
< tryblock
.start_level
) continue;
625 if (trylevel
> tryblock
.end_level
) continue;
627 /* got a try block */
628 catchblock
= rva_to_ptr(tryblock
.catchblock
, dispatch
->ImageBase
);
629 for (j
=0; j
<tryblock
.catchblock_count
; j
++)
633 read_catchblock_info(&catchblock
, &ci
, dispatch
->FunctionEntry
->BeginAddress
);
637 const cxx_type_info
*type
= find_caught_type(info
, exc_base
,
638 rva_to_ptr(ci
.type_info
, dispatch
->ImageBase
),
642 TRACE("matched type %p in tryblock %d catchblock %d\n", type
, i
, j
);
644 /* copy the exception to its destination on the stack */
645 copy_exception((void*)rec
->ExceptionInformation
[1],
646 orig_frame
, dispatch
, &ci
, type
, exc_base
);
650 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
653 TRACE("found catch(...) block\n");
656 /* unwind stack and call catch */
657 memset(&catch_record
, 0, sizeof(catch_record
));
658 catch_record
.ExceptionCode
= STATUS_UNWIND_CONSOLIDATE
;
659 catch_record
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
660 catch_record
.NumberParameters
= CONSOLIDATE_UNWIND_PARAMETER_COUNT
;
661 catch_record
.ExceptionInformation
[0] = (ULONG_PTR
)call_catch_block4
;
662 catch_record
.ExceptionInformation
[1] = orig_frame
;
663 catch_record
.ExceptionInformation
[2] = tryblock
.catch_level
;
664 catch_record
.ExceptionInformation
[3] = tryblock
.start_level
;
665 catch_record
.ExceptionInformation
[4] = (ULONG_PTR
)rec
;
666 catch_record
.ExceptionInformation
[5] =
667 (ULONG_PTR
)rva_to_ptr(ci
.handler
, dispatch
->ImageBase
);
668 catch_record
.ExceptionInformation
[6] = (ULONG_PTR
)untrans_rec
;
669 catch_record
.ExceptionInformation
[7] = (ULONG_PTR
)context
;
672 catch_record
.ExceptionInformation
[8] = (ULONG_PTR
)rva_to_ptr(
673 ci
.ret_addr
[0], dispatch
->ImageBase
);
677 catch_record
.ExceptionInformation
[9] = (ULONG_PTR
)rva_to_ptr(
678 ci
.ret_addr
[1], dispatch
->ImageBase
);
680 RtlUnwindEx((void*)frame
, (void*)dispatch
->ControlPc
, &catch_record
, NULL
, &ctx
, NULL
);
684 TRACE("no matching catch block found\n");
685 (*processing_throw
)--;
688 static LONG CALLBACK
se_translation_filter(EXCEPTION_POINTERS
*ep
, void *c
)
690 se_translator_ctx
*ctx
= (se_translator_ctx
*)c
;
691 EXCEPTION_RECORD
*rec
= ep
->ExceptionRecord
;
692 cxx_exception_type
*exc_type
;
694 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
696 TRACE("non-c++ exception thrown in SEH handler: %lx\n", rec
->ExceptionCode
);
700 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
701 find_catch_block4(rec
, ep
->ContextRecord
, ctx
->seh_rec
, ctx
->dest_frame
, ctx
->dispatch
,
702 ctx
->descr
, exc_type
, ctx
->orig_frame
, ctx
->trylevel
);
704 __DestructExceptionObject(rec
);
705 return ExceptionContinueSearch
;
708 /* Hacky way to obtain se_translator */
709 static inline _se_translator_function
get_se_translator(void)
711 return __current_exception()[-2];
714 static void check_noexcept( PEXCEPTION_RECORD rec
, const cxx_function_descr
*descr
)
716 if (!(descr
->header
& FUNC_DESCR_IS_CATCH
) &&
717 rec
->ExceptionCode
== CXX_EXCEPTION
&&
718 (descr
->header
& FUNC_DESCR_NO_EXCEPT
))
720 ERR("noexcept function propagating exception\n");
725 static DWORD
cxx_frame_handler4(EXCEPTION_RECORD
*rec
, ULONG64 frame
,
726 CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
,
727 const cxx_function_descr
*descr
, int trylevel
)
729 cxx_exception_type
*exc_type
;
730 ULONG64 orig_frame
= frame
;
732 if (descr
->header
& FUNC_DESCR_IS_CATCH
)
734 TRACE("nested exception detected\n");
735 orig_frame
= *(ULONG64
*)rva_to_ptr(descr
->frame
, frame
);
736 TRACE("setting orig_frame to %Ix\n", orig_frame
);
739 if (rec
->ExceptionFlags
& (EH_UNWINDING
|EH_EXIT_UNWIND
))
742 if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && cxx_is_consolidate(rec
))
743 last_level
= rec
->ExceptionInformation
[3];
744 else if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && rec
->ExceptionCode
== STATUS_LONGJUMP
)
745 last_level
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
746 descr
->ip_count
, dispatch
, dispatch
->TargetIp
);
748 cxx_local_unwind4(orig_frame
, dispatch
, descr
, trylevel
, last_level
);
749 return ExceptionContinueSearch
;
751 if (!descr
->tryblock_map
)
753 check_noexcept(rec
, descr
);
754 return ExceptionContinueSearch
;
757 if (rec
->ExceptionCode
== CXX_EXCEPTION
)
759 if (!rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
761 TRACE("rethrow detected.\n");
762 *rec
= *(EXCEPTION_RECORD
*)*__current_exception();
765 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
769 TRACE("handling C++ exception rec %p frame %Ix descr %p\n", rec
, frame
, descr
);
770 dump_exception_type(exc_type
, rec
->ExceptionInformation
[3]);
775 _se_translator_function se_translator
= get_se_translator();
778 TRACE("handling C exception code %lx rec %p frame %Ix descr %p\n",
779 rec
->ExceptionCode
, rec
, frame
, descr
);
782 EXCEPTION_POINTERS except_ptrs
;
783 se_translator_ctx ctx
;
785 ctx
.dest_frame
= frame
;
786 ctx
.orig_frame
= orig_frame
;
788 ctx
.dispatch
= dispatch
;
790 ctx
.trylevel
= trylevel
;
793 except_ptrs
.ExceptionRecord
= rec
;
794 except_ptrs
.ContextRecord
= context
;
795 se_translator(rec
->ExceptionCode
, &except_ptrs
);
797 __EXCEPT_CTX(se_translation_filter
, &ctx
)
804 find_catch_block4(rec
, context
, NULL
, frame
, dispatch
, descr
, exc_type
, orig_frame
, trylevel
);
805 check_noexcept(rec
, descr
);
806 return ExceptionContinueSearch
;
809 EXCEPTION_DISPOSITION __cdecl
__CxxFrameHandler4(EXCEPTION_RECORD
*rec
,
810 ULONG64 frame
, CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
)
812 cxx_function_descr descr
;
813 BYTE
*p
, *count
, *count_end
;
816 TRACE("%p %Ix %p %p\n", rec
, frame
, context
, dispatch
);
818 trylevel
= (DWORD_PTR
)FlsGetValue(fls_index
);
819 FlsSetValue(fls_index
, (void*)-2);
821 memset(&descr
, 0, sizeof(descr
));
822 p
= rva_to_ptr(*(UINT
*)dispatch
->HandlerData
, dispatch
->ImageBase
);
825 if ((descr
.header
& FUNC_DESCR_EHS
) &&
826 rec
->ExceptionCode
!= CXX_EXCEPTION
&&
827 !cxx_is_consolidate(rec
) &&
828 rec
->ExceptionCode
!= STATUS_LONGJUMP
)
829 return ExceptionContinueSearch
; /* handle only c++ exceptions */
831 if (descr
.header
& ~(FUNC_DESCR_IS_CATCH
| FUNC_DESCR_IS_SEPARATED
|
832 FUNC_DESCR_UNWIND_MAP
| FUNC_DESCR_TRYBLOCK_MAP
| FUNC_DESCR_EHS
|
833 FUNC_DESCR_NO_EXCEPT
))
835 FIXME("unsupported flags: %x\n", descr
.header
);
836 return ExceptionContinueSearch
;
839 if (descr
.header
& FUNC_DESCR_BBT
) descr
.bbt_flags
= decode_uint(&p
);
840 if (descr
.header
& FUNC_DESCR_UNWIND_MAP
)
842 descr
.unwind_map
= read_rva(&p
);
843 count_end
= count
= rva_to_ptr(descr
.unwind_map
, dispatch
->ImageBase
);
844 descr
.unwind_count
= decode_uint(&count_end
);
845 descr
.unwind_map
+= count_end
- count
;
847 if (descr
.header
& FUNC_DESCR_TRYBLOCK_MAP
)
849 descr
.tryblock_map
= read_rva(&p
);
850 count_end
= count
= rva_to_ptr(descr
.tryblock_map
, dispatch
->ImageBase
);
851 descr
.tryblock_count
= decode_uint(&count_end
);
852 descr
.tryblock_map
+= count_end
- count
;
854 descr
.ip_map
= read_rva(&p
);
855 if (descr
.header
& FUNC_DESCR_IS_SEPARATED
)
860 map
= rva_to_ptr(descr
.ip_map
, dispatch
->ImageBase
);
861 num
= decode_uint(&map
);
862 for (i
= 0; i
< num
; i
++)
864 func
= read_rva(&map
);
865 descr
.ip_map
= read_rva(&map
);
866 if (func
== dispatch
->FunctionEntry
->BeginAddress
)
871 FIXME("function ip_map not found\n");
872 return ExceptionContinueSearch
;
875 count_end
= count
= rva_to_ptr(descr
.ip_map
, dispatch
->ImageBase
);
876 descr
.ip_count
= decode_uint(&count_end
);
877 descr
.ip_map
+= count_end
- count
;
878 if (descr
.header
& FUNC_DESCR_IS_CATCH
) descr
.frame
= decode_uint(&p
);
880 if (!validate_cxx_function_descr4(&descr
, dispatch
))
881 return ExceptionContinueSearch
;
883 return cxx_frame_handler4(rec
, frame
, context
, dispatch
, &descr
, trylevel
);
886 BOOL
msvcrt_init_handler4(void)
888 fls_index
= FlsAlloc(NULL
);
889 if (fls_index
== FLS_OUT_OF_INDEXES
)
891 msvcrt_attach_handler4();
895 void msvcrt_attach_handler4(void)
897 FlsSetValue(fls_index
, (void*)-2);
900 void msvcrt_free_handler4(void)