Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49698 Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/signal_x86_64.c | 71 ++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 3ed89526893..28e4ec8ca6c 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -1011,8 +1011,8 @@ static DWORD call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT * 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 + * trick the unwinding functions into thinking the call came from the specified + * context. All CFI instructions are either DW_CFA_def_cfa_expression or * DW_CFA_expression, and the expressions have the following format: * * DW_OP_breg6; sleb128 0x10 | Load %rbp + 0x10 @@ -1025,15 +1025,26 @@ extern void * WINAPI call_consolidate_callback( CONTEXT *context, EXCEPTION_RECORD *rec ); __ASM_GLOBAL_FUNC( call_consolidate_callback, "pushq %rbp\n\t" - __ASM_SEH(".seh_pushreg %rbp\n\t") __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") __ASM_CFI(".cfi_rel_offset %rbp,0\n\t") "movq %rsp,%rbp\n\t" - __ASM_SEH(".seh_setframe %rbp,0\n\t") __ASM_CFI(".cfi_def_cfa_register %rbp\n\t") - "subq $0x20,%rsp\n\t" - __ASM_SEH(".seh_stackalloc 0x20\n\t") + + /* Setup SEH machine frame. */ + "subq $0x28,%rsp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t") + "movq 0xf8(%rcx),%rax\n\t" /* Context->Rip */ + "movq %rax,(%rsp)\n\t" + "movq 0x98(%rcx),%rax\n\t" /* context->Rsp */ + "movq %rax,0x18(%rsp)\n\t" + __ASM_SEH(".seh_pushframe\n\t") __ASM_SEH(".seh_endprologue\n\t") + + "subq $0xf8,%rsp\n\t" /* 10*16 (float regs) + 7*8 (int regs) + 32 (shadow store). */ + __ASM_SEH(".seh_stackalloc 0xf8\n\t") + __ASM_CFI(".cfi_adjust_cfa_offset 0xf8\n\t") + + /* Setup CFI unwind to context. */ "movq %rcx,0x10(%rbp)\n\t" __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_escape 0x0f,0x07,0x76,0x10,0x06,0x23,0x98,0x01,0x06\n\t") /* CFA */ @@ -1056,9 +1067,57 @@ __ASM_GLOBAL_FUNC( call_consolidate_callback, __ASM_CFI(".cfi_escape 0x10,0x1e,0x06,0x76,0x10,0x06,0x23,0xf0,0x04\n\t") /* %xmm13 */ __ASM_CFI(".cfi_escape 0x10,0x1f,0x06,0x76,0x10,0x06,0x23,0x80,0x05\n\t") /* %xmm14 */ __ASM_CFI(".cfi_escape 0x10,0x20,0x06,0x76,0x10,0x06,0x23,0x90,0x05\n\t") /* %xmm15 */ + + /* Setup SEH unwind registers restore. */ + "movq 0x90(%rcx),%rax\n\t" /* context->Rbx */ + "movq %rax,0x20(%rsp)\n\t" + __ASM_SEH(".seh_savereg %rbx, 0x20\n\t") + "movq 0xa8(%rcx),%rax\n\t" /* context->Rsi */ + "movq %rax,0x28(%rsp)\n\t" + __ASM_SEH(".seh_savereg %rsi, 0x28\n\t") + "movq 0xb0(%rcx),%rax\n\t" /* context->Rdi */ + "movq %rax,0x30(%rsp)\n\t" + __ASM_SEH(".seh_savereg %rdi, 0x30\n\t") + + "movq 0xd8(%rcx),%rax\n\t" /* context->R12 */ + "movq %rax,0x38(%rsp)\n\t" + __ASM_SEH(".seh_savereg %r12, 0x38\n\t") + "movq 0xe0(%rcx),%rax\n\t" /* context->R13 */ + "movq %rax,0x40(%rsp)\n\t" + __ASM_SEH(".seh_savereg %r13, 0x40\n\t") + "movq 0xe8(%rcx),%rax\n\t" /* context->R14 */ + "movq %rax,0x48(%rsp)\n\t" + __ASM_SEH(".seh_savereg %r14, 0x48\n\t") + "movq 0xf0(%rcx),%rax\n\t" /* context->R15 */ + "movq %rax,0x50(%rsp)\n\t" + __ASM_SEH(".seh_savereg %r15, 0x50\n\t") + "pushq %rsi\n\t" + "pushq %rdi\n\t" + "leaq 0x200(%rcx),%rsi\n\t" + "leaq 0x60(%rsp),%rdi\n\t" + "movq $0x14,%rcx\n\t" + "cld\n\t" + "rep; movsq\n\t" + "popq %rdi\n\t" + "popq %rsi\n\t" + __ASM_SEH(".seh_savexmm %xmm6, 0x60\n\t") + __ASM_SEH(".seh_savexmm %xmm7, 0x70\n\t") + __ASM_SEH(".seh_savexmm %xmm8, 0x80\n\t") + __ASM_SEH(".seh_savexmm %xmm9, 0x90\n\t") + __ASM_SEH(".seh_savexmm %xmm10, 0xa0\n\t") + __ASM_SEH(".seh_savexmm %xmm11, 0xb0\n\t") + __ASM_SEH(".seh_savexmm %xmm12, 0xc0\n\t") + __ASM_SEH(".seh_savexmm %xmm13, 0xd0\n\t") + __ASM_SEH(".seh_savexmm %xmm14, 0xe0\n\t") + __ASM_SEH(".seh_savexmm %xmm15, 0xf0\n\t") + + /* call the callback. */ "movq %r8,%rcx\n\t" "callq *%rdx\n\t" __ASM_CFI(".cfi_restore_state\n\t") + "nop\n\t" /* Otherwise RtlVirtualUnwind() will think we are inside epilogue and + * interpret / execute the rest of opcodes here instead of unwind through + * machine frame. */ "leaq 0(%rbp),%rsp\n\t" __ASM_CFI(".cfi_def_cfa_register %rsp\n\t") "popq %rbp\n\t"