Blob Blame History Raw
From 8c24c695052d156fd1322d6dacfab117b92cb175 Mon Sep 17 00:00:00 2001
From: Shawn Anastasio <sanastasio@raptorengineering.com>
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(-)

Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/CONTRIBUTORS
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/CONTRIBUTORS
+++ chromium-120.0.6099.71/third_party/crashpad/crashpad/CONTRIBUTORS
@@ -13,3 +13,5 @@ Mark Mentovai <mark@chromium.org>
 Robert Sesek <rsesek@chromium.org>
 Scott Graham <scottmg@chromium.org>
 Joshua Peraza <jperaza@chromium.org>
+Shawn Anastasio <sanastasio@raptorengineering.com>
+Timothy Pearson <tpearson@raptorengineering.com>
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/minidump_context.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/minidump/minidump_context.h
+++ chromium-120.0.6099.71/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_
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
+++ chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
@@ -110,6 +110,13 @@ MinidumpContextWriter::CreateFromSnapsho
       break;
     }
 
+    case kCPUArchitecturePPC64: {
+      context = std::make_unique<MinidumpContextPPC64Writer>();
+      reinterpret_cast<MinidumpContextPPC64Writer*>(context.get())
+          ->InitializeFromSnapshot(context_snapshot->ppc64);
+      break;
+    }
+
     default: {
       LOG(ERROR) << "unknown context architecture "
                  << context_snapshot->architecture;
@@ -601,5 +608,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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
+++ chromium-120.0.6099.71/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_
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
+++ chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
@@ -328,6 +328,21 @@ TYPED_TEST(MinidumpContextWriter, RISCV6
                    TypeParam>(context, ExpectMinidumpContextRISCV64, kSeed);
 }
 
+TEST(MinidumpContextWriter, PPC64_Zeros) {
+  EmptyContextTest<MinidumpContextPPC64Writer, MinidumpContextPPC64>(
+    ExpectMinidumpContextPPC64);
+}
+
+TEST(MinidumpContextWriter, PPC64_FromSnapshot) {
+  constexpr uint32_t kSeed = 64;
+  CPUContextPPC64 context_ppc64;
+  CPUContext context;
+  context.ppc64 = &context_ppc64;
+  InitializeCPUContextPPC64(&context, kSeed);
+  FromSnapshotTest<MinidumpContextPPC64Writer, MinidumpContextPPC64>(
+      context, ExpectMinidumpContextPPC64, kSeed);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace crashpad
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc
+++ chromium-120.0.6099.71/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<double>(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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/capture_memory.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/capture_memory.cc
+++ chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/capture_memory.cc
@@ -122,6 +122,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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/cpu_context.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/cpu_context.cc
+++ chromium-120.0.6099.71/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();
       return ~0ull;
@@ -191,6 +193,8 @@ uint64_t CPUContext::StackPointer() cons
       return arm64->sp;
     case kCPUArchitectureRISCV64:
       return riscv64->regs[1];
+    case kCPUArchitecturePPC64:
+      return ppc64->regs[1];
     default:
       NOTREACHED();
       return ~0ull;
@@ -231,6 +235,7 @@ bool CPUContext::Is64Bit() const {
     case kCPUArchitectureX86_64:
     case kCPUArchitectureARM64:
     case kCPUArchitectureMIPS64EL:
+    case kCPUArchitecturePPC64:
     case kCPUArchitectureRISCV64:
       return true;
     case kCPUArchitectureX86:
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/cpu_context.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/cpu_context.h
+++ chromium-120.0.6099.71/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;
   };
 };
 
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
+++ chromium-120.0.6099.71/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 <cstring>
 #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 <typename Traits>
+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 <typename Traits>
+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
 
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc
+++ chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/debug_rendezvous_test.cc
@@ -195,12 +195,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,
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
+++ chromium-120.0.6099.71/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 <typename Traits>
+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<ContextTraits64>(thread_context, fp_context,
+                            v_context, dest_context);
+
+  return true;
+}
+
+template<>
+bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
+    ProcessReaderLinux* reader,
+    LinuxVMAddress context_address) {
+  context_.architecture = kCPUArchitecturePPC64;
+  context_.ppc64 = &context_union_.ppc64;
+
+  return internal::ReadContext<ContextTraits64>(
+      reader, context_address, context_.ppc64);
+}
+
+template<>
+bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
+    ProcessReaderLinux* reader,
+    LinuxVMAddress context_address) {
+  // PPC64 is 64-bit
+  return false;
+}
+
 #endif  // ARCH_CPU_X86_FAMILY
 
 bool ExceptionSnapshotLinux::Initialize(
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
+++ chromium-120.0.6099.71/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_;
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
+++ chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
@@ -456,6 +456,89 @@ static_assert(offsetof(UContext<ContextT
                   offsetof(ucontext_t, uc_mcontext.__fpregs),
               "context offset mismatch");
 
+#elif defined(ARCH_CPU_PPC64_FAMILY)
+
+struct SignalThreadContext64 {
+  uint64_t regs[32];
+  uint64_t nip;
+  uint64_t msr;
+  uint64_t orig_r3;
+  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;
+  uint64_t dscr;
+  uint64_t fpr0[3];
+};
+
+struct SignalFloatContext64 {
+  double regs[32];
+  double fpscr;
+};
+
+struct SignalVectorContext64 {
+  int32_t vrregs[32][4];
+  struct {
+    int32_t __pad[3];
+    int32_t vscr_word;
+  } vscr;
+  int32_t vrsave;
+  int32_t __pad[3];
+} __attribute__((__aligned__(16)));
+
+
+#pragma pack(pop)
+struct MContext64 {
+  uint64_t reserved[4];
+  int32_t signal;
+  int32_t __pad0;
+  uint64_t handler;
+  uint64_t oldmask;
+  uint64_t pt_regs_ptr;
+  SignalThreadContext64 gp_regs;
+  SignalFloatContext64  fp_regs;
+  SignalVectorContext64 *v_regs;
+  int64_t vmx_reserve[69];
+};
+
+struct ContextTraits64 : public Traits64 {
+  using MContext = MContext64;
+  using SignalThreadContext = SignalThreadContext64;
+  using SignalFloatContext = SignalFloatContext64;
+  using SignalVectorContext = SignalVectorContext64;
+  using CPUContext = CPUContextPPC64;
+};
+
+struct ContextTraits32 : public Traits32 {};
+
+struct UContext {
+  uint64_t flags;
+  uint64_t link;
+  SignalStack<ContextTraits64> stack;
+  Sigset<ContextTraits64> 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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
+++ chromium-120.0.6099.71/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
@@ -385,6 +393,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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
+++ chromium-120.0.6099.71/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<ContextTraits64>(
+      thread.thread_info.thread_context.t64,
+      thread.thread_info.float_context.f64,
+      thread.thread_info.vector_context.v64,
+      context_.ppc64);
 #else
 #error Port.
 #endif
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc
+++ chromium-120.0.6099.71/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<double>(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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/test/linux/get_tls.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/test/linux/get_tls.cc
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/test/multiprocess_posix.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/test/multiprocess_posix.cc
+++ chromium-120.0.6099.71/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);
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/util/linux/auxiliary_vector.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/util/linux/auxiliary_vector.cc
+++ chromium-120.0.6099.71/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;
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/util/linux/ptracer.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/util/linux/ptracer.cc
+++ chromium-120.0.6099.71/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 <typename Destination>
+bool GetRegisterSet(pid_t tid, int set, Destination* dest, bool can_log) {
+  iovec iov;
+  iov.iov_base = reinterpret_cast<void*>(dest);
+  iov.iov_len = sizeof(*dest);
+  if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast<void*>(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,
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/util/linux/thread_info.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/util/linux/thread_info.h
+++ chromium-120.0.6099.71/third_party/crashpad/crashpad/util/linux/thread_info.h
@@ -34,6 +34,10 @@
 #include <asm/ptrace.h>
 #endif
 
+#if defined(ARCH_CPU_PPC64_FAMILY)
+#include <sys/ucontext.h>
+#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<FloatContext>::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;
 };
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/util/misc/capture_context.h
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/util/misc/capture_context.h
+++ chromium-120.0.6099.71/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.
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/util/misc/capture_context_linux.S
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/util/misc/capture_context_linux.S
+++ chromium-120.0.6099.71/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
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
+++ chromium-120.0.6099.71/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 =
Index: chromium-120.0.6099.71/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
===================================================================
--- chromium-120.0.6099.71.orig/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
+++ chromium-120.0.6099.71/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<uintptr_t>(&context));
+#elif defined(ARCH_CPU_PPC64_FAMILY)
+  EXPECT_EQ(context.uc_mcontext.gp_regs[3], FromPointerCast<uintptr_t>(&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
 }