[PATCH] ntdll: Implement __C_specific_handler and _local_unwind for arm64

Martin Storsjo martin at martin.st
Thu Sep 17 03:04:48 CDT 2020


The __C_specific_handler function is based on the existing one for
x86_64, but with a few small changes:
- The TargetIp field in DISPATCHER_CONTEXT is renamed to TargetPc
- The handler/filter functions are called via wrapper functions that
  set up the nonvolatile registers before calling them
- Adjust ControlPc backwards if ControlPcIsUnwound is set

Signed-off-by: Martin Storsjo <martin at martin.st>
---
 .../api-ms-win-crt-private-l1-1-0.spec        |   4 +-
 dlls/ntdll/ntdll.spec                         |   4 +-
 dlls/ntdll/signal_arm64.c                     | 174 ++++++++++++++++++
 dlls/ucrtbase/ucrtbase.spec                   |   4 +-
 dlls/vcruntime140/vcruntime140.spec           |   4 +-
 5 files changed, 182 insertions(+), 8 deletions(-)

diff --git a/dlls/api-ms-win-crt-private-l1-1-0/api-ms-win-crt-private-l1-1-0.spec b/dlls/api-ms-win-crt-private-l1-1-0/api-ms-win-crt-private-l1-1-0.spec
index f74cea4e14c..f9cfe67c1b0 100644
--- a/dlls/api-ms-win-crt-private-l1-1-0/api-ms-win-crt-private-l1-1-0.spec
+++ b/dlls/api-ms-win-crt-private-l1-1-0/api-ms-win-crt-private-l1-1-0.spec
@@ -14,7 +14,7 @@
 @ cdecl __AdjustPointer(ptr ptr) ucrtbase.__AdjustPointer
 @ stub __BuildCatchObject
 @ stub __BuildCatchObjectHelper
-@ stdcall -arch=x86_64 __C_specific_handler(ptr long ptr ptr) ucrtbase.__C_specific_handler
+@ stdcall -arch=x86_64,arm64 __C_specific_handler(ptr long ptr ptr) ucrtbase.__C_specific_handler
 @ stub __C_specific_handler_noexcept
 @ cdecl -arch=i386,x86_64,arm,arm64 __CxxDetectRethrow(ptr) ucrtbase.__CxxDetectRethrow
 @ cdecl -arch=i386,x86_64,arm,arm64 __CxxExceptionFilter(ptr ptr long ptr) ucrtbase.__CxxExceptionFilter
@@ -62,7 +62,7 @@
 @ cdecl _get_unexpected() ucrtbase._get_unexpected
 @ cdecl -arch=i386 _global_unwind2(ptr) ucrtbase._global_unwind2
 @ stub _is_exception_typeof
-@ cdecl -arch=x86_64 _local_unwind(ptr ptr) ucrtbase._local_unwind
+@ cdecl -arch=x86_64,arm64 _local_unwind(ptr ptr) ucrtbase._local_unwind
 @ cdecl -arch=i386 _local_unwind2(ptr long) ucrtbase._local_unwind2
 @ cdecl -arch=i386 _local_unwind4(ptr ptr long) ucrtbase._local_unwind4
 @ cdecl -arch=i386 _longjmpex(ptr long) ucrtbase._longjmpex
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 453c4827572..af1fac8df8e 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -1437,7 +1437,7 @@
 @ cdecl -private -arch=i386 _CIpow()
 @ cdecl -private -arch=i386 _CIsin()
 @ cdecl -private -arch=i386 _CIsqrt()
-@ stdcall -arch=x86_64 __C_specific_handler(ptr long ptr ptr)
+@ stdcall -arch=x86_64,arm64 __C_specific_handler(ptr long ptr ptr)
 @ cdecl -arch=arm,x86_64 -norelay __chkstk()
 @ cdecl __isascii(long)
 @ cdecl __iscsym(long)
@@ -1463,7 +1463,7 @@
 @ cdecl _itoa(long ptr long)
 @ cdecl _itow(long ptr long)
 @ cdecl _lfind(ptr ptr ptr long ptr)
