From 8c24c695052d156fd1322d6dacfab117b92cb175 Mon Sep 17 00:00:00 2001 From: Shawn Anastasio Date: Thu, 30 Aug 2018 17:32:05 -0500 Subject: [PATCH] Implement support for PPC64 on Linux This patch implements support for the PPC64 architecture on Linux hosts. --- CONTRIBUTORS | 1 + minidump/minidump_context.h | 64 ++++++ minidump/minidump_context_writer.cc | 50 +++++ minidump/minidump_context_writer.h | 39 ++++ minidump/minidump_context_writer_test.cc | 15 ++ minidump/minidump_misc_info_writer.cc | 2 + minidump/test/minidump_context_test_util.cc | 67 ++++++ minidump/test/minidump_context_test_util.h | 3 + snapshot/capture_memory.cc | 5 + snapshot/cpu_architecture.h | 5 +- snapshot/cpu_context.cc | 5 + snapshot/cpu_context.h | 19 ++ snapshot/linux/cpu_context_linux.h | 73 ++++++ snapshot/linux/debug_rendezvous_test.cc | 4 +- snapshot/linux/exception_snapshot_linux.cc | 63 ++++++ snapshot/linux/exception_snapshot_linux.h | 2 + .../linux/exception_snapshot_linux_test.cc | 21 ++ snapshot/linux/process_reader_linux.cc | 2 + snapshot/linux/signal_context.h | 83 +++++++ snapshot/linux/system_snapshot_linux.cc | 11 + snapshot/linux/thread_snapshot_linux.cc | 8 + snapshot/linux/thread_snapshot_linux.h | 2 + snapshot/test/test_cpu_context.cc | 33 +++ snapshot/test/test_cpu_context.h | 1 + test/linux/get_tls.cc | 2 + test/multiprocess_posix.cc | 3 +- util/linux/auxiliary_vector.cc | 5 + util/linux/ptracer.cc | 61 +++++ util/linux/thread_info.h | 55 +++++ util/misc/capture_context.h | 1 + util/misc/capture_context_linux.S | 212 +++++++++++++++++- util/misc/capture_context_test.cc | 3 +- util/misc/capture_context_test_util_linux.cc | 6 + 36 files changed, 932 insertions(+), 12 deletions(-) --- a/third_party/crashpad/crashpad/CONTRIBUTORS +++ b/third_party/crashpad/crashpad/CONTRIBUTORS @@ -13,3 +13,5 @@ Mark Mentovai Robert Sesek Scott Graham Joshua Peraza +Shawn Anastasio +Timothy Pearson --- a/third_party/crashpad/crashpad/minidump/minidump_context.h +++ b/third_party/crashpad/crashpad/minidump/minidump_context.h @@ -687,6 +687,70 @@ struct MinidumpContextRISCV64 { uint32_t fcsr; }; +//! \brief ppc64-specific flags for MinidumpPPC64::context_flags +//! Based on minidump_cpu_ppc64.h from breakpad +enum MinidumpContextPPC64Flags : uint32_t { + //! \brief Identifies the context as PPC64. + kMinidumpContextPPC64 = 0x01000000, + + //! \brief Indicates the validity of general purpose registers. + //! + //! Registers `r0`-`r31`, `nip`, `msr`, `lr`, etc. are valid. + kMinidumpContextPPC64Base = kMinidumpContextPPC64 | 0x00000001, + + //! \brief Indicates the validity of floating point registers. + //! + //! Registers `fp0`-`fp31`, `fpscr` are valid. + kMinidumpContextPPC64Floating = kMinidumpContextPPC64 | 0x00000008, + + //! \brief Indicates the validity of Altivec/VMX registers. + //! + //! Registers `v0`-`v31`, `vscr`, `vrsave`. + kMinidumpContextPPC64Vector = kMinidumpContextPPC64 | 0x00000020, + + //! \brief Indicates the validity of all registers + kMinidumpContextPPC64All = kMinidumpContextPPC64Base | + kMinidumpContextPPC64Floating | + kMinidumpContextPPC64Vector +}; + +//! \brief A PPC64 CPU context carried in a minidump file. +//! Based on minidump_cpu_ppc64.h from breakpad. +struct MinidumpContextPPC64 { + uint64_t context_flags; + + //! \brief General purpose registers. + uint64_t nip; + uint64_t msr; + uint64_t regs[32]; + uint64_t ccr; + uint64_t xer; + uint64_t lnk; + uint64_t ctr; + + //! \brief Floating point registers. + double fpregs[32]; + + //! \brief FPU status register. + double fpscr; + + //! \brief Altivec/VMX vector registers. + struct { + //! \brief Vector registers are 128bits. + uint128_struct save_vr[32]; + uint128_struct save_vscr; + + //! \brief Padding included for breakpad compatibiltiy. + uint32_t save_pad5[4]; + + //! \brief VRSAVE register. + uint32_t save_vrsave; + + //! \brief Padding included for breakpad compatibiltiy. + uint32_t save_pad6[7]; + } vregs; +}; + } // namespace crashpad #endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_ --- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc @@ -110,6 +110,13 @@ MinidumpContextWriter::CreateFromSnapsho break; } + case kCPUArchitecturePPC64: { + context = std::make_unique(); + reinterpret_cast(context.get()) + ->InitializeFromSnapshot(context_snapshot->ppc64); + break; + } + default: { LOG(ERROR) << "unknown context architecture " << context_snapshot->architecture; @@ -605,5 +612,48 @@ size_t MinidumpContextRISCV64Writer::Con DCHECK_GE(state(), kStateFrozen); return sizeof(context_); } + +MinidumpContextPPC64Writer::MinidumpContextPPC64Writer() + : MinidumpContextWriter(), context_() { + context_.context_flags = kMinidumpContextPPC64; +} + +MinidumpContextPPC64Writer::~MinidumpContextPPC64Writer() = default; + +void MinidumpContextPPC64Writer::InitializeFromSnapshot( + const CPUContextPPC64* context_snapshot) { + DCHECK_EQ(state(), kStateMutable); + DCHECK_EQ(context_.context_flags, kMinidumpContextPPC64); + + context_.context_flags = kMinidumpContextPPC64All; + + memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs)); + context_.nip = context_snapshot->nip; + context_.msr = context_snapshot->msr; + context_.ccr = context_snapshot->ccr; + context_.xer = context_snapshot->xer; + context_.lnk = context_snapshot->lnk; + context_.ctr = context_snapshot->ctr; + + memcpy(context_.fpregs, context_snapshot->fpregs, sizeof(context_.fpregs)); + context_.fpscr = context_snapshot->fpscr; + + memcpy(context_.vregs.save_vr, context_snapshot->vregs.save_vr, + sizeof(context_.vregs.save_vr)); + memcpy(&context_.vregs.save_vscr, &context_snapshot->vregs.save_vscr, + sizeof(context_.vregs.save_vscr)); + context_.vregs.save_vrsave = context_snapshot->vregs.save_vrsave; +} + +bool MinidumpContextPPC64Writer::WriteObject( + FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + return file_writer->Write(&context_, sizeof(context_)); +} + +size_t MinidumpContextPPC64Writer::ContextSize() const { + DCHECK_GE(state(), kStateFrozen); + return sizeof(context_); +} } // namespace crashpad --- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h @@ -413,6 +413,49 @@ class MinidumpContextRISCV64Writer final MinidumpContextRISCV64 context_; }; +//! \brief The writer for a MinidumpContextPPC64 structure in a minidump file. +class MinidumpContextPPC64Writer final : public MinidumpContextWriter { + public: + MinidumpContextPPC64Writer(); + + MinidumpContextPPC64Writer(const MinidumpContextPPC64Writer&) = delete; + MinidumpContextPPC64Writer& operator=(const MinidumpContextPPC64Writer&) = + delete; + + ~MinidumpContextPPC64Writer() override; + + //! \brief Initializes the MinidumpContextPPC based on \a context_snapshot. + //! + //! \param[in] context_snapshot The context snapshot to use as source data. + //! + //! \note Valid in #kStateMutable. No mutation of context() may be done before + //! calling this method, and it is not normally necessary to alter + //! context() after calling this method. + void InitializeFromSnapshot(const CPUContextPPC64* context_snapshot); + + //! \brief Returns a pointer to the context structure that this object will + //! write. + //! + //! \attention This returns a non-`const` pointer to this object’s private + //! data so that a caller can populate the context structure directly. + //! This is done because providing setter interfaces to each field in the + //! context structure would be unwieldy and cumbersome. Care must be taken + //! to populate the context structure correctly. The context structure + //! must only be modified while this object is in the #kStateMutable + //! state. + MinidumpContextPPC64* context() { return &context_; } + + protected: + // MinidumpWritable: + bool WriteObject(FileWriterInterface* file_writer) override; + + // MinidumpContextWriter: + size_t ContextSize() const override; + + private: + MinidumpContextPPC64 context_; +}; + } // namespace crashpad #endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_ --- a/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc @@ -322,6 +322,21 @@ TYPED_TEST(MinidumpContextWriter, RISCV6 TypeParam>(context, ExpectMinidumpContextRISCV64, kSeed); } +TEST(MinidumpContextWriter, PPC64_Zeros) { + EmptyContextTest( + ExpectMinidumpContextPPC64); +} + +TEST(MinidumpContextWriter, PPC64_FromSnapshot) { + constexpr uint32_t kSeed = 64; + CPUContextPPC64 context_ppc64; + CPUContext context; + context.ppc64 = &context_ppc64; + InitializeCPUContextPPC64(&context, kSeed); + FromSnapshotTest( + context, ExpectMinidumpContextPPC64, kSeed); +} + } // namespace } // namespace test } // namespace crashpad --- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc @@ -177,6 +177,8 @@ std::string MinidumpMiscInfoDebugBuildSt static constexpr char kCPU[] = "mips64"; #elif defined(ARCH_CPU_RISCV64) static constexpr char kCPU[] = "riscv64"; +#elif defined(ARCH_CPU_PPC64) + static constexpr char kCPU[] = "ppc64"; #else #error define kCPU for this CPU #endif --- a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc +++ b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc @@ -297,6 +297,40 @@ void InitializeMinidumpContextRISCV64(Mi context->fcsr = value++; } +void InitializeMinidumpContextPPC64(MinidumpContextPPC64* context, + uint32_t seed) { + if (seed == 0) { + memset(context, 0, sizeof(*context)); + context->context_flags = kMinidumpContextPPC64; + return; + } + + context->context_flags = kMinidumpContextPPC64All; + + uint64_t value = seed; + for (size_t i = 0; i < base::size(context->regs); ++i) { + context->regs[i] = value++; + } + + context->nip = value++; + context->msr = value++; + context->ccr = value++; + context->xer = value++; + context->lnk = value++; + context->ctr = value++; + + for (size_t i = 0; i < base::size(context->fpregs); ++i) { + context->fpregs[i] = static_cast(i); + } + context->fpscr = value++; + + for (size_t i = 0; i < base::size(context->vregs.save_vr); ++i) { + context->vregs.save_vr[i] = {value++, value++}; + } + context->vregs.save_vscr = {value++, value++}; + context->vregs.save_vrsave = value++; +} + namespace { // Using Google Test assertions, compares |expected| to |observed|. This is @@ -645,5 +679,38 @@ void ExpectMinidumpContextRISCV64(uint32 EXPECT_EQ(observed->fcsr, expected.fcsr); } +void ExpectMinidumpContextPPC64(uint32_t expect_seed, + const MinidumpContextPPC64* observed, + bool snapshot) { + MinidumpContextPPC64 expected; + InitializeMinidumpContextPPC64(&expected, expect_seed); + + EXPECT_EQ(observed->context_flags, expected.context_flags); + + for (size_t i = 0; i < base::size(expected.regs); ++i) { + EXPECT_EQ(observed->regs[i], expected.regs[i]); + } + + EXPECT_EQ(observed->nip, expected.nip); + EXPECT_EQ(observed->msr, expected.msr); + EXPECT_EQ(observed->ccr, expected.ccr); + EXPECT_EQ(observed->xer, expected.xer); + EXPECT_EQ(observed->lnk, expected.lnk); + EXPECT_EQ(observed->ctr, expected.ctr); + + for (size_t i = 0; i < base::size(expected.fpregs); ++i) { + EXPECT_EQ(observed->fpregs[i], expected.fpregs[i]); + } + EXPECT_EQ(observed->fpscr, expected.fpscr); + + for (size_t i = 0; i < base::size(expected.vregs.save_vr); ++ i) { + EXPECT_EQ(observed->vregs.save_vr[i].lo, expected.vregs.save_vr[i].lo); + EXPECT_EQ(observed->vregs.save_vr[i].hi, expected.vregs.save_vr[i].hi); + } + EXPECT_EQ(observed->vregs.save_vscr.lo, expected.vregs.save_vscr.lo); + EXPECT_EQ(observed->vregs.save_vscr.hi, expected.vregs.save_vscr.hi); + EXPECT_EQ(observed->vregs.save_vrsave, expected.vregs.save_vrsave); +} + } // namespace test } // namespace crashpad --- a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h +++ b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h @@ -90,6 +90,9 @@ void ExpectMinidumpContextMIPS64(uint32_ void ExpectMinidumpContextRISCV64(uint32_t expect_seed, const MinidumpContextRISCV64* observed, bool snapshot); +void ExpectMinidumpContextPPC64(uint32_t expect_seed, + const MinidumpContextPPC64* observed, + bool snapshot); //! \} } // namespace test --- a/third_party/crashpad/crashpad/snapshot/capture_memory.cc +++ b/third_party/crashpad/crashpad/snapshot/capture_memory.cc @@ -123,6 +123,11 @@ void CaptureMemory::PointedToByContext(c for (size_t i = 0; i < std::size(context.riscv64->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.riscv64->regs[i]); } +#elif defined(ARCH_CPU_PPC64_FAMILY) + MaybeCaptureMemoryAround(delegate, context.ppc64->nip); + for (size_t i = 0; i < std::size(context.ppc64->regs); ++i) { + MaybeCaptureMemoryAround(delegate, context.ppc64->regs[i]); + } #else #error Port. #endif --- a/third_party/crashpad/crashpad/snapshot/cpu_architecture.h +++ b/third_party/crashpad/crashpad/snapshot/cpu_architecture.h @@ -47,6 +47,9 @@ enum CPUArchitecture { //! \brief 64-bit RISC-V. kCPUArchitectureRISCV64, + + //! \brief 64-bit PPC64. + kCPUArchitecturePPC64 }; } // namespace crashpad --- a/third_party/crashpad/crashpad/snapshot/cpu_context.cc +++ b/third_party/crashpad/crashpad/snapshot/cpu_context.cc @@ -173,6 +173,8 @@ uint64_t CPUContext::InstructionPointer( return arm64->pc; case kCPUArchitectureRISCV64: return riscv64->pc; + case kCPUArchitecturePPC64: + return ppc64->nip; default: NOTREACHED(); } @@ -190,6 +192,8 @@ uint64_t CPUContext::StackPointer() cons return arm64->sp; case kCPUArchitectureRISCV64: return riscv64->regs[1]; + case kCPUArchitecturePPC64: + return ppc64->regs[1]; default: NOTREACHED(); } @@ -226,6 +230,7 @@ bool CPUContext::Is64Bit() const { case kCPUArchitectureX86_64: case kCPUArchitectureARM64: case kCPUArchitectureMIPS64EL: + case kCPUArchitecturePPC64: case kCPUArchitectureRISCV64: return true; case kCPUArchitectureX86: --- a/third_party/crashpad/crashpad/snapshot/cpu_context.h +++ b/third_party/crashpad/crashpad/snapshot/cpu_context.h @@ -371,6 +371,24 @@ struct CPUContextRISCV64 { uint32_t fcsr; }; +//! \brief A context structure carrying PPC64 CPU state. +struct CPUContextPPC64 { + uint64_t nip; + uint64_t msr; + uint64_t regs[32]; + uint64_t ccr; + uint64_t xer; + uint64_t lnk; + uint64_t ctr; + double fpregs[32]; + double fpscr; + struct { + uint128_struct save_vr[32]; + uint128_struct save_vscr; + uint32_t save_vrsave; + } vregs; +}; + //! \brief A context structure capable of carrying the context of any supported //! CPU architecture. struct CPUContext { @@ -412,6 +430,7 @@ struct CPUContext { CPUContextMIPS* mipsel; CPUContextMIPS64* mips64; CPUContextRISCV64* riscv64; + CPUContextPPC64* ppc64; }; }; --- a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h +++ b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_SNAPSHOT_LINUX_CPU_CONTEXT_LINUX_H_ #define CRASHPAD_SNAPSHOT_LINUX_CPU_CONTEXT_LINUX_H_ +#include #include "build/build_config.h" #include "snapshot/cpu_context.h" #include "snapshot/linux/signal_context.h" @@ -188,6 +189,78 @@ void InitializeCPUContextRISCV64(const T #endif // ARCH_CPU_RISCV64 || DOXYGEN +#if defined(ARCH_CPU_PPC64_FAMILY) || DOXYGEN + +//! \brief Initializes a CPUContextPPC64 structure from native context +//! structures on Linux. +//! +//! \param[in] thread_context The native thread context. +//! \param[in] float_context The native float context. +//! \param[in] vector_context The native vector context. +//! \param[out] context The CPUContextPPC64 structure to initialize. +template +void InitializeCPUContextPPC64( + const ThreadContext::t64_t& thread_context, + const FloatContext::f64_t& float_context, + const VectorContext::v64_t& vector_context, + typename Traits::CPUContext* context) { + + memcpy(context->regs, thread_context.gpr, sizeof(context->regs)); + context->nip = thread_context.nip; + context->msr = thread_context.msr; + context->ccr = thread_context.ccr; + context->xer = thread_context.xer; + context->lnk = thread_context.lnk; + context->ctr = thread_context.ctr; + + memcpy(context->fpregs, float_context.fpregs, sizeof(context->fpregs)); + context->fpscr = float_context.fpscr; + + for (uint8_t i = 0; i < 32; i++) { + context->vregs.save_vr[i] = { + (((uint64_t)vector_context.vrregs[i][0]) << 32) | + vector_context.vrregs[i][1], + (((uint64_t)vector_context.vrregs[i][2]) << 32) | + vector_context.vrregs[i][3] + }; + } + context->vregs.save_vrsave = vector_context.vrsave; + context->vregs.save_vscr = {0, (uint64_t)vector_context.vscr.vscr_word}; +} + +template +void InitializeCPUContextPPC64( + const SignalThreadContext64 &thread_context, + const SignalFloatContext64 &float_context, + const SignalVectorContext64 &vector_context, + typename Traits::CPUContext* context) { + + memcpy(context->regs, thread_context.regs, sizeof(context->regs)); + context->nip = thread_context.nip; + context->msr = thread_context.msr; + context->ccr = thread_context.ccr; + context->xer = thread_context.xer; + context->lnk = thread_context.lnk; + context->ctr = thread_context.ctr; + + memcpy(context->fpregs, float_context.regs, sizeof(context->fpregs)); + context->fpscr = float_context.fpscr; + + for (uint8_t i = 0; i < 32; i++) { + context->vregs.save_vr[i] = { + (((uint64_t)vector_context.vrregs[i][0]) << 32) | + vector_context.vrregs[i][1], + (((uint64_t)vector_context.vrregs[i][2]) << 32) | + vector_context.vrregs[i][3] + }; + } + context->vregs.save_vrsave = vector_context.vrsave; + context->vregs.save_vscr = {0, (uint64_t)vector_context.vscr.vscr_word}; +} + + +#endif + } // namespace internal } // namespace crashpad --- a/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc @@ -194,12 +194,15 @@ void TestAgainstTarget(PtraceConnection* device == 0 && inode == 0 && mapping_name == "[vdso]"; #if defined(ARCH_CPU_X86) static constexpr char kPrefix[] = "linux-gate.so."; + static constexpr char kPrefix64[] = "linux-gate.so."; #else static constexpr char kPrefix[] = "linux-vdso.so."; + static constexpr char kPrefix64[] = "linux-vdso64.so."; #endif return is_vdso_mapping == (module_name.empty() || - module_name.compare(0, strlen(kPrefix), kPrefix) == 0); + module_name.compare(0, strlen(kPrefix), kPrefix) == 0) || + module_name.compare(0, strlen(kPrefix64), kPrefix64) == 0); }, module_mapping->name, module_mapping->device, --- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc @@ -367,6 +367,69 @@ bool ExceptionSnapshotLinux::ReadContext return internal::ReadContext(reader, context_address, context_.riscv64); } +#elif defined(ARCH_CPU_PPC64_FAMILY) + +template +static bool ReadContext(ProcessReaderLinux* reader, + LinuxVMAddress context_address, + typename Traits::CPUContext* dest_context) { + const ProcessMemory* memory = reader->Memory(); + + LinuxVMAddress gp_regs_address = context_address + + offsetof(UContext, mcontext) + + offsetof(typename Traits::MContext, gp_regs); + + typename Traits::SignalThreadContext thread_context; + if (!memory->Read(gp_regs_address, sizeof(thread_context), &thread_context)) { + LOG(ERROR) << "Couldn't read gp_regs!"; + return false; + } + + LinuxVMAddress fp_regs_address = context_address + + offsetof(UContext, mcontext) + + offsetof(typename Traits::MContext, fp_regs); + + typename Traits::SignalFloatContext fp_context; + if (!memory->Read(fp_regs_address, sizeof(fp_context), &fp_context)) { + LOG(ERROR) << "Couldn't read fp_regs!"; + return false; + } + + LinuxVMAddress v_regs_ptr_address = context_address + + offsetof(UContext, mcontext) + + offsetof(typename Traits::MContext, vmx_reserve) + 8; + + typename Traits::SignalVectorContext v_context; + if (!memory->Read(v_regs_ptr_address, sizeof(v_context), &v_context)) { + LOG(ERROR) << "Couldn't read v_regs!"; + return false; + } + + InitializeCPUContextPPC64(thread_context, fp_context, + v_context, dest_context); + + return true; +} + +template<> +bool ExceptionSnapshotLinux::ReadContext( + ProcessReaderLinux* reader, + LinuxVMAddress context_address) { + context_.architecture = kCPUArchitecturePPC64; + context_.ppc64 = &context_union_.ppc64; + + return internal::ReadContext( + reader, context_address, context_.ppc64); +} + +template<> +bool ExceptionSnapshotLinux::ReadContext( + ProcessReaderLinux* reader, + LinuxVMAddress context_address) { + // PPC64 is 64-bit + return false; +} + #endif // ARCH_CPU_X86_FAMILY bool ExceptionSnapshotLinux::Initialize( --- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h +++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h @@ -91,6 +91,8 @@ class ExceptionSnapshotLinux final : pub CPUContextMIPS64 mips64; #elif defined(ARCH_CPU_RISCV64) CPUContextRISCV64 riscv64; +#elif defined(ARCH_CPU_PPC64_FAMILY) + CPUContextPPC64 ppc64; #endif } context_union_; CPUContext context_; --- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc @@ -325,7 +325,28 @@ void ExpectContext(const CPUContext& act sizeof(actual.riscv64->fpregs)), 0); } +#elif defined(ARCH_CPU_PPC64_FAMILY) +using NativeCPUContext = ucontext_t; +void InitializeContext(NativeCPUContext* context) { + for (size_t reg = 0; reg < 32; ++reg) { + context->uc_mcontext.gp_regs[reg] = reg; + } + + memset(&context->uc_mcontext.fp_regs, 44, + sizeof(context->uc_mcontext.fp_regs)); +} + +void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { + EXPECT_EQ(actual.architecture, kCPUArchitecturePPC64); + + for (size_t reg = 0; reg < 32; ++reg) { + EXPECT_EQ(actual.ppc64->regs[reg], expected.uc_mcontext.gp_regs[reg]); + } + + EXPECT_EQ(memcmp(actual.ppc64->fpregs, expected.uc_mcontext.fp_regs, + sizeof(actual.ppc64->fpregs)), 0); +} #else #error Port. #endif --- a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc @@ -129,6 +129,8 @@ void ProcessReaderLinux::Thread::Initial : thread_info.thread_context.t32.regs[29]; #elif defined(ARCH_CPU_RISCV64) stack_pointer = thread_info.thread_context.t64.regs[1]; +#elif defined(ARCH_CPU_PPC64_FAMILY) + stack_pointer = thread_info.thread_context.t64.gpr[1]; #else #error Port. #endif --- a/third_party/crashpad/crashpad/snapshot/linux/signal_context.h +++ b/third_party/crashpad/crashpad/snapshot/linux/signal_context.h @@ -456,6 +456,89 @@ static_assert(offsetof(UContext stack; + Sigset sigmask; + MContext64 mcontext; +}; +#pragma pack(push, 1) + +static_assert(sizeof(UContext) == sizeof(ucontext_t), + "ucontext_t size mismatch"); +static_assert(sizeof(MContext64) == sizeof(mcontext_t), + "mcontext_t size mismatch"); +static_assert(sizeof(SignalThreadContext64) == sizeof(gregset_t), + "gregset_t size mismatch"); +static_assert(sizeof(SignalFloatContext64) == sizeof(fpregset_t), + "fpregset_t size mismatch"); +static_assert(sizeof(SignalVectorContext64) == sizeof(_libc_vrstate), + "vrstate size mismatch"); +static_assert(offsetof(UContext, mcontext) == + offsetof(ucontext_t, uc_mcontext), "mcontext offset mismatch"); +static_assert(offsetof(MContext64, gp_regs) == + offsetof(mcontext_t, gp_regs), "gp_regs offset mismatch"); #else #error Port. #endif // ARCH_CPU_X86_FAMILY --- a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc @@ -208,6 +208,8 @@ CPUArchitecture SystemSnapshotLinux::Get : kCPUArchitectureMIPSEL; #elif defined(ARCH_CPU_RISCV64) return kCPUArchitectureRISCV64; +#elif defined(ARCH_CPU_PPC64_FAMILY) + return kCPUArchitecturePPC64; #else #error port to your architecture #endif @@ -226,6 +228,9 @@ uint32_t SystemSnapshotLinux::CPURevisio #elif defined(ARCH_CPU_RISCV64) // Not implemented return 0; +#elif defined(ARCH_CPU_PPC64_FAMILY) + // Not yet implemented on PPC64 + return 0; #else #error port to your architecture #endif @@ -249,6 +254,9 @@ std::string SystemSnapshotLinux::CPUVend #elif defined(ARCH_CPU_RISCV64) // Not implemented return std::string(); +#elif defined(ARCH_CPU_PPC64_FAMILY) + // Not yet implemented on PPC64 + return std::string(); #else #error port to your architecture #endif @@ -380,6 +388,9 @@ bool SystemSnapshotLinux::NXEnabled() co #elif defined(ARCH_CPU_RISCV64) // Not implemented return false; +#elif defined(ARCH_CPU_PPC64_FAMILY) + // Not yet implemented on PPC64 + return false; #else #error Port. #endif // ARCH_CPU_X86_FAMILY --- a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc @@ -196,6 +196,14 @@ bool ThreadSnapshotLinux::Initialize( InitializeCPUContextRISCV64(thread.thread_info.thread_context.t64, thread.thread_info.float_context.f64, context_.riscv64); +#elif defined(ARCH_CPU_PPC64_FAMILY) + context_.architecture = kCPUArchitecturePPC64; + context_.ppc64 = &context_union_.ppc64; + InitializeCPUContextPPC64( + thread.thread_info.thread_context.t64, + thread.thread_info.float_context.f64, + thread.thread_info.vector_context.v64, + context_.ppc64); #else #error Port. #endif --- a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h +++ b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h @@ -76,6 +76,8 @@ class ThreadSnapshotLinux final : public CPUContextMIPS64 mips64; #elif defined(ARCH_CPU_RISCV64) CPUContextRISCV64 riscv64; +#elif defined(ARCH_CPU_PPC64_FAMILY) + CPUContextPPC64 ppc64; #else #error Port. #endif // ARCH_CPU_X86_FAMILY --- a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc +++ b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc @@ -317,5 +317,38 @@ void InitializeCPUContextRISCV64(CPUCont riscv64->fcsr = value++; } +void InitializeCPUContextPPC64(CPUContext* context, uint32_t seed) { + context->architecture = kCPUArchitecturePPC64; + CPUContextPPC64* ppc64 = context->ppc64; + + if (seed == 0) { + memset(ppc64, 0, sizeof(*ppc64)); + return; + } + + uint64_t value = seed; + for (size_t i = 0; i < base::size(ppc64->regs); ++i) { + ppc64->regs[i] = value++; + } + + ppc64->nip = value++; + ppc64->msr = value++; + ppc64->ccr = value++; + ppc64->xer = value++; + ppc64->lnk = value++; + ppc64->ctr = value++; + + for (size_t i = 0; i < base::size(ppc64->fpregs); ++i) { + ppc64->fpregs[i] = static_cast(i); + } + ppc64->fpscr = value++; + + for (size_t i = 0; i < base::size(ppc64->vregs.save_vr); ++i) { + ppc64->vregs.save_vr[i] = {value++, value++}; + } + ppc64->vregs.save_vscr = {value++, value++}; + ppc64->vregs.save_vrsave = value++; +} + } // namespace test } // namespace crashpad --- a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h +++ b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h @@ -64,6 +64,7 @@ void InitializeCPUContextARM64(CPUContex void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed); void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed); void InitializeCPUContextRISCV64(CPUContext* context, uint32_t seed); +void InitializeCPUContextPPC64(CPUContext* context, uint32_t seed); //! \} } // namespace test --- a/third_party/crashpad/crashpad/test/linux/get_tls.cc +++ b/third_party/crashpad/crashpad/test/linux/get_tls.cc @@ -51,6 +51,8 @@ LinuxVMAddress GetTLS() { : "$3"); #elif defined(ARCH_CPU_RISCV64) asm("mv %0, tp" : "=r"(tls)); +#elif defined(ARCH_CPU_PPC64) + asm("mr %0, 13": "=r"(tls)); #else #error Port. #endif // ARCH_CPU_ARMEL --- a/third_party/crashpad/crashpad/test/multiprocess_posix.cc +++ b/third_party/crashpad/crashpad/test/multiprocess_posix.cc @@ -162,7 +162,8 @@ void Multiprocess::SetExpectedChildTermi } void Multiprocess::SetExpectedChildTerminationBuiltinTrap() { -#if defined(ARCH_CPU_ARM64) || defined(ARCH_CPU_MIPS_FAMILY) +#if defined(ARCH_CPU_ARM64) || defined(ARCH_CPU_MIPS_FAMILY) || \ + defined(ARCH_CPU_PPC64_FAMILY) SetExpectedChildTermination(kTerminationSignal, SIGTRAP); #else SetExpectedChildTermination(kTerminationSignal, SIGILL); --- a/third_party/crashpad/crashpad/util/linux/auxiliary_vector.cc +++ b/third_party/crashpad/crashpad/util/linux/auxiliary_vector.cc @@ -56,6 +56,11 @@ bool AuxiliaryVector::Read(PtraceConnect if (type == AT_IGNORE) { continue; } +#if defined(ARCH_CPU_PPC64_FAMILY) + if (type == AT_IGNOREPPC) { + continue; + } +#endif if (!MapInsertOrReplace(&values_, type, value, nullptr)) { LOG(ERROR) << "duplicate auxv entry"; return false; --- a/third_party/crashpad/crashpad/util/linux/ptracer.cc +++ b/third_party/crashpad/crashpad/util/linux/ptracer.cc @@ -430,6 +430,64 @@ bool GetThreadArea64(pid_t tid, return true; } +#elif defined(ARCH_CPU_PPC64_FAMILY) +// PPC64 has had HAVE_ARCH_TRACEHOOK set since 2.6.27 (even before x86 had it). +// That means we can simply use PTRACE_GETREGESET. + +template +bool GetRegisterSet(pid_t tid, int set, Destination* dest, bool can_log) { + iovec iov; + iov.iov_base = reinterpret_cast(dest); + iov.iov_len = sizeof(*dest); + if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast(set), &iov) != 0) { + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + if (iov.iov_len != sizeof(*dest)) { + LOG_IF(ERROR, can_log) << "Unexpected registers size"; + return false; + } + return true; +} + +bool GetVectorRegisters64(pid_t tid, + VectorContext* context, + bool can_log) { + return GetRegisterSet(tid, NT_PPC_VMX, &context->v64, can_log); +} + +bool GetFloatingPointRegisters64(pid_t tid, + FloatContext* context, + bool can_log) { + return GetRegisterSet(tid, NT_PRFPREG, &context->f64, can_log); +} + +bool GetThreadArea64(pid_t tid, + const ThreadContext& context, + LinuxVMAddress* address, + bool can_log) { + // PPC64 doesn't have PTRACE_GET_THREAD_AREA since the thread pointer + // is stored in GPR 13. + ThreadContext::t64_t tc; + if (!GetRegisterSet(tid, NT_PRSTATUS, &tc, can_log)) { + LOG_IF(ERROR, can_log) << "Unable to get thread pointer!"; + return false; + } + + *address = tc.gpr[13]; + + return true; +} + +// Stubs for 32-bit functions not applicable on PPC64 +bool GetFloatingPointRegisters32(pid_t tid, + FloatContext* context, + bool can_log) { return false; } +bool GetThreadArea32(pid_t tid, + const ThreadContext &context, + LinuxVMAddress *address, + bool can_log) { return false; } + #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -528,6 +586,9 @@ bool Ptracer::GetThreadInfo(pid_t tid, T if (is_64_bit_) { return GetGeneralPurposeRegisters64(tid, &info->thread_context, can_log_) && GetFloatingPointRegisters64(tid, &info->float_context, can_log_) && +#if defined(ARCH_CPU_PPC64_FAMILY) + GetVectorRegisters64(tid, &info->vector_context, can_log_) && +#endif GetThreadArea64(tid, info->thread_context, &info->thread_specific_data_address, --- a/third_party/crashpad/crashpad/util/linux/thread_info.h +++ b/third_party/crashpad/crashpad/util/linux/thread_info.h @@ -34,6 +34,10 @@ #include #endif +#if defined(ARCH_CPU_PPC64_FAMILY) +#include +#endif + namespace crashpad { //! \brief The set of general purpose registers for an architecture family. @@ -87,6 +91,8 @@ union ThreadContext { uint32_t padding1_; #elif defined(ARCH_CPU_RISCV64) // 32 bit RISC-V not supported +#elif defined(ARCH_CPU_PPC64_FAMILY) + // PPC64 is 64-bit #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -144,6 +150,21 @@ union ThreadContext { // Reflects user_regs_struct in asm/ptrace.h. uint64_t pc; uint64_t regs[31]; +#elif defined(ARCH_CPU_PPC64_FAMILY) + // Reflects struct pt_regs in asm/ptrace.h. + uint64_t gpr[32]; + uint64_t nip; + uint64_t msr; + uint64_t orig_gpr3; + uint64_t ctr; + uint64_t lnk; + uint64_t xer; + uint64_t ccr; + uint64_t softe; + uint64_t trap; + uint64_t dar; + uint64_t dsisr; + uint64_t result; #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -156,6 +177,8 @@ union ThreadContext { using NativeThreadContext = user_regs; #elif defined(ARCH_CPU_MIPS_FAMILY) // No appropriate NativeThreadsContext type available for MIPS +#elif defined(ARCH_CPU_PPC64_FAMILY) + using NativeThreadContext = struct pt_regs; #else #error Port. #endif // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64 || ARCH_CPU_RISCV64 @@ -233,6 +256,9 @@ union FloatContext { uint32_t fpu_id; #elif defined(ARCH_CPU_RISCV64) // 32 bit RISC-V not supported +#elif defined(ARCH_CPU_PPC64_FAMILY) + // Crashpad's PPC support is 64-bit only, so this + // 32bit-only struct is declared as empty. #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -271,6 +297,10 @@ union FloatContext { // Reflects __riscv_d_ext_state in asm/ptrace.h uint64_t fpregs[32]; uint64_t fcsr; +#elif defined(ARCH_CPU_PPC64_FAMILY) + // Reflects fpregset_t in sys/ucontext.h + double fpregs[32]; + double fpscr; #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -302,6 +332,8 @@ union FloatContext { // No appropriate floating point context native type for available MIPS. #elif defined(ARCH_CPU_RISCV64) static_assert(sizeof(f64) == sizeof(__riscv_d_ext_state), "Size mismatch"); +#elif defined(ARCH_CPU_PPC64_FAMILY) + static_assert(sizeof(f64) == sizeof(fpregset_t), "Size mismatch"); #else #error Port. #endif // ARCH_CPU_X86 @@ -309,6 +341,26 @@ union FloatContext { static_assert(std::is_standard_layout::value, "Not standard layout"); +//! \brief The vector registers used for an architecture family +union VectorContext { + struct v32_t {} v32; +#if defined(ARCH_CPU_PPC64_FAMILY) + __attribute__((__aligned__(16))) // Vector context must be doubleword aligned. +#endif + struct v64_t { +#if defined(ARCH_CPU_PPC64_FAMILY) + // Reflects vrregset_t in sys/ucontext.h + uint32_t vrregs[32][4]; + struct { + uint32_t __pad[3]; + uint32_t vscr_word; + } vscr; + uint32_t vrsave; + uint32_t __pad[3]; +#endif + } v64; +}; + //! \brief A collection of `ptrace`-able information about a thread. struct ThreadInfo { ThreadInfo(); @@ -320,6 +372,9 @@ struct ThreadInfo { //! \brief The floating point registers for the thread. FloatContext float_context; + //! \brief (Optional) The vector registers used for the thread. + VectorContext vector_context; + //! \brief The thread-local storage address for the thread. LinuxVMAddress thread_specific_data_address; }; --- a/third_party/crashpad/crashpad/util/misc/capture_context.h +++ b/third_party/crashpad/crashpad/util/misc/capture_context.h @@ -70,6 +70,7 @@ using NativeCPUContext = ucontext_t; //! Linux | ARM/ARM64 | `r0`/`x0` //! Linux | MIPS/MIPS64 | `$a0` //! Linux | RISCV64 | `a0` +//! Linux | PPC64 | `r3` //! //! Additionally, the value `LR` on ARM/ARM64 will be the return address of //! this function. --- a/third_party/crashpad/crashpad/util/misc/capture_context_linux.S +++ b/third_party/crashpad/crashpad/util/misc/capture_context_linux.S @@ -30,7 +30,7 @@ .globl CAPTURECONTEXT_SYMBOL2 #if defined(__i386__) || defined(__x86_64__) .balign 16, 0x90 -#elif defined(__arm__) || defined(__aarch64__) +#elif defined(__arm__) || defined(__aarch64__) || defined(__powerpc64__) .balign 4, 0x0 .type CAPTURECONTEXT_SYMBOL, %function .type CAPTURECONTEXT_SYMBOL2, %function @@ -430,6 +430,216 @@ CAPTURECONTEXT_SYMBOL2: .set at +#elif defined(__powerpc64__) + // Store r0-r31 + std 0, 0xe8(3) // context->uc_mcontext.gp_regs[0] + std 1, 0xf0(3) // context->uc_mcontext.gp_regs[1] + std 2, 0xf8(3) // context->uc_mcontext.gp_regs[2] + // note that r3's original value was lost + std 3, 0x100(3) // context->uc_mcontext.gp_regs[3] + std 4, 0x108(3) // context->uc_mcontext.gp_regs[4] + std 5, 0x110(3) // context->uc_mcontext.gp_regs[5] + std 6, 0x118(3) // context->uc_mcontext.gp_regs[6] + std 7, 0x120(3) // context->uc_mcontext.gp_regs[7] + std 8, 0x128(3) // context->uc_mcontext.gp_regs[8] + std 9, 0x130(3) // context->uc_mcontext.gp_regs[9] + std 10, 0x138(3) // context->uc_mcontext.gp_regs[10] + std 11, 0x140(3) // context->uc_mcontext.gp_regs[11] + std 12, 0x148(3) // context->uc_mcontext.gp_regs[12] + std 13, 0x150(3) // context->uc_mcontext.gp_regs[13] + std 14, 0x158(3) // context->uc_mcontext.gp_regs[14] + std 15, 0x160(3) // context->uc_mcontext.gp_regs[15] + std 16, 0x168(3) // context->uc_mcontext.gp_regs[16] + std 17, 0x170(3) // context->uc_mcontext.gp_regs[17] + std 18, 0x178(3) // context->uc_mcontext.gp_regs[18] + std 19, 0x180(3) // context->uc_mcontext.gp_regs[19] + std 20, 0x188(3) // context->uc_mcontext.gp_regs[20] + std 21, 0x190(3) // context->uc_mcontext.gp_regs[21] + std 22, 0x198(3) // context->uc_mcontext.gp_regs[22] + std 23, 0x1a0(3) // context->uc_mcontext.gp_regs[23] + std 24, 0x1a8(3) // context->uc_mcontext.gp_regs[24] + std 25, 0x1b0(3) // context->uc_mcontext.gp_regs[25] + std 26, 0x1b8(3) // context->uc_mcontext.gp_regs[26] + std 27, 0x1c0(3) // context->uc_mcontext.gp_regs[27] + std 28, 0x1c8(3) // context->uc_mcontext.gp_regs[28] + std 29, 0x1d0(3) // context->uc_mcontext.gp_regs[29] + std 30, 0x1d8(3) // context->uc_mcontext.gp_regs[30] + std 31, 0x1e0(3) // context->uc_mcontext.gp_regs[31] + + // For NIP, we can use the value in the link register + mflr 0 + std 0, 0x1e8(3) // context->uc_mcontext.gp_regs[PT_NIP] + + // CTR + mfctr 0 + std 0, 0x200(3) // context->uc_mcontext.gp_regs[PT_CTR] + + // For LNK, we'll use the caller's LR save area (2 stack frames up). + // r4 can be used as a scratch register since it has already been saved. + ld 4, 0(1) + ld 4, 16(4) + std 4, 0x208(3) // context->uc_mcontext.gp_regs[PT_LNK] + + // XER + mfxer 0 + std 0, 0x210(3) // context->uc_mcontext.gp_regs[PT_XER] + + // CCR + mfcr 0 + std 0, 0x218(3) // context->uc_mcontext.gp_regs[PT_CCR] + + // MSR, orig_r3, MQ, TRAP, DAR, DSISR, RESULT, DSCR, + // not used or not relevant, zero them out. + li 4, 0 + std 4, 0x1f0(3) // context->uc_mcontext.gp_regs[PT_MSR] + std 4, 0x1f8(3) // context->uc_mcontext.gp_regs[PT_ORIG_R3] + std 4, 0x220(3) // context->uc_mcontext.gp_regs[PT_MQ] + std 4, 0x228(3) // context->uc_mcontext.gp_regs[PT_TRAP] + std 4, 0x230(3) // context->uc_mcontext.gp_regs[PT_DAR] + std 4, 0x238(3) // context->uc_mcontext.gp_regs[PT_DSISR] + std 4, 0x240(3) // context->uc_mcontext.gp_regs[PT_RESULT] + std 4, 0x248(3) // context->uc_mcontext.gp_regs[PT_DSCR] + + // Update context->uc_mcontext.regs to point to gp_regs + addi 0, 3, 0xe8 + std 0, 0xe0(3) + + // Save floating point registers 0-31 + stfd 0, 0x268(3) // context->uc_mcontext.fp_regs[0] + stfd 1, 0x270(3) // context->uc_mcontext.fp_regs[1] + stfd 2, 0x278(3) // context->uc_mcontext.fp_regs[2] + stfd 3, 0x280(3) // context->uc_mcontext.fp_regs[3] + stfd 4, 0x288(3) // context->uc_mcontext.fp_regs[4] + stfd 5, 0x290(3) // context->uc_mcontext.fp_regs[5] + stfd 6, 0x298(3) // context->uc_mcontext.fp_regs[6] + stfd 7, 0x2a0(3) // context->uc_mcontext.fp_regs[7] + stfd 8, 0x2a8(3) // context->uc_mcontext.fp_regs[8] + stfd 9, 0x2b0(3) // context->uc_mcontext.fp_regs[9] + stfd 10, 0x2b8(3) // context->uc_mcontext.fp_regs[10] + stfd 11, 0x2c0(3) // context->uc_mcontext.fp_regs[11] + stfd 12, 0x2c8(3) // context->uc_mcontext.fp_regs[12] + stfd 13, 0x2d0(3) // context->uc_mcontext.fp_regs[13] + stfd 14, 0x2d8(3) // context->uc_mcontext.fp_regs[14] + stfd 15, 0x2e0(3) // context->uc_mcontext.fp_regs[15] + stfd 16, 0x2e8(3) // context->uc_mcontext.fp_regs[16] + stfd 17, 0x2f0(3) // context->uc_mcontext.fp_regs[17] + stfd 18, 0x2f8(3) // context->uc_mcontext.fp_regs[18] + stfd 19, 0x300(3) // context->uc_mcontext.fp_regs[19] + stfd 20, 0x308(3) // context->uc_mcontext.fp_regs[20] + stfd 21, 0x310(3) // context->uc_mcontext.fp_regs[21] + stfd 22, 0x318(3) // context->uc_mcontext.fp_regs[22] + stfd 23, 0x320(3) // context->uc_mcontext.fp_regs[23] + stfd 24, 0x328(3) // context->uc_mcontext.fp_regs[24] + stfd 25, 0x330(3) // context->uc_mcontext.fp_regs[25] + stfd 26, 0x338(3) // context->uc_mcontext.fp_regs[26] + stfd 27, 0x340(3) // context->uc_mcontext.fp_regs[27] + stfd 28, 0x348(3) // context->uc_mcontext.fp_regs[28] + stfd 29, 0x350(3) // context->uc_mcontext.fp_regs[29] + stfd 30, 0x358(3) // context->uc_mcontext.fp_regs[30] + stfd 31, 0x360(3) // context->uc_mcontext.fp_regs[31] + + // FPSCR + mffs 0 + stfd 0, 0x368(3) // context->uc_mcontext.fp_regs[32] + + // Save VMX Vector registers + // Update r4 to contain the base address of vmx_reserve + addi 4, 3, 0x378 + // Ensure that it is quadword aligned + andi. 5, 4, 0xF + beq 1f // No alignment is necessary + // Address is doubleword aligned and not quadword aligned, add 8 + addi 4, 4, 8 + +1: + // Store VMX registers 0-31 + // r4 will contain the base address + // r5 will contain the index + li 5, 0 + stvx 0, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 0] + addi 5, 5, 16 + stvx 1, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 1] + addi 5, 5, 16 + stvx 2, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 2] + addi 5, 5, 16 + stvx 3, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 3] + addi 5, 5, 16 + stvx 4, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 4] + addi 5, 5, 16 + stvx 5, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 5] + addi 5, 5, 16 + stvx 6, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 6] + addi 5, 5, 16 + stvx 7, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 7] + addi 5, 5, 16 + stvx 8, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 8] + addi 5, 5, 16 + stvx 9, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 9] + addi 5, 5, 16 + stvx 10, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 10] + addi 5, 5, 16 + stvx 11, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 11] + addi 5, 5, 16 + stvx 12, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 12] + addi 5, 5, 16 + stvx 13, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 13] + addi 5, 5, 16 + stvx 14, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 14] + addi 5, 5, 16 + stvx 15, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 15] + addi 5, 5, 16 + stvx 16, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 16] + addi 5, 5, 16 + stvx 17, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 17] + addi 5, 5, 16 + stvx 18, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 18] + addi 5, 5, 16 + stvx 19, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 19] + addi 5, 5, 16 + stvx 20, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 20] + addi 5, 5, 16 + stvx 21, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 21] + addi 5, 5, 16 + stvx 22, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 22] + addi 5, 5, 16 + stvx 23, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 23] + addi 5, 5, 16 + stvx 24, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 24] + addi 5, 5, 16 + stvx 25, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 25] + addi 5, 5, 16 + stvx 26, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 26] + addi 5, 5, 16 + stvx 27, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 27] + addi 5, 5, 16 + stvx 28, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 28] + addi 5, 5, 16 + stvx 29, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 29] + addi 5, 5, 16 + stvx 30, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 30] + addi 5, 5, 16 + stvx 31, 4, 5 // context->uc_mcontext.vmx_reserve[(align) + 31] + addi 5, 5, 16 + + // VSCR + mfvscr 0 + stvx 0, 4, 5 + addi 5, 5, 16 + + // VRSAVE + mfvrsave 0 + stwx 0, 4, 5 + + // Update context->uc_mcontext.v_regs to point to vmx_reserve + alignment. + std 4, 0x370(3) + + // Zero out all unused fields + li 4, 0 + std 4, 0xc8(3) // context->uc_mcontext.signal + std 4, 0xd0(3) // context->uc_mcontext.handler + std 4, 0xd8(3) // context->uc_mcontext.oldmask + + blr #elif defined(__riscv) #define MCONTEXT_GREGS_OFFSET 176 --- a/third_party/crashpad/crashpad/util/misc/capture_context_test.cc +++ b/third_party/crashpad/crashpad/util/misc/capture_context_test.cc @@ -48,7 +48,7 @@ void TestCaptureContext() { uintptr_t pc = ProgramCounterFromContext(context_1); #if !defined(ADDRESS_SANITIZER) && !defined(ARCH_CPU_MIPS_FAMILY) && \ - !defined(MEMORY_SANITIZER) + !defined(MEMORY_SANITIZER) && !defined(ARCH_CPU_PPC64_FAMILY) // Sanitizers can cause enough code bloat that the “nearby” check would // likely fail. const uintptr_t kReferencePC = --- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc +++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc @@ -38,6 +38,8 @@ void SanityCheckContext(const NativeCPUC #elif defined(ARCH_CPU_RISCV64) EXPECT_EQ(context.uc_mcontext.__gregs[10], FromPointerCast(&context)); +#elif defined(ARCH_CPU_PPC64_FAMILY) + EXPECT_EQ(context.uc_mcontext.gp_regs[3], FromPointerCast(&context)); #endif } @@ -54,6 +56,8 @@ uintptr_t ProgramCounterFromContext(cons return context.uc_mcontext.pc; #elif defined(ARCH_CPU_RISCV64) return context.uc_mcontext.__gregs[0]; +#elif defined(ARCH_CPU_PPC64_FAMILY) + return context.uc_mcontext.gp_regs[PT_NIP]; #endif } @@ -70,6 +74,8 @@ uintptr_t StackPointerFromContext(const return context.uc_mcontext.gregs[29]; #elif defined(ARCH_CPU_RISCV64) return context.uc_mcontext.__gregs[2]; +#elif defined(ARCH_CPU_PPC64_FAMILY) + return context.uc_mcontext.gp_regs[1]; #endif }