[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 <zhuqizheng@loongson.cn>

Co-authored-by: zhuqizheng <zhuqizheng@loongson.cn>
This commit is contained in:
Ami-zhang 2025-02-08 09:48:41 +08:00 committed by GitHub
parent 51ba9819b4
commit 12a154a94a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 4 deletions

View File

@ -31,8 +31,9 @@
#endif
#if defined(_LIBUNWIND_TARGET_LINUX) && \
(defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || \
defined(_LIBUNWIND_TARGET_S390X))
(defined(_LIBUNWIND_TARGET_AARCH64) || \
defined(_LIBUNWIND_TARGET_LOONGARCH) || \
defined(_LIBUNWIND_TARGET_RISCV) || defined(_LIBUNWIND_TARGET_S390X))
#include <errno.h>
#include <signal.h>
#include <sys/syscall.h>
@ -996,6 +997,10 @@ private:
bool setInfoForSigReturn(Registers_arm64 &);
int stepThroughSigReturn(Registers_arm64 &);
#endif
#if defined(_LIBUNWIND_TARGET_LOONGARCH)
bool setInfoForSigReturn(Registers_loongarch &);
int stepThroughSigReturn(Registers_loongarch &);
#endif
#if defined(_LIBUNWIND_TARGET_RISCV)
bool setInfoForSigReturn(Registers_riscv &);
int stepThroughSigReturn(Registers_riscv &);
@ -2815,6 +2820,61 @@ int UnwindCursor<A, R>::stepThroughSigReturn() {
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
// defined(_LIBUNWIND_TARGET_AARCH64)
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
defined(_LIBUNWIND_TARGET_LOONGARCH)
template <typename A, typename R>
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_loongarch &) {
const pint_t pc = static_cast<pint_t>(getReg(UNW_REG_IP));
// The PC might contain an invalid address if the unwind info is bad, so
// directly accessing it could cause a SIGSEGV.
if (!isReadableAddr(pc))
return false;
const auto *instructions = reinterpret_cast<const uint32_t *>(pc);
// Look for the two instructions used in the sigreturn trampoline
// __vdso_rt_sigreturn:
//
// 0x03822c0b li a7,0x8b
// 0x002b0000 syscall 0
if (instructions[0] != 0x03822c0b || instructions[1] != 0x002b0000)
return false;
_info = {};
_info.start_ip = pc;
_info.end_ip = pc + 4;
_isSigReturn = true;
return true;
}
template <typename A, typename R>
int UnwindCursor<A, R>::stepThroughSigReturn(Registers_loongarch &) {
// In the signal trampoline frame, sp points to an rt_sigframe[1], which is:
// - 128-byte siginfo struct
// - ucontext_t struct:
// - 8-byte long (__uc_flags)
// - 8-byte pointer (*uc_link)
// - 24-byte uc_stack
// - 8-byte uc_sigmask
// - 120-byte of padding to allow sigset_t to be expanded in the future
// - 8 bytes of padding because sigcontext has 16-byte alignment
// - struct sigcontext uc_mcontext
// [1]
// https://github.com/torvalds/linux/blob/master/arch/loongarch/kernel/signal.c
const pint_t kOffsetSpToSigcontext = 128 + 8 + 8 + 24 + 8 + 128;
const pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext;
_registers.setIP(_addressSpace.get64(sigctx));
for (int i = UNW_LOONGARCH_R1; i <= UNW_LOONGARCH_R31; ++i) {
// skip R0
uint64_t value =
_addressSpace.get64(sigctx + static_cast<pint_t>((i + 1) * 8));
_registers.setRegister(i, value);
}
_isSignalFrame = true;
return UNW_STEP_SUCCESS;
}
#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
// defined(_LIBUNWIND_TARGET_LOONGARCH)
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
defined(_LIBUNWIND_TARGET_RISCV)
template <typename A, typename R>

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
// Ensure that the unwinder can cope with the signal handler.
// REQUIRES: target={{(aarch64|riscv64|s390x|x86_64)-.+linux.*}}
// REQUIRES: target={{(aarch64|loongarch64|riscv64|s390x|x86_64)-.+linux.*}}
// TODO: Figure out why this fails with Memory Sanitizer.
// XFAIL: msan

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
// Ensure that leaf function can be unwund.
// REQUIRES: target={{(aarch64|riscv64|s390x|x86_64)-.+linux.*}}
// REQUIRES: target={{(aarch64|loongarch64|riscv64|s390x|x86_64)-.+linux.*}}
// TODO: Figure out why this fails with Memory Sanitizer.
// XFAIL: msan