|
32 | 32 |
|
33 | 33 | #if defined(_LIBUNWIND_TARGET_LINUX) && \ |
34 | 34 | (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || \ |
35 | | - defined(_LIBUNWIND_TARGET_S390X)) |
| 35 | + defined(_LIBUNWIND_TARGET_S390X) || defined(_LIBUNWIND_TARGET_LOONGARCH)) |
36 | 36 | #include <errno.h> |
37 | 37 | #include <signal.h> |
38 | 38 | #include <sys/syscall.h> |
@@ -1000,6 +1000,10 @@ class UnwindCursor : public AbstractUnwindCursor{ |
1000 | 1000 | bool setInfoForSigReturn(Registers_riscv &); |
1001 | 1001 | int stepThroughSigReturn(Registers_riscv &); |
1002 | 1002 | #endif |
| 1003 | +#if defined(_LIBUNWIND_TARGET_LOONGARCH) |
| 1004 | + bool setInfoForSigReturn(Registers_loongarch &); |
| 1005 | + int stepThroughSigReturn(Registers_loongarch &); |
| 1006 | +#endif |
1003 | 1007 | #if defined(_LIBUNWIND_TARGET_S390X) |
1004 | 1008 | bool setInfoForSigReturn(Registers_s390x &); |
1005 | 1009 | int stepThroughSigReturn(Registers_s390x &); |
@@ -2868,6 +2872,61 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_riscv &) { |
2868 | 2872 | #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && |
2869 | 2873 | // defined(_LIBUNWIND_TARGET_RISCV) |
2870 | 2874 |
|
| 2875 | +#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \ |
| 2876 | + defined(_LIBUNWIND_TARGET_LOONGARCH) |
| 2877 | +template <typename A, typename R> |
| 2878 | +bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_loongarch &) { |
| 2879 | + const pint_t pc = static_cast<pint_t>(getReg(UNW_REG_IP)); |
| 2880 | + // The PC might contain an invalid address if the unwind info is bad, so |
| 2881 | + // directly accessing it could cause a SIGSEGV. |
| 2882 | + if (!isReadableAddr(pc)) |
| 2883 | + return false; |
| 2884 | + const auto *instructions = reinterpret_cast<const uint32_t *>(pc); |
| 2885 | + // Look for the two instructions used in the sigreturn trampoline |
| 2886 | + // __vdso_rt_sigreturn: |
| 2887 | + // |
| 2888 | + // 0x03822c0b li a7,0x8b |
| 2889 | + // 0x002b0000 syscall 0 |
| 2890 | + if (instructions[0] != 0x03822c0b || instructions[1] != 0x002b0000) |
| 2891 | + return false; |
| 2892 | + |
| 2893 | + _info = {}; |
| 2894 | + _info.start_ip = pc; |
| 2895 | + _info.end_ip = pc + 4; |
| 2896 | + _isSigReturn = true; |
| 2897 | + return true; |
| 2898 | +} |
| 2899 | + |
| 2900 | +template <typename A, typename R> |
| 2901 | +int UnwindCursor<A, R>::stepThroughSigReturn(Registers_loongarch &) { |
| 2902 | + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: |
| 2903 | + // - 128-byte siginfo struct |
| 2904 | + // - ucontext_t struct: |
| 2905 | + // - 8-byte long (__uc_flags) |
| 2906 | + // - 8-byte pointer (*uc_link) |
| 2907 | + // - 24-byte uc_stack |
| 2908 | + // - 8-byte uc_sigmask |
| 2909 | + // - 120-byte of padding to allow sigset_t to be expanded in the future |
| 2910 | + // - 8 bytes of padding because sigcontext has 16-byte alignment |
| 2911 | + // - struct sigcontext uc_mcontext |
| 2912 | + // [1] |
| 2913 | + // https://github.com/torvalds/linux/blob/master/arch/loongarch/kernel/signal.c |
| 2914 | + const pint_t kOffsetSpToSigcontext = 128 + 8 + 8 + 24 + 8 + 128; |
| 2915 | + |
| 2916 | + const pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext; |
| 2917 | + _registers.setIP(_addressSpace.get64(sigctx)); |
| 2918 | + for (int i = UNW_LOONGARCH_R1; i <= UNW_LOONGARCH_R31; ++i) { |
| 2919 | + // skip R0 |
| 2920 | + uint64_t value = |
| 2921 | + _addressSpace.get64(sigctx + static_cast<pint_t>((i + 1) * 8)); |
| 2922 | + _registers.setRegister(i, value); |
| 2923 | + } |
| 2924 | + _isSignalFrame = true; |
| 2925 | + return UNW_STEP_SUCCESS; |
| 2926 | +} |
| 2927 | +#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && |
| 2928 | + // defined(_LIBUNWIND_TARGET_RISCV) |
| 2929 | + |
2871 | 2930 | #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \ |
2872 | 2931 | defined(_LIBUNWIND_TARGET_S390X) |
2873 | 2932 | template <typename A, typename R> |
|
0 commit comments