From: Piotr Caban Subject: [PATCH] vcruntime140_1: Add support for exception separated code segments. Message-Id: Date: Sat, 4 Dec 2021 18:15:06 +0100 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51396 Signed-off-by: Piotr Caban --- dlls/vcruntime140_1/except_x86_64.c | 62 +++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/dlls/vcruntime140_1/except_x86_64.c b/dlls/vcruntime140_1/except_x86_64.c index f50847d886d..b29a2baa696 100644 --- a/dlls/vcruntime140_1/except_x86_64.c +++ b/dlls/vcruntime140_1/except_x86_64.c @@ -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;