makefiles: Explicitly create destination dirs when installing symlinks.
[wine/zf.git] / dlls / vcruntime140_1 / except_x86_64.c
bloba5a760b7b08b0214644b322d33417ac602039166
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 "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;
33 typedef struct
35 BYTE header;
36 UINT bbt_flags;
37 UINT unwind_count;
38 UINT unwind_map;
39 UINT tryblock_count;
40 UINT tryblock_map;
41 UINT ip_count;
42 UINT ip_map;
43 UINT frame;
44 } cxx_function_descr;
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
54 typedef struct
56 UINT type;
57 BYTE *prev;
58 UINT handler;
59 UINT object;
60 } unwind_info;
62 typedef struct
64 BYTE header;
65 UINT flags;
66 UINT type_info;
67 int offset;
68 UINT handler;
69 UINT ret_addr;
70 } catchblock_info;
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
80 #define UNWIND_TYPE_NO_HANDLER 0
81 #define UNWIND_TYPE_DTOR_OBJ 1
82 #define UNWIND_TYPE_DTOR_PTR 2
83 #define UNWIND_TYPE_FRAME 3
85 typedef struct
87 UINT start_level;
88 UINT end_level;
89 UINT catch_level;
90 UINT catchblock_count;
91 UINT catchblock;
92 } tryblock_info;
94 typedef struct
96 UINT ip_off; /* relative to start of function or earlier ipmap_info */
97 INT state;
98 } ipmap_info;
100 typedef struct
102 cxx_frame_info frame_info;
103 BOOL rethrow;
104 INT search_state;
105 INT unwind_state;
106 EXCEPTION_RECORD *prev_rec;
107 } cxx_catch_ctx;
109 typedef struct
111 ULONG64 dest_frame;
112 ULONG64 orig_frame;
113 EXCEPTION_RECORD *seh_rec;
114 DISPATCHER_CONTEXT *dispatch;
115 const cxx_function_descr *descr;
116 int trylevel;
117 } se_translator_ctx;
119 static UINT decode_uint(BYTE **b)
121 UINT ret;
122 BYTE *p = *b;
124 if ((*p & 1) == 0)
126 ret = p[0] >> 1;
127 p += 1;
129 else if ((*p & 3) == 1)
131 ret = (p[0] >> 2) + (p[1] << 6);
132 p += 2;
134 else if ((*p & 7) == 3)
136 ret = (p[0] >> 3) + (p[1] << 5) + (p[2] << 13);
137 p += 3;
139 else if ((*p & 15) == 7)
141 ret = (p[0] >> 4) + (p[1] << 4) + (p[2] << 12) + (p[3] << 20);
142 p += 4;
144 else
146 FIXME("not implemented - expect crash\n");
147 ret = 0;
148 p += 5;
151 *b = p;
152 return ret;
155 static UINT read_rva(BYTE **b)
157 UINT ret = *(UINT*)(*b);
158 *b += sizeof(UINT);
159 return ret;
162 static inline void* rva_to_ptr(UINT rva, ULONG64 base)
164 return rva ? (void*)(base+rva) : NULL;
167 static void read_unwind_info(BYTE **b, unwind_info *ui)
169 BYTE *p = *b;
171 memset(ui, 0, sizeof(*ui));
172 ui->type = decode_uint(b);
173 ui->prev = p - (ui->type >> 2);
174 ui->type &= 0x3;
176 switch (ui->type)
178 case UNWIND_TYPE_NO_HANDLER:
179 break;
180 case UNWIND_TYPE_DTOR_OBJ:
181 ui->handler = read_rva(b);
182 ui->object = decode_uint(b); /* frame offset to object */
183 break;
184 case UNWIND_TYPE_DTOR_PTR:
185 ui->handler = read_rva(b);
186 ui->object = decode_uint(b); /* frame offset to pointer to object */
187 break;
188 case UNWIND_TYPE_FRAME:
189 ui->handler = read_rva(b);
190 break;
194 static void read_tryblock_info(BYTE **b, tryblock_info *ti, ULONG64 image_base)
196 BYTE *count, *count_end;
198 ti->start_level = decode_uint(b);
199 ti->end_level = decode_uint(b);
200 ti->catch_level = decode_uint(b);
201 ti->catchblock = read_rva(b);
203 count = count_end = rva_to_ptr(ti->catchblock, image_base);
204 if (count)
206 ti->catchblock_count = decode_uint(&count_end);
207 ti->catchblock += count_end - count;
209 else
211 ti->catchblock_count = 0;
215 static BOOL read_catchblock_info(BYTE **b, catchblock_info *ci)
217 memset(ci, 0, sizeof(*ci));
218 ci->header = **b;
219 (*b)++;
220 if (ci->header & ~(CATCHBLOCK_FLAGS | CATCHBLOCK_TYPE_INFO | CATCHBLOCK_OFFSET | CATCHBLOCK_RET_ADDR))
222 FIXME("unknown header: %x\n", ci->header);
223 return FALSE;
225 if (ci->header & CATCHBLOCK_FLAGS) ci->flags = decode_uint(b);
226 if (ci->header & CATCHBLOCK_TYPE_INFO) ci->type_info = read_rva(b);
227 if (ci->header & CATCHBLOCK_OFFSET) ci->offset = decode_uint(b);
228 ci->handler = read_rva(b);
229 if (ci->header & CATCHBLOCK_RET_ADDR) ci->ret_addr = decode_uint(b);
230 return TRUE;
233 static void read_ipmap_info(BYTE **b, ipmap_info *ii)
235 ii->ip_off = decode_uint(b);
236 ii->state = (INT)decode_uint(b) - 1;
239 static inline void dump_type(UINT type_rva, ULONG64 base)
241 const cxx_type_info *type = rva_to_ptr(type_rva, base);
243 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n",
244 type->flags, type->type_info, dbgstr_type_info(rva_to_ptr(type->type_info, base)),
245 type->offsets.this_offset, type->offsets.vbase_descr, type->offsets.vbase_offset,
246 type->size, type->copy_ctor, rva_to_ptr(type->copy_ctor, base));
249 static void dump_exception_type(const cxx_exception_type *type, ULONG64 base)
251 const cxx_type_info_table *type_info_table = rva_to_ptr(type->type_info_table, base);
252 UINT i;
254 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
255 type->flags, type->destructor, rva_to_ptr(type->destructor, base),
256 type->custom_handler, rva_to_ptr(type->custom_handler, base),
257 type->type_info_table, type_info_table);
258 for (i = 0; i < type_info_table->count; i++)
260 TRACE(" %d: ", i);
261 dump_type(type_info_table->info[i], base);
265 static BOOL validate_cxx_function_descr4(const cxx_function_descr *descr, DISPATCHER_CONTEXT *dispatch)
267 ULONG64 image_base = dispatch->ImageBase;
268 BYTE *unwind_map = rva_to_ptr(descr->unwind_map, image_base);
269 BYTE *tryblock_map = rva_to_ptr(descr->tryblock_map, image_base);
270 BYTE *ip_map = rva_to_ptr(descr->ip_map, image_base);
271 UINT i, j;
272 char *ip;
274 TRACE("header 0x%x\n", descr->header);
275 TRACE("basic block transformations flags: 0x%x\n", descr->bbt_flags);
277 TRACE("unwind table: 0x%x(%p) %d\n", descr->unwind_map, unwind_map, descr->unwind_count);
278 for (i = 0; i < descr->unwind_count; i++)
280 BYTE *entry = unwind_map;
281 unwind_info ui;
283 read_unwind_info(&unwind_map, &ui);
284 if (ui.prev < (BYTE*)rva_to_ptr(descr->unwind_map, image_base)) ui.prev = NULL;
285 TRACE(" %d (%p): type 0x%x prev %p func 0x%x(%p) object 0x%x\n",
286 i, entry, ui.type, ui.prev, ui.handler,
287 rva_to_ptr(ui.handler, image_base), ui.object);
290 TRACE("try table: 0x%x(%p) %d\n", descr->tryblock_map, tryblock_map, descr->tryblock_count);
291 for (i = 0; i < descr->tryblock_count; i++)
293 tryblock_info ti;
294 BYTE *catchblock;
296 read_tryblock_info(&tryblock_map, &ti, image_base);
297 catchblock = rva_to_ptr(ti.catchblock, image_base);
298 TRACE(" %d: start %d end %d catchlevel %d catch 0x%x(%p) %d\n",
299 i, ti.start_level, ti.end_level, ti.catch_level,
300 ti.catchblock, catchblock, ti.catchblock_count);
301 for (j = 0; j < ti.catchblock_count; j++)
303 catchblock_info ci;
304 if (!read_catchblock_info(&catchblock, &ci)) return FALSE;
305 TRACE(" %d: header 0x%x offset %d handler 0x%x(%p) "
306 "ret addr %x type %x %s\n", j, ci.header, ci.offset,
307 ci.handler, rva_to_ptr(ci.handler, image_base),
308 ci.ret_addr, ci.type_info,
309 dbgstr_type_info(rva_to_ptr(ci.type_info, image_base)));
313 TRACE("ipmap: 0x%x(%p) %d\n", descr->ip_map, ip_map, descr->ip_count);
314 ip = rva_to_ptr(dispatch->FunctionEntry->BeginAddress, image_base);
315 for (i = 0; i < descr->ip_count; i++)
317 ipmap_info ii;
319 read_ipmap_info(&ip_map, &ii);
320 ip += ii.ip_off;
321 TRACE(" %d: ip offset 0x%x (%p) state %d\n", i, ii.ip_off, ip, ii.state);
324 TRACE("establisher frame: %x\n", descr->frame);
325 return TRUE;
328 static inline int ip_to_state4(BYTE *ip_map, UINT count, DISPATCHER_CONTEXT *dispatch, ULONG64 ip)
330 ULONG64 state_ip;
331 ipmap_info ii;
332 int ret = -1;
333 UINT i;
335 state_ip = dispatch->ImageBase + dispatch->FunctionEntry->BeginAddress;
336 for (i = 0; i < count; i++)
338 read_ipmap_info(&ip_map, &ii);
339 state_ip += ii.ip_off;
340 if (ip < state_ip) break;
341 ret = ii.state;
344 TRACE("state %d\n", ret);
345 return ret;
348 static const cxx_type_info *find_caught_type(cxx_exception_type *exc_type, ULONG64 exc_base,
349 const type_info *catch_ti, UINT catch_flags)
351 const cxx_type_info_table *type_info_table = rva_to_ptr(exc_type->type_info_table, exc_base);
352 UINT i;
354 for (i = 0; i < type_info_table->count; i++)
356 const cxx_type_info *type = rva_to_ptr(type_info_table->info[i], exc_base);
357 const type_info *ti = rva_to_ptr(type->type_info, exc_base);
359 if (!catch_ti) return type; /* catch(...) matches any type */
360 if (catch_ti != ti)
362 if (strcmp( catch_ti->mangled, ti->mangled )) continue;
364 /* type is the same, now check the flags */
365 if ((exc_type->flags & TYPE_FLAG_CONST) &&
366 !(catch_flags & TYPE_FLAG_CONST)) continue;
367 if ((exc_type->flags & TYPE_FLAG_VOLATILE) &&
368 !(catch_flags & TYPE_FLAG_VOLATILE)) continue;
369 return type; /* it matched */
371 return NULL;
374 static inline void copy_exception(void *object, ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
375 const catchblock_info *catchblock, const cxx_type_info *type, ULONG64 exc_base)
377 const type_info *catch_ti = rva_to_ptr(catchblock->type_info, dispatch->ImageBase);
378 void **dest = rva_to_ptr(catchblock->offset, frame);
380 if (!catch_ti || !catch_ti->mangled[0]) return;
381 if (!catchblock->offset) return;
383 if (catchblock->flags & TYPE_FLAG_REFERENCE)
385 *dest = get_this_pointer(&type->offsets, object);
387 else if (type->flags & CLASS_IS_SIMPLE_TYPE)
389 memmove(dest, object, type->size);
390 /* if it is a pointer, adjust it */
391 if (type->size == sizeof(void*)) *dest = get_this_pointer(&type->offsets, *dest);
393 else /* copy the object */
395 if (type->copy_ctor)
397 if (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS)
399 void (__cdecl *copy_ctor)(void*, void*, int) =
400 rva_to_ptr(type->copy_ctor, exc_base);
401 copy_ctor(dest, get_this_pointer(&type->offsets, object), 1);
403 else
405 void (__cdecl *copy_ctor)(void*, void*) =
406 rva_to_ptr(type->copy_ctor, exc_base);
407 copy_ctor(dest, get_this_pointer(&type->offsets, object));
410 else
411 memmove(dest, get_this_pointer(&type->offsets,object), type->size);
415 static void cxx_local_unwind4(ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
416 const cxx_function_descr *descr, int trylevel, int last_level)
418 void (__cdecl *handler_dtor)(void *obj, ULONG64 frame);
419 BYTE *unwind_data, *last;
420 unwind_info ui;
421 void *obj;
422 int i;
424 if (trylevel == -2)
426 trylevel = ip_to_state4(rva_to_ptr(descr->ip_map, dispatch->ImageBase),
427 descr->ip_count, dispatch, dispatch->ControlPc);
430 TRACE("current level: %d, last level: %d\n", trylevel, last_level);
432 if (trylevel<-1 || trylevel>=(int)descr->unwind_count)
434 ERR("invalid trylevel %d\n", trylevel);
435 terminate();
438 if (trylevel <= last_level) return;
440 unwind_data = rva_to_ptr(descr->unwind_map, dispatch->ImageBase);
441 last = unwind_data - 1;
442 for (i = 0; i < trylevel; i++)
444 BYTE *addr = unwind_data;
445 read_unwind_info(&unwind_data, &ui);
446 if (i == last_level) last = addr;
449 while (unwind_data > last)
451 read_unwind_info(&unwind_data, &ui);
452 unwind_data = ui.prev;
454 if (ui.handler)
456 handler_dtor = rva_to_ptr(ui.handler, dispatch->ImageBase);
457 obj = rva_to_ptr(ui.object, frame);
458 if(ui.type == UNWIND_TYPE_DTOR_PTR)
459 obj = *(void**)obj;
460 TRACE("handler: %p object: %p\n", handler_dtor, obj);
461 handler_dtor(obj, frame);
466 static LONG CALLBACK cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs, void *c)
468 EXCEPTION_RECORD *rec = eptrs->ExceptionRecord;
469 cxx_catch_ctx *ctx = c;
471 if (rec->ExceptionCode == CXX_EXCEPTION && !rec->ExceptionInformation[1] && !rec->ExceptionInformation[2])
472 return EXCEPTION_EXECUTE_HANDLER;
474 FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx->search_state);
475 if (rec->ExceptionCode != CXX_EXCEPTION)
476 return EXCEPTION_CONTINUE_SEARCH;
477 if (rec->ExceptionInformation[1] == ctx->prev_rec->ExceptionInformation[1])
478 ctx->rethrow = TRUE;
479 return EXCEPTION_CONTINUE_SEARCH;
482 static void CALLBACK cxx_catch_cleanup(BOOL normal, void *c)
484 cxx_catch_ctx *ctx = c;
485 __CxxUnregisterExceptionObject(&ctx->frame_info, ctx->rethrow);
487 FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx->unwind_state);
490 static void* WINAPI call_catch_block4(EXCEPTION_RECORD *rec)
492 ULONG64 frame = rec->ExceptionInformation[1];
493 EXCEPTION_RECORD *prev_rec = (void*)rec->ExceptionInformation[4];
494 EXCEPTION_RECORD *untrans_rec = (void*)rec->ExceptionInformation[6];
495 CONTEXT *context = (void*)rec->ExceptionInformation[7];
496 void* (__cdecl *handler)(ULONG64 unk, ULONG64 rbp) = (void*)rec->ExceptionInformation[5];
497 EXCEPTION_POINTERS ep = { prev_rec, context };
498 cxx_catch_ctx ctx;
499 void *ret_addr = NULL;
501 TRACE("calling handler %p\n", handler);
503 ctx.rethrow = FALSE;
504 __CxxRegisterExceptionObject(&ep, &ctx.frame_info);
505 ctx.search_state = rec->ExceptionInformation[2];
506 ctx.unwind_state = rec->ExceptionInformation[3];
507 ctx.prev_rec = prev_rec;
508 (*__processing_throw())--;
509 __TRY
511 __TRY
513 ret_addr = handler(0, frame);
515 __EXCEPT_CTX(cxx_rethrow_filter, &ctx)
517 TRACE("detect rethrow: exception code: %x\n", prev_rec->ExceptionCode);
518 ctx.rethrow = TRUE;
519 FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx.search_state);
521 if (untrans_rec)
523 __DestructExceptionObject(prev_rec);
524 RaiseException(untrans_rec->ExceptionCode, untrans_rec->ExceptionFlags,
525 untrans_rec->NumberParameters, untrans_rec->ExceptionInformation);
527 else
529 RaiseException(prev_rec->ExceptionCode, prev_rec->ExceptionFlags,
530 prev_rec->NumberParameters, prev_rec->ExceptionInformation);
533 __ENDTRY
535 __FINALLY_CTX(cxx_catch_cleanup, &ctx)
537 FlsSetValue(fls_index, (void*)-2);
538 if (rec->ExceptionInformation[8]) return (void*)rec->ExceptionInformation[8];
539 return ret_addr;
542 static inline BOOL cxx_is_consolidate(const EXCEPTION_RECORD *rec)
544 return rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==9 &&
545 rec->ExceptionInformation[0]==(ULONG_PTR)call_catch_block4;
548 static inline void find_catch_block4(EXCEPTION_RECORD *rec, CONTEXT *context,
549 EXCEPTION_RECORD *untrans_rec, ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
550 const cxx_function_descr *descr, cxx_exception_type *info,
551 ULONG64 orig_frame, int trylevel)
553 ULONG64 exc_base = (rec->NumberParameters == 4 ? rec->ExceptionInformation[3] : 0);
554 int *processing_throw = __processing_throw();
555 EXCEPTION_RECORD catch_record;
556 BYTE *tryblock_map;
557 CONTEXT ctx;
558 UINT i, j;
560 (*processing_throw)++;
562 if (trylevel == -2)
564 trylevel = ip_to_state4(rva_to_ptr(descr->ip_map, dispatch->ImageBase),
565 descr->ip_count, dispatch, dispatch->ControlPc);
567 TRACE("current trylevel: %d\n", trylevel);
569 tryblock_map = rva_to_ptr(descr->tryblock_map, dispatch->ImageBase);
570 for (i=0; i<descr->tryblock_count; i++)
572 tryblock_info tryblock;
573 BYTE *catchblock;
575 read_tryblock_info(&tryblock_map, &tryblock, dispatch->ImageBase);
577 if (trylevel < tryblock.start_level) continue;
578 if (trylevel > tryblock.end_level) continue;
580 /* got a try block */
581 catchblock = rva_to_ptr(tryblock.catchblock, dispatch->ImageBase);
582 for (j=0; j<tryblock.catchblock_count; j++)
584 catchblock_info ci;
586 read_catchblock_info(&catchblock, &ci);
588 if (info)
590 const cxx_type_info *type = find_caught_type(info, exc_base,
591 rva_to_ptr(ci.type_info, dispatch->ImageBase),
592 ci.flags);
593 if (!type) continue;
595 TRACE("matched type %p in tryblock %d catchblock %d\n", type, i, j);
597 /* copy the exception to its destination on the stack */
598 copy_exception((void*)rec->ExceptionInformation[1],
599 orig_frame, dispatch, &ci, type, exc_base);
601 else
603 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
604 if (ci.type_info)
605 continue;
606 TRACE("found catch(...) block\n");
609 /* unwind stack and call catch */
610 memset(&catch_record, 0, sizeof(catch_record));
611 catch_record.ExceptionCode = STATUS_UNWIND_CONSOLIDATE;
612 catch_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
613 catch_record.NumberParameters = 9;
614 catch_record.ExceptionInformation[0] = (ULONG_PTR)call_catch_block4;
615 catch_record.ExceptionInformation[1] = orig_frame;
616 catch_record.ExceptionInformation[2] = tryblock.catch_level;
617 catch_record.ExceptionInformation[3] = tryblock.start_level;
618 catch_record.ExceptionInformation[4] = (ULONG_PTR)rec;
619 catch_record.ExceptionInformation[5] =
620 (ULONG_PTR)rva_to_ptr(ci.handler, dispatch->ImageBase);
621 catch_record.ExceptionInformation[6] = (ULONG_PTR)untrans_rec;
622 catch_record.ExceptionInformation[7] = (ULONG_PTR)context;
623 if (ci.ret_addr)
624 catch_record.ExceptionInformation[8] = (ULONG_PTR)rva_to_ptr(
625 ci.ret_addr + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase);
626 RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &ctx, NULL);
630 TRACE("no matching catch block found\n");
631 (*processing_throw)--;
634 static LONG CALLBACK se_translation_filter(EXCEPTION_POINTERS *ep, void *c)
636 se_translator_ctx *ctx = (se_translator_ctx *)c;
637 EXCEPTION_RECORD *rec = ep->ExceptionRecord;
638 cxx_exception_type *exc_type;
640 if (rec->ExceptionCode != CXX_EXCEPTION)
642 TRACE("non-c++ exception thrown in SEH handler: %x\n", rec->ExceptionCode);
643 terminate();
646 exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
647 find_catch_block4(rec, ep->ContextRecord, ctx->seh_rec, ctx->dest_frame, ctx->dispatch,
648 ctx->descr, exc_type, ctx->orig_frame, ctx->trylevel);
650 __DestructExceptionObject(rec);
651 return ExceptionContinueSearch;
654 /* Hacky way to obtain se_translator */
655 static inline _se_translator_function get_se_translator(void)
657 return __current_exception()[-2];
660 static void check_noexcept( PEXCEPTION_RECORD rec, const cxx_function_descr *descr )
662 if (!(descr->header & FUNC_DESCR_IS_CATCH) &&
663 rec->ExceptionCode == CXX_EXCEPTION &&
664 (descr->header & FUNC_DESCR_NO_EXCEPT))
666 ERR("noexcept function propagating exception\n");
667 terminate();
671 static DWORD cxx_frame_handler4(EXCEPTION_RECORD *rec, ULONG64 frame,
672 CONTEXT *context, DISPATCHER_CONTEXT *dispatch,
673 const cxx_function_descr *descr, int trylevel)
675 cxx_exception_type *exc_type;
676 ULONG64 orig_frame = frame;
678 if (descr->header & FUNC_DESCR_IS_CATCH)
680 TRACE("nested exception detected\n");
681 orig_frame = *(ULONG64*)rva_to_ptr(descr->frame, frame);
682 TRACE("setting orig_frame to %lx\n", orig_frame);
685 if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND))
687 int last_level = -1;
688 if ((rec->ExceptionFlags & EH_TARGET_UNWIND) && cxx_is_consolidate(rec))
689 last_level = rec->ExceptionInformation[3];
690 else if ((rec->ExceptionFlags & EH_TARGET_UNWIND) && rec->ExceptionCode == STATUS_LONGJUMP)
691 last_level = ip_to_state4(rva_to_ptr(descr->ip_map, dispatch->ImageBase),
692 descr->ip_count, dispatch, dispatch->TargetIp);
694 cxx_local_unwind4(orig_frame, dispatch, descr, trylevel, last_level);
695 return ExceptionContinueSearch;
697 if (!descr->tryblock_map)
699 check_noexcept(rec, descr);
700 return ExceptionContinueSearch;
703 if (rec->ExceptionCode == CXX_EXCEPTION)
705 if (!rec->ExceptionInformation[1] && !rec->ExceptionInformation[2])
707 TRACE("rethrow detected.\n");
708 *rec = *(EXCEPTION_RECORD*)*__current_exception();
711 exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
713 if (TRACE_ON(seh))
715 TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec, frame, descr);
716 dump_exception_type(exc_type, rec->ExceptionInformation[3]);
719 else
721 _se_translator_function se_translator = get_se_translator();
723 exc_type = NULL;
724 TRACE("handling C exception code %x rec %p frame %lx descr %p\n",
725 rec->ExceptionCode, rec, frame, descr);
727 if (se_translator) {
728 EXCEPTION_POINTERS except_ptrs;
729 se_translator_ctx ctx;
731 ctx.dest_frame = frame;
732 ctx.orig_frame = orig_frame;
733 ctx.seh_rec = rec;
734 ctx.dispatch = dispatch;
735 ctx.descr = descr;
736 ctx.trylevel = trylevel;
737 __TRY
739 except_ptrs.ExceptionRecord = rec;
740 except_ptrs.ContextRecord = context;
741 se_translator(rec->ExceptionCode, &except_ptrs);
743 __EXCEPT_CTX(se_translation_filter, &ctx)
746 __ENDTRY
750 find_catch_block4(rec, context, NULL, frame, dispatch, descr, exc_type, orig_frame, trylevel);
751 check_noexcept(rec, descr);
752 return ExceptionContinueSearch;
755 EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler4(EXCEPTION_RECORD *rec,
756 ULONG64 frame, CONTEXT *context, DISPATCHER_CONTEXT *dispatch)
758 cxx_function_descr descr;
759 BYTE *p, *count, *count_end;
760 int trylevel;
762 TRACE("%p %lx %p %p\n", rec, frame, context, dispatch);
764 trylevel = (DWORD_PTR)FlsGetValue(fls_index);
765 FlsSetValue(fls_index, (void*)-2);
767 memset(&descr, 0, sizeof(descr));
768 p = rva_to_ptr(*(UINT*)dispatch->HandlerData, dispatch->ImageBase);
769 descr.header = *p++;
771 if ((descr.header & FUNC_DESCR_EHS) &&
772 rec->ExceptionCode != CXX_EXCEPTION &&
773 !cxx_is_consolidate(rec) &&
774 rec->ExceptionCode != STATUS_LONGJUMP)
775 return ExceptionContinueSearch; /* handle only c++ exceptions */
777 if (descr.header & ~(FUNC_DESCR_IS_CATCH | FUNC_DESCR_UNWIND_MAP |
778 FUNC_DESCR_TRYBLOCK_MAP | FUNC_DESCR_EHS | FUNC_DESCR_NO_EXCEPT))
780 FIXME("unsupported flags: %x\n", descr.header);
781 return ExceptionContinueSearch;
784 if (descr.header & FUNC_DESCR_BBT) descr.bbt_flags = decode_uint(&p);
785 if (descr.header & FUNC_DESCR_UNWIND_MAP)
787 descr.unwind_map = read_rva(&p);
788 count_end = count = rva_to_ptr(descr.unwind_map, dispatch->ImageBase);
789 descr.unwind_count = decode_uint(&count_end);
790 descr.unwind_map += count_end - count;
792 if (descr.header & FUNC_DESCR_TRYBLOCK_MAP)
794 descr.tryblock_map = read_rva(&p);
795 count_end = count = rva_to_ptr(descr.tryblock_map, dispatch->ImageBase);
796 descr.tryblock_count = decode_uint(&count_end);
797 descr.tryblock_map += count_end - count;
799 descr.ip_map = read_rva(&p);
800 count_end = count = rva_to_ptr(descr.ip_map, dispatch->ImageBase);
801 descr.ip_count = decode_uint(&count_end);
802 descr.ip_map += count_end - count;
803 if (descr.header & FUNC_DESCR_IS_CATCH) descr.frame = decode_uint(&p);
805 if (!validate_cxx_function_descr4(&descr, dispatch))
806 return ExceptionContinueSearch;
808 return cxx_frame_handler4(rec, frame, context, dispatch, &descr, trylevel);
811 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
813 switch (fdwReason)
815 case DLL_PROCESS_ATTACH:
816 fls_index = FlsAlloc(NULL);
817 if (fls_index == FLS_OUT_OF_INDEXES)
818 return FALSE;
819 /* fall through */
820 case DLL_THREAD_ATTACH:
821 FlsSetValue(fls_index, (void*)-2);
822 break;
823 case DLL_PROCESS_DETACH:
824 if (reserved) break;
825 FlsFree(fls_index);
826 break;
828 return TRUE;
831 #endif