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

Reply via email to