From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52213 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54346 --- dlls/ntdll/unix/signal_x86_64.c | 103 ++++++++++++++++++++------------ dlls/ntdll/unix/thread.c | 7 ++- 2 files changed, 72 insertions(+), 38 deletions(-)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 1e4d43fd702..41bf1da8f68 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1650,13 +1650,15 @@ NTSTATUS KeUserModeCallback( ULONG id, const void *args, ULONG len, void **ret_p { struct syscall_frame *frame = amd64_thread_data()->syscall_frame; void *args_data = (void *)((frame->rsp - len) & ~15); + NTSTATUS status;
if ((char *)ntdll_get_thread_data()->kernel_stack + min_kernel_stack > (char *)&frame) return STATUS_STACK_OVERFLOW;
memcpy( args_data, args, len ); - return call_user_mode_callback( id, args_data, len, ret_ptr, ret_len, - pKiUserCallbackDispatcher, NtCurrentTeb() ); + status = call_user_mode_callback( id, args_data, len, ret_ptr, ret_len, pKiUserCallbackDispatcher, NtCurrentTeb() ); + if (status == STATUS_THREAD_IS_TERMINATING) abort_thread( 0 ); + return status; }
@@ -2100,10 +2102,17 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) * * Handler for SIGQUIT. */ -static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext ) +static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { + ucontext_t *ucontext = sigcontext; + struct syscall_frame *frame; + init_handler( ucontext ); - abort_thread(0); + + if (!is_inside_syscall( ucontext ) && (frame = amd64_thread_data()->syscall_frame)) + NtCallbackReturn( NULL, 0, STATUS_THREAD_IS_TERMINATING ); + + abort_thread( 0 ); }
@@ -2647,8 +2656,6 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "1:\txsave64 0xc0(%rcx)\n\t" "jmp 3f\n" "2:\tfxsave64 0xc0(%rcx)\n" - /* remember state when $rcx is pointing to "frame" */ - __ASM_CFI(".cfi_remember_state\n\t") "3:\tleaq 0x98(%rcx),%rbp\n\t" __ASM_CFI_CFA_IS_AT1(rbp, 0x70) __ASM_CFI_REG_IS_AT1(rsp, rbp, 0x70) @@ -2680,6 +2687,18 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "leaq 0x38(%rsp),%rsi\n\t" /* 7th argument */ /* switch to kernel stack */ "movq %rcx,%rsp\n\t" + /* we're now on the kernel stack, stitch unwind info with previous frame */ + __ASM_CFI_CFA_IS_AT1(rbp, 0x20) /* frame->syscall_cfa */ + __ASM_CFI_REG_IS_AT1(rsp, rbp, 0x20) + __ASM_CFI(".cfi_rel_offset %rip,-0x08\n\t") + __ASM_CFI(".cfi_rel_offset %rbp,-0x10\n\t") + __ASM_CFI(".cfi_rel_offset %rbx,-0x18\n\t") + __ASM_CFI(".cfi_rel_offset %r12,-0x20\n\t") + __ASM_CFI(".cfi_rel_offset %r13,-0x28\n\t") + __ASM_CFI(".cfi_rel_offset %r14,-0x30\n\t") + __ASM_CFI(".cfi_rel_offset %r15,-0x38\n\t") + __ASM_CFI(".cfi_undefined %rdi\n\t") + __ASM_CFI(".cfi_undefined %rsi\n\t") "movq 0x00(%rcx),%rax\n\t" "movq 0x18(%rcx),%r11\n\t" /* 2nd argument */ "movl %eax,%ebx\n\t" @@ -2709,8 +2728,6 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq (%rbx),%r10\n\t" /* table->ServiceTable */ "callq *(%r10,%rax,8)\n\t" "leaq -0x98(%rbp),%rcx\n\t" - /* $rcx is now pointing to "frame" again */ - __ASM_CFI(".cfi_restore_state\n") __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") ":\n\t" "movl 0xb4(%rcx),%edx\n\t" /* frame->restore_flags */ #ifdef __linux__ @@ -2764,30 +2781,36 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq 0x80(%rcx),%r11\n\t" /* frame->eflags */ "pushq %r11\n\t" "popfq\n\t" + + /* push kernel stack cfi */ + __ASM_CFI("\t.cfi_remember_state\n") /* switch to user stack */ "movq 0x88(%rcx),%rsp\n\t" - __ASM_CFI(".cfi_def_cfa rsp, 0\n\t") - __ASM_CFI(".cfi_same_value rsp\n\t") + __ASM_CFI(".cfi_def_cfa %rsp, 0\n\t") + __ASM_CFI(".cfi_same_value %rsp\n\t") + __ASM_CFI_REG_IS_AT2(rip, rcx, 0x70, 0x00) + __ASM_CFI(".cfi_undefined %rbp\n\t") + __ASM_CFI(".cfi_undefined %rbx\n\t") + __ASM_CFI(".cfi_undefined %r12\n\t") + __ASM_CFI(".cfi_undefined %r13\n\t") + __ASM_CFI(".cfi_same_value r14\n\t") + __ASM_CFI(".cfi_undefined %r15\n\t") + __ASM_CFI(".cfi_same_value rdi\n\t") + __ASM_CFI(".cfi_same_value rsi\n\t") "movq 0x70(%rcx),%rcx\n\t" /* frame->rip */ __ASM_CFI(".cfi_register rip, rcx\n\t") "pushq %rcx\n\t" __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") "ret\n\t" - /* $rcx is now pointing to "frame" again */ - __ASM_CFI(".cfi_restore_state\n\t") - /* remember state when $rcx is pointing to "frame" */ - __ASM_CFI(".cfi_remember_state\n\t") + /* pop kernel stack cfi */ + __ASM_CFI("\t.cfi_restore_state\n") + "1:\tleaq 0x70(%rcx),%rsp\n\t" - __ASM_CFI_CFA_IS_AT1(rsp, 0x18) - __ASM_CFI_REG_IS_AT1(rsp, rsp, 0x18) - __ASM_CFI_REG_IS_AT1(rip, rsp, 0x00) "testl $0x2,%edx\n\t" /* CONTEXT_INTEGER */ "jnz 1f\n\t" "movq 0x10(%rsp),%r11\n\t" /* frame->eflags */ "movq (%rsp),%rcx\n\t" /* frame->rip */ - __ASM_CFI(".cfi_register rip, rcx\n\t") "iretq\n" - __ASM_CFI_REG_IS_AT1(rip, rsp, 0x00) "1:\tmovq 0x00(%rcx),%rax\n\t" "movq 0x18(%rcx),%rdx\n\t" "movq 0x30(%rcx),%r8\n\t" @@ -2796,21 +2819,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq 0x48(%rcx),%r11\n\t" "movq 0x10(%rcx),%rcx\n" "iretq\n" - __ASM_CFI_CFA_IS_AT1(rbp, 0x70) - __ASM_CFI_REG_IS_AT1(rsp, rbp, 0x70) - __ASM_CFI_REG_IS_AT1(rip, rbp, 0x58) - __ASM_CFI_REG_IS_AT2(rbx, rbp, 0xf0, 0x7e) - __ASM_CFI_REG_IS_AT2(rsi, rbp, 0x88, 0x7f) - __ASM_CFI_REG_IS_AT2(rdi, rbp, 0x90, 0x7f) - __ASM_CFI_REG_IS_AT2(r12, rbp, 0xb8, 0x7f) - __ASM_CFI_REG_IS_AT1(r13, rbp, 0x40) - __ASM_CFI_REG_IS_AT1(r14, rbp, 0x48) - __ASM_CFI_REG_IS_AT1(r15, rbp, 0x50) - __ASM_CFI_REG_IS_AT1(rbp, rbp, 0x00) "5:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */ "movq %rsp,%rcx\n\t" - /* $rcx is now pointing to "frame" again */ - __ASM_CFI(".cfi_restore_state\n\t") "jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t" ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n" __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t" @@ -2884,9 +2894,22 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, #endif /* switch to kernel stack */ "movq %rcx,%rsp\n" + /* we're now on the kernel stack, stitch unwind info with previous frame */ + __ASM_CFI_CFA_IS_AT2(rsp, 0xb8, 0x01) /* frame->syscall_cfa */ + __ASM_CFI_REG_IS_AT2(rsp, rsp, 0xb8, 0x01) + __ASM_CFI(".cfi_rel_offset %rip,-0x08\n\t") + __ASM_CFI(".cfi_rel_offset %rbp,-0x10\n\t") + __ASM_CFI(".cfi_rel_offset %rbx,-0x18\n\t") + __ASM_CFI(".cfi_rel_offset %r12,-0x20\n\t") + __ASM_CFI(".cfi_rel_offset %r13,-0x28\n\t") + __ASM_CFI(".cfi_rel_offset %r14,-0x30\n\t") + __ASM_CFI(".cfi_rel_offset %r15,-0x38\n\t") + __ASM_CFI(".cfi_undefined %rdi\n\t") + __ASM_CFI(".cfi_undefined %rsi\n\t") "movq %r8,%rdi\n\t" /* args */ "callq *(%r10,%rdx,8)\n\t" "movq %rsp,%rcx\n" + "movq 0x98(%rcx),%rbp\n\t" "movdqa 0x1c0(%rcx),%xmm6\n\t" "movdqa 0x1d0(%rcx),%xmm7\n\t" "movdqa 0x1e0(%rcx),%xmm8\n\t" @@ -2906,15 +2929,21 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, "1:\n\t" #endif "movq 0x60(%rcx),%r14\n\t" - __ASM_CFI(".cfi_same_value r14\n\t") "movq 0x28(%rcx),%rdi\n\t" - __ASM_CFI(".cfi_same_value rdi\n\t") "movq 0x20(%rcx),%rsi\n\t" /* switch to user stack */ - __ASM_CFI(".cfi_same_value rsi\n\t") "movq 0x88(%rcx),%rsp\n\t" - __ASM_CFI(".cfi_def_cfa rsp, 0\n\t") - __ASM_CFI(".cfi_same_value rsp\n\t") + __ASM_CFI(".cfi_def_cfa %rsp, 0\n\t") + __ASM_CFI(".cfi_same_value %rsp\n\t") + __ASM_CFI_REG_IS_AT2(rip, rcx, 0x70, 0x00) + __ASM_CFI(".cfi_undefined %rbp\n\t") + __ASM_CFI(".cfi_undefined %rbx\n\t") + __ASM_CFI(".cfi_undefined %r12\n\t") + __ASM_CFI(".cfi_undefined %r13\n\t") + __ASM_CFI(".cfi_same_value r14\n\t") + __ASM_CFI(".cfi_undefined %r15\n\t") + __ASM_CFI(".cfi_same_value rdi\n\t") + __ASM_CFI(".cfi_same_value rsi\n\t") "pushq 0x70(%rcx)\n\t" /* frame->rip */ __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") "ret" ) diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 2a9bc41e788..04cdcba41ed 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1078,7 +1078,7 @@ static void contexts_from_server( CONTEXT *context, context_t server_contexts[2] /*********************************************************************** * pthread_exit_wrapper */ -static void pthread_exit_wrapper( int status ) +static DECLSPEC_NORETURN void pthread_exit_wrapper( int status ) { close( ntdll_get_thread_data()->wait_fd[0] ); close( ntdll_get_thread_data()->wait_fd[1] ); @@ -1404,7 +1404,12 @@ void abort_thread( int status ) { pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); if (InterlockedDecrement( &nb_threads ) <= 0) abort_process( status ); + +#if defined(__x86_64__) + pthread_exit_wrapper( status ); +#else signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() ); +#endif }