-@ stdcall -arch=x86_64 _local_unwind(ptr ptr)
+@ stdcall -arch=x86_64,arm64 _local_unwind(ptr ptr)
 @ cdecl _ltoa(long ptr long)
 @ cdecl _ltow(long ptr long)
 @ cdecl _memccpy(ptr ptr long long)
diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c
index 2335a6cc0a8..d585fe0d93c 100644
--- a/dlls/ntdll/signal_arm64.c
+++ b/dlls/ntdll/signal_arm64.c
@@ -39,6 +39,19 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(seh);
 
+typedef struct _SCOPE_TABLE
+{
+    ULONG Count;
+    struct
+    {
+        ULONG BeginAddress;
+        ULONG EndAddress;
+        ULONG HandlerAddress;
+        ULONG JumpTarget;
+    } ScopeRecord[1];
+} SCOPE_TABLE, *PSCOPE_TABLE;
+
+
 /* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */
 struct MSVCRT_JUMP_BUFFER
 {
@@ -63,6 +76,19 @@ struct MSVCRT_JUMP_BUFFER
 };
 
 
+static void dump_scope_table( ULONG64 base, const SCOPE_TABLE *table )
+{
+    unsigned int i;
+
+    TRACE( "scope table at %p\n", table );
+    for (i = 0; i < table->Count; i++)
+        TRACE( "  %u: %lx-%lx handler %lx target %lx\n", i,
+               base + table->ScopeRecord[i].BeginAddress,
+               base + table->ScopeRecord[i].EndAddress,
+               base + table->ScopeRecord[i].HandlerAddress,
+               base + table->ScopeRecord[i].JumpTarget );
+}
+
 /*******************************************************************
  *         is_valid_frame
  */
@@ -1225,6 +1251,154 @@ void WINAPI RtlUnwind( void *frame, void *target_ip, EXCEPTION_RECORD *rec, void
     RtlUnwindEx( frame, target_ip, rec, retval, &context, NULL );
 }
 
+/*******************************************************************
+ *		_local_unwind (NTDLL.@)
+ */
+void WINAPI _local_unwind( void *frame, void *target_ip )
+{
+    CONTEXT context;
+    RtlUnwindEx( frame, target_ip, NULL, NULL, &context, NULL );
+}
+
+extern LONG __C_ExecuteExceptionFilter(PEXCEPTION_POINTERS ptrs, PVOID frame,
+                                       PEXCEPTION_FILTER filter,
+                                       PUCHAR nonvolatile);
+__ASM_GLOBAL_FUNC( __C_ExecuteExceptionFilter,
+                   "stp x29, x30, [sp, #-96]!\n\t"
+                   __ASM_SEH(".seh_save_fplr_x 96\n\t")
+                   "stp x19, x20, [sp, #16]\n\t"
+                   __ASM_SEH(".seh_save_regp x19, 16\n\t")
+                   "stp x21, x22, [sp, #32]\n\t"
+                   __ASM_SEH(".seh_save_regp x21, 32\n\t")
+                   "stp x23, x24, [sp, #48]\n\t"
+                   __ASM_SEH(".seh_save_regp x23, 48\n\t")
+                   "stp x25, x26, [sp, #64]\n\t"
+                   __ASM_SEH(".seh_save_regp x25, 64\n\t")
+                   "stp x27, x28, [sp, #80]\n\t"
+                   __ASM_SEH(".seh_save_regp x27, 80\n\t")
+                   "mov x29, sp\n\t"
+                   __ASM_SEH(".seh_set_fp\n\t")
+                   __ASM_SEH(".seh_endprologue\n\t")
+
+                   __ASM_CFI(".cfi_def_cfa x29, 96\n\t")
+                   __ASM_CFI(".cfi_offset x29, -96\n\t")
+                   __ASM_CFI(".cfi_offset x30, -88\n\t")
+                   __ASM_CFI(".cfi_offset x19, -80\n\t")
+                   __ASM_CFI(".cfi_offset x20, -72\n\t")
+                   __ASM_CFI(".cfi_offset x21, -64\n\t")
+                   __ASM_CFI(".cfi_offset x22, -56\n\t")
+                   __ASM_CFI(".cfi_offset x23, -48\n\t")
+                   __ASM_CFI(".cfi_offset x24, -40\n\t")
+                   __ASM_CFI(".cfi_offset x25, -32\n\t")
+                   __ASM_CFI(".cfi_offset x26, -24\n\t")
+                   __ASM_CFI(".cfi_offset x27, -16\n\t")
+                   __ASM_CFI(".cfi_offset x28, -8\n\t")
+
+                   "ldp x19, x20, [x3, #0]\n\t"
+                   "ldp x21, x22, [x3, #16]\n\t"
+                   "ldp x23, x24, [x3, #32]\n\t"
+                   "ldp x25, x26, [x3, #48]\n\t"
+                   "ldp x27, x28, [x3, #64]\n\t"
+                   /* Overwrite the frame parameter with Fp from the
+                    * nonvolatile regs */
+                   "ldr x1, [x3, #80]\n\t"
+                   "blr x2\n\t"
+                   "ldp x19, x20, [sp, #16]\n\t"
+                   "ldp x21, x22, [sp, #32]\n\t"
+                   "ldp x23, x24, [sp, #48]\n\t"
+                   "ldp x25, x26, [sp, #64]\n\t"
+                   "ldp x27, x28, [sp, #80]\n\t"
+                   "ldp x29, x30, [sp], #96\n\t"
+                   "ret")
+
+extern void __C_ExecuteTerminationHandler(BOOL abnormal, PVOID frame,
+                                          PTERMINATION_HANDLER handler,
+                                          PUCHAR nonvolatile);
+/* This is, implementation wise, identical to __C_ExecuteExceptionFilter. */
+__ASM_GLOBAL_FUNC( __C_ExecuteTerminationHandler,
+                   "b " __ASM_NAME("__C_ExecuteExceptionFilter") "\n\t");
+
+/*******************************************************************
+ *		__C_specific_handler (NTDLL.@)
+ */
+EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
+                                                   void *frame,
+                                                   CONTEXT *context,
+                                                   struct _DISPATCHER_CONTEXT *dispatch )
+{
+    SCOPE_TABLE *table = dispatch->HandlerData;
+    ULONG i;
+    DWORD64 ControlPc = dispatch->ControlPc;
+
+    TRACE( "%p %p %p %p\n", rec, frame, context, dispatch );
+    if (TRACE_ON(seh)) dump_scope_table( dispatch->ImageBase, table );
+
+    if (dispatch->ControlPcIsUnwound)
+        ControlPc -= 4;
+
+    if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
+    {
+        for (i = dispatch->ScopeIndex; i < table->Count; i++)
+        {
+            if (ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
+                ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
+            {
+                PTERMINATION_HANDLER handler;
+
+                if (table->ScopeRecord[i].JumpTarget) continue;
+
+                if (rec->ExceptionFlags & EH_TARGET_UNWIND &&
+                    dispatch->TargetPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
+                    dispatch->TargetPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
+                {
+                    break;
+                }
+
+                handler = (PTERMINATION_HANDLER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
+                dispatch->ScopeIndex = i+1;
+
+                TRACE( "calling __finally %p frame %p\n", handler, frame );
+                __C_ExecuteTerminationHandler( TRUE, frame, handler,
+                                               dispatch->NonVolatileRegisters );
+            }
+        }
+        return ExceptionContinueSearch;
+    }
+
+    for (i = dispatch->ScopeIndex; i < table->Count; i++)
+    {
+        if (ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
+            ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
+        {
+            if (!table->ScopeRecord[i].JumpTarget) continue;
+            if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
+            {
+                EXCEPTION_POINTERS ptrs;
+                PEXCEPTION_FILTER filter;
+
+                filter = (PEXCEPTION_FILTER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
+                ptrs.ExceptionRecord = rec;
+                ptrs.ContextRecord = context;
+                TRACE( "calling filter %p ptrs %p frame %p\n", filter, &ptrs, frame );
+                switch (__C_ExecuteExceptionFilter( &ptrs, frame, filter,
+                                                    dispatch->NonVolatileRegisters ))
+                {
+                case EXCEPTION_EXECUTE_HANDLER:
+                    break;
+                case EXCEPTION_CONTINUE_SEARCH:
+                    continue;
+                case EXCEPTION_CONTINUE_EXECUTION:
+                    return ExceptionContinueExecution;
+                }
+            }
+            TRACE( "unwinding to target %lx\n", dispatch->ImageBase + table->ScopeRecord[i].JumpTarget );
+            RtlUnwindEx( frame, (char *)dispatch->ImageBase + table->ScopeRecord[i].JumpTarget,
+                         rec, 0, dispatch->ContextRecord, dispatch->HistoryTable );
+        }
+    }
+    return ExceptionContinueSearch;
+}
+
 
 /***********************************************************************
  *		RtlRaiseException (NTDLL.@)
diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec
index 05ac3d3427a..4981d7fbac7 100644
--- a/dlls/ucrtbase/ucrtbase.spec
+++ b/dlls/ucrtbase/ucrtbase.spec
@@ -48,7 +48,7 @@
 @ cdecl __AdjustPointer(ptr ptr)
 @ stub __BuildCatchObject
 @ stub __BuildCatchObjectHelper
-@ stdcall -arch=x86_64 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler
+@ stdcall -arch=x86_64,arm64 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler
 @ cdecl -arch=i386,x86_64,arm,arm64 __CxxDetectRethrow(ptr)
 @ cdecl -arch=i386,x86_64,arm,arm64 __CxxExceptionFilter(ptr ptr long ptr)
 @ cdecl -arch=i386,x86_64,arm,arm64 -norelay __CxxFrameHandler(ptr ptr ptr ptr)
@@ -555,7 +555,7 @@
 @ cdecl -arch=i386 -norelay _libm_sse2_sqrt_precise() MSVCRT___libm_sse2_sqrt_precise
 @ cdecl -arch=i386 -norelay _libm_sse2_tan_precise() MSVCRT___libm_sse2_tan
 @ cdecl _loaddll(str)
-@ cdecl -arch=x86_64 _local_unwind(ptr ptr)
+@ cdecl -arch=x86_64,arm64 _local_unwind(ptr ptr)
 @ cdecl -arch=i386 _local_unwind2(ptr long)
 @ cdecl -arch=i386 _local_unwind4(ptr ptr long)
 @ cdecl _localtime32(ptr) MSVCRT__localtime32
diff --git a/dlls/vcruntime140/vcruntime140.spec b/dlls/vcruntime140/vcruntime140.spec
index 45d9370c86a..f799bcd4db5 100644
--- a/dlls/vcruntime140/vcruntime140.spec
+++ b/dlls/vcruntime140/vcruntime140.spec
@@ -10,7 +10,7 @@
 @ cdecl __AdjustPointer(ptr ptr) ucrtbase.__AdjustPointer
 @ stub __BuildCatchObject
 @ stub __BuildCatchObjectHelper
-@ stdcall -arch=x86_64 __C_specific_handler(ptr long ptr ptr) ucrtbase.__C_specific_handler
+@ stdcall -arch=x86_64,arm64 __C_specific_handler(ptr long ptr ptr) ucrtbase.__C_specific_handler
 @ stub __C_specific_handler_noexcept
 @ cdecl -arch=i386,x86_64,arm,arm64 __CxxDetectRethrow(ptr) ucrtbase.__CxxDetectRethrow
 @ cdecl -arch=i386,x86_64,arm,arm64 __CxxExceptionFilter(ptr ptr long ptr) ucrtbase.__CxxExceptionFilter
@@ -64,7 +64,7 @@
 @ cdecl -arch=i386 _local_unwind2(ptr long) ucrtbase._local_unwind2
 @ cdecl -arch=i386 _local_unwind4(ptr ptr long) ucrtbase._local_unwind4
 @ cdecl -arch=i386 _longjmpex(ptr long) ucrtbase._longjmpex
-@ cdecl -arch=x86_64 _local_unwind(ptr ptr) ucrtbase._local_unwind
+@ cdecl -arch=x86_64,arm64 _local_unwind(ptr ptr) ucrtbase._local_unwind
 @ cdecl _purecall() ucrtbase._purecall
 @ stdcall -arch=i386 _seh_longjmp_unwind4(ptr) ucrtbase._seh_longjmp_unwind4
 @ stdcall -arch=i386 _seh_longjmp_unwind(ptr) ucrtbase._seh_longjmp_unwind
-- 
2.17.1




More information about the wine-devel mailing list