diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -2695,8 +2695,14 @@ // own restorer function, though, or user-mode QEMU might write a trampoline // onto the stack. const pint_t pc = static_cast(this->getReg(UNW_REG_IP)); - const uint16_t inst = _addressSpace.get16(pc); - if (inst == 0x0a77 || inst == 0x0aad) { + // The PC might contain an invalid address if the unwind info is bad, so + // directly accessing it could cause a segfault. Use process_vm_readv to + // read the memory safely instead. + uint16_t inst; + struct iovec local_iov = {&inst, sizeof inst}; + struct iovec remote_iov = {reinterpret_cast(pc), sizeof inst}; + long bytesRead = process_vm_readv(getpid(), &local_iov, 1, &remote_iov, 1, 0); + if (bytesRead == sizeof inst && (inst == 0x0a77 || inst == 0x0aad)) { _info = {}; _info.start_ip = pc; _info.end_ip = pc + 2; diff --git a/libunwind/test/bad_unwind_info.pass.cpp b/libunwind/test/bad_unwind_info.pass.cpp --- a/libunwind/test/bad_unwind_info.pass.cpp +++ b/libunwind/test/bad_unwind_info.pass.cpp @@ -10,7 +10,7 @@ // Ensure that libunwind doesn't crash on invalid info; the Linux aarch64 // sigreturn frame check would previously attempt to access invalid memory in // this scenario. -// REQUIRES: linux && (target={{aarch64-.+}} || target={{x86_64-.+}}) +// REQUIRES: linux && (target={{aarch64-.+}} || target={{s390x-.+}} || target={{x86_64-.+}}) // GCC doesn't support __attribute__((naked)) on AArch64. // UNSUPPORTED: gcc @@ -36,6 +36,20 @@ ".cfi_def_cfa_offset 0\n" ".cfi_restore x30\n" "ret\n"); +#elif defined(__s390x__) + __asm__("stmg %r14,%r15,112(%r15)\n" + "mvghi 104(%r15),4\n" + "# purposely use incorrect offset for %r14\n" + ".cfi_offset 14, -56\n" + ".cfi_offset 15, -40\n" + "lay %r15,-160(%r15)\n" + ".cfi_def_cfa_offset 320\n" + "brasl %r14,stepper\n" + "lmg %r14,%r15,272(%r15)\n" + ".cfi_restore 15\n" + ".cfi_restore 14\n" + ".cfi_def_cfa_offset 160\n" + "br %r14\n"); #elif defined(__x86_64__) __asm__("pushq %rbx\n" ".cfi_def_cfa_offset 16\n" @@ -48,7 +62,7 @@ ".cfi_def_cfa_offset 8\n" "ret\n"); #else -#error This test is only supported on aarch64 or x86-64 +#error This test is only supported on aarch64, s390x, or x86-64 #endif }