mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-16 07:56:37 +00:00
vcruntime140_1: Add __CxxFrameHandler4 implementation.
Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7f4a880fc5
commit
a715a0c4ca
|
@ -46,9 +46,74 @@ typedef struct __cxx_type_info
|
||||||
unsigned int copy_ctor;
|
unsigned int copy_ctor;
|
||||||
} cxx_type_info;
|
} cxx_type_info;
|
||||||
|
|
||||||
|
#define CLASS_IS_SIMPLE_TYPE 1
|
||||||
|
#define CLASS_HAS_VIRTUAL_BASE_CLASS 4
|
||||||
|
|
||||||
|
/* table of C++ types that apply for a given object */
|
||||||
|
typedef struct __cxx_type_info_table
|
||||||
|
{
|
||||||
|
UINT count;
|
||||||
|
unsigned int info[3];
|
||||||
|
} cxx_type_info_table;
|
||||||
|
|
||||||
|
struct __cxx_exception_frame;
|
||||||
|
struct __cxx_function_descr;
|
||||||
|
|
||||||
|
/* type information for an exception object */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UINT flags;
|
||||||
|
unsigned int destructor;
|
||||||
|
unsigned int custom_handler;
|
||||||
|
unsigned int type_info_table;
|
||||||
|
} cxx_exception_type;
|
||||||
|
|
||||||
static inline const char *dbgstr_type_info( const type_info *info )
|
static inline const char *dbgstr_type_info( const type_info *info )
|
||||||
{
|
{
|
||||||
if (!info) return "{}";
|
if (!info) return "{}";
|
||||||
return wine_dbg_sprintf( "{vtable=%p name=%s (%s)}",
|
return wine_dbg_sprintf( "{vtable=%p name=%s (%s)}",
|
||||||
info->vtable, info->mangled, info->name ? info->name : "" );
|
info->vtable, info->mangled, info->name ? info->name : "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* compute the this pointer for a base class of a given type */
|
||||||
|
static inline void *get_this_pointer( const this_ptr_offsets *off, void *object )
|
||||||
|
{
|
||||||
|
if (!object) return NULL;
|
||||||
|
|
||||||
|
if (off->vbase_descr >= 0)
|
||||||
|
{
|
||||||
|
int *offset_ptr;
|
||||||
|
|
||||||
|
/* move this ptr to vbase descriptor */
|
||||||
|
object = (char *)object + off->vbase_descr;
|
||||||
|
/* and fetch additional offset from vbase descriptor */
|
||||||
|
offset_ptr = (int *)(*(char **)object + off->vbase_offset);
|
||||||
|
object = (char *)object + *offset_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
object = (char *)object + off->this_offset;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (__cdecl *_se_translator_function)(unsigned int code, struct _EXCEPTION_POINTERS *info);
|
||||||
|
|
||||||
|
typedef struct _frame_info
|
||||||
|
{
|
||||||
|
void *object;
|
||||||
|
struct _frame_info *next;
|
||||||
|
} frame_info;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
frame_info frame_info;
|
||||||
|
EXCEPTION_RECORD *rec;
|
||||||
|
CONTEXT *context;
|
||||||
|
} cxx_frame_info;
|
||||||
|
|
||||||
|
BOOL __cdecl __CxxRegisterExceptionObject(EXCEPTION_POINTERS*, cxx_frame_info*);
|
||||||
|
void __cdecl __CxxUnregisterExceptionObject(cxx_frame_info*, BOOL);
|
||||||
|
void __cdecl __DestructExceptionObject(EXCEPTION_RECORD *rec);
|
||||||
|
|
||||||
|
void** __cdecl __current_exception(void);
|
||||||
|
int* __cdecl __processing_throw(void);
|
||||||
|
void __cdecl terminate(void);
|
||||||
|
|
|
@ -20,11 +20,16 @@
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
#include "wine/exception.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
#include "cppexcept.h"
|
#include "cppexcept.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||||
|
|
||||||
|
#define CXX_EXCEPTION 0xe06d7363
|
||||||
|
|
||||||
|
static DWORD fls_index;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
BYTE header;
|
BYTE header;
|
||||||
|
@ -87,6 +92,24 @@ typedef struct
|
||||||
INT state;
|
INT state;
|
||||||
} ipmap_info;
|
} ipmap_info;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
cxx_frame_info frame_info;
|
||||||
|
BOOL rethrow;
|
||||||
|
INT search_state;
|
||||||
|
INT unwind_state;
|
||||||
|
} cxx_catch_ctx;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG64 dest_frame;
|
||||||
|
ULONG64 orig_frame;
|
||||||
|
EXCEPTION_RECORD *seh_rec;
|
||||||
|
DISPATCHER_CONTEXT *dispatch;
|
||||||
|
const cxx_function_descr *descr;
|
||||||
|
int trylevel;
|
||||||
|
} se_translator_ctx;
|
||||||
|
|
||||||
static UINT decode_uint(BYTE **b)
|
static UINT decode_uint(BYTE **b)
|
||||||
{
|
{
|
||||||
UINT ret;
|
UINT ret;
|
||||||
|
@ -211,6 +234,22 @@ static inline void dump_type(UINT type_rva, ULONG64 base)
|
||||||
type->size, type->copy_ctor, rva_to_ptr(type->copy_ctor, base));
|
type->size, type->copy_ctor, rva_to_ptr(type->copy_ctor, base));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_exception_type(const cxx_exception_type *type, ULONG64 base)
|
||||||
|
{
|
||||||
|
const cxx_type_info_table *type_info_table = rva_to_ptr(type->type_info_table, base);
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
|
||||||
|
type->flags, type->destructor, rva_to_ptr(type->destructor, base),
|
||||||
|
type->custom_handler, rva_to_ptr(type->custom_handler, base),
|
||||||
|
type->type_info_table, type_info_table);
|
||||||
|
for (i = 0; i < type_info_table->count; i++)
|
||||||
|
{
|
||||||
|
TRACE(" %d: ", i);
|
||||||
|
dump_type(type_info_table->info[i], base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL validate_cxx_function_descr4(const cxx_function_descr *descr, DISPATCHER_CONTEXT *dispatch)
|
static BOOL validate_cxx_function_descr4(const cxx_function_descr *descr, DISPATCHER_CONTEXT *dispatch)
|
||||||
{
|
{
|
||||||
ULONG64 image_base = dispatch->ImageBase;
|
ULONG64 image_base = dispatch->ImageBase;
|
||||||
|
@ -274,18 +313,426 @@ static BOOL validate_cxx_function_descr4(const cxx_function_descr *descr, DISPAT
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int ip_to_state4(BYTE *ip_map, UINT count, DISPATCHER_CONTEXT *dispatch, ULONG64 ip)
|
||||||
|
{
|
||||||
|
ULONG64 state_ip;
|
||||||
|
ipmap_info ii;
|
||||||
|
int ret = -1;
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
state_ip = dispatch->ImageBase + dispatch->FunctionEntry->BeginAddress;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
read_ipmap_info(&ip_map, &ii);
|
||||||
|
state_ip += ii.ip_off;
|
||||||
|
if (ip < state_ip) break;
|
||||||
|
ret = ii.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("state %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const cxx_type_info *find_caught_type(cxx_exception_type *exc_type, ULONG64 exc_base,
|
||||||
|
const type_info *catch_ti, UINT catch_flags)
|
||||||
|
{
|
||||||
|
const cxx_type_info_table *type_info_table = rva_to_ptr(exc_type->type_info_table, exc_base);
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
for (i = 0; i < type_info_table->count; i++)
|
||||||
|
{
|
||||||
|
const cxx_type_info *type = rva_to_ptr(type_info_table->info[i], exc_base);
|
||||||
|
const type_info *ti = rva_to_ptr(type->type_info, exc_base);
|
||||||
|
|
||||||
|
if (!catch_ti) return type; /* catch(...) matches any type */
|
||||||
|
if (catch_ti != ti)
|
||||||
|
{
|
||||||
|
if (strcmp( catch_ti->mangled, ti->mangled )) continue;
|
||||||
|
}
|
||||||
|
/* type is the same, now check the flags */
|
||||||
|
if ((exc_type->flags & TYPE_FLAG_CONST) &&
|
||||||
|
!(catch_flags & TYPE_FLAG_CONST)) continue;
|
||||||
|
if ((exc_type->flags & TYPE_FLAG_VOLATILE) &&
|
||||||
|
!(catch_flags & TYPE_FLAG_VOLATILE)) continue;
|
||||||
|
return type; /* it matched */
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void copy_exception(void *object, ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
|
||||||
|
const catchblock_info *catchblock, const cxx_type_info *type, ULONG64 exc_base)
|
||||||
|
{
|
||||||
|
const type_info *catch_ti = rva_to_ptr(catchblock->type_info, dispatch->ImageBase);
|
||||||
|
void **dest = rva_to_ptr(catchblock->offset, frame);
|
||||||
|
|
||||||
|
if (!catch_ti || !catch_ti->mangled[0]) return;
|
||||||
|
if (!catchblock->offset) return;
|
||||||
|
|
||||||
|
if (catchblock->flags & TYPE_FLAG_REFERENCE)
|
||||||
|
{
|
||||||
|
*dest = get_this_pointer(&type->offsets, object);
|
||||||
|
}
|
||||||
|
else if (type->flags & CLASS_IS_SIMPLE_TYPE)
|
||||||
|
{
|
||||||
|
memmove(dest, object, type->size);
|
||||||
|
/* if it is a pointer, adjust it */
|
||||||
|
if (type->size == sizeof(void*)) *dest = get_this_pointer(&type->offsets, *dest);
|
||||||
|
}
|
||||||
|
else /* copy the object */
|
||||||
|
{
|
||||||
|
if (type->copy_ctor)
|
||||||
|
{
|
||||||
|
if (type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS)
|
||||||
|
{
|
||||||
|
void (__cdecl *copy_ctor)(void*, void*, int) =
|
||||||
|
rva_to_ptr(type->copy_ctor, exc_base);
|
||||||
|
copy_ctor(dest, get_this_pointer(&type->offsets, object), 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
void (__cdecl *copy_ctor)(void*, void*) =
|
||||||
|
rva_to_ptr(type->copy_ctor, exc_base);
|
||||||
|
copy_ctor(dest, get_this_pointer(&type->offsets, object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memmove(dest, get_this_pointer(&type->offsets,object), type->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cxx_local_unwind4(ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
|
||||||
|
const cxx_function_descr *descr, int trylevel, int last_level)
|
||||||
|
{
|
||||||
|
void (__cdecl *handler_dtor)(void *obj);
|
||||||
|
BYTE *unwind_data, *last;
|
||||||
|
unwind_info ui;
|
||||||
|
void *obj;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (trylevel == -2)
|
||||||
|
{
|
||||||
|
trylevel = ip_to_state4(rva_to_ptr(descr->ip_map, dispatch->ImageBase),
|
||||||
|
descr->ip_count, dispatch, dispatch->ControlPc);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("current level: %d, last level: %d\n", trylevel, last_level);
|
||||||
|
|
||||||
|
if (trylevel<0 || trylevel>=descr->unwind_count)
|
||||||
|
{
|
||||||
|
ERR("invalid trylevel %d\n", trylevel);
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
unwind_data = rva_to_ptr(descr->unwind_map, dispatch->ImageBase);
|
||||||
|
last = unwind_data;
|
||||||
|
for (i = 0; i < trylevel; i++)
|
||||||
|
{
|
||||||
|
BYTE *addr = unwind_data;
|
||||||
|
read_unwind_info(&unwind_data, &ui);
|
||||||
|
if (i == last_level) last = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (unwind_data > last)
|
||||||
|
{
|
||||||
|
read_unwind_info(&unwind_data, &ui);
|
||||||
|
unwind_data = ui.prev;
|
||||||
|
|
||||||
|
if (ui.handler)
|
||||||
|
{
|
||||||
|
handler_dtor = rva_to_ptr(ui.handler, dispatch->ImageBase);
|
||||||
|
obj = rva_to_ptr(ui.object, frame);
|
||||||
|
TRACE("handler: %p object: %p\n", handler_dtor, obj);
|
||||||
|
handler_dtor(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LONG CALLBACK cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs, void *c)
|
||||||
|
{
|
||||||
|
EXCEPTION_RECORD *rec = eptrs->ExceptionRecord;
|
||||||
|
cxx_catch_ctx *ctx = c;
|
||||||
|
|
||||||
|
FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx->search_state);
|
||||||
|
|
||||||
|
if (rec->ExceptionCode != CXX_EXCEPTION)
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
if (!rec->ExceptionInformation[1] && !rec->ExceptionInformation[2])
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
if (rec->ExceptionInformation[1] == ((EXCEPTION_RECORD*)*__current_exception())->ExceptionInformation[1])
|
||||||
|
ctx->rethrow = TRUE;
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CALLBACK cxx_catch_cleanup(BOOL normal, void *c)
|
||||||
|
{
|
||||||
|
cxx_catch_ctx *ctx = c;
|
||||||
|
__CxxUnregisterExceptionObject(&ctx->frame_info, ctx->rethrow);
|
||||||
|
|
||||||
|
FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx->unwind_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* WINAPI call_catch_block4(EXCEPTION_RECORD *rec)
|
||||||
|
{
|
||||||
|
ULONG64 frame = rec->ExceptionInformation[1];
|
||||||
|
EXCEPTION_RECORD *prev_rec = (void*)rec->ExceptionInformation[4];
|
||||||
|
EXCEPTION_RECORD *untrans_rec = (void*)rec->ExceptionInformation[6];
|
||||||
|
CONTEXT *context = (void*)rec->ExceptionInformation[7];
|
||||||
|
void* (__cdecl *handler)(ULONG64 unk, ULONG64 rbp) = (void*)rec->ExceptionInformation[5];
|
||||||
|
EXCEPTION_POINTERS ep = { prev_rec, context };
|
||||||
|
cxx_catch_ctx ctx;
|
||||||
|
void *ret_addr = NULL;
|
||||||
|
|
||||||
|
TRACE("calling handler %p\n", handler);
|
||||||
|
|
||||||
|
ctx.rethrow = FALSE;
|
||||||
|
__CxxRegisterExceptionObject(&ep, &ctx.frame_info);
|
||||||
|
ctx.search_state = rec->ExceptionInformation[2];
|
||||||
|
ctx.unwind_state = rec->ExceptionInformation[3];
|
||||||
|
(*__processing_throw())--;
|
||||||
|
__TRY
|
||||||
|
{
|
||||||
|
__TRY
|
||||||
|
{
|
||||||
|
ret_addr = handler(0, frame);
|
||||||
|
}
|
||||||
|
__EXCEPT_CTX(cxx_rethrow_filter, &ctx)
|
||||||
|
{
|
||||||
|
TRACE("detect rethrow: exception code: %x\n", prev_rec->ExceptionCode);
|
||||||
|
ctx.rethrow = TRUE;
|
||||||
|
|
||||||
|
if (untrans_rec)
|
||||||
|
{
|
||||||
|
__DestructExceptionObject(prev_rec);
|
||||||
|
RaiseException(untrans_rec->ExceptionCode, untrans_rec->ExceptionFlags,
|
||||||
|
untrans_rec->NumberParameters, untrans_rec->ExceptionInformation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RaiseException(prev_rec->ExceptionCode, prev_rec->ExceptionFlags,
|
||||||
|
prev_rec->NumberParameters, prev_rec->ExceptionInformation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__ENDTRY
|
||||||
|
}
|
||||||
|
__FINALLY_CTX(cxx_catch_cleanup, &ctx)
|
||||||
|
|
||||||
|
FlsSetValue(fls_index, (void*)-2);
|
||||||
|
if (rec->ExceptionInformation[8]) return (void*)rec->ExceptionInformation[8];
|
||||||
|
return ret_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BOOL cxx_is_consolidate(const EXCEPTION_RECORD *rec)
|
||||||
|
{
|
||||||
|
return rec->ExceptionCode==STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters==9 &&
|
||||||
|
rec->ExceptionInformation[0]==(ULONG_PTR)call_catch_block4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void find_catch_block4(EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||||
|
EXCEPTION_RECORD *untrans_rec, ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
|
||||||
|
const cxx_function_descr *descr, cxx_exception_type *info,
|
||||||
|
ULONG64 orig_frame, int trylevel)
|
||||||
|
{
|
||||||
|
ULONG64 exc_base = (rec->NumberParameters == 4 ? rec->ExceptionInformation[3] : 0);
|
||||||
|
int *processing_throw = __processing_throw();
|
||||||
|
EXCEPTION_RECORD catch_record;
|
||||||
|
BYTE *tryblock_map;
|
||||||
|
CONTEXT ctx;
|
||||||
|
UINT i, j;
|
||||||
|
|
||||||
|
(*processing_throw)++;
|
||||||
|
|
||||||
|
if (trylevel == -2)
|
||||||
|
{
|
||||||
|
trylevel = ip_to_state4(rva_to_ptr(descr->ip_map, dispatch->ImageBase),
|
||||||
|
descr->ip_count, dispatch, dispatch->ControlPc);
|
||||||
|
}
|
||||||
|
TRACE("current trylevel: %d\n", trylevel);
|
||||||
|
|
||||||
|
tryblock_map = rva_to_ptr(descr->tryblock_map, dispatch->ImageBase);
|
||||||
|
for (i=0; i<descr->tryblock_count; i++)
|
||||||
|
{
|
||||||
|
tryblock_info tryblock;
|
||||||
|
BYTE *catchblock;
|
||||||
|
|
||||||
|
read_tryblock_info(&tryblock_map, &tryblock, dispatch->ImageBase);
|
||||||
|
|
||||||
|
if (trylevel < tryblock.start_level) continue;
|
||||||
|
if (trylevel > tryblock.end_level) continue;
|
||||||
|
|
||||||
|
/* got a try block */
|
||||||
|
catchblock = rva_to_ptr(tryblock.catchblock, dispatch->ImageBase);
|
||||||
|
for (j=0; j<tryblock.catchblock_count; j++)
|
||||||
|
{
|
||||||
|
catchblock_info ci;
|
||||||
|
|
||||||
|
read_catchblock_info(&catchblock, &ci);
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
const cxx_type_info *type = find_caught_type(info, exc_base,
|
||||||
|
rva_to_ptr(ci.type_info, dispatch->ImageBase),
|
||||||
|
ci.flags);
|
||||||
|
if (!type) continue;
|
||||||
|
|
||||||
|
TRACE("matched type %p in tryblock %d catchblock %d\n", type, i, j);
|
||||||
|
|
||||||
|
/* copy the exception to its destination on the stack */
|
||||||
|
copy_exception((void*)rec->ExceptionInformation[1],
|
||||||
|
orig_frame, dispatch, &ci, type, exc_base);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no CXX_EXCEPTION only proceed with a catch(...) block*/
|
||||||
|
if (ci.type_info)
|
||||||
|
continue;
|
||||||
|
TRACE("found catch(...) block\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unwind stack and call catch */
|
||||||
|
memset(&catch_record, 0, sizeof(catch_record));
|
||||||
|
catch_record.ExceptionCode = STATUS_UNWIND_CONSOLIDATE;
|
||||||
|
catch_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||||
|
catch_record.NumberParameters = 9;
|
||||||
|
catch_record.ExceptionInformation[0] = (ULONG_PTR)call_catch_block4;
|
||||||
|
catch_record.ExceptionInformation[1] = orig_frame;
|
||||||
|
catch_record.ExceptionInformation[2] = tryblock.catch_level;
|
||||||
|
catch_record.ExceptionInformation[3] = tryblock.start_level;
|
||||||
|
catch_record.ExceptionInformation[4] = (ULONG_PTR)rec;
|
||||||
|
catch_record.ExceptionInformation[5] =
|
||||||
|
(ULONG_PTR)rva_to_ptr(ci.handler, dispatch->ImageBase);
|
||||||
|
catch_record.ExceptionInformation[6] = (ULONG_PTR)untrans_rec;
|
||||||
|
catch_record.ExceptionInformation[7] = (ULONG_PTR)context;
|
||||||
|
catch_record.ExceptionInformation[8] = (ULONG_PTR)rva_to_ptr(
|
||||||
|
ci.ret_addr + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase);
|
||||||
|
RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &ctx, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("no matching catch block found\n");
|
||||||
|
(*processing_throw)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LONG CALLBACK se_translation_filter(EXCEPTION_POINTERS *ep, void *c)
|
||||||
|
{
|
||||||
|
se_translator_ctx *ctx = (se_translator_ctx *)c;
|
||||||
|
EXCEPTION_RECORD *rec = ep->ExceptionRecord;
|
||||||
|
cxx_exception_type *exc_type;
|
||||||
|
|
||||||
|
if (rec->ExceptionCode != CXX_EXCEPTION)
|
||||||
|
{
|
||||||
|
TRACE("non-c++ exception thrown in SEH handler: %x\n", rec->ExceptionCode);
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
|
||||||
|
find_catch_block4(rec, ep->ContextRecord, ctx->seh_rec, ctx->dest_frame, ctx->dispatch,
|
||||||
|
ctx->descr, exc_type, ctx->orig_frame, ctx->trylevel);
|
||||||
|
|
||||||
|
__DestructExceptionObject(rec);
|
||||||
|
return ExceptionContinueSearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hacky way to obtain se_translator */
|
||||||
|
static inline _se_translator_function get_se_translator(void)
|
||||||
|
{
|
||||||
|
return __current_exception()[-2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD cxx_frame_handler4(EXCEPTION_RECORD *rec, ULONG64 frame,
|
||||||
|
CONTEXT *context, DISPATCHER_CONTEXT *dispatch,
|
||||||
|
const cxx_function_descr *descr, int trylevel)
|
||||||
|
{
|
||||||
|
cxx_exception_type *exc_type;
|
||||||
|
ULONG64 orig_frame = frame;
|
||||||
|
|
||||||
|
if (descr->header & FUNC_DESCR_IS_CATCH)
|
||||||
|
{
|
||||||
|
TRACE("nested exception detected\n");
|
||||||
|
orig_frame = *(ULONG64*)rva_to_ptr(descr->frame, frame);
|
||||||
|
TRACE("setting orig_frame to %lx\n", orig_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rec->ExceptionFlags & (EH_UNWINDING|EH_EXIT_UNWIND))
|
||||||
|
{
|
||||||
|
int last_level = -1;
|
||||||
|
if ((rec->ExceptionFlags & EH_TARGET_UNWIND) && cxx_is_consolidate(rec))
|
||||||
|
last_level = rec->ExceptionInformation[3];
|
||||||
|
else if ((rec->ExceptionFlags & EH_TARGET_UNWIND) && rec->ExceptionCode == STATUS_LONGJUMP)
|
||||||
|
last_level = ip_to_state4(rva_to_ptr(descr->ip_map, dispatch->ImageBase),
|
||||||
|
descr->ip_count, dispatch, dispatch->TargetIp);
|
||||||
|
|
||||||
|
cxx_local_unwind4(orig_frame, dispatch, descr, trylevel, last_level);
|
||||||
|
return ExceptionContinueSearch;
|
||||||
|
}
|
||||||
|
if (!descr->tryblock_map) return ExceptionContinueSearch;
|
||||||
|
|
||||||
|
if (rec->ExceptionCode == CXX_EXCEPTION)
|
||||||
|
{
|
||||||
|
exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
|
||||||
|
|
||||||
|
if (TRACE_ON(seh))
|
||||||
|
{
|
||||||
|
TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec, frame, descr);
|
||||||
|
dump_exception_type(exc_type, rec->ExceptionInformation[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_se_translator_function se_translator = get_se_translator();
|
||||||
|
|
||||||
|
exc_type = NULL;
|
||||||
|
TRACE("handling C exception code %x rec %p frame %lx descr %p\n",
|
||||||
|
rec->ExceptionCode, rec, frame, descr);
|
||||||
|
|
||||||
|
if (se_translator) {
|
||||||
|
EXCEPTION_POINTERS except_ptrs;
|
||||||
|
se_translator_ctx ctx;
|
||||||
|
|
||||||
|
ctx.dest_frame = frame;
|
||||||
|
ctx.orig_frame = orig_frame;
|
||||||
|
ctx.seh_rec = rec;
|
||||||
|
ctx.dispatch = dispatch;
|
||||||
|
ctx.descr = descr;
|
||||||
|
ctx.trylevel = trylevel;
|
||||||
|
__TRY
|
||||||
|
{
|
||||||
|
except_ptrs.ExceptionRecord = rec;
|
||||||
|
except_ptrs.ContextRecord = context;
|
||||||
|
se_translator(rec->ExceptionCode, &except_ptrs);
|
||||||
|
}
|
||||||
|
__EXCEPT_CTX(se_translation_filter, &ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
__ENDTRY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
find_catch_block4(rec, context, NULL, frame, dispatch, descr, exc_type, orig_frame, trylevel);
|
||||||
|
return ExceptionContinueSearch;
|
||||||
|
}
|
||||||
|
|
||||||
EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler4(EXCEPTION_RECORD *rec,
|
EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler4(EXCEPTION_RECORD *rec,
|
||||||
ULONG64 frame, CONTEXT *context, DISPATCHER_CONTEXT *dispatch)
|
ULONG64 frame, CONTEXT *context, DISPATCHER_CONTEXT *dispatch)
|
||||||
{
|
{
|
||||||
cxx_function_descr descr;
|
cxx_function_descr descr;
|
||||||
BYTE *p, *count, *count_end;
|
BYTE *p, *count, *count_end;
|
||||||
|
int trylevel;
|
||||||
|
|
||||||
FIXME("%p %lx %p %p\n", rec, frame, context, dispatch);
|
TRACE("%p %lx %p %p\n", rec, frame, context, dispatch);
|
||||||
|
|
||||||
|
trylevel = (DWORD_PTR)FlsGetValue(fls_index);
|
||||||
|
FlsSetValue(fls_index, (void*)-2);
|
||||||
|
|
||||||
memset(&descr, 0, sizeof(descr));
|
memset(&descr, 0, sizeof(descr));
|
||||||
p = rva_to_ptr(*(UINT*)dispatch->HandlerData, dispatch->ImageBase);
|
p = rva_to_ptr(*(UINT*)dispatch->HandlerData, dispatch->ImageBase);
|
||||||
descr.header = *p++;
|
descr.header = *p++;
|
||||||
|
|
||||||
|
if ((descr.header & FUNC_DESCR_EHS) &&
|
||||||
|
rec->ExceptionCode != CXX_EXCEPTION &&
|
||||||
|
!cxx_is_consolidate(rec) &&
|
||||||
|
rec->ExceptionCode != STATUS_LONGJUMP)
|
||||||
|
return ExceptionContinueSearch; /* handle only c++ exceptions */
|
||||||
|
|
||||||
if (descr.header & ~(FUNC_DESCR_IS_CATCH | FUNC_DESCR_UNWIND_MAP |
|
if (descr.header & ~(FUNC_DESCR_IS_CATCH | FUNC_DESCR_UNWIND_MAP |
|
||||||
FUNC_DESCR_TRYBLOCK_MAP | FUNC_DESCR_EHS))
|
FUNC_DESCR_TRYBLOCK_MAP | FUNC_DESCR_EHS))
|
||||||
{
|
{
|
||||||
|
@ -317,7 +764,27 @@ EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler4(EXCEPTION_RECORD *rec,
|
||||||
if (!validate_cxx_function_descr4(&descr, dispatch))
|
if (!validate_cxx_function_descr4(&descr, dispatch))
|
||||||
return ExceptionContinueSearch;
|
return ExceptionContinueSearch;
|
||||||
|
|
||||||
return ExceptionContinueSearch;
|
return cxx_frame_handler4(rec, frame, context, dispatch, &descr, trylevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
|
||||||
|
{
|
||||||
|
switch (fdwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
fls_index = FlsAlloc(NULL);
|
||||||
|
if (fls_index == FLS_OUT_OF_INDEXES)
|
||||||
|
return FALSE;
|
||||||
|
/* fall through */
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
FlsSetValue(fls_index, (void*)-2);
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
if (reserved) break;
|
||||||
|
FlsFree(fls_index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue