Piotr Caban : vcruntime140_1: Add support for exception separated code segments.

Alexandre Julliard julliard at winehq.org
Mon Dec 6 16:07:59 CST 2021


Module: wine
Branch: master
Commit: 9ccd84b945c4935e200becfe08a9a5bdb4799bd5
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=9ccd84b945c4935e200becfe08a9a5bdb4799bd5

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Sat Dec  4 18:15:06 2021 +0100

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 at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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;




More information about the wine-cvs mailing list