rpcrt4: Avoid casting an object to IUnknown.
[wine.git] / dlls / vcruntime140_1 / except_x86_64.c
blobec6b06c69d66652a8084ba32c9478b4e85ae2da8
1 /*
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
21 #ifdef __x86_64__
23 #include <stdarg.h>
24 #include <stdlib.h>
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;
36 typedef struct
38 BYTE header;
39 UINT bbt_flags;
40 UINT unwind_count;
41 UINT unwind_map;
42 UINT tryblock_count;
43 UINT tryblock_map;
44 UINT ip_count;
45 UINT ip_map;
46 UINT frame;
47 } cxx_function_descr;
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
57 typedef struct
59 UINT type;
60 BYTE *prev;
61 UINT handler;
62 UINT object;
63 } unwind_info;
65 typedef struct
67 BYTE header;
68 UINT flags;
69 UINT type_info;
70 int offset;
71 UINT handler;
72 UINT ret_addr[2];
73 } catchblock_info;
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
93 typedef struct
95 UINT start_level;
96 UINT end_level;
97 UINT catch_level;
98 UINT catchblock_count;
99 UINT catchblock;
100 } tryblock_info;
102 typedef struct
104 UINT ip_off; /* relative to start of function or earlier ipmap_info */
105 INT state;
106 } ipmap_info;
108 typedef struct
110 cxx_frame_info frame_info;
111 BOOL rethrow;
112 INT search_state;
113 INT unwind_state;
114 EXCEPTION_RECORD *prev_rec;
115 } cxx_catch_ctx;
117 typedef struct
119 ULONG64 dest_frame;
120 ULONG64 orig_frame;
121 EXCEPTION_RECORD *seh_rec;
122 DISPATCHER_CONTEXT *dispatch;
123 const cxx_function_descr *descr;
124 int trylevel;
125 } se_translator_ctx;
127 static UINT decode_uint(BYTE **b)
129 UINT ret;
130 BYTE *p = *b;
132 if ((*p & 1) == 0)
134 ret = p[0] >> 1;
135 p += 1;
137 else if ((*p & 3) == 1)
139 ret = (p[0] >> 2) + (p[1] << 6);
140 p += 2;
142 else if ((*p & 7) == 3)
144 ret = (p[0] >> 3) + (p[1] << 5) + (p[2] << 13);
145 p += 3;
147 else if ((*p & 15) == 7)
149 ret = (p[0] >> 4) + (p[1] << 4) + (p[2] << 12) + (p[3] << 20);
150 p += 4;
152 else
154 FIXME("not implemented - expect crash\n");
155 ret = 0;
156 p += 5;
159 *b = p;
160 return ret;
163 static UINT read_rva(BYTE **b)
165 UINT ret = *(UINT*)(*b);
166 *b += sizeof(UINT);
167 return ret;
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)
177 BYTE *p = *b;
179 memset(ui, 0, sizeof(*ui));
180 ui->type = decode_uint(b);
181 ui->prev = p - (ui->type >> 2);
182 ui->type &= 0x3;
184 switch (ui->type)
186 case UNWIND_TYPE_NO_HANDLER:
187 break;
188 case UNWIND_TYPE_DTOR_OBJ:
189 ui->handler = read_rva(b);
190 ui->object = decode_uint(b); /* frame offset to object */
191 break;
192 case UNWIND_TYPE_DTOR_PTR:
193 ui->handler = read_rva(b);
194 ui->object = decode_uint(b); /* frame offset to pointer to object */
195 break;
196 case UNWIND_TYPE_FRAME:
197 ui->handler = read_rva(b);
198 break;
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);
212 if (count)
214 ti->catchblock_count = decode_uint(&count_end);
215 ti->catchblock += count_end - count;
217 else
219 ti->catchblock_count = 0;
223 static BOOL read_catchblock_info(BYTE **b, catchblock_info *ci, DWORD func_rva)
225 BYTE ret_addr_type;
226 memset(ci, 0, sizeof(*ci));
227 ci->header = **b;
228 (*b)++;
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);
233 return FALSE;
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");
239 return FALSE;
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);
253 else
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;
261 return TRUE;
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);
283 UINT i;
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++)
291 TRACE(" %d: ", 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);
302 UINT i, j;
303 char *ip;
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;
312 unwind_info ui;
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++)
324 tryblock_info ti;
325 BYTE *catchblock;
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++)
334 catchblock_info ci;
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++)
349 ipmap_info ii;
351 read_ipmap_info(&ip_map, &ii);
352 ip += ii.ip_off;
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);
357 return TRUE;
360 static inline int ip_to_state4(BYTE *ip_map, UINT count, DISPATCHER_CONTEXT *dispatch, ULONG64 ip)
362 ULONG64 state_ip;
363 ipmap_info ii;
364 int ret = -1;
365 UINT i;
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;
373 ret = ii.state;
376 TRACE("state %d\n", ret);
377 return 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);
384 UINT i;
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 */
392 if (catch_ti != ti)
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 */
403 return NULL;
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 */
427 if (type->copy_ctor)
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);
435 else
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));
442 else
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;
452 unwind_info ui;
453 void *obj;
454 int i;
456 if (trylevel == -2)
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);
467 terminate();
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;
486 if (ui.handler)
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)
491 obj = *(void**)obj;
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])
510 ctx->rethrow = TRUE;
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 };
530 cxx_catch_ctx ctx;
531 void *ret_addr = NULL;
533 TRACE("calling handler %p\n", handler);
535 ctx.rethrow = FALSE;
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())--;
541 __TRY
543 __TRY
545 ret_addr = handler(0, frame);
547 __EXCEPT_CTX(cxx_rethrow_filter, &ctx)
549 TRACE("detect rethrow: exception code: %lx\n", prev_rec->ExceptionCode);
550 ctx.rethrow = TRUE;
551 FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx.search_state);
553 if (untrans_rec)
555 __DestructExceptionObject(prev_rec);
556 RaiseException(untrans_rec->ExceptionCode, untrans_rec->ExceptionFlags,
557 untrans_rec->NumberParameters, untrans_rec->ExceptionInformation);
559 else
561 RaiseException(prev_rec->ExceptionCode, prev_rec->ExceptionFlags,
562 prev_rec->NumberParameters, prev_rec->ExceptionInformation);
565 __ENDTRY
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);
578 abort();
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;
600 BYTE *tryblock_map;
601 CONTEXT ctx;
602 UINT i, j;
604 (*processing_throw)++;
606 if (trylevel == -2)
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;
617 BYTE *catchblock;
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++)
628 catchblock_info ci;
630 read_catchblock_info(&catchblock, &ci, dispatch->FunctionEntry->BeginAddress);
632 if (info)
634 const cxx_type_info *type = find_caught_type(info, exc_base,
635 rva_to_ptr(ci.type_info, dispatch->ImageBase),
636 ci.flags);
637 if (!type) continue;
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);
645 else
647 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
648 if (ci.type_info)
649 continue;
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;
667 if (ci.ret_addr[0])
669 catch_record.ExceptionInformation[8] = (ULONG_PTR)rva_to_ptr(
670 ci.ret_addr[0], dispatch->ImageBase);
672 if (ci.ret_addr[1])
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);
694 terminate();
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");
718 terminate();
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))
738 int last_level = -1;
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];
764 if (TRACE_ON(seh))
766 TRACE("handling C++ exception rec %p frame %Ix descr %p\n", rec, frame, descr);
767 dump_exception_type(exc_type, rec->ExceptionInformation[3]);
770 else
772 _se_translator_function se_translator = get_se_translator();
774 exc_type = NULL;
775 TRACE("handling C exception code %lx rec %p frame %Ix descr %p\n",
776 rec->ExceptionCode, rec, frame, descr);
778 if (se_translator) {
779 EXCEPTION_POINTERS except_ptrs;
780 se_translator_ctx ctx;
782 ctx.dest_frame = frame;
783 ctx.orig_frame = orig_frame;
784 ctx.seh_rec = rec;
785 ctx.dispatch = dispatch;
786 ctx.descr = descr;
787 ctx.trylevel = trylevel;
788 __TRY
790 except_ptrs.ExceptionRecord = rec;
791 except_ptrs.ContextRecord = context;
792 se_translator(rec->ExceptionCode, &except_ptrs);
794 __EXCEPT_CTX(se_translation_filter, &ctx)
797 __ENDTRY
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;
811 int trylevel;
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);
820 descr.header = *p++;
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)
854 UINT i, num, func;
855 BYTE *map;
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)
864 break;
866 if (i == num)
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)
885 switch (fdwReason)
887 case DLL_PROCESS_ATTACH:
888 fls_index = FlsAlloc(NULL);
889 if (fls_index == FLS_OUT_OF_INDEXES)
890 return FALSE;
891 /* fall through */
892 case DLL_THREAD_ATTACH:
893 FlsSetValue(fls_index, (void*)-2);
894 break;
895 case DLL_PROCESS_DETACH:
896 if (reserved) break;
897 FlsFree(fls_index);
898 break;
900 return TRUE;
903 #endif