wined3d: Use the bo binding in wined3d_context_gl_map_bo_address().
[wine.git] / dlls / vcruntime140_1 / except_x86_64.c
blob5d07a1ac2cba3ae715784d8a54a29d04f9f378f4
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 flags;
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 typedef struct
82 UINT start_level;
83 UINT end_level;
84 UINT catch_level;
85 UINT catchblock_count;
86 UINT catchblock;
87 } tryblock_info;
89 typedef struct
91 UINT ip_off; /* relative to start of function or earlier ipmap_info */
92 INT state;
93 } ipmap_info;
95 typedef struct
97 cxx_frame_info frame_info;
98 BOOL rethrow;
99 INT search_state;
100 INT unwind_state;
101 } cxx_catch_ctx;
103 typedef struct
105 ULONG64 dest_frame;
106 ULONG64 orig_frame;
107 EXCEPTION_RECORD *seh_rec;
108 DISPATCHER_CONTEXT *dispatch;
109 const cxx_function_descr *descr;
110 int trylevel;
111 } se_translator_ctx;
113 static UINT decode_uint(BYTE **b)
115 UINT ret;
117 if ((**b & 1) == 0)
119 ret = *b[0] >> 1;
120 *b += 1;
122 else if ((**b & 3) == 1)
124 ret = (*b[0] >> 2) + (*b[1] << 6);
125 *b += 2;
127 else if ((**b & 7) == 3)
129 ret = (*b[0] >> 3) + (*b[1] << 5) + (*b[2] << 13);
130 *b += 3;
132 else if ((**b & 15) == 7)
134 ret = (*b[0] >> 4) + (*b[1] << 4) + (*b[2] << 12) + (*b[3] << 20);
135 *b += 4;
137 else
139 FIXME("not implemented - expect crash\n");
140 ret = 0;
141 *b += 5;
144 return ret;
147 static UINT read_rva(BYTE **b)
149 UINT ret = *(UINT*)(*b);
150 *b += sizeof(UINT);
151 return ret;
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)
161 BYTE *p = *b;
163 memset(ui, 0, sizeof(*ui));
164 ui->flags = decode_uint(b);
165 ui->prev = p - (ui->flags >> 2);
166 ui->flags &= 0x3;
168 if (ui->flags & 0x1)
170 ui->handler = read_rva(b);
171 ui->object = decode_uint(b); /* frame offset */
174 if (ui->flags & 0x2)
176 FIXME("unknown flag: %x\n", ui->flags);
177 return FALSE;
179 return TRUE;
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);
192 if (count)
194 ti->catchblock_count = decode_uint(&count_end);
195 ti->catchblock += count_end - count;
197 else
199 ti->catchblock_count = 0;
203 static BOOL read_catchblock_info(BYTE **b, catchblock_info *ci)
205 memset(ci, 0, sizeof(*ci));
206 ci->header = **b;
207 (*b)++;
208 if (ci->header & ~(CATCHBLOCK_FLAGS | CATCHBLOCK_TYPE_INFO | CATCHBLOCK_OFFSET | CATCHBLOCK_RET_ADDR))
210 FIXME("unknown header: %x\n", ci->header);
211 return FALSE;
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);
218 return TRUE;
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);
240 UINT i;
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++)
248 TRACE(" %d: ", 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);
259 UINT i, j;
260 char *ip;
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;
269 unwind_info ui;
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++)
281 tryblock_info ti;
282 BYTE *catchblock;
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++)
291 catchblock_info ci;
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++)
305 ipmap_info ii;
307 read_ipmap_info(&ip_map, &ii);
308 ip += ii.ip_off;
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);
313 return TRUE;
316 static inline int ip_to_state4(BYTE *ip_map, UINT count, DISPATCHER_CONTEXT *dispatch, ULONG64 ip)
318 ULONG64 state_ip;
319 ipmap_info ii;
320 int ret = -1;
321 UINT i;
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;
329 ret = ii.state;
332 TRACE("state %d\n", ret);
333 return 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);
340 UINT i;
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 */
348 if (catch_ti != ti)
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 */
359 return NULL;
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 */
383 if (type->copy_ctor)
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);
391 else
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));
398 else
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;
408 unwind_info ui;
409 void *obj;
410 int i;
412 if (trylevel == -2)
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);
423 terminate();
426 unwind_data = rva_to_ptr(descr->unwind_map, dispatch->ImageBase);
427 last = unwind_data;
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;
440 if (ui.handler)
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);
445 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])
462 ctx->rethrow = TRUE;
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 };
482 cxx_catch_ctx ctx;
483 void *ret_addr = NULL;
485 TRACE("calling handler %p\n", handler);
487 ctx.rethrow = FALSE;
488 __CxxRegisterExceptionObject(&ep, &ctx.frame_info);
489 ctx.search_state = rec->ExceptionInformation[2];
490 ctx.unwind_state = rec->ExceptionInformation[3];
491 (*__processing_throw())--;
492 __TRY
494 __TRY
496 ret_addr = handler(0, frame);
498 __EXCEPT_CTX(cxx_rethrow_filter, &ctx)
500 TRACE("detect rethrow: exception code: %x\n", prev_rec->ExceptionCode);
501 ctx.rethrow = TRUE;
503 if (untrans_rec)
505 __DestructExceptionObject(prev_rec);
506 RaiseException(untrans_rec->ExceptionCode, untrans_rec->ExceptionFlags,
507 untrans_rec->NumberParameters, untrans_rec->ExceptionInformation);
509 else
511 RaiseException(prev_rec->ExceptionCode, prev_rec->ExceptionFlags,
512 prev_rec->NumberParameters, prev_rec->ExceptionInformation);
515 __ENDTRY
517 __FINALLY_CTX(cxx_catch_cleanup, &ctx)
519 FlsSetValue(fls_index, (void*)-2);
520 if (rec->ExceptionInformation[8]) return (void*)rec->ExceptionInformation[8];
521 return ret_addr;
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;
538 BYTE *tryblock_map;
539 CONTEXT ctx;
540 UINT i, j;
542 (*processing_throw)++;
544 if (trylevel == -2)
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;
555 BYTE *catchblock;
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++)
566 catchblock_info ci;
568 read_catchblock_info(&catchblock, &ci);
570 if (info)
572 const cxx_type_info *type = find_caught_type(info, exc_base,
573 rva_to_ptr(ci.type_info, dispatch->ImageBase),
574 ci.flags);
575 if (!type) continue;
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);
583 else
585 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
586 if (ci.type_info)
587 continue;
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);
624 terminate();
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))
657 int last_level = -1;
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];
673 if (TRACE_ON(seh))
675 TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec, frame, descr);
676 dump_exception_type(exc_type, rec->ExceptionInformation[3]);
679 else
681 _se_translator_function se_translator = get_se_translator();
683 exc_type = NULL;
684 TRACE("handling C exception code %x rec %p frame %lx descr %p\n",
685 rec->ExceptionCode, rec, frame, descr);
687 if (se_translator) {
688 EXCEPTION_POINTERS except_ptrs;
689 se_translator_ctx ctx;
691 ctx.dest_frame = frame;
692 ctx.orig_frame = orig_frame;
693 ctx.seh_rec = rec;
694 ctx.dispatch = dispatch;
695 ctx.descr = descr;
696 ctx.trylevel = trylevel;
697 __TRY
699 except_ptrs.ExceptionRecord = rec;
700 except_ptrs.ContextRecord = context;
701 se_translator(rec->ExceptionCode, &except_ptrs);
703 __EXCEPT_CTX(se_translation_filter, &ctx)
706 __ENDTRY
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;
719 int trylevel;
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);
728 descr.header = *p++;
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)
772 switch (fdwReason)
774 case DLL_PROCESS_ATTACH:
775 fls_index = FlsAlloc(NULL);
776 if (fls_index == FLS_OUT_OF_INDEXES)
777 return FALSE;
778 /* fall through */
779 case DLL_THREAD_ATTACH:
780 FlsSetValue(fls_index, (void*)-2);
781 break;
782 case DLL_PROCESS_DETACH:
783 if (reserved) break;
784 FlsFree(fls_index);
785 break;
787 return TRUE;
790 #endif