| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* | |
| * Sigreturn trampoline for returning from a signal when the SA_RESTORER | |
| * flag is not set. It serves primarily as a hall of shame for crappy | |
| * unwinders and features an exciting but mysterious NOP instruction. | |
| * | |
| * It's also fragile as hell, so please think twice before changing anything | |
| * in here. | |
| * | |
| * Copyright (C) 2012 ARM Limited | |
| * | |
| * Author: Will Deacon <will.deacon@arm.com> | |
| */ | |
| #include <linux/linkage.h> | |
| #include <asm/assembler.h> | |
| #include <asm/unistd.h> | |
| .text | |
| /* | |
| * NOTE!!! You may notice that all of the .cfi directives in this file have | |
| * been commented out. This is because they have been shown to trigger segfaults | |
| * in libgcc when unwinding out of a SIGCANCEL handler to invoke pthread | |
| * cleanup handlers during the thread cancellation dance. By omitting the | |
| * directives, we trigger an arm64-specific fallback path in the unwinder which | |
| * recognises the signal frame and restores many of the registers directly from | |
| * the sigcontext. Re-enabling the cfi directives here therefore needs to be | |
| * much more comprehensive to reduce the risk of further regressions. | |
| */ | |
| /* Ensure that the mysterious NOP can be associated with a function. */ | |
| // .cfi_startproc | |
| /* | |
| * .cfi_signal_frame causes the corresponding Frame Description Entry (FDE) in | |
| * the .eh_frame section to be annotated as a signal frame. This allows DWARF | |
| * unwinders (e.g. libstdc++) to implement _Unwind_GetIPInfo() and identify | |
| * the next frame using the unmodified return address instead of subtracting 1, | |
| * which may yield the wrong FDE. | |
| */ | |
| // .cfi_signal_frame | |
| /* | |
| * Tell the unwinder where to locate the frame record linking back to the | |
| * interrupted context. We don't provide unwind info for registers other than | |
| * the frame pointer and the link register here; in practice, this is likely to | |
| * be insufficient for unwinding in C/C++ based runtimes, especially without a | |
| * means to restore the stack pointer. Thankfully, unwinders and debuggers | |
| * already have baked-in strategies for attempting to unwind out of signals. | |
| */ | |
| // .cfi_def_cfa x29, 0 | |
| // .cfi_offset x29, 0 * 8 | |
| // .cfi_offset x30, 1 * 8 | |
| /* | |
| * This mysterious NOP is required for some unwinders (e.g. libc++) that | |
| * unconditionally subtract one from the result of _Unwind_GetIP() in order to | |
| * identify the calling function. | |
| * Hack borrowed from arch/powerpc/kernel/vdso64/sigtramp.S. | |
| */ | |
| nop // Mysterious NOP | |
| /* | |
| * GDB, libgcc and libunwind rely on being able to identify the sigreturn | |
| * instruction sequence to unwind from signal handlers. We cannot, therefore, | |
| * use SYM_FUNC_START() here, as it will emit a BTI C instruction and break the | |
| * unwinder. Thankfully, this function is only ever called from a RET and so | |
| * omitting the landing pad is perfectly fine. | |
| */ | |
| SYM_CODE_START(__kernel_rt_sigreturn) | |
| // PLEASE DO NOT MODIFY | |
| mov x8, #__NR_rt_sigreturn | |
| // PLEASE DO NOT MODIFY | |
| svc #0 | |
| // PLEASE DO NOT MODIFY | |
| // .cfi_endproc | |
| SYM_CODE_END(__kernel_rt_sigreturn) | |
| emit_aarch64_feature_1_and |