[PATCH v2 3/3] ntdll: Save unwind information in KiUserApcDispatcher() on x64.
Paul Gofman
pgofman at codeweavers.com
Mon Sep 7 08:31:21 CDT 2020
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v2:
- fix saving unwind return address.
dlls/ntdll/tests/exception.c | 43 +++++++++++++++++++++++++++++++++
dlls/ntdll/thread.c | 28 ++++++++++++++++++++-
dlls/ntdll/unix/signal_x86_64.c | 27 ++++++++++++++++++---
3 files changed, 93 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 43c4859e005..d35f31f5fe3 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -37,6 +37,8 @@ static void *code_mem;
static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*);
static NTSTATUS (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*);
+static NTSTATUS (WINAPI *pNtQueueApcThread)(HANDLE handle, PNTAPCFUNC func,
+ ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3);
static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec);
static PVOID (WINAPI *pRtlUnwind)(PVOID, PVOID, PEXCEPTION_RECORD, PVOID);
static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*);
@@ -3953,6 +3955,45 @@ static void test_nested_exception(void)
ok(got_prev_frame_exception, "Did not get nested exception in the previous frame.\n");
}
+static CONTEXT test_unwind_apc_context;
+static BOOL test_unwind_apc_called;
+
+static void CALLBACK test_unwind_apc(ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3)
+{
+ EXCEPTION_RECORD rec;
+
+ test_unwind_apc_called = TRUE;
+ memset(&rec, 0, sizeof(rec));
+ pRtlUnwind((void *)test_unwind_apc_context.Rsp, (void *)test_unwind_apc_context.Rip, &rec, (void *)0xdeadbeef);
+ ok(0, "Should not get here.\n");
+}
+
+static void test_unwind_from_apc(void)
+{
+ NTSTATUS status;
+ int pass;
+
+ if (!pNtQueueApcThread)
+ {
+ win_skip("NtQueueApcThread is not available.\n");
+ return;
+ }
+
+ pass = 0;
+ InterlockedIncrement(&pass);
+ RtlCaptureContext(&test_unwind_apc_context);
+ InterlockedIncrement(&pass);
+
+ if (pass == 2)
+ {
+ test_unwind_apc_called = FALSE;
+ status = pNtQueueApcThread(GetCurrentThread(), test_unwind_apc, 0, 0, 0);
+ ok(!status, "Got unexpected status %#x.\n", status);
+ SleepEx(0, TRUE);
+ }
+ ok(pass == 3, "Got unexpected pass %d.\n", pass);
+ ok(test_unwind_apc_called, "Test user APC was not called.\n");
+}
#elif defined(__arm__)
static void test_thread_context(void)
@@ -7511,6 +7552,7 @@ START_TEST(exception)
#define X(f) p##f = (void*)GetProcAddress(hntdll, #f)
X(NtGetContextThread);
X(NtSetContextThread);
+ X(NtQueueApcThread);
X(NtReadVirtualMemory);
X(NtClose);
X(RtlUnwind);
@@ -7672,6 +7714,7 @@ START_TEST(exception)
skip( "Dynamic unwind functions not found\n" );
test_extended_context();
test_copy_context();
+ test_unwind_from_apc();
#elif defined(__aarch64__)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 0f31fe18a7d..6fae8771107 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -77,13 +77,39 @@ int __cdecl __wine_dbg_output( const char *str )
/*******************************************************************
* KiUserApcDispatcher (NTDLL.@)
*/
-void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+#ifdef __x86_64__
+void WINAPI dispatch_apc( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
PNTAPCFUNC func )
{
func( ctx, arg1, arg2 );
NtContinue( context, TRUE );
}
+__ASM_GLOBAL_FUNC( KiUserApcDispatcher,
+ "addq $0x8,%rsp\n\t"
+ "mov 0x98(%rcx),%r10\n\t" /* context->Rsp */
+ "mov 0xf8(%rcx),%r11\n\t" /* context->Rip */
+ "mov %r11,-0x8(%r10)\n\t"
+ "mov %rbp,-0x10(%r10)\n\t"
+ "lea -0x10(%r10),%rbp\n\t"
+ __ASM_SEH(".seh_pushreg %rbp\n\t")
+ __ASM_SEH(".seh_setframe %rbp,0\n\t")
+ __ASM_SEH(".seh_endprologue\n\t")
+ __ASM_CFI(".cfi_signal_frame\n\t")
+ __ASM_CFI(".cfi_adjust_cfa_offset 0x10\n\t")
+ __ASM_CFI(".cfi_def_cfa %rbp,0x10\n\t")
+ __ASM_CFI(".cfi_rel_offset %rip,0x8\n\t")
+ __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
+ "call " __ASM_NAME("dispatch_apc") "\n\t"
+ "int3")
+#else
+void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+ PNTAPCFUNC func )
+{
+ func( ctx, arg1, arg2 );
+ NtContinue( context, TRUE );
+}
+#endif
/***********************************************************************
* RtlExitUserThread (NTDLL.@)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 9d480f3ae28..5660cbc1dc8 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -1551,6 +1551,23 @@ static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcon
}
+/***********************************************************************
+ * set_nonvolatile_regs
+ */
+extern void WINAPI set_nonvolatile_regs( const CONTEXT *context );
+__ASM_GLOBAL_FUNC( set_nonvolatile_regs,
+ "movq 0x90(%rcx),%rbx\n\t" /* context->Rbx */
+ "movq 0xa0(%rcx),%rbp\n\t" /* context->Rbp */
+ "movq 0xa8(%rcx),%rsi\n\t" /* context->Rsi */
+ "movq 0xb0(%rcx),%rdi\n\t" /* context->Rdi */
+ "movq 0xd8(%rcx),%r12\n\t" /* context->R12 */
+ "movq 0xe0(%rcx),%r13\n\t" /* context->R13 */
+ "movq 0xe8(%rcx),%r14\n\t" /* context->R14 */
+ "movq 0xf0(%rcx),%r15\n\t" /* context->R15 */
+ "fxrstor 0x100(%rcx)\n\t" /* context->FltSave */
+ "ret" );
+
+
/***********************************************************************
* set_full_cpu_context
*
@@ -2014,14 +2031,15 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
*/
__ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
"movq 0x28(%rsp),%rsi\n\t" /* func */
- "movq 0x30(%rsp),%rdi\n\t" /* dispatcher */
+ "movq 0x30(%rsp),%r10\n\t" /* dispatcher */
"movq %gs:0x30,%rbx\n\t"
"jrcxz 1f\n\t"
"movq 0x98(%rcx),%rax\n\t" /* context_ptr->Rsp */
- "leaq -0x5c0(%rax),%rsp\n\t" /* sizeof(CONTEXT) + offsetof(frame,ret_addr) */
+ "leaq -0x5e0(%rax),%rsp\n\t" /* 0x20 (unwind regs space )
+ * + sizeof(CONTEXT) + offsetof(frame,ret_addr) */
"jmp 2f\n"
"1:\tmovq 0x328(%rbx),%rax\n\t" /* amd64_thread_data()->syscall_frame */
- "leaq -0x4d0(%rax),%rsp\n\t"
+ "leaq -0x4f0(%rax),%rsp\n\t" /* 0x20 (unwind regs space ) + sizeof(CONTEXT) */
"andq $~15,%rsp\n\t"
"movq %rdx,%r12\n\t" /* ctx */
"movq %r8,%r13\n\t" /* arg1 */
@@ -2039,7 +2057,8 @@ __ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
"movq %rsi,0x20(%rsp)\n\t" /* func */
"movq 0xa0(%rcx),%rbp\n\t" /* context.Rbp */
"pushq 0xf8(%rcx)\n\t" /* context.Rip */
- "jmp *%rdi" )
+ "call " __ASM_NAME("set_nonvolatile_regs") "\n\t"
+ "jmp *%r10" )
/***********************************************************************
--
2.26.2
More information about the wine-devel
mailing list