Skip to content

Commit 2871e9f

Browse files
[libunwind] Unwind through loongarch64/Linux sigreturn frame
Similar to D90898 (Linux AArch64), D124765 (SystemZ), and D148499 (RISCV). In this commit, I enabled two test cases, while zhuqizheng supported with the source code development. Co-Authored-By: zhuqizheng <[email protected]>
1 parent 6f0a627 commit 2871e9f

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

libunwind/src/UnwindCursor.hpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
#if defined(_LIBUNWIND_TARGET_LINUX) && \
3434
(defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || \
35-
defined(_LIBUNWIND_TARGET_S390X))
35+
defined(_LIBUNWIND_TARGET_S390X) || defined(_LIBUNWIND_TARGET_LOONGARCH))
3636
#include <errno.h>
3737
#include <signal.h>
3838
#include <sys/syscall.h>
@@ -1000,6 +1000,10 @@ class UnwindCursor : public AbstractUnwindCursor{
10001000
bool setInfoForSigReturn(Registers_riscv &);
10011001
int stepThroughSigReturn(Registers_riscv &);
10021002
#endif
1003+
#if defined(_LIBUNWIND_TARGET_LOONGARCH)
1004+
bool setInfoForSigReturn(Registers_loongarch &);
1005+
int stepThroughSigReturn(Registers_loongarch &);
1006+
#endif
10031007
#if defined(_LIBUNWIND_TARGET_S390X)
10041008
bool setInfoForSigReturn(Registers_s390x &);
10051009
int stepThroughSigReturn(Registers_s390x &);
@@ -2868,6 +2872,61 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_riscv &) {
28682872
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
28692873
// defined(_LIBUNWIND_TARGET_RISCV)
28702874

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+
28712930
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
28722931
defined(_LIBUNWIND_TARGET_S390X)
28732932
template <typename A, typename R>

libunwind/test/signal_unwind.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//===----------------------------------------------------------------------===//
99

1010
// Ensure that the unwinder can cope with the signal handler.
11-
// REQUIRES: target={{(aarch64|riscv64|s390x|x86_64)-.+linux.*}}
11+
// REQUIRES: target={{(aarch64|loongarch64|riscv64|s390x|x86_64)-.+linux.*}}
1212

1313
// TODO: Figure out why this fails with Memory Sanitizer.
1414
// XFAIL: msan

libunwind/test/unwind_leaffunction.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//===----------------------------------------------------------------------===//
99

1010
// Ensure that leaf function can be unwund.
11-
// REQUIRES: target={{(aarch64|riscv64|s390x|x86_64)-.+linux.*}}
11+
// REQUIRES: target={{(aarch64|loongarch64|riscv64|s390x|x86_64)-.+linux.*}}
1212

1313
// TODO: Figure out why this fails with Memory Sanitizer.
1414
// XFAIL: msan

0 commit comments

Comments
 (0)