ntdll: Fix arm64 unwind across ELF/PE boundaries.

The previous implementation might have given the impression of
working, as long in some cases where the PE code actually used frame
pointers, but turned out to be subly wrong.

This essentially reverts the functional aspects of 1c9fdaab0f.

Use the new value of the Lr register, after fetching the registers
from unw_step, as the return value.

To make single-stepping unwinding work properly, treat the registers
consistently:

- Make RtlCaptureContext store the current values of x29/Fp and x30/Lr
from within the function, not the ones backed up from the stack.

- After unwinding one step, first fetch the new values of all registers,
including the new value of Lr - then use this value of Lr to set the
new value of Pc (the address to actually return to).

This makes the unwinding actually coherent in reading unwind opcodes and
return addresses from one single function; previously these were out of
sync where the return address ended up being read from the function
one step further up in the call stack.

This fixes unwinding for setjmp for binaries compiled with clang
(in mingw mode).

Signed-off-by: Martin Storsjo <martin@martin.st>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Martin Storsjo 2020-05-18 15:16:27 +03:00 committed by Alexandre Julliard
parent 2fb948e0ea
commit 93082b3d52
1 changed files with 2 additions and 3 deletions

View File

@ -265,8 +265,7 @@ __ASM_STDCALL_FUNC( RtlCaptureContext, 8,
"stp x23, x24, [x0, #0xc0]\n\t" /* context->X23,X24 */ "stp x23, x24, [x0, #0xc0]\n\t" /* context->X23,X24 */
"stp x25, x26, [x0, #0xd0]\n\t" /* context->X25,X26 */ "stp x25, x26, [x0, #0xd0]\n\t" /* context->X25,X26 */
"stp x27, x28, [x0, #0xe0]\n\t" /* context->X27,X28 */ "stp x27, x28, [x0, #0xe0]\n\t" /* context->X27,X28 */
"ldp x1, x2, [x29]\n\t" "stp x29, x30, [x0, #0xf0]\n\t" /* context->Fp,Lr */
"stp x1, x2, [x0, #0xf0]\n\t" /* context->Fp,Lr */
"add x1, x29, #0x10\n\t" "add x1, x29, #0x10\n\t"
"stp x1, x30, [x0, #0x100]\n\t" /* context->Sp,Pc */ "stp x1, x30, [x0, #0x100]\n\t" /* context->Sp,Pc */
"mov w1, #0x400000\n\t" /* CONTEXT_ARM64 */ "mov w1, #0x400000\n\t" /* CONTEXT_ARM64 */
@ -545,7 +544,6 @@ static NTSTATUS libunwind_virtual_unwind( ULONG_PTR ip, ULONG_PTR *frame, CONTEX
*handler = (void *)info.handler; *handler = (void *)info.handler;
*handler_data = (void *)info.lsda; *handler_data = (void *)info.lsda;
*frame = context->Sp; *frame = context->Sp;
context->Pc = context->u.s.Lr;
unw_get_reg( &cursor, UNW_AARCH64_X0, (unw_word_t *)&context->u.s.X0 ); unw_get_reg( &cursor, UNW_AARCH64_X0, (unw_word_t *)&context->u.s.X0 );
unw_get_reg( &cursor, UNW_AARCH64_X1, (unw_word_t *)&context->u.s.X1 ); unw_get_reg( &cursor, UNW_AARCH64_X1, (unw_word_t *)&context->u.s.X1 );
unw_get_reg( &cursor, UNW_AARCH64_X2, (unw_word_t *)&context->u.s.X2 ); unw_get_reg( &cursor, UNW_AARCH64_X2, (unw_word_t *)&context->u.s.X2 );
@ -578,6 +576,7 @@ static NTSTATUS libunwind_virtual_unwind( ULONG_PTR ip, ULONG_PTR *frame, CONTEX
unw_get_reg( &cursor, UNW_AARCH64_X29, (unw_word_t *)&context->u.s.Fp ); unw_get_reg( &cursor, UNW_AARCH64_X29, (unw_word_t *)&context->u.s.Fp );
unw_get_reg( &cursor, UNW_AARCH64_X30, (unw_word_t *)&context->u.s.Lr ); unw_get_reg( &cursor, UNW_AARCH64_X30, (unw_word_t *)&context->u.s.Lr );
unw_get_reg( &cursor, UNW_AARCH64_SP, (unw_word_t *)&context->Sp ); unw_get_reg( &cursor, UNW_AARCH64_SP, (unw_word_t *)&context->Sp );
context->Pc = context->u.s.Lr;
TRACE( "next function pc=%016lx%s\n", context->Pc, rc ? "" : " (last frame)" ); TRACE( "next function pc=%016lx%s\n", context->Pc, rc ? "" : " (last frame)" );
TRACE(" x0=%016lx x1=%016lx x2=%016lx x3=%016lx\n", TRACE(" x0=%016lx x1=%016lx x2=%016lx x3=%016lx\n",