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
26 #include "wine/exception.h"
27 #include "wine/debug.h"
28 #include "cppexcept.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
32 #define CXX_EXCEPTION 0xe06d7363
34 static DWORD fls_index
;
48 #define FUNC_DESCR_IS_CATCH 0x01
49 #define FUNC_DESCR_IS_SEPARATED 0x02
50 #define FUNC_DESCR_BBT 0x04
51 #define FUNC_DESCR_UNWIND_MAP 0x08
52 #define FUNC_DESCR_TRYBLOCK_MAP 0x10
53 #define FUNC_DESCR_EHS 0x20
54 #define FUNC_DESCR_NO_EXCEPT 0x40
55 #define FUNC_DESCR_RESERVED 0x80
74 #define CATCHBLOCK_FLAGS 0x01
75 #define CATCHBLOCK_TYPE_INFO 0x02
76 #define CATCHBLOCK_OFFSET 0x04
77 #define CATCHBLOCK_SEPARATED 0x08
78 #define CATCHBLOCK_RET_ADDR_MASK 0x30
79 #define CATCHBLOCK_RET_ADDR 0x10
80 #define CATCHBLOCK_TWO_RET_ADDRS 0x20
82 #define TYPE_FLAG_CONST 1
83 #define TYPE_FLAG_VOLATILE 2
84 #define TYPE_FLAG_REFERENCE 8
86 #define UNWIND_TYPE_NO_HANDLER 0
87 #define UNWIND_TYPE_DTOR_OBJ 1
88 #define UNWIND_TYPE_DTOR_PTR 2
89 #define UNWIND_TYPE_FRAME 3
91 #define CONSOLIDATE_UNWIND_PARAMETER_COUNT 10
98 UINT catchblock_count
;
104 UINT ip_off
; /* relative to start of function or earlier ipmap_info */
110 cxx_frame_info frame_info
;
114 EXCEPTION_RECORD
*prev_rec
;
121 EXCEPTION_RECORD
*seh_rec
;
122 DISPATCHER_CONTEXT
*dispatch
;
123 const cxx_function_descr
*descr
;
127 static UINT
decode_uint(BYTE
**b
)
137 else if ((*p
& 3) == 1)
139 ret
= (p
[0] >> 2) + (p
[1] << 6);
142 else if ((*p
& 7) == 3)
144 ret
= (p
[0] >> 3) + (p
[1] << 5) + (p
[2] << 13);
147 else if ((*p
& 15) == 7)
149 ret
= (p
[0] >> 4) + (p
[1] << 4) + (p
[2] << 12) + (p
[3] << 20);
154 FIXME("not implemented - expect crash\n");
163 static UINT
read_rva(BYTE
**b
)
165 UINT ret
= *(UINT
*)(*b
);
170 static inline void* rva_to_ptr(UINT rva
, ULONG64 base
)
172 return rva
? (void*)(base
+rva
) : NULL
;
175 static void read_unwind_info(BYTE
**b
, unwind_info
*ui
)
179 memset(ui
, 0, sizeof(*ui
));
180 ui
->type
= decode_uint(b
);
181 ui
->prev
= p
- (ui
->type
>> 2);
186 case UNWIND_TYPE_NO_HANDLER
:
188 case UNWIND_TYPE_DTOR_OBJ
:
189 ui
->handler
= read_rva(b
);
190 ui
->object
= decode_uint(b
); /* frame offset to object */
192 case UNWIND_TYPE_DTOR_PTR
:
193 ui
->handler
= read_rva(b
);
194 ui
->object
= decode_uint(b
); /* frame offset to pointer to object */
196 case UNWIND_TYPE_FRAME
:
197 ui
->handler
= read_rva(b
);
202 static void read_tryblock_info(BYTE
**b
, tryblock_info
*ti
, ULONG64 image_base
)
204 BYTE
*count
, *count_end
;
206 ti
->start_level
= decode_uint(b
);
207 ti
->end_level
= decode_uint(b
);
208 ti
->catch_level
= decode_uint(b
);
209 ti
->catchblock
= read_rva(b
);
211 count
= count_end
= rva_to_ptr(ti
->catchblock
, image_base
);
214 ti
->catchblock_count
= decode_uint(&count_end
);
215 ti
->catchblock
+= count_end
- count
;
219 ti
->catchblock_count
= 0;
223 static BOOL
read_catchblock_info(BYTE
**b
, catchblock_info
*ci
, DWORD func_rva
)
226 memset(ci
, 0, sizeof(*ci
));
229 if (ci
->header
& ~(CATCHBLOCK_FLAGS
| CATCHBLOCK_TYPE_INFO
| CATCHBLOCK_OFFSET
|
230 CATCHBLOCK_SEPARATED
| CATCHBLOCK_RET_ADDR_MASK
))
232 FIXME("unknown header: %x\n", ci
->header
);
235 ret_addr_type
= ci
->header
& CATCHBLOCK_RET_ADDR_MASK
;
236 if (ret_addr_type
== (CATCHBLOCK_RET_ADDR
| CATCHBLOCK_TWO_RET_ADDRS
))
238 FIXME("unsupported ret addr type.\n");
242 if (ci
->header
& CATCHBLOCK_FLAGS
) ci
->flags
= decode_uint(b
);
243 if (ci
->header
& CATCHBLOCK_TYPE_INFO
) ci
->type_info
= read_rva(b
);
244 if (ci
->header
& CATCHBLOCK_OFFSET
) ci
->offset
= decode_uint(b
);
245 ci
->handler
= read_rva(b
);
246 if (ci
->header
& CATCHBLOCK_SEPARATED
)
248 if (ret_addr_type
== CATCHBLOCK_RET_ADDR
|| ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
249 ci
->ret_addr
[0] = read_rva(b
);
250 if (ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
251 ci
->ret_addr
[1] = read_rva(b
);
255 if (ret_addr_type
== CATCHBLOCK_RET_ADDR
|| ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
256 ci
->ret_addr
[0] = decode_uint(b
) + func_rva
;
257 if (ret_addr_type
== CATCHBLOCK_TWO_RET_ADDRS
)
258 ci
->ret_addr
[1] = decode_uint(b
) + func_rva
;
264 static void read_ipmap_info(BYTE
**b
, ipmap_info
*ii
)
266 ii
->ip_off
= decode_uint(b
);
267 ii
->state
= (INT
)decode_uint(b
) - 1;
270 static inline void dump_type(UINT type_rva
, ULONG64 base
)
272 const cxx_type_info
*type
= rva_to_ptr(type_rva
, base
);
274 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n",
275 type
->flags
, type
->type_info
, dbgstr_type_info(rva_to_ptr(type
->type_info
, base
)),
276 type
->offsets
.this_offset
, type
->offsets
.vbase_descr
, type
->offsets
.vbase_offset
,
277 type
->size
, type
->copy_ctor
, rva_to_ptr(type
->copy_ctor
, base
));
280 static void dump_exception_type(const cxx_exception_type
*type
, ULONG64 base
)
282 const cxx_type_info_table
*type_info_table
= rva_to_ptr(type
->type_info_table
, base
);
285 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
286 type
->flags
, type
->destructor
, rva_to_ptr(type
->destructor
, base
),
287 type
->custom_handler
, rva_to_ptr(type
->custom_handler
, base
),
288 type
->type_info_table
, type_info_table
);
289 for (i
= 0; i
< type_info_table
->count
; i
++)
292 dump_type(type_info_table
->info
[i
], base
);
296 static BOOL
validate_cxx_function_descr4(const cxx_function_descr
*descr
, DISPATCHER_CONTEXT
*dispatch
)
298 ULONG64 image_base
= dispatch
->ImageBase
;
299 BYTE
*unwind_map
= rva_to_ptr(descr
->unwind_map
, image_base
);
300 BYTE
*tryblock_map
= rva_to_ptr(descr
->tryblock_map
, image_base
);
301 BYTE
*ip_map
= rva_to_ptr(descr
->ip_map
, image_base
);
305 TRACE("header 0x%x\n", descr
->header
);
306 TRACE("basic block transformations flags: 0x%x\n", descr
->bbt_flags
);
308 TRACE("unwind table: 0x%x(%p) %d\n", descr
->unwind_map
, unwind_map
, descr
->unwind_count
);
309 for (i
= 0; i
< descr
->unwind_count
; i
++)
311 BYTE
*entry
= unwind_map
;
314 read_unwind_info(&unwind_map
, &ui
);
315 if (ui
.prev
< (BYTE
*)rva_to_ptr(descr
->unwind_map
, image_base
)) ui
.prev
= NULL
;
316 TRACE(" %d (%p): type 0x%x prev %p func 0x%x(%p) object 0x%x\n",
317 i
, entry
, ui
.type
, ui
.prev
, ui
.handler
,
318 rva_to_ptr(ui
.handler
, image_base
), ui
.object
);
321 TRACE("try table: 0x%x(%p) %d\n", descr
->tryblock_map
, tryblock_map
, descr
->tryblock_count
);
322 for (i
= 0; i
< descr
->tryblock_count
; i
++)
327 read_tryblock_info(&tryblock_map
, &ti
, image_base
);
328 catchblock
= rva_to_ptr(ti
.catchblock
, image_base
);
329 TRACE(" %d: start %d end %d catchlevel %d catch 0x%x(%p) %d\n",
330 i
, ti
.start_level
, ti
.end_level
, ti
.catch_level
,
331 ti
.catchblock
, catchblock
, ti
.catchblock_count
);
332 for (j
= 0; j
< ti
.catchblock_count
; j
++)
335 if (!read_catchblock_info(&catchblock
, &ci
,
336 dispatch
->FunctionEntry
->BeginAddress
)) return FALSE
;
337 TRACE(" %d: header 0x%x offset %d handler 0x%x(%p) "
338 "ret addr[0] %#x ret_addr[1] %#x type %#x %s\n", j
, ci
.header
, ci
.offset
,
339 ci
.handler
, rva_to_ptr(ci
.handler
, image_base
),
340 ci
.ret_addr
[0], ci
.ret_addr
[1], ci
.type_info
,
341 dbgstr_type_info(rva_to_ptr(ci
.type_info
, image_base
)));
345 TRACE("ipmap: 0x%x(%p) %d\n", descr
->ip_map
, ip_map
, descr
->ip_count
);
346 ip
= rva_to_ptr(dispatch
->FunctionEntry
->BeginAddress
, image_base
);
347 for (i
= 0; i
< descr
->ip_count
; i
++)
351 read_ipmap_info(&ip_map
, &ii
);
353 TRACE(" %d: ip offset 0x%x (%p) state %d\n", i
, ii
.ip_off
, ip
, ii
.state
);
356 TRACE("establisher frame: %x\n", descr
->frame
);
360 static inline int ip_to_state4(BYTE
*ip_map
, UINT count
, DISPATCHER_CONTEXT
*dispatch
, ULONG64 ip
)
367 state_ip
= dispatch
->ImageBase
+ dispatch
->FunctionEntry
->BeginAddress
;
368 for (i
= 0; i
< count
; i
++)
370 read_ipmap_info(&ip_map
, &ii
);
371 state_ip
+= ii
.ip_off
;
372 if (ip
< state_ip
) break;
376 TRACE("state %d\n", ret
);
380 static const cxx_type_info
*find_caught_type(cxx_exception_type
*exc_type
, ULONG64 exc_base
,
381 const type_info
*catch_ti
, UINT catch_flags
)
383 const cxx_type_info_table
*type_info_table
= rva_to_ptr(exc_type
->type_info_table
, exc_base
);
386 for (i
= 0; i
< type_info_table
->count
; i
++)
388 const cxx_type_info
*type
= rva_to_ptr(type_info_table
->info
[i
], exc_base
);
389 const type_info
*ti
= rva_to_ptr(type
->type_info
, exc_base
);
391 if (!catch_ti
) return type
; /* catch(...) matches any type */
394 if (strcmp( catch_ti
->mangled
, ti
->mangled
)) continue;
396 /* type is the same, now check the flags */
397 if ((exc_type
->flags
& TYPE_FLAG_CONST
) &&
398 !(catch_flags
& TYPE_FLAG_CONST
)) continue;
399 if ((exc_type
->flags
& TYPE_FLAG_VOLATILE
) &&
400 !(catch_flags
& TYPE_FLAG_VOLATILE
)) continue;
401 return type
; /* it matched */
406 static inline void copy_exception(void *object
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
407 const catchblock_info
*catchblock
, const cxx_type_info
*type
, ULONG64 exc_base
)
409 const type_info
*catch_ti
= rva_to_ptr(catchblock
->type_info
, dispatch
->ImageBase
);
410 void **dest
= rva_to_ptr(catchblock
->offset
, frame
);
412 if (!catch_ti
|| !catch_ti
->mangled
[0]) return;
413 if (!catchblock
->offset
) return;
415 if (catchblock
->flags
& TYPE_FLAG_REFERENCE
)
417 *dest
= get_this_pointer(&type
->offsets
, object
);
419 else if (type
->flags
& CLASS_IS_SIMPLE_TYPE
)
421 memmove(dest
, object
, type
->size
);
422 /* if it is a pointer, adjust it */
423 if (type
->size
== sizeof(void*)) *dest
= get_this_pointer(&type
->offsets
, *dest
);
425 else /* copy the object */
429 if (type
->flags
& CLASS_HAS_VIRTUAL_BASE_CLASS
)
431 void (__cdecl
*copy_ctor
)(void*, void*, int) =
432 rva_to_ptr(type
->copy_ctor
, exc_base
);
433 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
), 1);
437 void (__cdecl
*copy_ctor
)(void*, void*) =
438 rva_to_ptr(type
->copy_ctor
, exc_base
);
439 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
));
443 memmove(dest
, get_this_pointer(&type
->offsets
,object
), type
->size
);
447 static void cxx_local_unwind4(ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
448 const cxx_function_descr
*descr
, int trylevel
, int last_level
)
450 void (__cdecl
*handler_dtor
)(void *obj
, ULONG64 frame
);
451 BYTE
*unwind_data
, *last
;
458 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
459 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
462 TRACE("current level: %d, last level: %d\n", trylevel
, last_level
);
464 if (trylevel
<-1 || trylevel
>=(int)descr
->unwind_count
)
466 ERR("invalid trylevel %d\n", trylevel
);
470 if (trylevel
<= last_level
) return;
472 unwind_data
= rva_to_ptr(descr
->unwind_map
, dispatch
->ImageBase
);
473 last
= unwind_data
- 1;
474 for (i
= 0; i
< trylevel
; i
++)
476 BYTE
*addr
= unwind_data
;
477 read_unwind_info(&unwind_data
, &ui
);
478 if (i
== last_level
) last
= addr
;
481 while (unwind_data
> last
)
483 read_unwind_info(&unwind_data
, &ui
);
484 unwind_data
= ui
.prev
;
488 handler_dtor
= rva_to_ptr(ui
.handler
, dispatch
->ImageBase
);
489 obj
= rva_to_ptr(ui
.object
, frame
);
490 if(ui
.type
== UNWIND_TYPE_DTOR_PTR
)
492 TRACE("handler: %p object: %p\n", handler_dtor
, obj
);
493 handler_dtor(obj
, frame
);
498 static LONG CALLBACK
cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs
, void *c
)
500 EXCEPTION_RECORD
*rec
= eptrs
->ExceptionRecord
;
501 cxx_catch_ctx
*ctx
= c
;
503 if (rec
->ExceptionCode
== CXX_EXCEPTION
&& !rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
504 return EXCEPTION_EXECUTE_HANDLER
;
506 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->search_state
);
507 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
508 return EXCEPTION_CONTINUE_SEARCH
;
509 if (rec
->ExceptionInformation
[1] == ctx
->prev_rec
->ExceptionInformation
[1])
511 return EXCEPTION_CONTINUE_SEARCH
;
514 static void CALLBACK
cxx_catch_cleanup(BOOL normal
, void *c
)
516 cxx_catch_ctx
*ctx
= c
;
517 __CxxUnregisterExceptionObject(&ctx
->frame_info
, ctx
->rethrow
);
519 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->unwind_state
);
522 static void* WINAPI
call_catch_block4(EXCEPTION_RECORD
*rec
)
524 ULONG64 frame
= rec
->ExceptionInformation
[1];
525 EXCEPTION_RECORD
*prev_rec
= (void*)rec
->ExceptionInformation
[4];
526 EXCEPTION_RECORD
*untrans_rec
= (void*)rec
->ExceptionInformation
[6];
527 CONTEXT
*context
= (void*)rec
->ExceptionInformation
[7];
528 void* (__cdecl
*handler
)(ULONG64 unk
, ULONG64 rbp
) = (void*)rec
->ExceptionInformation
[5];
529 EXCEPTION_POINTERS ep
= { prev_rec
, context
};
531 void *ret_addr
= NULL
;
533 TRACE("calling handler %p\n", handler
);
536 __CxxRegisterExceptionObject(&ep
, &ctx
.frame_info
);
537 ctx
.search_state
= rec
->ExceptionInformation
[2];
538 ctx
.unwind_state
= rec
->ExceptionInformation
[3];
539 ctx
.prev_rec
= prev_rec
;
540 (*__processing_throw())--;
545 ret_addr
= handler(0, frame
);
547 __EXCEPT_CTX(cxx_rethrow_filter
, &ctx
)
549 TRACE("detect rethrow: exception code: %lx\n", prev_rec
->ExceptionCode
);
551 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
.search_state
);
555 __DestructExceptionObject(prev_rec
);
556 RaiseException(untrans_rec
->ExceptionCode
, untrans_rec
->ExceptionFlags
,
557 untrans_rec
->NumberParameters
, untrans_rec
->ExceptionInformation
);
561 RaiseException(prev_rec
->ExceptionCode
, prev_rec
->ExceptionFlags
,
562 prev_rec
->NumberParameters
, prev_rec
->ExceptionInformation
);
567 __FINALLY_CTX(cxx_catch_cleanup
, &ctx
)
569 FlsSetValue(fls_index
, (void*)-2);
570 TRACE("handler returned %p, ret_addr[0] %#Ix, ret_addr[1] %#Ix.\n",
571 ret_addr
, rec
->ExceptionInformation
[8], rec
->ExceptionInformation
[9]);
573 if (rec
->ExceptionInformation
[9])
575 if ((ULONG_PTR
)ret_addr
> 1)
577 ERR("unexpected handler result %p.\n", ret_addr
);
580 return (void*)rec
->ExceptionInformation
[8 + (ULONG_PTR
)ret_addr
];
582 return rec
->ExceptionInformation
[8] ? (void *)rec
->ExceptionInformation
[8] : ret_addr
;
585 static inline BOOL
cxx_is_consolidate(const EXCEPTION_RECORD
*rec
)
587 return rec
->ExceptionCode
== STATUS_UNWIND_CONSOLIDATE
588 && rec
->NumberParameters
== CONSOLIDATE_UNWIND_PARAMETER_COUNT
589 && rec
->ExceptionInformation
[0] == (ULONG_PTR
)call_catch_block4
;
592 static inline void find_catch_block4(EXCEPTION_RECORD
*rec
, CONTEXT
*context
,
593 EXCEPTION_RECORD
*untrans_rec
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
594 const cxx_function_descr
*descr
, cxx_exception_type
*info
,
595 ULONG64 orig_frame
, int trylevel
)
597 ULONG64 exc_base
= (rec
->NumberParameters
== 4 ? rec
->ExceptionInformation
[3] : 0);
598 int *processing_throw
= __processing_throw();
599 EXCEPTION_RECORD catch_record
;
604 (*processing_throw
)++;
608 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
609 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
611 TRACE("current trylevel: %d\n", trylevel
);
613 tryblock_map
= rva_to_ptr(descr
->tryblock_map
, dispatch
->ImageBase
);
614 for (i
=0; i
<descr
->tryblock_count
; i
++)
616 tryblock_info tryblock
;
619 read_tryblock_info(&tryblock_map
, &tryblock
, dispatch
->ImageBase
);
621 if (trylevel
< tryblock
.start_level
) continue;
622 if (trylevel
> tryblock
.end_level
) continue;
624 /* got a try block */
625 catchblock
= rva_to_ptr(tryblock
.catchblock
, dispatch
->ImageBase
);
626 for (j
=0; j
<tryblock
.catchblock_count
; j
++)
630 read_catchblock_info(&catchblock
, &ci
, dispatch
->FunctionEntry
->BeginAddress
);
634 const cxx_type_info
*type
= find_caught_type(info
, exc_base
,
635 rva_to_ptr(ci
.type_info
, dispatch
->ImageBase
),
639 TRACE("matched type %p in tryblock %d catchblock %d\n", type
, i
, j
);
641 /* copy the exception to its destination on the stack */
642 copy_exception((void*)rec
->ExceptionInformation
[1],
643 orig_frame
, dispatch
, &ci
, type
, exc_base
);
647 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
650 TRACE("found catch(...) block\n");
653 /* unwind stack and call catch */
654 memset(&catch_record
, 0, sizeof(catch_record
));
655 catch_record
.ExceptionCode
= STATUS_UNWIND_CONSOLIDATE
;
656 catch_record
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
657 catch_record
.NumberParameters
= CONSOLIDATE_UNWIND_PARAMETER_COUNT
;
658 catch_record
.ExceptionInformation
[0] = (ULONG_PTR
)call_catch_block4
;
659 catch_record
.ExceptionInformation
[1] = orig_frame
;
660 catch_record
.ExceptionInformation
[2] = tryblock
.catch_level
;
661 catch_record
.ExceptionInformation
[3] = tryblock
.start_level
;
662 catch_record
.ExceptionInformation
[4] = (ULONG_PTR
)rec
;
663 catch_record
.ExceptionInformation
[5] =
664 (ULONG_PTR
)rva_to_ptr(ci
.handler
, dispatch
->ImageBase
);
665 catch_record
.ExceptionInformation
[6] = (ULONG_PTR
)untrans_rec
;
666 catch_record
.ExceptionInformation
[7] = (ULONG_PTR
)context
;
669 catch_record
.ExceptionInformation
[8] = (ULONG_PTR
)rva_to_ptr(
670 ci
.ret_addr
[0], dispatch
->ImageBase
);
674 catch_record
.ExceptionInformation
[9] = (ULONG_PTR
)rva_to_ptr(
675 ci
.ret_addr
[1], dispatch
->ImageBase
);
677 RtlUnwindEx((void*)frame
, (void*)dispatch
->ControlPc
, &catch_record
, NULL
, &ctx
, NULL
);
681 TRACE("no matching catch block found\n");
682 (*processing_throw
)--;
685 static LONG CALLBACK
se_translation_filter(EXCEPTION_POINTERS
*ep
, void *c
)
687 se_translator_ctx
*ctx
= (se_translator_ctx
*)c
;
688 EXCEPTION_RECORD
*rec
= ep
->ExceptionRecord
;
689 cxx_exception_type
*exc_type
;
691 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
693 TRACE("non-c++ exception thrown in SEH handler: %lx\n", rec
->ExceptionCode
);
697 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
698 find_catch_block4(rec
, ep
->ContextRecord
, ctx
->seh_rec
, ctx
->dest_frame
, ctx
->dispatch
,
699 ctx
->descr
, exc_type
, ctx
->orig_frame
, ctx
->trylevel
);
701 __DestructExceptionObject(rec
);
702 return ExceptionContinueSearch
;
705 /* Hacky way to obtain se_translator */
706 static inline _se_translator_function
get_se_translator(void)
708 return __current_exception()[-2];
711 static void check_noexcept( PEXCEPTION_RECORD rec
, const cxx_function_descr
*descr
)
713 if (!(descr
->header
& FUNC_DESCR_IS_CATCH
) &&
714 rec
->ExceptionCode
== CXX_EXCEPTION
&&
715 (descr
->header
& FUNC_DESCR_NO_EXCEPT
))
717 ERR("noexcept function propagating exception\n");
722 static DWORD
cxx_frame_handler4(EXCEPTION_RECORD
*rec
, ULONG64 frame
,
723 CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
,
724 const cxx_function_descr
*descr
, int trylevel
)
726 cxx_exception_type
*exc_type
;
727 ULONG64 orig_frame
= frame
;
729 if (descr
->header
& FUNC_DESCR_IS_CATCH
)
731 TRACE("nested exception detected\n");
732 orig_frame
= *(ULONG64
*)rva_to_ptr(descr
->frame
, frame
);
733 TRACE("setting orig_frame to %Ix\n", orig_frame
);
736 if (rec
->ExceptionFlags
& (EH_UNWINDING
|EH_EXIT_UNWIND
))
739 if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && cxx_is_consolidate(rec
))
740 last_level
= rec
->ExceptionInformation
[3];
741 else if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && rec
->ExceptionCode
== STATUS_LONGJUMP
)
742 last_level
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
743 descr
->ip_count
, dispatch
, dispatch
->TargetIp
);
745 cxx_local_unwind4(orig_frame
, dispatch
, descr
, trylevel
, last_level
);
746 return ExceptionContinueSearch
;
748 if (!descr
->tryblock_map
)
750 check_noexcept(rec
, descr
);
751 return ExceptionContinueSearch
;
754 if (rec
->ExceptionCode
== CXX_EXCEPTION
)
756 if (!rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
758 TRACE("rethrow detected.\n");
759 *rec
= *(EXCEPTION_RECORD
*)*__current_exception();
762 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
766 TRACE("handling C++ exception rec %p frame %Ix descr %p\n", rec
, frame
, descr
);
767 dump_exception_type(exc_type
, rec
->ExceptionInformation
[3]);
772 _se_translator_function se_translator
= get_se_translator();
775 TRACE("handling C exception code %lx rec %p frame %Ix descr %p\n",
776 rec
->ExceptionCode
, rec
, frame
, descr
);
779 EXCEPTION_POINTERS except_ptrs
;
780 se_translator_ctx ctx
;
782 ctx
.dest_frame
= frame
;
783 ctx
.orig_frame
= orig_frame
;
785 ctx
.dispatch
= dispatch
;
787 ctx
.trylevel
= trylevel
;
790 except_ptrs
.ExceptionRecord
= rec
;
791 except_ptrs
.ContextRecord
= context
;
792 se_translator(rec
->ExceptionCode
, &except_ptrs
);
794 __EXCEPT_CTX(se_translation_filter
, &ctx
)
801 find_catch_block4(rec
, context
, NULL
, frame
, dispatch
, descr
, exc_type
, orig_frame
, trylevel
);
802 check_noexcept(rec
, descr
);
803 return ExceptionContinueSearch
;
806 EXCEPTION_DISPOSITION __cdecl
__CxxFrameHandler4(EXCEPTION_RECORD
*rec
,
807 ULONG64 frame
, CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
)
809 cxx_function_descr descr
;
810 BYTE
*p
, *count
, *count_end
;
813 TRACE("%p %Ix %p %p\n", rec
, frame
, context
, dispatch
);
815 trylevel
= (DWORD_PTR
)FlsGetValue(fls_index
);
816 FlsSetValue(fls_index
, (void*)-2);
818 memset(&descr
, 0, sizeof(descr
));
819 p
= rva_to_ptr(*(UINT
*)dispatch
->HandlerData
, dispatch
->ImageBase
);
822 if ((descr
.header
& FUNC_DESCR_EHS
) &&
823 rec
->ExceptionCode
!= CXX_EXCEPTION
&&
824 !cxx_is_consolidate(rec
) &&
825 rec
->ExceptionCode
!= STATUS_LONGJUMP
)
826 return ExceptionContinueSearch
; /* handle only c++ exceptions */
828 if (descr
.header
& ~(FUNC_DESCR_IS_CATCH
| FUNC_DESCR_IS_SEPARATED
|
829 FUNC_DESCR_UNWIND_MAP
| FUNC_DESCR_TRYBLOCK_MAP
| FUNC_DESCR_EHS
|
830 FUNC_DESCR_NO_EXCEPT
))
832 FIXME("unsupported flags: %x\n", descr
.header
);
833 return ExceptionContinueSearch
;
836 if (descr
.header
& FUNC_DESCR_BBT
) descr
.bbt_flags
= decode_uint(&p
);
837 if (descr
.header
& FUNC_DESCR_UNWIND_MAP
)
839 descr
.unwind_map
= read_rva(&p
);
840 count_end
= count
= rva_to_ptr(descr
.unwind_map
, dispatch
->ImageBase
);
841 descr
.unwind_count
= decode_uint(&count_end
);
842 descr
.unwind_map
+= count_end
- count
;
844 if (descr
.header
& FUNC_DESCR_TRYBLOCK_MAP
)
846 descr
.tryblock_map
= read_rva(&p
);
847 count_end
= count
= rva_to_ptr(descr
.tryblock_map
, dispatch
->ImageBase
);
848 descr
.tryblock_count
= decode_uint(&count_end
);
849 descr
.tryblock_map
+= count_end
- count
;
851 descr
.ip_map
= read_rva(&p
);
852 if (descr
.header
& FUNC_DESCR_IS_SEPARATED
)
857 map
= rva_to_ptr(descr
.ip_map
, dispatch
->ImageBase
);
858 num
= decode_uint(&map
);
859 for (i
= 0; i
< num
; i
++)
861 func
= read_rva(&map
);
862 descr
.ip_map
= read_rva(&map
);
863 if (func
== dispatch
->FunctionEntry
->BeginAddress
)
868 FIXME("function ip_map not found\n");
869 return ExceptionContinueSearch
;
872 count_end
= count
= rva_to_ptr(descr
.ip_map
, dispatch
->ImageBase
);
873 descr
.ip_count
= decode_uint(&count_end
);
874 descr
.ip_map
+= count_end
- count
;
875 if (descr
.header
& FUNC_DESCR_IS_CATCH
) descr
.frame
= decode_uint(&p
);
877 if (!validate_cxx_function_descr4(&descr
, dispatch
))
878 return ExceptionContinueSearch
;
880 return cxx_frame_handler4(rec
, frame
, context
, dispatch
, &descr
, trylevel
);
883 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
887 case DLL_PROCESS_ATTACH
:
888 fls_index
= FlsAlloc(NULL
);
889 if (fls_index
== FLS_OUT_OF_INDEXES
)
892 case DLL_THREAD_ATTACH
:
893 FlsSetValue(fls_index
, (void*)-2);
895 case DLL_PROCESS_DETACH
: