Skip to content

Commit 12a154a

Browse files
[libunwind] Unwind through loongarch64/Linux sigreturn frame (#123682)
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]> Co-authored-by: zhuqizheng <[email protected]>
1 parent 51ba981 commit 12a154a

File tree

3 files changed

+64
-4
lines changed

3 files changed

+64
-4
lines changed

libunwind/src/UnwindCursor.hpp

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131
#endif
3232

3333
#if defined(_LIBUNWIND_TARGET_LINUX) && \
34-
(defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || \
35-
defined(_LIBUNWIND_TARGET_S390X))
34+
(defined(_LIBUNWIND_TARGET_AARCH64) || \
35+
defined(_LIBUNWIND_TARGET_LOONGARCH) || \
36+
defined(_LIBUNWIND_TARGET_RISCV) || defined(_LIBUNWIND_TARGET_S390X))
3637
#include <errno.h>
3738
#include <signal.h>
3839
#include <sys/syscall.h>
@@ -996,6 +997,10 @@ class UnwindCursor : public AbstractUnwindCursor{
996997
bool setInfoForSigReturn(Registers_arm64 &);
997998
int stepThroughSigReturn(Registers_arm64 &);
998999
#endif
1000+
#if defined(_LIBUNWIND_TARGET_LOONGARCH)
1001+
bool setInfoForSigReturn(Registers_loongarch &);
1002+
int stepThroughSigReturn(Registers_loongarch &);
1003+
#endif
9991004
#if defined(_LIBUNWIND_TARGET_RISCV)
10001005
bool setInfoForSigReturn(Registers_riscv &);
10011006
int stepThroughSigReturn(Registers_riscv &);
@@ -2815,6 +2820,61 @@ int UnwindCursor<A, R>::stepThroughSigReturn() {
28152820
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
28162821
// defined(_LIBUNWIND_TARGET_AARCH64)
28172822

2823+
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
2824+
defined(_LIBUNWIND_TARGET_LOONGARCH)
2825+
template <typename A, typename R>
2826+
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_loongarch &) {
2827+
const pint_t pc = static_cast<pint_t>(getReg(UNW_REG_IP));
2828+
// The PC might contain an invalid address if the unwind info is bad, so
2829+
// directly accessing it could cause a SIGSEGV.
2830+
if (!isReadableAddr(pc))
2831+
return false;
2832+
const auto *instructions = reinterpret_cast<const uint32_t *>(pc);
2833+
// Look for the two instructions used in the sigreturn trampoline
2834+
// __vdso_rt_sigreturn:
2835+
//
2836+
// 0x03822c0b li a7,0x8b
2837+
// 0x002b0000 syscall 0
2838+
if (instructions[0] != 0x03822c0b || instructions[1] != 0x002b0000)
2839+
return false;
2840+
2841+
_info = {};
2842+
_info.start_ip = pc;
2843+
_info.end_ip = pc + 4;
2844+
_isSigReturn = true;
2845+
return true;
2846+
}
2847+
2848+
template <typename A, typename R>
2849+
int UnwindCursor<A, R>::stepThroughSigReturn(Registers_loongarch &) {
2850+
// In the signal trampoline frame, sp points to an rt_sigframe[1], which is:
2851+
// - 128-byte siginfo struct
2852+
// - ucontext_t struct:
2853+
// - 8-byte long (__uc_flags)
2854+
// - 8-byte pointer (*uc_link)
2855+
// - 24-byte uc_stack
2856+
// - 8-byte uc_sigmask
2857+
// - 120-byte of padding to allow sigset_t to be expanded in the future
2858+
// - 8 bytes of padding because sigcontext has 16-byte alignment
2859+
// - struct sigcontext uc_mcontext
2860+
// [1]
2861+
// https://github.com/torvalds/linux/blob/master/arch/loongarch/kernel/signal.c
2862+
const pint_t kOffsetSpToSigcontext = 128 + 8 + 8 + 24 + 8 + 128;
2863+
2864+
const pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext;
2865+
_registers.setIP(_addressSpace.get64(sigctx));
2866+
for (int i = UNW_LOONGARCH_R1; i <= UNW_LOONGARCH_R31; ++i) {
2867+
// skip R0
2868+
uint64_t value =
2869+
_addressSpace.get64(sigctx + static_cast<pint_t>((i + 1) * 8));
2870+
_registers.setRegister(i, value);
2871+
}
2872+
_isSignalFrame = true;
2873+
return UNW_STEP_SUCCESS;
2874+
}
2875+
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
2876+
// defined(_LIBUNWIND_TARGET_LOONGARCH)
2877+
28182878
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
28192879
defined(_LIBUNWIND_TARGET_RISCV)
28202880
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)