================
@@ -2944,8 +2950,14 @@ int UnwindCursor<A,
R>::stepThroughSigReturn(Registers_arm64 &) {
static_cast<pint_t>(i * 8));
_registers.setRegister(UNW_AARCH64_X0 + i, value);
}
- _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp));
- _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc));
+ uint64_t sp = _addressSpace.get64(sigctx + kOffsetSp);
+ uint64_t ip = _addressSpace.get64(sigctx + kOffsetPc);
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+ ip = (uint64_t)ptrauth_sign_unauthenticated((void *)ip,
+ ptrauth_key_return_address, sp);
----------------
atrosinenko wrote:
As far as I can see, this value is read from an `mcontext_t` structure written
to the stack by the Linux kernel itself. This is the value that was in IP at
the time regular execution flow was interrupted by the kernel to invoke SIGSEGV
handler.
Here is what I see in the debugger running inside QEMU just before SIGSEGV
(full system emulation, not qemu-user; simulated CPU is `neoverse-v1` and the
guest kernel is rebuilt with narrower virtual addresses / wider PAC field):
```
(gdb) x/7i Signaller
0x5555560ff0 <_Z9Signallerv>: pacibsp
0x5555560ff4 <_Z9Signallerv+4>: str x30, [sp, #-16]!
0x5555560ff8 <_Z9Signallerv+8>: adrp x8, 0x5555581000
0x5555560ffc <_Z9Signallerv+12>: ldr x8, [x8, #2408]
=> 0x5555561000 <_Z9Signallerv+16>: str xzr, [x8]
0x5555561004 <_Z9Signallerv+20>: ldr x30, [sp], #16
0x5555561008 <_Z9Signallerv+24>: retab
(gdb) p/x $sp
$1 = 0x7ffffff290
(gdb) p/x $lr
$2 = 0x28c6d555561040
```
After stepping to the next instruction, signal handler is invoked:
```
(gdb) x/4i $pc
=> 0x5555560f8c <_Z7Handleri>: pacibsp
0x5555560f90 <_Z7Handleri+4>: sub sp, sp, #0x30
0x5555560f94 <_Z7Handleri+8>: stp x29, x30, [sp, #32]
0x5555560f98 <_Z7Handleri+12>: add x29, sp, #0x20
(gdb) p/x $sp
$4 = 0x7fffffe030
(gdb) p/x $lr
$5 = 0x7ff7fbadc4
(gdb) x/2i $lr
0x7ff7fbadc4 <__restore_rt>: mov x8, #0x8b // #139
0x7ff7fbadc8 <__restore_rt+4>: svc #0x0
```
Note that SP was decremented by 0x1260 and LR was arranged so that when our
signal handler returns, execution is transferred to `__restore_rt` (as far as I
understand, in this particular case `__restore_rt` is implemented by musl libc
and its address is passed to the kernel in `sa_restorer` field of `struct
sigaction` by the libc itself). LR is not signed at this point but this is
correct: it is signed by the `Handler`'s prologue as usual. Invocation of
`Handler` is unwound as usual thanks to CFI information emitted for `Handler`
and then it is `__restore_rt` frame that `setInfoForSigReturn` and
`stepThroughSigReturn` deal with.
Here is what is stored on the stack (by the kernel, I assume) at several
offsets mentioned in `stepThroughSigReturn` function's implementation for
AArch64:
```
# SP:
(gdb) p/x *(uintptr_t *)($sp + 304 + 256)
$7 = 0x7ffffff290
# PC:
(gdb) p/x *(uintptr_t *)($sp + 304 + 264)
$8 = 0x5555561000
(gdb) x/3i 0x5555561000
0x5555561000 <_Z9Signallerv+16>: str xzr, [x8]
0x5555561004 <_Z9Signallerv+20>: ldr x30, [sp], #16
0x5555561008 <_Z9Signallerv+24>: retab
# LR:
(gdb) p/x *(uintptr_t *)($sp + 304 + 8 + 30 * 8)
$9 = 0x28c6d555561040
(gdb) x/4i (0x28c6d555561040 & 0x7fffffffff)
0x5555561040 <_Z6Calleri+52>: b 0x5555561044 <_Z6Calleri+56>
0x5555561044 <_Z6Calleri+56>: ldp x29, x30, [sp, #16]
0x5555561048 <_Z6Calleri+60>: add sp, sp, #0x20
0x555556104c <_Z6Calleri+64>: retab
```
The registers' values are stored exactly as they were immediately before the
execution of faulted `str` instruction.
https://github.com/llvm/llvm-project/pull/184661
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits