ntdll: Fix unwind from call_consolidate_callback() for PE build on x64.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49698
Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2020-08-12 23:19:55 +03:00 committed by Alexandre Julliard
parent 76556bc588
commit c76dc32fef
1 changed files with 65 additions and 6 deletions

View File

@ -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"