vcruntime140_1: Add support for exception separated code segments.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51396
Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
(cherry picked from commit 9ccd84b945)
Signed-off-by: Michael Stefaniuc <mstefani@winehq.org>
This commit is contained in:
Piotr Caban 2021-12-04 18:15:06 +01:00 committed by Michael Stefaniuc
parent 6dfcf590e1
commit c2efc7ed8a
1 changed files with 50 additions and 12 deletions

View File

@ -74,6 +74,7 @@ typedef struct
#define CATCHBLOCK_FLAGS 0x01
#define CATCHBLOCK_TYPE_INFO 0x02
#define CATCHBLOCK_OFFSET 0x04
#define CATCHBLOCK_SEPARATED 0x08
#define CATCHBLOCK_RET_ADDR_MASK 0x30
#define CATCHBLOCK_RET_ADDR 0x10
#define CATCHBLOCK_TWO_RET_ADDRS 0x20
@ -219,13 +220,14 @@ static void read_tryblock_info(BYTE **b, tryblock_info *ti, ULONG64 image_base)
}
}
static BOOL read_catchblock_info(BYTE **b, catchblock_info *ci)
static BOOL read_catchblock_info(BYTE **b, catchblock_info *ci, DWORD func_rva)
{
BYTE ret_addr_type;
memset(ci, 0, sizeof(*ci));
ci->header = **b;
(*b)++;
if (ci->header & ~(CATCHBLOCK_FLAGS | CATCHBLOCK_TYPE_INFO | CATCHBLOCK_OFFSET | CATCHBLOCK_RET_ADDR_MASK))
if (ci->header & ~(CATCHBLOCK_FLAGS | CATCHBLOCK_TYPE_INFO | CATCHBLOCK_OFFSET |
CATCHBLOCK_SEPARATED | CATCHBLOCK_RET_ADDR_MASK))
{
FIXME("unknown header: %x\n", ci->header);
return FALSE;
@ -241,10 +243,20 @@ static BOOL read_catchblock_info(BYTE **b, catchblock_info *ci)
if (ci->header & CATCHBLOCK_TYPE_INFO) ci->type_info = read_rva(b);
if (ci->header & CATCHBLOCK_OFFSET) ci->offset = decode_uint(b);
ci->handler = read_rva(b);
if (ret_addr_type == CATCHBLOCK_RET_ADDR || ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
ci->ret_addr[0] = decode_uint(b);
if (ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
ci->ret_addr[1] = decode_uint(b);
if (ci->header & CATCHBLOCK_SEPARATED)
{
if (ret_addr_type == CATCHBLOCK_RET_ADDR || ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
ci->ret_addr[0] = read_rva(b);
if (ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
ci->ret_addr[1] = read_rva(b);
}
else
{
if (ret_addr_type == CATCHBLOCK_RET_ADDR || ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
ci->ret_addr[0] = decode_uint(b) + func_rva;
if (ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
ci->ret_addr[1] = decode_uint(b) + func_rva;
}
return TRUE;
}
@ -320,7 +332,8 @@ static BOOL validate_cxx_function_descr4(const cxx_function_descr *descr, DISPAT
for (j = 0; j < ti.catchblock_count; j++)
{
catchblock_info ci;
if (!read_catchblock_info(&catchblock, &ci)) return FALSE;
if (!read_catchblock_info(&catchblock, &ci,
dispatch->FunctionEntry->BeginAddress)) return FALSE;
TRACE(" %d: header 0x%x offset %d handler 0x%x(%p) "
"ret addr[0] %#x ret_addr[1] %#x type %#x %s\n", j, ci.header, ci.offset,
ci.handler, rva_to_ptr(ci.handler, image_base),
@ -614,7 +627,7 @@ static inline void find_catch_block4(EXCEPTION_RECORD *rec, CONTEXT *context,
{
catchblock_info ci;
read_catchblock_info(&catchblock, &ci);
read_catchblock_info(&catchblock, &ci, dispatch->FunctionEntry->BeginAddress);
if (info)
{
@ -652,11 +665,15 @@ static inline void find_catch_block4(EXCEPTION_RECORD *rec, CONTEXT *context,
catch_record.ExceptionInformation[6] = (ULONG_PTR)untrans_rec;
catch_record.ExceptionInformation[7] = (ULONG_PTR)context;
if (ci.ret_addr[0])
{
catch_record.ExceptionInformation[8] = (ULONG_PTR)rva_to_ptr(
ci.ret_addr[0] + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase);
ci.ret_addr[0], dispatch->ImageBase);
}
if (ci.ret_addr[1])
{
catch_record.ExceptionInformation[9] = (ULONG_PTR)rva_to_ptr(
ci.ret_addr[1] + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase);
ci.ret_addr[1], dispatch->ImageBase);
}
RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &ctx, NULL);
}
}
@ -808,8 +825,9 @@ EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler4(EXCEPTION_RECORD *rec,
rec->ExceptionCode != STATUS_LONGJUMP)
return ExceptionContinueSearch; /* handle only c++ exceptions */
if (descr.header & ~(FUNC_DESCR_IS_CATCH | FUNC_DESCR_UNWIND_MAP |
FUNC_DESCR_TRYBLOCK_MAP | FUNC_DESCR_EHS | FUNC_DESCR_NO_EXCEPT))
if (descr.header & ~(FUNC_DESCR_IS_CATCH | FUNC_DESCR_IS_SEPARATED |
FUNC_DESCR_UNWIND_MAP | FUNC_DESCR_TRYBLOCK_MAP | FUNC_DESCR_EHS |
FUNC_DESCR_NO_EXCEPT))
{
FIXME("unsupported flags: %x\n", descr.header);
return ExceptionContinueSearch;
@ -831,6 +849,26 @@ EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler4(EXCEPTION_RECORD *rec,
descr.tryblock_map += count_end - count;
}
descr.ip_map = read_rva(&p);
if (descr.header & FUNC_DESCR_IS_SEPARATED)
{
UINT i, num, func;
BYTE *map;
map = rva_to_ptr(descr.ip_map, dispatch->ImageBase);
num = decode_uint(&map);
for (i = 0; i < num; i++)
{
func = read_rva(&map);
descr.ip_map = read_rva(&map);
if (func == dispatch->FunctionEntry->BeginAddress)
break;
}
if (i == num)
{
FIXME("function ip_map not found\n");
return ExceptionContinueSearch;
}
}
count_end = count = rva_to_ptr(descr.ip_map, dispatch->ImageBase);
descr.ip_count = decode_uint(&count_end);
descr.ip_map += count_end - count;