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
85 UINT catchblock_count
;
91 UINT ip_off
; /* relative to start of function or earlier ipmap_info */
97 cxx_frame_info frame_info
;
107 EXCEPTION_RECORD
*seh_rec
;
108 DISPATCHER_CONTEXT
*dispatch
;
109 const cxx_function_descr
*descr
;
113 static UINT
decode_uint(BYTE
**b
)
122 else if ((**b
& 3) == 1)
124 ret
= (*b
[0] >> 2) + (*b
[1] << 6);
127 else if ((**b
& 7) == 3)
129 ret
= (*b
[0] >> 3) + (*b
[1] << 5) + (*b
[2] << 13);
132 else if ((**b
& 15) == 7)
134 ret
= (*b
[0] >> 4) + (*b
[1] << 4) + (*b
[2] << 12) + (*b
[3] << 20);
139 FIXME("not implemented - expect crash\n");
147 static UINT
read_rva(BYTE
**b
)
149 UINT ret
= *(UINT
*)(*b
);
154 static inline void* rva_to_ptr(UINT rva
, ULONG64 base
)
156 return rva
? (void*)(base
+rva
) : NULL
;
159 static BOOL
read_unwind_info(BYTE
**b
, unwind_info
*ui
)
163 memset(ui
, 0, sizeof(*ui
));
164 ui
->flags
= decode_uint(b
);
165 ui
->prev
= p
- (ui
->flags
>> 2);
170 ui
->handler
= read_rva(b
);
171 ui
->object
= decode_uint(b
); /* frame offset */
176 FIXME("unknown flag: %x\n", ui
->flags
);
182 static void read_tryblock_info(BYTE
**b
, tryblock_info
*ti
, ULONG64 image_base
)
184 BYTE
*count
, *count_end
;
186 ti
->start_level
= decode_uint(b
);
187 ti
->end_level
= decode_uint(b
);
188 ti
->catch_level
= decode_uint(b
);
189 ti
->catchblock
= read_rva(b
);
191 count
= count_end
= rva_to_ptr(ti
->catchblock
, image_base
);
194 ti
->catchblock_count
= decode_uint(&count_end
);
195 ti
->catchblock
+= count_end
- count
;
199 ti
->catchblock_count
= 0;
203 static BOOL
read_catchblock_info(BYTE
**b
, catchblock_info
*ci
)
205 memset(ci
, 0, sizeof(*ci
));
208 if (ci
->header
& ~(CATCHBLOCK_FLAGS
| CATCHBLOCK_TYPE_INFO
| CATCHBLOCK_OFFSET
| CATCHBLOCK_RET_ADDR
))
210 FIXME("unknown header: %x\n", ci
->header
);
213 if (ci
->header
& CATCHBLOCK_FLAGS
) ci
->flags
= decode_uint(b
);
214 if (ci
->header
& CATCHBLOCK_TYPE_INFO
) ci
->type_info
= read_rva(b
);
215 if (ci
->header
& CATCHBLOCK_OFFSET
) ci
->offset
= decode_uint(b
);
216 ci
->handler
= read_rva(b
);
217 if (ci
->header
& CATCHBLOCK_RET_ADDR
) ci
->ret_addr
= decode_uint(b
);
221 static void read_ipmap_info(BYTE
**b
, ipmap_info
*ii
)
223 ii
->ip_off
= decode_uint(b
);
224 ii
->state
= (INT
)decode_uint(b
) - 1;
227 static inline void dump_type(UINT type_rva
, ULONG64 base
)
229 const cxx_type_info
*type
= rva_to_ptr(type_rva
, base
);
231 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n",
232 type
->flags
, type
->type_info
, dbgstr_type_info(rva_to_ptr(type
->type_info
, base
)),
233 type
->offsets
.this_offset
, type
->offsets
.vbase_descr
, type
->offsets
.vbase_offset
,
234 type
->size
, type
->copy_ctor
, rva_to_ptr(type
->copy_ctor
, base
));
237 static void dump_exception_type(const cxx_exception_type
*type
, ULONG64 base
)
239 const cxx_type_info_table
*type_info_table
= rva_to_ptr(type
->type_info_table
, base
);
242 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
243 type
->flags
, type
->destructor
, rva_to_ptr(type
->destructor
, base
),
244 type
->custom_handler
, rva_to_ptr(type
->custom_handler
, base
),
245 type
->type_info_table
, type_info_table
);
246 for (i
= 0; i
< type_info_table
->count
; i
++)
249 dump_type(type_info_table
->info
[i
], base
);
253 static BOOL
validate_cxx_function_descr4(const cxx_function_descr
*descr
, DISPATCHER_CONTEXT
*dispatch
)
255 ULONG64 image_base
= dispatch
->ImageBase
;
256 BYTE
*unwind_map
= rva_to_ptr(descr
->unwind_map
, image_base
);
257 BYTE
*tryblock_map
= rva_to_ptr(descr
->tryblock_map
, image_base
);
258 BYTE
*ip_map
= rva_to_ptr(descr
->ip_map
, image_base
);
262 TRACE("header 0x%x\n", descr
->header
);
263 TRACE("basic block transformations flags: 0x%x\n", descr
->bbt_flags
);
265 TRACE("unwind table: 0x%x(%p) %d\n", descr
->unwind_map
, unwind_map
, descr
->unwind_count
);
266 for (i
= 0; i
< descr
->unwind_count
; i
++)
268 BYTE
*entry
= unwind_map
;
271 if (!read_unwind_info(&unwind_map
, &ui
)) return FALSE
;
272 if (ui
.prev
< (BYTE
*)rva_to_ptr(descr
->unwind_map
, image_base
)) ui
.prev
= NULL
;
273 TRACE(" %d (%p): flags 0x%x prev %p func 0x%x(%p) object 0x%x\n",
274 i
, entry
, ui
.flags
, ui
.prev
, ui
.handler
,
275 rva_to_ptr(ui
.handler
, image_base
), ui
.object
);
278 TRACE("try table: 0x%x(%p) %d\n", descr
->tryblock_map
, tryblock_map
, descr
->tryblock_count
);
279 for (i
= 0; i
< descr
->tryblock_count
; i
++)
284 read_tryblock_info(&tryblock_map
, &ti
, image_base
);
285 catchblock
= rva_to_ptr(ti
.catchblock
, image_base
);
286 TRACE(" %d: start %d end %d catchlevel %d catch 0x%x(%p) %d\n",
287 i
, ti
.start_level
, ti
.end_level
, ti
.catch_level
,
288 ti
.catchblock
, catchblock
, ti
.catchblock_count
);
289 for (j
= 0; j
< ti
.catchblock_count
; j
++)
292 if (!read_catchblock_info(&catchblock
, &ci
)) return FALSE
;
293 TRACE(" %d: header 0x%x offset %d handler 0x%x(%p) "
294 "ret addr %x type %x %s\n", j
, ci
.header
, ci
.offset
,
295 ci
.handler
, rva_to_ptr(ci
.handler
, image_base
),
296 ci
.ret_addr
, ci
.type_info
,
297 dbgstr_type_info(rva_to_ptr(ci
.type_info
, image_base
)));
301 TRACE("ipmap: 0x%x(%p) %d\n", descr
->ip_map
, ip_map
, descr
->ip_count
);
302 ip
= rva_to_ptr(dispatch
->FunctionEntry
->BeginAddress
, image_base
);
303 for (i
= 0; i
< descr
->ip_count
; i
++)
307 read_ipmap_info(&ip_map
, &ii
);
309 TRACE(" %d: ip offset 0x%x (%p) state %d\n", i
, ii
.ip_off
, ip
, ii
.state
);
312 TRACE("establisher frame: %x\n", descr
->frame
);
316 static inline int ip_to_state4(BYTE
*ip_map
, UINT count
, DISPATCHER_CONTEXT
*dispatch
, ULONG64 ip
)
323 state_ip
= dispatch
->ImageBase
+ dispatch
->FunctionEntry
->BeginAddress
;
324 for (i
= 0; i
< count
; i
++)
326 read_ipmap_info(&ip_map
, &ii
);
327 state_ip
+= ii
.ip_off
;
328 if (ip
< state_ip
) break;
332 TRACE("state %d\n", ret
);
336 static const cxx_type_info
*find_caught_type(cxx_exception_type
*exc_type
, ULONG64 exc_base
,
337 const type_info
*catch_ti
, UINT catch_flags
)
339 const cxx_type_info_table
*type_info_table
= rva_to_ptr(exc_type
->type_info_table
, exc_base
);
342 for (i
= 0; i
< type_info_table
->count
; i
++)
344 const cxx_type_info
*type
= rva_to_ptr(type_info_table
->info
[i
], exc_base
);
345 const type_info
*ti
= rva_to_ptr(type
->type_info
, exc_base
);
347 if (!catch_ti
) return type
; /* catch(...) matches any type */
350 if (strcmp( catch_ti
->mangled
, ti
->mangled
)) continue;
352 /* type is the same, now check the flags */
353 if ((exc_type
->flags
& TYPE_FLAG_CONST
) &&
354 !(catch_flags
& TYPE_FLAG_CONST
)) continue;
355 if ((exc_type
->flags
& TYPE_FLAG_VOLATILE
) &&
356 !(catch_flags
& TYPE_FLAG_VOLATILE
)) continue;
357 return type
; /* it matched */
362 static inline void copy_exception(void *object
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
363 const catchblock_info
*catchblock
, const cxx_type_info
*type
, ULONG64 exc_base
)
365 const type_info
*catch_ti
= rva_to_ptr(catchblock
->type_info
, dispatch
->ImageBase
);
366 void **dest
= rva_to_ptr(catchblock
->offset
, frame
);
368 if (!catch_ti
|| !catch_ti
->mangled
[0]) return;
369 if (!catchblock
->offset
) return;
371 if (catchblock
->flags
& TYPE_FLAG_REFERENCE
)
373 *dest
= get_this_pointer(&type
->offsets
, object
);
375 else if (type
->flags
& CLASS_IS_SIMPLE_TYPE
)
377 memmove(dest
, object
, type
->size
);
378 /* if it is a pointer, adjust it */
379 if (type
->size
== sizeof(void*)) *dest
= get_this_pointer(&type
->offsets
, *dest
);
381 else /* copy the object */
385 if (type
->flags
& CLASS_HAS_VIRTUAL_BASE_CLASS
)
387 void (__cdecl
*copy_ctor
)(void*, void*, int) =
388 rva_to_ptr(type
->copy_ctor
, exc_base
);
389 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
), 1);
393 void (__cdecl
*copy_ctor
)(void*, void*) =
394 rva_to_ptr(type
->copy_ctor
, exc_base
);
395 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
));
399 memmove(dest
, get_this_pointer(&type
->offsets
,object
), type
->size
);
403 static void cxx_local_unwind4(ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
404 const cxx_function_descr
*descr
, int trylevel
, int last_level
)
406 void (__cdecl
*handler_dtor
)(void *obj
);
407 BYTE
*unwind_data
, *last
;
414 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
415 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
418 TRACE("current level: %d, last level: %d\n", trylevel
, last_level
);
420 if (trylevel
<0 || trylevel
>=descr
->unwind_count
)
422 ERR("invalid trylevel %d\n", trylevel
);
426 unwind_data
= rva_to_ptr(descr
->unwind_map
, dispatch
->ImageBase
);
428 for (i
= 0; i
< trylevel
; i
++)
430 BYTE
*addr
= unwind_data
;
431 read_unwind_info(&unwind_data
, &ui
);
432 if (i
== last_level
) last
= addr
;
435 while (unwind_data
> last
)
437 read_unwind_info(&unwind_data
, &ui
);
438 unwind_data
= ui
.prev
;
442 handler_dtor
= rva_to_ptr(ui
.handler
, dispatch
->ImageBase
);
443 obj
= rva_to_ptr(ui
.object
, frame
);
444 TRACE("handler: %p object: %p\n", handler_dtor
, obj
);
450 static LONG CALLBACK
cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs
, void *c
)
452 EXCEPTION_RECORD
*rec
= eptrs
->ExceptionRecord
;
453 cxx_catch_ctx
*ctx
= c
;
455 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->search_state
);
457 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
458 return EXCEPTION_CONTINUE_SEARCH
;
459 if (!rec
->ExceptionInformation
[1] && !rec
->ExceptionInformation
[2])
460 return EXCEPTION_EXECUTE_HANDLER
;
461 if (rec
->ExceptionInformation
[1] == ((EXCEPTION_RECORD
*)*__current_exception())->ExceptionInformation
[1])
463 return EXCEPTION_CONTINUE_SEARCH
;
466 static void CALLBACK
cxx_catch_cleanup(BOOL normal
, void *c
)
468 cxx_catch_ctx
*ctx
= c
;
469 __CxxUnregisterExceptionObject(&ctx
->frame_info
, ctx
->rethrow
);
471 FlsSetValue(fls_index
, (void*)(DWORD_PTR
)ctx
->unwind_state
);
474 static void* WINAPI
call_catch_block4(EXCEPTION_RECORD
*rec
)
476 ULONG64 frame
= rec
->ExceptionInformation
[1];
477 EXCEPTION_RECORD
*prev_rec
= (void*)rec
->ExceptionInformation
[4];
478 EXCEPTION_RECORD
*untrans_rec
= (void*)rec
->ExceptionInformation
[6];
479 CONTEXT
*context
= (void*)rec
->ExceptionInformation
[7];
480 void* (__cdecl
*handler
)(ULONG64 unk
, ULONG64 rbp
) = (void*)rec
->ExceptionInformation
[5];
481 EXCEPTION_POINTERS ep
= { prev_rec
, context
};
483 void *ret_addr
= NULL
;
485 TRACE("calling handler %p\n", handler
);
488 __CxxRegisterExceptionObject(&ep
, &ctx
.frame_info
);
489 ctx
.search_state
= rec
->ExceptionInformation
[2];
490 ctx
.unwind_state
= rec
->ExceptionInformation
[3];
491 (*__processing_throw())--;
496 ret_addr
= handler(0, frame
);
498 __EXCEPT_CTX(cxx_rethrow_filter
, &ctx
)
500 TRACE("detect rethrow: exception code: %x\n", prev_rec
->ExceptionCode
);
505 __DestructExceptionObject(prev_rec
);
506 RaiseException(untrans_rec
->ExceptionCode
, untrans_rec
->ExceptionFlags
,
507 untrans_rec
->NumberParameters
, untrans_rec
->ExceptionInformation
);
511 RaiseException(prev_rec
->ExceptionCode
, prev_rec
->ExceptionFlags
,
512 prev_rec
->NumberParameters
, prev_rec
->ExceptionInformation
);
517 __FINALLY_CTX(cxx_catch_cleanup
, &ctx
)
519 FlsSetValue(fls_index
, (void*)-2);
520 if (rec
->ExceptionInformation
[8]) return (void*)rec
->ExceptionInformation
[8];
524 static inline BOOL
cxx_is_consolidate(const EXCEPTION_RECORD
*rec
)
526 return rec
->ExceptionCode
==STATUS_UNWIND_CONSOLIDATE
&& rec
->NumberParameters
==9 &&
527 rec
->ExceptionInformation
[0]==(ULONG_PTR
)call_catch_block4
;
530 static inline void find_catch_block4(EXCEPTION_RECORD
*rec
, CONTEXT
*context
,
531 EXCEPTION_RECORD
*untrans_rec
, ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
532 const cxx_function_descr
*descr
, cxx_exception_type
*info
,
533 ULONG64 orig_frame
, int trylevel
)
535 ULONG64 exc_base
= (rec
->NumberParameters
== 4 ? rec
->ExceptionInformation
[3] : 0);
536 int *processing_throw
= __processing_throw();
537 EXCEPTION_RECORD catch_record
;
542 (*processing_throw
)++;
546 trylevel
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
547 descr
->ip_count
, dispatch
, dispatch
->ControlPc
);
549 TRACE("current trylevel: %d\n", trylevel
);
551 tryblock_map
= rva_to_ptr(descr
->tryblock_map
, dispatch
->ImageBase
);
552 for (i
=0; i
<descr
->tryblock_count
; i
++)
554 tryblock_info tryblock
;
557 read_tryblock_info(&tryblock_map
, &tryblock
, dispatch
->ImageBase
);
559 if (trylevel
< tryblock
.start_level
) continue;
560 if (trylevel
> tryblock
.end_level
) continue;
562 /* got a try block */
563 catchblock
= rva_to_ptr(tryblock
.catchblock
, dispatch
->ImageBase
);
564 for (j
=0; j
<tryblock
.catchblock_count
; j
++)
568 read_catchblock_info(&catchblock
, &ci
);
572 const cxx_type_info
*type
= find_caught_type(info
, exc_base
,
573 rva_to_ptr(ci
.type_info
, dispatch
->ImageBase
),
577 TRACE("matched type %p in tryblock %d catchblock %d\n", type
, i
, j
);
579 /* copy the exception to its destination on the stack */
580 copy_exception((void*)rec
->ExceptionInformation
[1],
581 orig_frame
, dispatch
, &ci
, type
, exc_base
);
585 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
588 TRACE("found catch(...) block\n");
591 /* unwind stack and call catch */
592 memset(&catch_record
, 0, sizeof(catch_record
));
593 catch_record
.ExceptionCode
= STATUS_UNWIND_CONSOLIDATE
;
594 catch_record
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
595 catch_record
.NumberParameters
= 9;
596 catch_record
.ExceptionInformation
[0] = (ULONG_PTR
)call_catch_block4
;
597 catch_record
.ExceptionInformation
[1] = orig_frame
;
598 catch_record
.ExceptionInformation
[2] = tryblock
.catch_level
;
599 catch_record
.ExceptionInformation
[3] = tryblock
.start_level
;
600 catch_record
.ExceptionInformation
[4] = (ULONG_PTR
)rec
;
601 catch_record
.ExceptionInformation
[5] =
602 (ULONG_PTR
)rva_to_ptr(ci
.handler
, dispatch
->ImageBase
);
603 catch_record
.ExceptionInformation
[6] = (ULONG_PTR
)untrans_rec
;
604 catch_record
.ExceptionInformation
[7] = (ULONG_PTR
)context
;
605 catch_record
.ExceptionInformation
[8] = (ULONG_PTR
)rva_to_ptr(
606 ci
.ret_addr
+ dispatch
->FunctionEntry
->BeginAddress
, dispatch
->ImageBase
);
607 RtlUnwindEx((void*)frame
, (void*)dispatch
->ControlPc
, &catch_record
, NULL
, &ctx
, NULL
);
611 TRACE("no matching catch block found\n");
612 (*processing_throw
)--;
615 static LONG CALLBACK
se_translation_filter(EXCEPTION_POINTERS
*ep
, void *c
)
617 se_translator_ctx
*ctx
= (se_translator_ctx
*)c
;
618 EXCEPTION_RECORD
*rec
= ep
->ExceptionRecord
;
619 cxx_exception_type
*exc_type
;
621 if (rec
->ExceptionCode
!= CXX_EXCEPTION
)
623 TRACE("non-c++ exception thrown in SEH handler: %x\n", rec
->ExceptionCode
);
627 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
628 find_catch_block4(rec
, ep
->ContextRecord
, ctx
->seh_rec
, ctx
->dest_frame
, ctx
->dispatch
,
629 ctx
->descr
, exc_type
, ctx
->orig_frame
, ctx
->trylevel
);
631 __DestructExceptionObject(rec
);
632 return ExceptionContinueSearch
;
635 /* Hacky way to obtain se_translator */
636 static inline _se_translator_function
get_se_translator(void)
638 return __current_exception()[-2];
641 static DWORD
cxx_frame_handler4(EXCEPTION_RECORD
*rec
, ULONG64 frame
,
642 CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
,
643 const cxx_function_descr
*descr
, int trylevel
)
645 cxx_exception_type
*exc_type
;
646 ULONG64 orig_frame
= frame
;
648 if (descr
->header
& FUNC_DESCR_IS_CATCH
)
650 TRACE("nested exception detected\n");
651 orig_frame
= *(ULONG64
*)rva_to_ptr(descr
->frame
, frame
);
652 TRACE("setting orig_frame to %lx\n", orig_frame
);
655 if (rec
->ExceptionFlags
& (EH_UNWINDING
|EH_EXIT_UNWIND
))
658 if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && cxx_is_consolidate(rec
))
659 last_level
= rec
->ExceptionInformation
[3];
660 else if ((rec
->ExceptionFlags
& EH_TARGET_UNWIND
) && rec
->ExceptionCode
== STATUS_LONGJUMP
)
661 last_level
= ip_to_state4(rva_to_ptr(descr
->ip_map
, dispatch
->ImageBase
),
662 descr
->ip_count
, dispatch
, dispatch
->TargetIp
);
664 cxx_local_unwind4(orig_frame
, dispatch
, descr
, trylevel
, last_level
);
665 return ExceptionContinueSearch
;
667 if (!descr
->tryblock_map
) return ExceptionContinueSearch
;
669 if (rec
->ExceptionCode
== CXX_EXCEPTION
)
671 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
675 TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec
, frame
, descr
);
676 dump_exception_type(exc_type
, rec
->ExceptionInformation
[3]);
681 _se_translator_function se_translator
= get_se_translator();
684 TRACE("handling C exception code %x rec %p frame %lx descr %p\n",
685 rec
->ExceptionCode
, rec
, frame
, descr
);
688 EXCEPTION_POINTERS except_ptrs
;
689 se_translator_ctx ctx
;
691 ctx
.dest_frame
= frame
;
692 ctx
.orig_frame
= orig_frame
;
694 ctx
.dispatch
= dispatch
;
696 ctx
.trylevel
= trylevel
;
699 except_ptrs
.ExceptionRecord
= rec
;
700 except_ptrs
.ContextRecord
= context
;
701 se_translator(rec
->ExceptionCode
, &except_ptrs
);
703 __EXCEPT_CTX(se_translation_filter
, &ctx
)
710 find_catch_block4(rec
, context
, NULL
, frame
, dispatch
, descr
, exc_type
, orig_frame
, trylevel
);
711 return ExceptionContinueSearch
;
714 EXCEPTION_DISPOSITION __cdecl
__CxxFrameHandler4(EXCEPTION_RECORD
*rec
,
715 ULONG64 frame
, CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
)
717 cxx_function_descr descr
;
718 BYTE
*p
, *count
, *count_end
;
721 TRACE("%p %lx %p %p\n", rec
, frame
, context
, dispatch
);
723 trylevel
= (DWORD_PTR
)FlsGetValue(fls_index
);
724 FlsSetValue(fls_index
, (void*)-2);
726 memset(&descr
, 0, sizeof(descr
));
727 p
= rva_to_ptr(*(UINT
*)dispatch
->HandlerData
, dispatch
->ImageBase
);
730 if ((descr
.header
& FUNC_DESCR_EHS
) &&
731 rec
->ExceptionCode
!= CXX_EXCEPTION
&&
732 !cxx_is_consolidate(rec
) &&
733 rec
->ExceptionCode
!= STATUS_LONGJUMP
)
734 return ExceptionContinueSearch
; /* handle only c++ exceptions */
736 if (descr
.header
& ~(FUNC_DESCR_IS_CATCH
| FUNC_DESCR_UNWIND_MAP
|
737 FUNC_DESCR_TRYBLOCK_MAP
| FUNC_DESCR_EHS
))
739 FIXME("unsupported flags: %x\n", descr
.header
);
740 return ExceptionContinueSearch
;
743 if (descr
.header
& FUNC_DESCR_BBT
) descr
.bbt_flags
= decode_uint(&p
);
744 if (descr
.header
& FUNC_DESCR_UNWIND_MAP
)
746 descr
.unwind_map
= read_rva(&p
);
747 count_end
= count
= rva_to_ptr(descr
.unwind_map
, dispatch
->ImageBase
);
748 descr
.unwind_count
= decode_uint(&count_end
);
749 descr
.unwind_map
+= count_end
- count
;
751 if (descr
.header
& FUNC_DESCR_TRYBLOCK_MAP
)
753 descr
.tryblock_map
= read_rva(&p
);
754 count_end
= count
= rva_to_ptr(descr
.tryblock_map
, dispatch
->ImageBase
);
755 descr
.tryblock_count
= decode_uint(&count_end
);
756 descr
.tryblock_map
+= count_end
- count
;
758 descr
.ip_map
= read_rva(&p
);
759 count_end
= count
= rva_to_ptr(descr
.ip_map
, dispatch
->ImageBase
);
760 descr
.ip_count
= decode_uint(&count_end
);
761 descr
.ip_map
+= count_end
- count
;
762 if (descr
.header
& FUNC_DESCR_IS_CATCH
) descr
.frame
= decode_uint(&p
);
764 if (!validate_cxx_function_descr4(&descr
, dispatch
))
765 return ExceptionContinueSearch
;
767 return cxx_frame_handler4(rec
, frame
, context
, dispatch
, &descr
, trylevel
);
770 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
774 case DLL_PROCESS_ATTACH
:
775 fls_index
= FlsAlloc(NULL
);
776 if (fls_index
== FLS_OUT_OF_INDEXES
)
779 case DLL_THREAD_ATTACH
:
780 FlsSetValue(fls_index
, (void*)-2);
782 case DLL_PROCESS_DETACH
: