Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2021
- 83 participants
- 2620 messages
[PATCH 17/18] ucrtbase: Hook up __intrinsic_setjmpex for arm.
by Martin Storsjö
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
.../api-ms-win-crt-private-l1-1-0.spec | 2 +-
dlls/ucrtbase/ucrtbase.spec | 2 +-
dlls/vcruntime140/vcruntime140.spec | 2 +-
3 files changed, 3 insertions(+), 3 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 3366a435966..4fa47035afe 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
@@ -40,7 +40,7 @@
@ stub __dcrt_initial_narrow_environment
@ cdecl __intrinsic_abnormal_termination() ucrtbase.__intrinsic_abnormal_termination
@ cdecl -arch=i386,x86_64,arm,arm64 -norelay __intrinsic_setjmp(ptr) ucrtbase.__intrinsic_setjmp
-@ cdecl -arch=x86_64,arm64 -norelay __intrinsic_setjmpex(ptr ptr) ucrtbase.__intrinsic_setjmpex
+@ cdecl -arch=x86_64,arm,arm64 -norelay __intrinsic_setjmpex(ptr ptr) ucrtbase.__intrinsic_setjmpex
@ stdcall -arch=arm __jump_unwind(ptr ptr) ucrtbase.__jump_unwind
@ cdecl __processing_throw() ucrtbase.__processing_throw
@ stub __report_gsfailure
diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec
index 831bff9eee1..1838f31d515 100644
--- a/dlls/ucrtbase/ucrtbase.spec
+++ b/dlls/ucrtbase/ucrtbase.spec
@@ -94,7 +94,7 @@
@ cdecl __initialize_lconv_for_unsigned_char() __lconv_init
@ cdecl __intrinsic_abnormal_termination()
@ cdecl -arch=i386,x86_64,arm,arm64 -norelay __intrinsic_setjmp(ptr) MSVCRT__setjmp
-@ cdecl -arch=x86_64,arm64 -norelay __intrinsic_setjmpex(ptr ptr) __wine_setjmpex
+@ cdecl -arch=x86_64,arm,arm64 -norelay __intrinsic_setjmpex(ptr ptr) __wine_setjmpex
@ cdecl __isascii(long)
@ cdecl __iscsym(long)
@ cdecl __iscsymf(long)
diff --git a/dlls/vcruntime140/vcruntime140.spec b/dlls/vcruntime140/vcruntime140.spec
index 7bbb37afcec..074578efe99 100644
--- a/dlls/vcruntime140/vcruntime140.spec
+++ b/dlls/vcruntime140/vcruntime140.spec
@@ -33,7 +33,7 @@
@ cdecl __current_exception() ucrtbase.__current_exception
@ cdecl __current_exception_context() ucrtbase.__current_exception_context
@ cdecl -arch=i386,x86_64,arm,arm64 -norelay __intrinsic_setjmp(ptr) ucrtbase.__intrinsic_setjmp
-@ cdecl -arch=x86_64,arm64 -norelay __intrinsic_setjmpex(ptr ptr) ucrtbase.__intrinsic_setjmpex
+@ cdecl -arch=x86_64,arm,arm64 -norelay __intrinsic_setjmpex(ptr ptr) ucrtbase.__intrinsic_setjmpex
@ stdcall -arch=arm __jump_unwind(ptr ptr) ucrtbase.__jump_unwind
@ cdecl __processing_throw() ucrtbase.__processing_throw
@ stub __report_gsfailure
--
2.25.1
Nov. 9, 2021
[PATCH 16/18] ntdll: Implement __C_specific_handler and __jump_unwind for arm.
by Martin Storsjö
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
.../api-ms-win-crt-private-l1-1-0.spec | 3 +-
dlls/ntdll/ntdll.spec | 3 +-
dlls/ntdll/signal_arm.c | 145 ++++++++++++++++++
dlls/ucrtbase/ucrtbase.spec | 3 +-
dlls/vcruntime140/vcruntime140.spec | 3 +-
5 files changed, 153 insertions(+), 4 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 ea6cfa2a7f9..3366a435966 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,arm64 __C_specific_handler(ptr long ptr ptr) ucrtbase.__C_specific_handler
+@ stdcall -arch=x86_64,arm,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
@@ -41,6 +41,7 @@
@ cdecl __intrinsic_abnormal_termination() ucrtbase.__intrinsic_abnormal_termination
@ cdecl -arch=i386,x86_64,arm,arm64 -norelay __intrinsic_setjmp(ptr) ucrtbase.__intrinsic_setjmp
@ cdecl -arch=x86_64,arm64 -norelay __intrinsic_setjmpex(ptr ptr) ucrtbase.__intrinsic_setjmpex
+@ stdcall -arch=arm __jump_unwind(ptr ptr) ucrtbase.__jump_unwind
@ cdecl __processing_throw() ucrtbase.__processing_throw
@ stub __report_gsfailure
@ cdecl __std_exception_copy(ptr ptr) ucrtbase.__std_exception_copy
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index c703219cfbb..e7c1fa1dcf3 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -1464,11 +1464,12 @@
@ cdecl -private -arch=i386 _CIpow()
@ cdecl -private -arch=i386 _CIsin()
@ cdecl -private -arch=i386 _CIsqrt()
-@ stdcall -arch=x86_64,arm64 __C_specific_handler(ptr long ptr ptr)
+@ stdcall -arch=x86_64,arm,arm64 __C_specific_handler(ptr long ptr ptr)
@ cdecl -arch=arm,arm64,x86_64 -norelay __chkstk()
@ cdecl __isascii(long)
@ cdecl __iscsym(long)
@ cdecl __iscsymf(long)
+@ stdcall -arch=arm __jump_unwind(ptr ptr)
@ cdecl __toascii(long)
@ cdecl -norelay -arch=i386 -ret64 _alldiv(int64 int64)
@ cdecl -arch=i386 -norelay _alldvrm(int64 int64)
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index a24cac97df7..72f3b023e45 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -37,6 +37,18 @@
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
@@ -56,6 +68,20 @@ struct MSVCRT_JUMP_BUFFER
unsigned long long D[8];
};
+
+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
*/
@@ -1260,6 +1286,125 @@ void WINAPI RtlUnwind( void *frame, void *target_ip, EXCEPTION_RECORD *rec, void
}
+/*******************************************************************
+ * __jump_unwind (NTDLL.@)
+ */
+void WINAPI __jump_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,
+ "push {r4-r11,lr}\n\t"
+
+ __ASM_CFI(".cfi_def_cfa 13, 36\n\t")
+ __ASM_CFI(".cfi_offset r4, -36\n\t")
+ __ASM_CFI(".cfi_offset r5, -32\n\t")
+ __ASM_CFI(".cfi_offset r6, -28\n\t")
+ __ASM_CFI(".cfi_offset r7, -24\n\t")
+ __ASM_CFI(".cfi_offset r8, -20\n\t")
+ __ASM_CFI(".cfi_offset r9, -16\n\t")
+ __ASM_CFI(".cfi_offset r10, -12\n\t")
+ __ASM_CFI(".cfi_offset r11, -8\n\t")
+ __ASM_CFI(".cfi_offset lr, -4\n\t")
+
+ "ldm r3, {r4-r11,lr}\n\t"
+ "blx r2\n\t"
+ "pop {r4-r11,pc}\n\t" )
+
+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 -= 2;
+
+ 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 d39387d5f00..831bff9eee1 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,arm64 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler
+@ stdcall -arch=x86_64,arm,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)
@@ -100,6 +100,7 @@
@ cdecl __iscsymf(long)
@ stub __iswcsym
@ stub __iswcsymf
+@ stdcall -arch=arm __jump_unwind(ptr ptr) ntdll.__jump_unwind
@ cdecl -arch=i386 -norelay __libm_sse2_acos()
@ cdecl -arch=i386 -norelay __libm_sse2_acosf()
@ cdecl -arch=i386 -norelay __libm_sse2_asin()
diff --git a/dlls/vcruntime140/vcruntime140.spec b/dlls/vcruntime140/vcruntime140.spec
index 9ca10cc2a70..7bbb37afcec 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,arm64 __C_specific_handler(ptr long ptr ptr) ucrtbase.__C_specific_handler
+@ stdcall -arch=x86_64,arm,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
@@ -34,6 +34,7 @@
@ cdecl __current_exception_context() ucrtbase.__current_exception_context
@ cdecl -arch=i386,x86_64,arm,arm64 -norelay __intrinsic_setjmp(ptr) ucrtbase.__intrinsic_setjmp
@ cdecl -arch=x86_64,arm64 -norelay __intrinsic_setjmpex(ptr ptr) ucrtbase.__intrinsic_setjmpex
+@ stdcall -arch=arm __jump_unwind(ptr ptr) ucrtbase.__jump_unwind
@ cdecl __processing_throw() ucrtbase.__processing_throw
@ stub __report_gsfailure
@ cdecl __std_exception_copy(ptr ptr) ucrtbase.__std_exception_copy
--
2.25.1
Nov. 9, 2021
[PATCH 15/18] ntdll: Implement stack unwinding on arm.
by Martin Storsjö
This is a very close copy of the arm64 implementation.
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
.../api-ms-win-core-rtlsupport-l1-1-0.spec | 4 +-
.../api-ms-win-core-rtlsupport-l1-2-0.spec | 4 +-
dlls/kernel32/kernel32.spec | 4 +-
dlls/ntdll/ntdll.spec | 4 +-
dlls/ntdll/signal_arm.c | 599 +++++++++++++++---
dlls/ntdll/unix/signal_arm.c | 107 +++-
6 files changed, 641 insertions(+), 81 deletions(-)
diff --git a/dlls/api-ms-win-core-rtlsupport-l1-1-0/api-ms-win-core-rtlsupport-l1-1-0.spec b/dlls/api-ms-win-core-rtlsupport-l1-1-0/api-ms-win-core-rtlsupport-l1-1-0.spec
index fefac9dc400..43e95d62dae 100644
--- a/dlls/api-ms-win-core-rtlsupport-l1-1-0/api-ms-win-core-rtlsupport-l1-1-0.spec
+++ b/dlls/api-ms-win-core-rtlsupport-l1-1-0/api-ms-win-core-rtlsupport-l1-1-0.spec
@@ -9,7 +9,7 @@
@ stdcall -arch=arm,arm64,x86_64 RtlLookupFunctionEntry(long ptr ptr) ntdll.RtlLookupFunctionEntry
@ stdcall RtlPcToFileHeader(ptr ptr) ntdll.RtlPcToFileHeader
@ stdcall -norelay RtlRaiseException(ptr) ntdll.RtlRaiseException
-@ cdecl -arch=arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
+@ cdecl -arch=arm,arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
@ stdcall -norelay RtlUnwind(ptr ptr ptr ptr) ntdll.RtlUnwind
-@ stdcall -arch=arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr) ntdll.RtlUnwindEx
+@ stdcall -arch=arm,arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr) ntdll.RtlUnwindEx
@ stdcall -arch=arm,arm64,x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr) ntdll.RtlVirtualUnwind
diff --git a/dlls/api-ms-win-core-rtlsupport-l1-2-0/api-ms-win-core-rtlsupport-l1-2-0.spec b/dlls/api-ms-win-core-rtlsupport-l1-2-0/api-ms-win-core-rtlsupport-l1-2-0.spec
index bff03b1d2ae..31540f6c9f7 100644
--- a/dlls/api-ms-win-core-rtlsupport-l1-2-0/api-ms-win-core-rtlsupport-l1-2-0.spec
+++ b/dlls/api-ms-win-core-rtlsupport-l1-2-0/api-ms-win-core-rtlsupport-l1-2-0.spec
@@ -10,7 +10,7 @@
@ stdcall -arch=arm,arm64,x86_64 RtlLookupFunctionEntry(long ptr ptr) ntdll.RtlLookupFunctionEntry
@ stdcall RtlPcToFileHeader(ptr ptr) ntdll.RtlPcToFileHeader
@ stdcall -norelay RtlRaiseException(ptr) ntdll.RtlRaiseException
-@ cdecl -arch=arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
+@ cdecl -arch=arm,arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
@ stdcall -norelay RtlUnwind(ptr ptr ptr ptr) ntdll.RtlUnwind
-@ stdcall -arch=arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr) ntdll.RtlUnwindEx
+@ stdcall -arch=arm,arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr) ntdll.RtlUnwindEx
@ stdcall -arch=arm,arm64,x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr) ntdll.RtlVirtualUnwind
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 18ec187a683..7c25caf19d7 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -1311,9 +1311,9 @@
@ stdcall RtlMoveMemory(ptr ptr long) ntdll.RtlMoveMemory
@ stdcall RtlPcToFileHeader(ptr ptr) ntdll.RtlPcToFileHeader
@ stdcall -arch=arm,arm64,x86_64 -norelay RtlRaiseException(ptr) ntdll.RtlRaiseException
-@ cdecl -arch=arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
+@ cdecl -arch=arm,arm64,x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
@ stdcall RtlUnwind(ptr ptr ptr long) ntdll.RtlUnwind
-@ stdcall -arch=arm64,x86_64 RtlUnwindEx(long long ptr long ptr) ntdll.RtlUnwindEx
+@ stdcall -arch=arm,arm64,x86_64 RtlUnwindEx(long long ptr long ptr) ntdll.RtlUnwindEx
@ stdcall -arch=arm,arm64,x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr) ntdll.RtlVirtualUnwind
@ stdcall RtlZeroMemory(ptr long) ntdll.RtlZeroMemory
@ stdcall -i386 -private -norelay SMapLS() krnl386.exe16.SMapLS
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 070b57efb59..c703219cfbb 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -941,7 +941,7 @@
@ stdcall RtlRemoveVectoredContinueHandler(ptr)
@ stdcall RtlRemoveVectoredExceptionHandler(ptr)
@ stdcall RtlResetRtlTranslations(ptr)
-@ cdecl -arch=arm64,x86_64 RtlRestoreContext(ptr ptr)
+@ cdecl -arch=arm,arm64,x86_64 RtlRestoreContext(ptr ptr)
@ stdcall RtlRestoreLastWin32Error(long) RtlSetLastWin32Error
@ stub RtlRevertMemoryStream
@ stub RtlRunDecodeUnicodeString
@@ -1044,7 +1044,7 @@
@ stdcall RtlUnlockHeap(long)
# @ stub RtlUnlockMemoryStreamRegion
@ stdcall -norelay RtlUnwind(ptr ptr ptr ptr)
-@ stdcall -arch=arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr)
+@ stdcall -arch=arm,arm64,x86_64 RtlUnwindEx(ptr ptr ptr ptr ptr ptr)
@ stdcall RtlUpcaseUnicodeChar(long)
@ stdcall RtlUpcaseUnicodeString(ptr ptr long)
@ stdcall RtlUpcaseUnicodeStringToAnsiString(ptr ptr long)
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index a1a732201cf..a24cac97df7 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -38,13 +38,31 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh);
+/* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */
+struct MSVCRT_JUMP_BUFFER
+{
+ unsigned long Frame;
+ unsigned long R4;
+ unsigned long R5;
+ unsigned long R6;
+ unsigned long R7;
+ unsigned long R8;
+ unsigned long R9;
+ unsigned long R10;
+ unsigned long R11;
+ unsigned long Sp;
+ unsigned long Pc;
+ unsigned long Fpscr;
+ unsigned long long D[8];
+};
+
/*******************************************************************
* is_valid_frame
*/
-static inline BOOL is_valid_frame( void *frame )
+static inline BOOL is_valid_frame( ULONG_PTR frame )
{
- if ((ULONG_PTR)frame & 3) return FALSE;
- return (frame >= NtCurrentTeb()->Tib.StackLimit &&
+ if (frame & 3) return FALSE;
+ return ((void *)frame >= NtCurrentTeb()->Tib.StackLimit &&
(void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
}
@@ -83,54 +101,322 @@ __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
/**********************************************************************
- * call_stack_handlers
+ * virtual_unwind
+ */
+static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context )
+{
+ LDR_DATA_TABLE_ENTRY *module;
+ NTSTATUS status;
+
+ dispatch->ImageBase = 0;
+ dispatch->ScopeIndex = 0;
+ dispatch->EstablisherFrame = 0;
+ dispatch->ControlPc = context->Pc;
+ /*
+ * TODO: CONTEXT_UNWOUND_TO_CALL should be cleared if unwound past a
+ * signal frame.
+ */
+ dispatch->ControlPcIsUnwound = (context->ContextFlags & CONTEXT_UNWOUND_TO_CALL) != 0;
+
+ /* first look for PE exception information */
+
+ if ((dispatch->FunctionEntry = lookup_function_info(
+ context->Pc - (dispatch->ControlPcIsUnwound ? 2 : 0),
+ (ULONG_PTR*)&dispatch->ImageBase, &module )))
+ {
+ dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, context->Pc,
+ dispatch->FunctionEntry, context,
+ &dispatch->HandlerData, (ULONG_PTR *)&dispatch->EstablisherFrame,
+ NULL );
+ return STATUS_SUCCESS;
+ }
+
+ /* then look for host system exception information */
+
+ if (!module || (module->Flags & LDR_WINE_INTERNAL))
+ {
+ status = unix_funcs->unwind_builtin_dll( type, dispatch, context );
+ if (status != STATUS_SUCCESS) return status;
+
+ if (dispatch->EstablisherFrame)
+ {
+ dispatch->FunctionEntry = NULL;
+ if (dispatch->LanguageHandler && !module)
+ {
+ FIXME( "calling personality routine in system library not supported yet\n" );
+ dispatch->LanguageHandler = NULL;
+ }
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ status = context->Pc != context->Lr ?
+ STATUS_SUCCESS : STATUS_INVALID_DISPOSITION;
+ WARN( "exception data not found in %s for %p, LR %p, status %x\n",
+ debugstr_w(module->BaseDllName.Buffer), (void*) context->Pc,
+ (void*) context->Lr, status );
+ dispatch->EstablisherFrame = context->Sp;
+ dispatch->LanguageHandler = NULL;
+ context->Pc = context->Lr;
+ context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
+ return status;
+ }
+
+ dispatch->EstablisherFrame = context->Sp;
+ dispatch->LanguageHandler = NULL;
+ context->Pc = context->Lr;
+ context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
+ return STATUS_SUCCESS;
+}
+
+
+struct unwind_exception_frame
+{
+ EXCEPTION_REGISTRATION_RECORD frame;
+ DISPATCHER_CONTEXT *dispatch;
+};
+
+/**********************************************************************
+ * unwind_exception_handler
+ *
+ * Handler for exceptions happening while calling an unwind handler.
+ */
+static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
+ CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
+{
+ struct unwind_exception_frame *unwind_frame = (struct unwind_exception_frame *)frame;
+ DISPATCHER_CONTEXT *dispatch = (DISPATCHER_CONTEXT *)dispatcher;
+
+ /* copy the original dispatcher into the current one, except for the TargetIp */
+ dispatch->ControlPc = unwind_frame->dispatch->ControlPc;
+ dispatch->ImageBase = unwind_frame->dispatch->ImageBase;
+ dispatch->FunctionEntry = unwind_frame->dispatch->FunctionEntry;
+ dispatch->EstablisherFrame = unwind_frame->dispatch->EstablisherFrame;
+ dispatch->ContextRecord = unwind_frame->dispatch->ContextRecord;
+ dispatch->LanguageHandler = unwind_frame->dispatch->LanguageHandler;
+ dispatch->HandlerData = unwind_frame->dispatch->HandlerData;
+ dispatch->HistoryTable = unwind_frame->dispatch->HistoryTable;
+ dispatch->ScopeIndex = unwind_frame->dispatch->ScopeIndex;
+ TRACE( "detected collided unwind\n" );
+ return ExceptionCollidedUnwind;
+}
+
+/**********************************************************************
+ * call_unwind_handler
+ *
+ * Call a single unwind handler.
+ */
+static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
+{
+ struct unwind_exception_frame frame;
+ DWORD res;
+
+ frame.frame.Handler = unwind_exception_handler;
+ frame.dispatch = dispatch;
+ __wine_push_frame( &frame.frame );
+
+ TRACE( "calling handler %p (rec=%p, frame=0x%x context=%p, dispatch=%p)\n",
+ dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
+ res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
+ TRACE( "handler %p returned %x\n", dispatch->LanguageHandler, res );
+
+ __wine_pop_frame( &frame.frame );
+
+ switch (res)
+ {
+ case ExceptionContinueSearch:
+ case ExceptionCollidedUnwind:
+ break;
+ default:
+ raise_status( STATUS_INVALID_DISPOSITION, rec );
+ break;
+ }
+
+ return res;
+}
+
+
+/**********************************************************************
+ * call_teb_unwind_handler
*
- * Call the stack handlers chain.
+ * Call a single unwind handler from the TEB chain.
*/
-static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
+static DWORD call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
+ EXCEPTION_REGISTRATION_RECORD *teb_frame )
{
- EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
DWORD res;
- frame = NtCurrentTeb()->Tib.ExceptionList;
- nested_frame = NULL;
- while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
+ TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
+ teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, dispatch );
+ res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, (EXCEPTION_REGISTRATION_RECORD**)dispatch );
+ TRACE( "handler at %p returned %u\n", teb_frame->Handler, res );
+
+ switch (res)
{
- /* Check frame address */
- if (!is_valid_frame( frame ))
+ case ExceptionContinueSearch:
+ case ExceptionCollidedUnwind:
+ break;
+ default:
+ raise_status( STATUS_INVALID_DISPOSITION, rec );
+ break;
+ }
+
+ return res;
+}
+
+
+static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
+ CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
+{
+ if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
+ rec->ExceptionFlags |= EH_NESTED_CALL;
+
+ return ExceptionContinueSearch;
+}
+
+
+/**********************************************************************
+ * call_handler
+ *
+ * Call a single exception handler.
+ * FIXME: Handle nested exceptions.
+ */
+static DWORD call_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_CONTEXT *dispatch )
+{
+ EXCEPTION_REGISTRATION_RECORD frame;
+ DWORD res;
+
+ frame.Handler = nested_exception_handler;
+ __wine_push_frame( &frame );
+
+ TRACE( "calling handler %p (rec=%p, frame=0x%x context=%p, dispatch=%p)\n",
+ dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
+ res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, context, dispatch );
+ TRACE( "handler at %p returned %u\n", dispatch->LanguageHandler, res );
+
+ rec->ExceptionFlags &= EH_NONCONTINUABLE;
+ __wine_pop_frame( &frame );
+ return res;
+}
+
+
+/**********************************************************************
+ * call_teb_handler
+ *
+ * Call a single exception handler from the TEB chain.
+ * FIXME: Handle nested exceptions.
+ */
+static DWORD call_teb_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_CONTEXT *dispatch,
+ EXCEPTION_REGISTRATION_RECORD *teb_frame )
+{
+ DWORD res;
+
+ TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
+ teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, dispatch );
+ res = teb_frame->Handler( rec, teb_frame, context, (EXCEPTION_REGISTRATION_RECORD**)dispatch );
+ TRACE( "handler at %p returned %u\n", teb_frame->Handler, res );
+ return res;
+}
+
+
+/**********************************************************************
+ * call_function_handlers
+ *
+ * Call the per-function handlers.
+ */
+static NTSTATUS call_function_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
+{
+ EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
+ UNWIND_HISTORY_TABLE table;
+ DISPATCHER_CONTEXT dispatch;
+ CONTEXT context, prev_context;
+ NTSTATUS status;
+
+ context = *orig_context;
+ dispatch.TargetPc = 0;
+ dispatch.ContextRecord = &context;
+ dispatch.HistoryTable = &table;
+ prev_context = context;
+ dispatch.NonVolatileRegisters = (BYTE *)&prev_context.R4;
+
+ for (;;)
+ {
+ status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context );
+ if (status != STATUS_SUCCESS) return status;
+
+ unwind_done:
+ if (!dispatch.EstablisherFrame) break;
+
+ if (!is_valid_frame( dispatch.EstablisherFrame ))
{
+ ERR( "invalid frame %x (%p-%p)\n", dispatch.EstablisherFrame,
+ NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
rec->ExceptionFlags |= EH_STACK_INVALID;
break;
}
- /* Call handler */
- TRACE( "calling handler at %p code=%x flags=%x\n",
- frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
- res = frame->Handler( rec, frame, context, &dispatch );
- TRACE( "handler at %p returned %x\n", frame->Handler, res );
-
- if (frame == nested_frame)
+ if (dispatch.LanguageHandler)
{
- /* no longer nested */
- nested_frame = NULL;
- rec->ExceptionFlags &= ~EH_NESTED_CALL;
+ switch (call_handler( rec, orig_context, &dispatch ))
+ {
+ case ExceptionContinueExecution:
+ if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
+ return STATUS_SUCCESS;
+ case ExceptionContinueSearch:
+ break;
+ case ExceptionNestedException:
+ FIXME( "nested exception\n" );
+ break;
+ case ExceptionCollidedUnwind: {
+ ULONG_PTR frame;
+
+ context = *dispatch.ContextRecord;
+ dispatch.ContextRecord = &context;
+ RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
+ dispatch.ControlPc, dispatch.FunctionEntry,
+ &context, (PVOID *)&dispatch.HandlerData, &frame, NULL );
+ goto unwind_done;
+ }
+ default:
+ return STATUS_INVALID_DISPOSITION;
+ }
}
-
- switch(res)
+ /* hack: call wine handlers registered in the tib list */
+ else while ((DWORD)teb_frame < context.Sp)
{
- case ExceptionContinueExecution:
- if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
- return STATUS_NONCONTINUABLE_EXCEPTION;
- case ExceptionContinueSearch:
- break;
- case ExceptionNestedException:
- if (nested_frame < dispatch) nested_frame = dispatch;
- rec->ExceptionFlags |= EH_NESTED_CALL;
- break;
- default:
- return STATUS_INVALID_DISPOSITION;
+ TRACE( "found wine frame %p rsp %x handler %p\n",
+ teb_frame, context.Sp, teb_frame->Handler );
+ dispatch.EstablisherFrame = (DWORD)teb_frame;
+ switch (call_teb_handler( rec, orig_context, &dispatch, teb_frame ))
+ {
+ case ExceptionContinueExecution:
+ if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
+ return STATUS_SUCCESS;
+ case ExceptionContinueSearch:
+ break;
+ case ExceptionNestedException:
+ FIXME( "nested exception\n" );
+ break;
+ case ExceptionCollidedUnwind: {
+ ULONG_PTR frame;
+
+ context = *dispatch.ContextRecord;
+ dispatch.ContextRecord = &context;
+ RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
+ dispatch.ControlPc, dispatch.FunctionEntry,
+ &context, (PVOID *)&dispatch.HandlerData, &frame, NULL );
+ teb_frame = teb_frame->Prev;
+ goto unwind_done;
+ }
+ default:
+ return STATUS_INVALID_DISPOSITION;
+ }
+ teb_frame = teb_frame->Prev;
}
- frame = frame->Prev;
+
+ if (context.Sp == (DWORD)NtCurrentTeb()->Tib.StackBase) break;
+ prev_context = context;
}
return STATUS_UNHANDLED_EXCEPTION;
}
@@ -191,7 +477,7 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte
if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
NtContinue( context, FALSE );
- if ((status = call_stack_handlers( rec, context )) == STATUS_SUCCESS)
+ if ((status = call_function_handlers( rec, context )) == STATUS_SUCCESS)
NtContinue( context, FALSE );
if (status != STATUS_UNHANDLED_EXCEPTION) RtlRaiseStatus( status );
@@ -745,18 +1031,116 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PTR pc,
}
+/**********************************************************************
+ * call_consolidate_callback
+ *
+ * Wrapper function to call a consolidate callback from a fake frame.
+ * If the callback executes RtlUnwindEx (like for example done in C++ handlers),
+ * we have to skip all frames which were already processed. To do that we
+ * trick the unwinding functions into thinking the call came from somewhere
+ * else. All CFI instructions are either DW_CFA_def_cfa_expression or
+ * DW_CFA_expression, and the expressions have the following format:
+ *
+ * DW_OP_breg13; sleb128 <OFFSET> | Load SP + struct member offset
+ * [DW_OP_deref] | Dereference, only for CFA
+ */
+extern void * WINAPI call_consolidate_callback( CONTEXT *context,
+ void *(CALLBACK *callback)(EXCEPTION_RECORD *),
+ EXCEPTION_RECORD *rec );
+__ASM_GLOBAL_FUNC( call_consolidate_callback,
+ "push {r0-r2,lr}\n\t"
+ "sub sp, sp, #0x1a0\n\t"
+ "mov r1, r0\n\t"
+ "mov r0, sp\n\t"
+ "mov r2, #0x1a0\n\t"
+ "bl " __ASM_NAME("memcpy") "\n\t"
+ __ASM_CFI(".cfi_def_cfa 13, 0\n\t")
+ __ASM_CFI(".cfi_escape 0x0f,0x04,0x7d,0xb8,0x00,0x06\n\t") /* DW_CFA_def_cfa_expression: DW_OP_breg13 + 56, DW_OP_deref */
+ __ASM_CFI(".cfi_escape 0x10,0x04,0x02,0x7d,0x14\n\t") /* DW_CFA_expression: R4 DW_OP_breg13 + 20 */
+ __ASM_CFI(".cfi_escape 0x10,0x05,0x02,0x7d,0x18\n\t") /* DW_CFA_expression: R5 DW_OP_breg13 + 24 */
+ __ASM_CFI(".cfi_escape 0x10,0x06,0x02,0x7d,0x1c\n\t") /* DW_CFA_expression: R6 DW_OP_breg13 + 28 */
+ __ASM_CFI(".cfi_escape 0x10,0x07,0x02,0x7d,0x20\n\t") /* DW_CFA_expression: R7 DW_OP_breg13 + 32 */
+ __ASM_CFI(".cfi_escape 0x10,0x08,0x02,0x7d,0x24\n\t") /* DW_CFA_expression: R8 DW_OP_breg13 + 36 */
+ __ASM_CFI(".cfi_escape 0x10,0x09,0x02,0x7d,0x28\n\t") /* DW_CFA_expression: R9 DW_OP_breg13 + 40 */
+ __ASM_CFI(".cfi_escape 0x10,0x0a,0x02,0x7d,0x2c\n\t") /* DW_CFA_expression: R10 DW_OP_breg13 + 44 */
+ __ASM_CFI(".cfi_escape 0x10,0x0b,0x02,0x7d,0x30\n\t") /* DW_CFA_expression: R11 DW_OP_breg13 + 48 */
+ __ASM_CFI(".cfi_escape 0x10,0x0e,0x03,0x7d,0xc0,0x00\n\t") /* DW_CFA_expression: LR DW_OP_breg13 + 64 (PC) */
+ /* Libunwind doesn't support the registers D8-D15 like this */
+#if 0
+ __ASM_CFI(".cfi_escape 0x10,0x88,0x02,0x03,0x7d,0x90,0x01\n\t") /* DW_CFA_expression: D8 DW_OP_breg13 + 144 */
+ __ASM_CFI(".cfi_escape 0x10,0x89,0x02,0x03,0x7d,0x98,0x01\n\t") /* DW_CFA_expression: D9 DW_OP_breg13 + 152 */
+ __ASM_CFI(".cfi_escape 0x10,0x8a,0x02,0x03,0x7d,0xa0,0x01\n\t") /* DW_CFA_expression: D10 DW_OP_breg13 + 160 */
+ __ASM_CFI(".cfi_escape 0x10,0x8b,0x02,0x03,0x7d,0xa8,0x01\n\t") /* DW_CFA_expression: D11 DW_OP_breg13 + 168 */
+ __ASM_CFI(".cfi_escape 0x10,0x8c,0x02,0x03,0x7d,0xb0,0x01\n\t") /* DW_CFA_expression: D12 DW_OP_breg13 + 176 */
+ __ASM_CFI(".cfi_escape 0x10,0x8d,0x02,0x03,0x7d,0xb8,0x01\n\t") /* DW_CFA_expression: D13 DW_OP_breg13 + 184 */
+ __ASM_CFI(".cfi_escape 0x10,0x8e,0x02,0x03,0x7d,0xc0,0x01\n\t") /* DW_CFA_expression: D14 DW_OP_breg13 + 192 */
+ __ASM_CFI(".cfi_escape 0x10,0x8f,0x02,0x03,0x7d,0xc8,0x01\n\t") /* DW_CFA_expression: D15 DW_OP_breg13 + 200 */
+#endif
+ "ldrd r1, r2, [sp, #0x1a4]\n\t"
+ "mov r0, r2\n\t"
+ "blx r1\n\t"
+ "add sp, sp, #0x1ac\n\t"
+ "pop {pc}\n\t")
+
+
+
+/*******************************************************************
+ * RtlRestoreContext (NTDLL.@)
+ */
+void CDECL RtlRestoreContext( CONTEXT *context, EXCEPTION_RECORD *rec )
+{
+ EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
+
+ if (rec && rec->ExceptionCode == STATUS_LONGJUMP && rec->NumberParameters >= 1)
+ {
+ struct MSVCRT_JUMP_BUFFER *jmp = (struct MSVCRT_JUMP_BUFFER *)rec->ExceptionInformation[0];
+ int i;
+
+ for (i = 4; i <= 11; i++)
+ (&context->R4)[i-4] = (&jmp->R4)[i-4];
+ context->Lr = jmp->Pc;
+ context->Sp = jmp->Sp;
+ context->Fpscr = jmp->Fpscr;
+
+ for (i = 0; i < 8; i++)
+ context->u.D[8+i] = jmp->D[i];
+ }
+ else if (rec && rec->ExceptionCode == STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters >= 1)
+ {
+ PVOID (CALLBACK *consolidate)(EXCEPTION_RECORD *) = (void *)rec->ExceptionInformation[0];
+ TRACE( "calling consolidate callback %p (rec=%p)\n", consolidate, rec );
+ rec->ExceptionInformation[10] = (ULONG_PTR)&context->R4;
+
+ context->Pc = (DWORD)call_consolidate_callback( context, consolidate, rec );
+ }
+
+ /* hack: remove no longer accessible TEB frames */
+ while ((DWORD)teb_frame < context->Sp)
+ {
+ TRACE( "removing TEB frame: %p\n", teb_frame );
+ teb_frame = __wine_pop_frame( teb_frame );
+ }
+
+ TRACE( "returning to %x stack %x\n", context->Pc, context->Sp );
+ NtContinue( context, FALSE );
+}
+
+
/***********************************************************************
- * RtlUnwind (NTDLL.@)
+ * RtlUnwindEx (NTDLL.@)
*/
-void WINAPI RtlUnwind( void *endframe, void *target_ip, EXCEPTION_RECORD *rec, void *retval )
+void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec,
+ PVOID retval, CONTEXT *context, UNWIND_HISTORY_TABLE *table )
{
- CONTEXT context;
+ EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
EXCEPTION_RECORD record;
- EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
- DWORD res;
+ DISPATCHER_CONTEXT dispatch;
+ CONTEXT new_context;
+ NTSTATUS status;
+ DWORD i;
- RtlCaptureContext( &context );
- context.R0 = (DWORD)retval;
+ RtlCaptureContext( context );
+ new_context = *context;
/* build an exception record, if we do not have one */
if (!rec)
@@ -764,44 +1148,115 @@ void WINAPI RtlUnwind( void *endframe, void *target_ip, EXCEPTION_RECORD *rec, v
record.ExceptionCode = STATUS_UNWIND;
record.ExceptionFlags = 0;
record.ExceptionRecord = NULL;
- record.ExceptionAddress = (void *)context.Pc;
+ record.ExceptionAddress = (void *)context->Pc;
record.NumberParameters = 0;
rec = &record;
}
- rec->ExceptionFlags |= EH_UNWINDING | (endframe ? 0 : EH_EXIT_UNWIND);
-
- TRACE( "code=%x flags=%x\n", rec->ExceptionCode, rec->ExceptionFlags );
-
- /* get chain of exception frames */
- frame = NtCurrentTeb()->Tib.ExceptionList;
- while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != endframe))
+ rec->ExceptionFlags |= EH_UNWINDING | (end_frame ? 0 : EH_EXIT_UNWIND);
+
+ TRACE( "code=%x flags=%x end_frame=%p target_ip=%p pc=%08x\n",
+ rec->ExceptionCode, rec->ExceptionFlags, end_frame, target_ip, context->Pc );
+ for (i = 0; i < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); i++)
+ TRACE( " info[%d]=%016lx\n", i, rec->ExceptionInformation[i] );
+ TRACE(" r0=%08x r1=%08x r2=%08x r3=%08x\n",
+ context->R0, context->R1, context->R2, context->R3 );
+ TRACE(" r4=%08x r5=%08x r6=%08x r7=%08x\n",
+ context->R4, context->R5, context->R6, context->R7 );
+ TRACE(" r8=%08x r9=%08x r10=%08x r11=%08x\n",
+ context->R8, context->R9, context->R10, context->R11 );
+ TRACE(" r12=%08x sp=%08x lr=%08x pc=%08x\n",
+ context->R12, context->Sp, context->Lr, context->Pc );
+
+ dispatch.TargetPc = (ULONG_PTR)target_ip;
+ dispatch.ContextRecord = context;
+ dispatch.HistoryTable = table;
+ dispatch.NonVolatileRegisters = (BYTE *)&context->R4;
+
+ for (;;)
{
- /* Check frame address */
- if (endframe && ((void*)frame > endframe))
- raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
+ status = virtual_unwind( UNW_FLAG_UHANDLER, &dispatch, &new_context );
+ if (status != STATUS_SUCCESS) raise_status( status, rec );
- if (!is_valid_frame( frame )) raise_status( STATUS_BAD_STACK, rec );
+ unwind_done:
+ if (!dispatch.EstablisherFrame) break;
- /* Call handler */
- TRACE( "calling handler at %p code=%x flags=%x\n",
- frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
- res = frame->Handler(rec, frame, &context, &dispatch);
- TRACE( "handler at %p returned %x\n", frame->Handler, res );
-
- switch(res)
+ if (!is_valid_frame( dispatch.EstablisherFrame ))
{
- case ExceptionContinueSearch:
- break;
- case ExceptionCollidedUnwind:
- frame = dispatch;
- break;
- default:
- raise_status( STATUS_INVALID_DISPOSITION, rec );
+ ERR( "invalid frame %x (%p-%p)\n", dispatch.EstablisherFrame,
+ NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
+ rec->ExceptionFlags |= EH_STACK_INVALID;
break;
}
- frame = __wine_pop_frame( frame );
+
+ if (dispatch.LanguageHandler)
+ {
+ if (end_frame && (dispatch.EstablisherFrame > (DWORD)end_frame))
+ {
+ ERR( "invalid end frame %x/%p\n", dispatch.EstablisherFrame, end_frame );
+ raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
+ }
+ if (dispatch.EstablisherFrame == (DWORD)end_frame) rec->ExceptionFlags |= EH_TARGET_UNWIND;
+ if (call_unwind_handler( rec, &dispatch ) == ExceptionCollidedUnwind)
+ {
+ ULONG_PTR frame;
+
+ *context = new_context = *dispatch.ContextRecord;
+ dispatch.ContextRecord = context;
+ RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
+ dispatch.ControlPc, dispatch.FunctionEntry,
+ &new_context, &dispatch.HandlerData, &frame,
+ NULL );
+ rec->ExceptionFlags |= EH_COLLIDED_UNWIND;
+ goto unwind_done;
+ }
+ rec->ExceptionFlags &= ~EH_COLLIDED_UNWIND;
+ }
+ else /* hack: call builtin handlers registered in the tib list */
+ {
+ DWORD64 backup_frame = dispatch.EstablisherFrame;
+ while ((DWORD)teb_frame < new_context.Sp && (DWORD)teb_frame < (DWORD)end_frame)
+ {
+ TRACE( "found builtin frame %p handler %p\n", teb_frame, teb_frame->Handler );
+ dispatch.EstablisherFrame = (DWORD)teb_frame;
+ if (call_teb_unwind_handler( rec, &dispatch, teb_frame ) == ExceptionCollidedUnwind)
+ {
+ ULONG_PTR frame;
+
+ teb_frame = __wine_pop_frame( teb_frame );
+
+ *context = new_context = *dispatch.ContextRecord;
+ dispatch.ContextRecord = context;
+ RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
+ dispatch.ControlPc, dispatch.FunctionEntry,
+ &new_context, &dispatch.HandlerData,
+ &frame, NULL );
+ rec->ExceptionFlags |= EH_COLLIDED_UNWIND;
+ goto unwind_done;
+ }
+ teb_frame = __wine_pop_frame( teb_frame );
+ }
+ if ((DWORD)teb_frame == (DWORD)end_frame && (DWORD)end_frame < new_context.Sp) break;
+ dispatch.EstablisherFrame = backup_frame;
+ }
+
+ if (dispatch.EstablisherFrame == (DWORD)end_frame) break;
+ *context = new_context;
}
+
+ context->R0 = (DWORD)retval;
+ context->Pc = (DWORD)target_ip;
+ RtlRestoreContext(context, rec);
+}
+
+
+/***********************************************************************
+ * RtlUnwind (NTDLL.@)
+ */
+void WINAPI RtlUnwind( void *frame, void *target_ip, EXCEPTION_RECORD *rec, void *retval )
+{
+ CONTEXT context;
+ RtlUnwindEx( frame, target_ip, rec, retval, &context, NULL );
}
@@ -811,6 +1266,8 @@ void WINAPI RtlUnwind( void *endframe, void *target_ip, EXCEPTION_RECORD *rec, v
__ASM_STDCALL_FUNC( RtlRaiseException, 4,
"push {r0, lr}\n\t"
"sub sp, sp, #0x1a0\n\t" /* sizeof(CONTEXT) */
+ __ASM_CFI(".cfi_adjust_cfa_offset 424\n\t")
+ __ASM_CFI(".cfi_offset lr, -4\n\t")
"mov r0, sp\n\t" /* context */
"bl " __ASM_NAME("RtlCaptureContext") "\n\t"
"ldr r0, [sp, #0x1a0]\n\t" /* rec */
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index 1cc34a9218e..fc37f917219 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -51,6 +51,10 @@
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
+#ifdef HAVE_LIBUNWIND
+# define UNW_LOCAL_ONLY
+# include <libunwind.h>
+#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
@@ -217,13 +221,96 @@ static BOOL is_inside_syscall( ucontext_t *sigcontext )
(char *)SP_sig(sigcontext) <= (char *)arm_thread_data()->syscall_frame);
}
+extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, void *dispatcher );
/***********************************************************************
* unwind_builtin_dll
*/
NTSTATUS CDECL unwind_builtin_dll( ULONG type, struct _DISPATCHER_CONTEXT *dispatch, CONTEXT *context )
{
- return STATUS_UNSUCCESSFUL;
+#ifdef HAVE_LIBUNWIND
+ DWORD ip = context->Pc;
+ unw_context_t unw_context;
+ unw_cursor_t cursor;
+ unw_proc_info_t info;
+ int rc, i;
+
+ for (i = 0; i <= 12; i++)
+ unw_context.regs[i] = (&context->R0)[i];
+ unw_context.regs[13] = context->Sp;
+ unw_context.regs[14] = context->Lr;
+ unw_context.regs[15] = context->Pc;
+ rc = unw_init_local( &cursor, &unw_context );
+
+ if (rc != UNW_ESUCCESS)
+ {
+ WARN( "setup failed: %d\n", rc );
+ return STATUS_INVALID_DISPOSITION;
+ }
+ rc = unw_get_proc_info( &cursor, &info );
+ if (rc != UNW_ESUCCESS && rc != -UNW_ENOINFO)
+ {
+ WARN( "failed to get info: %d\n", rc );
+ return STATUS_INVALID_DISPOSITION;
+ }
+ if (rc == -UNW_ENOINFO || ip < info.start_ip || ip > info.end_ip)
+ {
+ TRACE( "no info found for %x ip %x-%x, assuming leaf function\n",
+ ip, info.start_ip, info.end_ip );
+ dispatch->LanguageHandler = NULL;
+ dispatch->EstablisherFrame = context->Sp;
+ context->Pc = context->Lr;
+ context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
+ return STATUS_SUCCESS;
+ }
+
+ TRACE( "ip %#x function %#lx-%#lx personality %#lx lsda %#lx fde %#lx\n",
+ ip, (unsigned long)info.start_ip, (unsigned long)info.end_ip, (unsigned long)info.handler,
+ (unsigned long)info.lsda, (unsigned long)info.unwind_info );
+
+ rc = unw_step( &cursor );
+ if (rc < 0)
+ {
+ WARN( "failed to unwind: %d %d\n", rc, UNW_ENOINFO );
+ return STATUS_INVALID_DISPOSITION;
+ }
+
+ dispatch->LanguageHandler = (void *)info.handler;
+ dispatch->HandlerData = (void *)info.lsda;
+ dispatch->EstablisherFrame = context->Sp;
+
+ for (i = 0; i <= 12; i++)
+ unw_get_reg( &cursor, UNW_ARM_R0 + i, (unw_word_t *)&(&context->R0)[i] );
+ unw_get_reg( &cursor, UNW_ARM_R13, (unw_word_t *)&context->Sp );
+ unw_get_reg( &cursor, UNW_ARM_R14, (unw_word_t *)&context->Lr );
+ unw_get_reg( &cursor, UNW_REG_IP, (unw_word_t *)&context->Pc );
+ context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
+
+ if ((info.start_ip & ~(unw_word_t)1) ==
+ ((unw_word_t)raise_func_trampoline & ~(unw_word_t)1)) {
+ /* raise_func_trampoline stores the original Lr at the bottom of the
+ * stack. The unwinder normally can't restore both Pc and Lr to
+ * individual values, thus do that manually here.
+ * (The function we unwind to might be a leaf function that hasn't
+ * backed up its own original Lr value on the stack.) */
+ const DWORD *orig_lr = (const DWORD *) dispatch->EstablisherFrame;
+ context->Lr = *orig_lr;
+ }
+
+ TRACE( "next function pc=%08x%s\n", context->Pc, rc ? "" : " (last frame)" );
+ TRACE(" r0=%08x r1=%08x r2=%08x r3=%08x\n",
+ context->R0, context->R1, context->R2, context->R3 );
+ TRACE(" r4=%08x r5=%08x r6=%08x r7=%08x\n",
+ context->R4, context->R5, context->R6, context->R7 );
+ TRACE(" r8=%08x r9=%08x r10=%08x r11=%08x\n",
+ context->R8, context->R9, context->R10, context->R11 );
+ TRACE(" r12=%08x sp=%08x lr=%08x pc=%08x\n",
+ context->R12, context->Sp, context->Lr, context->Pc );
+ return STATUS_SUCCESS;
+#else
+ ERR("libunwind not available, unable to unwind\n");
+ return STATUS_INVALID_DISPOSITION;
+#endif
}
@@ -467,6 +554,20 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
}
+__ASM_GLOBAL_FUNC( raise_func_trampoline,
+ "push {r12,lr}\n\t" /* (Padding +) Pc in the original frame */
+ "ldr r3, [r1, #0x38]\n\t" /* context->Sp */
+ "push {r3}\n\t" /* Original Sp */
+ __ASM_CFI(".cfi_escape 0x0f,0x03,0x7D,0x04,0x06\n\t") /* CFA, DW_OP_breg13 + 0x04, DW_OP_deref */
+ __ASM_CFI(".cfi_escape 0x10,0x0e,0x02,0x7D,0x0c\n\t") /* LR, DW_OP_breg13 + 0x0c */
+ /* We can't express restoring both Pc and Lr with CFI
+ * directives, but we manually load Lr from the stack
+ * in unwind_builtin_dll above. */
+ "ldr r3, [r1, #0x3c]\n\t" /* context->Lr */
+ "push {r3}\n\t" /* Original Lr */
+ "blx r2\n\t"
+ "udf #0")
+
/***********************************************************************
* setup_exception
*
@@ -500,11 +601,13 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
/* now modify the sigcontext to return to the raise function */
SP_sig(sigcontext) = (DWORD)stack;
- PC_sig(sigcontext) = (DWORD)pKiUserExceptionDispatcher;
+ LR_sig(sigcontext) = context.Pc;
+ PC_sig(sigcontext) = (DWORD)raise_func_trampoline;
if (PC_sig(sigcontext) & 1) CPSR_sig(sigcontext) |= 0x20;
else CPSR_sig(sigcontext) &= ~0x20;
REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for KiUserExceptionDispatcher */
REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for KiUserExceptionDispatcher */
+ REGn_sig(2, sigcontext) = (DWORD)pKiUserExceptionDispatcher;
}
--
2.25.1
Nov. 9, 2021
[PATCH 14/18] ntdll: Remove stack gap in syscalls on arm.
by Martin Storsjö
Store the original stack pointer (on entry to the syscall dispatcher)
in syscall_frame; the stack pointer itself is incremented by
"pop {r0-r3}" right before calling the syscall itself.
This fixes unwinding from functions set up by syscalls, like
KiUserExceptionDispatcher.
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
dlls/ntdll/unix/signal_arm.c | 4 +++-
tools/winebuild/import.c | 1 -
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index 88718e938a8..1cc34a9218e 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -1041,7 +1041,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"ldr r1, [r1, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
"add r0, r1, #0x10\n\t"
"stm r0, {r4-r12,lr}\n\t"
- "str sp, [r1, #0x38]\n\t"
+ "add r2, sp, #0x10\n\t"
+ "str r2, [r1, #0x38]\n\t"
"str r3, [r1, #0x3c]\n\t"
"mrs r0, CPSR\n\t"
"bfi r0, lr, #5, #1\n\t" /* set thumb bit */
@@ -1099,6 +1100,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"ldm r8, {r4-r12,pc}\n"
"5:\tmovw r0, #0x000d\n\t" /* STATUS_INVALID_PARAMETER */
"movt r0, #0xc000\n\t"
+ "add sp, sp, #0x10\n\t"
"b 4b\n"
__ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
"mov r8, r0\n\t"
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index 104397716f1..7972fc7b1d9 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -1492,7 +1492,6 @@ void output_syscalls( DLLSPEC *spec )
output( "\tmovw ip, #%u\n", id );
output( "\tmov r3, lr\n" );
output( "\tbl %s\n", asm_name("__wine_syscall") );
- output( "\tadd sp, #16\n" );
output( "\tbx lr\n" );
break;
case CPU_ARM64:
--
2.25.1
Nov. 9, 2021
[PATCH 13/18] ntdll: Include d0-d15 in RtlCaptureContext.
by Martin Storsjö
We ideally should back up all of d0-d31, but when building in ELF
form, only d0-d15 are normally available (with common distributions'
default compilers), unless object files are built with flags to enable
support for d16-d31 (with e.g. -mfpu=neon).
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
dlls/ntdll/signal_arm.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index 3bf8e19e126..a1a732201cf 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -75,6 +75,10 @@ __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
"str r1, [r0, #0x3c]\n\t" /* context->Lr */
"add r0, #0x0c\n\t"
"stm r0, {r2-r12}\n\t" /* context->R2..R12 */
+#ifndef __SOFTFP__
+ "add r0, #0x44\n\t" /* 0x50 - 0x0c */
+ "vstm r0, {d0-d15}\n\t" /* context->D0-D15 */
+#endif
"bx lr" )
--
2.25.1
Nov. 9, 2021
[PATCH 12/18] ntdll: Save context->Lr in the arm version of RtlRaiseException.
by Martin Storsjö
RtlCaptureContext doesn't set context->Lr, which is needed for
being able to unwind from the context.
This matches what is done in the arm64 version.
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
dlls/ntdll/signal_arm.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index 27e27deabfe..3bf8e19e126 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -811,6 +811,7 @@ __ASM_STDCALL_FUNC( RtlRaiseException, 4,
"bl " __ASM_NAME("RtlCaptureContext") "\n\t"
"ldr r0, [sp, #0x1a0]\n\t" /* rec */
"ldr r1, [sp, #0x1a4]\n\t"
+ "str r1, [sp, #0x3c]\n\t" /* context->Lr */
"str r1, [sp, #0x40]\n\t" /* context->Pc */
"mrs r2, CPSR\n\t"
"bfi r2, r1, #5, #1\n\t" /* Thumb bit */
--
2.25.1
Nov. 9, 2021
[PATCH 11/18] ntdll: Fix arm call_user_exception_dispatcher with kernel stack for syscalls.
by Martin Storsjö
This does the same as 23b44e8df62847872d036cd88d72e36b5424ee35,
but for arm:
Don't call KiUserExceptionDispatcher directly on the stack pointer
stored in the CONTEXT, but use the one stored in syscall_frame
(which includes the stack allocation in e.g. RtlRaiseException).
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
dlls/ntdll/unix/signal_arm.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index 798d7b9cc87..88718e938a8 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -563,12 +563,16 @@ void call_raise_user_exception_dispatcher(void)
NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
{
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
+ DWORD lr = frame->lr;
+ DWORD sp = frame->sp;
NTSTATUS status = NtSetContextThread( GetCurrentThread(), context );
if (status) return status;
frame->r0 = (DWORD)rec;
frame->r1 = (DWORD)context;
frame->pc = (DWORD)pKiUserExceptionDispatcher;
+ frame->lr = lr;
+ frame->sp = sp;
frame->restore_flags |= CONTEXT_INTEGER | CONTEXT_CONTROL;
return status;
}
--
2.25.1
Nov. 9, 2021
[PATCH 10/18] winedump: Rewrite dumping of packed ARM unwind info.
by Martin Storsjö
This differs slightly from the official docs (which is clear in some
places, vague in others, and contradictory in some places), based
on actual observed behaviour.
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
tools/winedump/pe.c | 146 ++++++++++++++++++--------------------------
1 file changed, 58 insertions(+), 88 deletions(-)
diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c
index 43ba0618615..6ff14f95791 100644
--- a/tools/winedump/pe.c
+++ b/tools/winedump/pe.c
@@ -787,7 +787,7 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
if (fnc->u.s.Flag)
{
char intregs[32] = {0}, intregspop[32] = {0}, vfpregs[32] = {0};
- WORD pf = 0, ef = 0, sc = 0;
+ WORD pf = 0, ef = 0, fpoffset = 0, stack = fnc->u.s.StackAdjust;
printf( "\nFunction %08x-%08x:\n", fnc->BeginAddress & ~1,
(fnc->BeginAddress & ~1) + fnc->u.s.FunctionLength * 2 );
@@ -805,86 +805,60 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
{
pf = fnc->u.s.StackAdjust & 0x04;
ef = fnc->u.s.StackAdjust & 0x08;
+ stack = (fnc->u.s.StackAdjust & 3) + 1;
}
- if (!fnc->u.s.R && !pf)
+ if (!fnc->u.s.R || pf)
{
- if (fnc->u.s.Reg)
+ int first = 4, last = fnc->u.s.Reg + 4;
+ if (pf)
{
- sprintf(intregs, "r4-r%u", fnc->u.s.Reg + 4);
- sprintf(intregspop, "r4-r%u", fnc->u.s.Reg + 4);
+ first = (~fnc->u.s.StackAdjust) & 3;
+ if (fnc->u.s.R)
+ last = 3;
}
+ if (first == last)
+ sprintf(intregs, "r%u", first);
else
- {
- strcpy(intregs, "r4");
- strcpy(intregspop, "r4");
- }
- sc = fnc->u.s.Reg + 1;
- if (fnc->u.s.C || fnc->u.s.L)
- {
- strcat(intregs, ", ");
- if (fnc->u.s.C || (fnc->u.s.L && !fnc->u.s.H))
- strcat(intregspop, ", ");
- }
+ sprintf(intregs, "r%u-r%u", first, last);
+ fpoffset = last + 1 - first;
}
- else if (fnc->u.s.R && pf)
+
+ if (!fnc->u.s.R || ef)
{
- if (((~fnc->u.s.StackAdjust) & 3) != 3)
+ int first = 4, last = fnc->u.s.Reg + 4;
+ if (ef)
{
- sprintf(intregs, "r%u-r3", (~fnc->u.s.StackAdjust) & 3);
- sprintf(intregspop, "r%u-r3", (~fnc->u.s.StackAdjust) & 3);
+ first = (~fnc->u.s.StackAdjust) & 3;
+ if (fnc->u.s.R)
+ last = 3;
}
+ if (first == last)
+ sprintf(intregspop, "r%u", first);
else
- {
- sprintf(intregs, "r3");
- sprintf(intregspop, "r3");
- }
- sc = 4 - ((~fnc->u.s.StackAdjust) & 3);
- if (fnc->u.s.C || fnc->u.s.L)
- {
- strcat(intregs, ", ");
- if (fnc->u.s.C || (fnc->u.s.L && !fnc->u.s.H))
- strcat(intregspop, ", ");
- }
- }
- else if (!fnc->u.s.R && pf)
- {
- sprintf(intregs, "r%u-r%u", (~fnc->u.s.StackAdjust) & 3, fnc->u.s.Reg + 4);
- sprintf(intregspop, "r%u-r%u", (~fnc->u.s.StackAdjust) & 3, fnc->u.s.Reg + 4);
- sc = fnc->u.s.Reg + 5 - ((~fnc->u.s.StackAdjust) & 3);
- if (fnc->u.s.C || fnc->u.s.L)
- {
- strcat(intregs, ", ");
- if (fnc->u.s.C || (fnc->u.s.L && !fnc->u.s.H))
- strcat(intregspop, ", ");
- }
- }
- else if (fnc->u.s.R && !pf)
- {
- if (!fnc->u.s.C && !fnc->u.s.L)
- {
- strcpy(intregs, "none");
- strcpy(intregspop, "none");
- }
+ sprintf(intregspop, "r%u-r%u", first, last);
}
- if (fnc->u.s.C && !fnc->u.s.L)
+ if (fnc->u.s.C)
{
+ if (intregs[0])
+ strcat(intregs, ", ");
+ if (intregspop[0])
+ strcat(intregspop, ", ");
strcat(intregs, "r11");
strcat(intregspop, "r11");
}
- else if (fnc->u.s.C && fnc->u.s.L)
- {
- strcat(intregs, "r11, lr");
- if (fnc->u.s.H)
- strcat(intregspop, "r11");
- else
- strcat(intregspop, "r11, pc");
- }
- else if (!fnc->u.s.C && fnc->u.s.L)
+ if (fnc->u.s.L)
{
+ if (intregs[0])
+ strcat(intregs, ", ");
strcat(intregs, "lr");
- if (!fnc->u.s.H)
+
+ if (intregspop[0] && (fnc->u.s.Ret != 0 || !fnc->u.s.H))
+ strcat(intregspop, ", ");
+ if (fnc->u.s.Ret != 0)
+ strcat(intregspop, "lr");
+ else if (!fnc->u.s.H)
strcat(intregspop, "pc");
}
@@ -895,46 +869,42 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
else
strcpy(vfpregs, "d8");
}
- else
- strcpy(vfpregs, "none");
- if (fnc->u.s.H)
- printf( " Unwind Code\tpush {r0-r3}\n" );
+ if (fnc->u.s.Flag == 1) {
+ if (fnc->u.s.H)
+ printf( " Unwind Code\tpush {r0-r3}\n" );
- if (fnc->u.s.R || fnc->u.s.L || fnc->u.s.C || pf)
- printf( " Unwind Code\tpush {%s}\n", intregs );
+ if (intregs[0])
+ printf( " Unwind Code\tpush {%s}\n", intregs );
- if (fnc->u.s.C && fnc->u.s.R && !fnc->u.s.L && !pf)
- printf( " Unwind Code\tmov r11, sp\n" );
- else if (fnc->u.s.C && (!fnc->u.s.R || fnc->u.s.L || pf))
- {
- if (fnc->u.s.StackAdjust >= 0x03f4 && !sc)
- printf( " Unwind Code\tadd r11, sp, #<unknown>\n");
- else if (fnc->u.s.StackAdjust >= 0x03f4)
- printf( " Unwind Code\tadd r11, sp, #%d\n", sc * 4 );
- else
- printf( " Unwind Code\tadd r11, sp, #%d\n", fnc->u.s.StackAdjust * 4 );
- }
+ if (fnc->u.s.C && fpoffset == 0)
+ printf( " Unwind Code\tmov r11, sp\n" );
+ else if (fnc->u.s.C)
+ printf( " Unwind Code\tadd r11, sp, #%d\n", fpoffset * 4 );
- if (fnc->u.s.R && fnc->u.s.Reg != 0x07)
- printf( " Unwind Code\tvpush {%s}\n", vfpregs );
+ if (fnc->u.s.R && fnc->u.s.Reg != 0x07)
+ printf( " Unwind Code\tvpush {%s}\n", vfpregs );
- if (fnc->u.s.StackAdjust < 0x03f4 && !pf)
- printf( " Unwind Code\tsub sp, sp, #%d\n", fnc->u.s.StackAdjust * 4 );
+ if (stack && !pf)
+ printf( " Unwind Code\tsub sp, sp, #%d\n", stack * 4 );
+ }
+ if (fnc->u.s.Ret == 3)
+ return;
+ printf( "Epilogue:\n" );
- if (fnc->u.s.StackAdjust < 0x03f4 && !ef)
- printf( " Unwind Code\tadd sp, sp, #%d\n", fnc->u.s.StackAdjust * 4 );
+ if (stack && !ef)
+ printf( " Unwind Code\tadd sp, sp, #%d\n", stack * 4 );
if (fnc->u.s.R && fnc->u.s.Reg != 0x07)
printf( " Unwind Code\tvpop {%s}\n", vfpregs );
- if (fnc->u.s.C || !fnc->u.s.R || ef || (fnc->u.s.L && !fnc->u.s.H))
+ if (intregspop[0])
printf( " Unwind Code\tpop {%s}\n", intregspop );
- if (fnc->u.s.H && !fnc->u.s.L)
+ if (fnc->u.s.H && !(fnc->u.s.L && fnc->u.s.Ret == 0))
printf( " Unwind Code\tadd sp, sp, #16\n" );
- else if (fnc->u.s.H && fnc->u.s.L)
+ else if (fnc->u.s.H && (fnc->u.s.L && fnc->u.s.Ret == 0))
printf( " Unwind Code\tldr pc, [sp], #20\n" );
if (fnc->u.s.Ret == 1)
--
2.25.1
Nov. 9, 2021
[PATCH 09/18] winedump: Fix printing of the prologue version of the "ldr lr, [sp], #offset" opcode.
by Martin Storsjö
This isn't mentioned in the documentation (which only writes out the
instruction that is executed while unwinding, i.e. the mirror form of
it), but a prologue version of this instruction would look like this.
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
tools/winedump/pe.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c
index 5d325fba3da..43ba0618615 100644
--- a/tools/winedump/pe.c
+++ b/tools/winedump/pe.c
@@ -1113,7 +1113,7 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
if (inepilogue)
printf( "ldr lr, [sp], #%u\n", (excode & 0x0f) * 4 );
else
- printf( "unknown 32\n" );
+ printf( "str lr, [sp, #-%u]!\n", (excode & 0x0f) * 4 );
}
else
printf( "unknown 32\n" );
--
2.25.1
Nov. 9, 2021
[PATCH 08/18] winedump: Distinguish between 16 and 32 bit nop opcodes in ARM unwind data.
by Martin Storsjö
Signed-off-by: Martin Storsjö <martin(a)martin.st>
---
tools/winedump/pe.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c
index 4629c3082f9..5d325fba3da 100644
--- a/tools/winedump/pe.c
+++ b/tools/winedump/pe.c
@@ -1171,13 +1171,20 @@ static void dump_armnt_unwind_info( const struct runtime_function_armnt *fnc )
excode = (code << 24) | (excodes[0] << 16) | (excodes[1] << 8) | excodes[2];
printf( "%s sp, sp, #%u\n", inepilogue ? "add" : "sub", (excode & 0xffffff) * 4 );
}
- else if (code <= 0xfc)
+ else if (code <= 0xfb)
printf( "nop\n" );
- else if (code <= 0xfe)
+ else if (code <= 0xfc)
+ printf( "nop.w\n" );
+ else if (code <= 0xfd)
{
printf( "(end) nop\n" );
inepilogue = TRUE;
}
+ else if (code <= 0xfe)
+ {
+ printf( "(end) nop.w\n" );
+ inepilogue = TRUE;
+ }
else
{
printf( "end\n" );
--
2.25.1
Nov. 9, 2021