From cb41ba7471a02113447f621027bc08a75b35be11 Mon Sep 17 00:00:00 2001 From: Djordje Golubovic Date: Tue, 10 Jul 2018 11:17:22 +0200 Subject: [PATCH] Added MIPS support to crashpad. Modified gyp/gn files to support MIPS targets. Implemented thread_info, cpu_context, signal context classes for MIPS target. Addressed MIPS specific signal ordering. Added "MIPS Technologies, Inc." to AUTHORS file. Bug: crashpad:232 Change-Id: Ibfc221ba54088e95f984b9dc6be5fd52f86abcc2 Reviewed-on: https://chromium-review.googlesource.com/1064594 Commit-Queue: Joshua Peraza Reviewed-by: Joshua Peraza --- AUTHORS | 1 + compat/linux/sys/ptrace.h | 7 + minidump/minidump_context.h | 132 +++++++++++++++++ minidump/minidump_context_writer.cc | 111 ++++++++++++++ minidump/minidump_context_writer.h | 80 ++++++++++ minidump/minidump_context_writer_test.cc | 30 ++++ minidump/minidump_misc_info_writer.cc | 4 + minidump/test/minidump_context_test_util.cc | 139 ++++++++++++++++++ minidump/test/minidump_context_test_util.h | 9 ++ snapshot/BUILD.gn | 6 +- snapshot/capture_memory.cc | 4 + snapshot/cpu_architecture.h | 8 +- snapshot/cpu_context.cc | 2 + snapshot/cpu_context.h | 48 ++++++ snapshot/linux/cpu_context_linux.h | 36 +++++ snapshot/linux/exception_snapshot_linux.cc | 55 +++++++ snapshot/linux/exception_snapshot_linux.h | 3 + .../linux/exception_snapshot_linux_test.cc | 30 ++++ snapshot/linux/process_reader_linux.cc | 3 + snapshot/linux/signal_context.h | 121 +++++++++++++++ snapshot/linux/system_snapshot_linux.cc | 12 ++ snapshot/linux/thread_snapshot_linux.cc | 16 ++ snapshot/linux/thread_snapshot_linux.h | 3 + snapshot/snapshot_test.gyp | 23 ++- snapshot/test/test_cpu_context.cc | 72 +++++++++ snapshot/test/test_cpu_context.h | 2 + test/linux/get_tls.cc | 14 ++ test/multiprocess_posix.cc | 2 +- util/linux/auxiliary_vector_test.cc | 9 +- util/linux/ptracer.cc | 127 +++++++++++++++- util/linux/thread_info.h | 43 ++++++ util/misc/capture_context.h | 1 + util/misc/capture_context_linux.S | 91 +++++++++++- util/misc/capture_context_test.cc | 2 +- util/misc/capture_context_test_util_linux.cc | 6 + util/posix/symbolic_constants_posix.cc | 34 +++++ util/posix/symbolic_constants_posix_test.cc | 2 + 37 files changed, 1271 insertions(+), 17 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7c40c4fe..8dcac323 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,3 +11,4 @@ Intel Corporation Opera Software ASA Vewd Software AS LG Electronics, Inc. +MIPS Technologies, Inc. diff --git a/compat/linux/sys/ptrace.h b/compat/linux/sys/ptrace.h index e5c95c7c..fa894381 100644 --- a/compat/linux/sys/ptrace.h +++ b/compat/linux/sys/ptrace.h @@ -30,6 +30,13 @@ static constexpr __ptrace_request PTRACE_GET_THREAD_AREA = static constexpr __ptrace_request PTRACE_GET_THREAD_AREA = static_cast<__ptrace_request>(22); #define PTRACE_GET_THREAD_AREA PTRACE_GET_THREAD_AREA +#elif defined(__mips__) +static constexpr __ptrace_request PTRACE_GET_THREAD_AREA = + static_cast<__ptrace_request>(25); +#define PTRACE_GET_THREAD_AREA PTRACE_GET_THREAD_AREA +static constexpr __ptrace_request PTRACE_GET_THREAD_AREA_3264 = + static_cast<__ptrace_request>(0xc4); +#define PTRACE_GET_THREAD_AREA_3264 PTRACE_GET_THREAD_AREA_3264 #endif #endif // !PTRACE_GET_THREAD_AREA && !PT_GET_THREAD_AREA && defined(__GLIBC__) diff --git a/minidump/minidump_context.h b/minidump/minidump_context.h index a7328cad..6f51b5a4 100644 --- a/minidump/minidump_context.h +++ b/minidump/minidump_context.h @@ -432,6 +432,138 @@ struct MinidumpContextARM64 { uint128_struct fpsimd[32]; }; +//! \brief 32bit MIPS-specifc flags for MinidumpContextMIPS::context_flags. +//! Based on minidump_cpu_mips.h from breakpad +enum MinidumpContextMIPSFlags : uint32_t { + //! \brief Identifies the context structure as MIPSEL. + kMinidumpContextMIPS = 0x00040000, + + //! \brief Indicates the validity of integer registers. + //! + //! Registers `0`-`31`, `mdhi`, `mdlo`, `epc`, `badvaddr`, `status` and + //! `cause` are valid. + kMinidumpContextMIPSInteger = kMinidumpContextMIPS | 0x00000002, + + //! \brief Indicates the validity of floating point registers. + //! + //! Floating point registers `0`-`31`, `fpcsr` and `fir` are valid + kMinidumpContextMIPSFloatingPoint = kMinidumpContextMIPS | 0x00000004, + + //! \brief Indicates the validity of DSP registers. + //! + //! Registers `hi0`-`hi2`, `lo0`-`lo2` and `dsp_control` are valid + kMinidumpContextMIPSDSP = kMinidumpContextMIPS | 0x00000008, + + //! \brief Indicates the validity of all registers. + kMinidumpContextMIPSAll = kMinidumpContextMIPSInteger | + kMinidumpContextMIPSFloatingPoint | + kMinidumpContextMIPSDSP, +}; + +//! \brief A 32bit MIPS CPU context (register state) carried in a minidump file. +struct MinidumpContextMIPS { + uint32_t context_flags; + + //! \brief This padding field is included for breakpad compatibility. + uint32_t _pad0; + //! \brief General purpose registers `0`-`31`. + uint64_t regs[32]; + + //! \brief Multiply/divide result. + uint64_t mdhi, mdlo; + + //! \brief DSP registers. + uint32_t hi[3]; + uint32_t lo[3]; + uint32_t dsp_control; + //! \brief This padding field is included for breakpad compatibility. + uint32_t _pad1; + + // \brief cp0 registers. + uint64_t epc; + uint64_t badvaddr; + uint32_t status; + uint32_t cause; + + //! \brief FPU registers. + union { + struct { + float _fp_fregs; + uint32_t _fp_pad; + } fregs[32]; + double dregs[32]; + } fpregs; + + //! \brief FPU status register. + uint32_t fpcsr; + //! \brief FPU implementation register. + uint32_t fir; +}; + +//! \brief 64bit MIPS-specifc flags for MinidumpContextMIPS64::context_flags. +//! Based on minidump_cpu_mips.h from breakpad +enum MinidumpContextMIPS64Flags : uint32_t { + //! \brief Identifies the context structure as MIPS64EL. + kMinidumpContextMIPS64 = 0x00080000, + + //! \brief Indicates the validity of integer registers. + //! + //! Registers `0`-`31`, `mdhi`, `mdlo`, `epc`, `badvaddr`, `status` and + //! `cause` are valid. + kMinidumpContextMIPS64Integer = kMinidumpContextMIPS64 | 0x00000002, + + //! \brief Indicates the validity of floating point registers. + //! + //! Floating point registers `0`-`31`, `fpcsr` and `fir` are valid + kMinidumpContextMIPS64FloatingPoint = kMinidumpContextMIPS64 | 0x00000004, + + //! \brief Indicates the validity of DSP registers. + //! + //! Registers `hi0`-`hi2`, `lo0`-`lo2` and `dsp_control` are valid. + kMinidumpContextMIPS64DSP = kMinidumpContextMIPS64 | 0x00000008, + + //! \brief Indicates the validity of all registers. + kMinidumpContextMIPS64All = kMinidumpContextMIPS64Integer | + kMinidumpContextMIPS64FloatingPoint | + kMinidumpContextMIPS64DSP, +}; + +//! \brief A 32bit MIPS CPU context (register state) carried in a minidump file. +struct MinidumpContextMIPS64 { + uint64_t context_flags; + + //! \brief General purpose registers. + uint64_t regs[32]; + + //! \brief Multiply/divide result. + uint64_t mdhi, mdlo; + + //! \brief DSP registers. + uint64_t hi[3]; + uint64_t lo[3]; + uint64_t dsp_control; + + //! \brief cp0 registers. + uint64_t epc; + uint64_t badvaddr; + uint64_t status; + uint64_t cause; + + //! \brief FPU registers. + union { + struct { + float _fp_fregs; + uint32_t _fp_pad; + } fregs[32]; + double dregs[32]; + } fpregs; + + //! \brief FPU status register. + uint64_t fpcsr; + //! \brief FPU implementation register. + uint64_t fir; +}; + } // namespace crashpad #endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_ diff --git a/minidump/minidump_context_writer.cc b/minidump/minidump_context_writer.cc index 2fa2e53e..20adbf3f 100644 --- a/minidump/minidump_context_writer.cc +++ b/minidump/minidump_context_writer.cc @@ -87,6 +87,20 @@ MinidumpContextWriter::CreateFromSnapshot(const CPUContext* context_snapshot) { break; } + case kCPUArchitectureMIPSEL: { + context = std::make_unique(); + reinterpret_cast(context.get()) + ->InitializeFromSnapshot(context_snapshot->mipsel); + break; + } + + case kCPUArchitectureMIPS64EL: { + context = std::make_unique(); + reinterpret_cast(context.get()) + ->InitializeFromSnapshot(context_snapshot->mips64); + break; + } + default: { LOG(ERROR) << "unknown context architecture " << context_snapshot->architecture; @@ -339,4 +353,101 @@ size_t MinidumpContextARM64Writer::ContextSize() const { return sizeof(context_); } +MinidumpContextMIPSWriter::MinidumpContextMIPSWriter() + : MinidumpContextWriter(), context_() { + context_.context_flags = kMinidumpContextMIPS; +} + +MinidumpContextMIPSWriter::~MinidumpContextMIPSWriter() = default; + +void MinidumpContextMIPSWriter::InitializeFromSnapshot( + const CPUContextMIPS* context_snapshot) { + DCHECK_EQ(state(), kStateMutable); + DCHECK_EQ(context_.context_flags, kMinidumpContextMIPS); + + context_.context_flags = kMinidumpContextMIPSAll; + + static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs), + "GPRs size mismatch"); + memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs)); + context_.mdhi = context_snapshot->mdhi; + context_.mdlo = context_snapshot->mdlo; + context_.epc = context_snapshot->cp0_epc; + context_.badvaddr = context_snapshot->cp0_badvaddr; + context_.status = context_snapshot->cp0_status; + context_.cause = context_snapshot->cp0_cause; + + static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs), + "FPRs size mismatch"); + memcpy(&context_.fpregs, &context_snapshot->fpregs, sizeof(context_.fpregs)); + context_.fpcsr = context_snapshot->fpcsr; + context_.fir = context_snapshot->fir; + + for (size_t index = 0; index < 3; ++index) { + context_.hi[index] = context_snapshot->hi[index]; + context_.lo[index] = context_snapshot->lo[index]; + } + context_.dsp_control = context_snapshot->dsp_control; +} + +bool MinidumpContextMIPSWriter::WriteObject(FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + return file_writer->Write(&context_, sizeof(context_)); +} + +size_t MinidumpContextMIPSWriter::ContextSize() const { + DCHECK_GE(state(), kStateFrozen); + return sizeof(context_); +} + +MinidumpContextMIPS64Writer::MinidumpContextMIPS64Writer() + : MinidumpContextWriter(), context_() { + context_.context_flags = kMinidumpContextMIPS64; +} + +MinidumpContextMIPS64Writer::~MinidumpContextMIPS64Writer() = default; + +void MinidumpContextMIPS64Writer::InitializeFromSnapshot( + const CPUContextMIPS64* context_snapshot) { + DCHECK_EQ(state(), kStateMutable); + DCHECK_EQ(context_.context_flags, kMinidumpContextMIPS64); + + context_.context_flags = kMinidumpContextMIPS64All; + + static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs), + "GPRs size mismatch"); + memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs)); + context_.mdhi = context_snapshot->mdhi; + context_.mdlo = context_snapshot->mdlo; + context_.epc = context_snapshot->cp0_epc; + context_.badvaddr = context_snapshot->cp0_badvaddr; + context_.status = context_snapshot->cp0_status; + context_.cause = context_snapshot->cp0_cause; + + static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs), + "FPRs size mismatch"); + memcpy(context_.fpregs.dregs, + context_snapshot->fpregs.dregs, + sizeof(context_.fpregs.dregs)); + context_.fpcsr = context_snapshot->fpcsr; + context_.fir = context_snapshot->fir; + + for (size_t index = 0; index < 3; ++index) { + context_.hi[index] = context_snapshot->hi[index]; + context_.lo[index] = context_snapshot->lo[index]; + } + context_.dsp_control = context_snapshot->dsp_control; +} + +bool MinidumpContextMIPS64Writer::WriteObject( + FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + return file_writer->Write(&context_, sizeof(context_)); +} + +size_t MinidumpContextMIPS64Writer::ContextSize() const { + DCHECK_GE(state(), kStateFrozen); + return sizeof(context_); +} + } // namespace crashpad diff --git a/minidump/minidump_context_writer.h b/minidump/minidump_context_writer.h index fb3b1513..d4ab936e 100644 --- a/minidump/minidump_context_writer.h +++ b/minidump/minidump_context_writer.h @@ -235,6 +235,86 @@ class MinidumpContextARM64Writer final : public MinidumpContextWriter { DISALLOW_COPY_AND_ASSIGN(MinidumpContextARM64Writer); }; +//! \brief The writer for a MinidumpContextMIPS structure in a minidump file. +class MinidumpContextMIPSWriter final : public MinidumpContextWriter { + public: + MinidumpContextMIPSWriter(); + ~MinidumpContextMIPSWriter() override; + + //! \brief Initializes the MinidumpContextMIPS 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 CPUContextMIPS* 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. + MinidumpContextMIPS* context() { return &context_; } + + protected: + // MinidumpWritable: + bool WriteObject(FileWriterInterface* file_writer) override; + + // MinidumpContextWriter: + size_t ContextSize() const override; + + private: + MinidumpContextMIPS context_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpContextMIPSWriter); +}; + +//! \brief The writer for a MinidumpContextMIPS64 structure in a minidump file. +class MinidumpContextMIPS64Writer final : public MinidumpContextWriter { + public: + MinidumpContextMIPS64Writer(); + ~MinidumpContextMIPS64Writer() override; + + //! \brief Initializes the MinidumpContextMIPS 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 CPUContextMIPS64* 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. + MinidumpContextMIPS64* context() { return &context_; } + + protected: + // MinidumpWritable: + bool WriteObject(FileWriterInterface* file_writer) override; + + // MinidumpContextWriter: + size_t ContextSize() const override; + + private: + MinidumpContextMIPS64 context_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpContextMIPS64Writer); +}; + } // namespace crashpad #endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_ diff --git a/minidump/minidump_context_writer_test.cc b/minidump/minidump_context_writer_test.cc index 0122683c..3216a906 100644 --- a/minidump/minidump_context_writer_test.cc +++ b/minidump/minidump_context_writer_test.cc @@ -183,6 +183,36 @@ TEST(MinidumpContextWriter, ARM64_FromSnapshot) { context, ExpectMinidumpContextARM64, kSeed); } +TEST(MinidumpContextWriter, MIPS_Zeros) { + EmptyContextTest( + ExpectMinidumpContextMIPS); +} + +TEST(MinidumpContextWriter, MIPS64_Zeros) { + EmptyContextTest( + ExpectMinidumpContextMIPS64); +} + +TEST(MinidumpContextWriter, MIPS_FromSnapshot) { + constexpr uint32_t kSeed = 32; + CPUContextMIPS context_mips; + CPUContext context; + context.mipsel = &context_mips; + InitializeCPUContextMIPS(&context, kSeed); + FromSnapshotTest( + context, ExpectMinidumpContextMIPS, kSeed); +} + +TEST(MinidumpContextWriter, MIPS64_FromSnapshot) { + constexpr uint32_t kSeed = 64; + CPUContextMIPS64 context_mips; + CPUContext context; + context.mips64 = &context_mips; + InitializeCPUContextMIPS64(&context, kSeed); + FromSnapshotTest( + context, ExpectMinidumpContextMIPS64, kSeed); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/minidump/minidump_misc_info_writer.cc b/minidump/minidump_misc_info_writer.cc index c1e24892..d83ed237 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -122,6 +122,10 @@ std::string MinidumpMiscInfoDebugBuildString() { static constexpr char kCPU[] = "arm"; #elif defined(ARCH_CPU_ARM64) static constexpr char kCPU[] = "arm64"; +#elif defined(ARCH_CPU_MIPSEL) + static constexpr char kCPU[] = "mips"; +#elif defined(ARCH_CPU_MIPS64EL) + static constexpr char kCPU[] = "mips64"; #else #error define kCPU for this CPU #endif diff --git a/minidump/test/minidump_context_test_util.cc b/minidump/test/minidump_context_test_util.cc index 0dc3a971..28f94106 100644 --- a/minidump/test/minidump_context_test_util.cc +++ b/minidump/test/minidump_context_test_util.cc @@ -195,6 +195,80 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, context->fpcr = value++; } +void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, + uint32_t seed) { + if (seed == 0) { + memset(context, 0, sizeof(*context)); + context->context_flags = kMinidumpContextMIPS; + return; + } + + context->context_flags = kMinidumpContextMIPSAll; + + uint32_t value = seed; + + for (size_t index = 0; index < arraysize(context->regs); ++index) { + context->regs[index] = value++; + } + + context->mdlo = value++; + context->mdhi = value++; + context->epc = value++; + context->badvaddr = value++; + context->status = value++; + context->cause = value++; + + for (size_t index = 0; index < arraysize(context->fpregs.fregs); ++index) { + context->fpregs.fregs[index]._fp_fregs = static_cast(value++); + } + + context->fpcsr = value++; + context->fir = value++; + + for (size_t index = 0; index < 3; ++index) { + context->hi[index] = value++; + context->lo[index] = value++; + } + + context->dsp_control = value++; +} + +void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context, + uint32_t seed) { + if (seed == 0) { + memset(context, 0, sizeof(*context)); + context->context_flags = kMinidumpContextMIPS64; + return; + } + + context->context_flags = kMinidumpContextMIPS64All; + + uint64_t value = seed; + + for (size_t index = 0; index < arraysize(context->regs); ++index) { + context->regs[index] = value++; + } + + context->mdlo = value++; + context->mdhi = value++; + context->epc = value++; + context->badvaddr = value++; + context->status = value++; + context->cause = value++; + + for (size_t index = 0; index < arraysize(context->fpregs.dregs); ++index) { + context->fpregs.dregs[index] = static_cast(value++); + } + context->fpcsr = value++; + context->fir = value++; + + for (size_t index = 0; index < 3; ++index) { + context->hi[index] = value++; + context->lo[index] = value++; + } + context->dsp_control = value++; +} + namespace { // Using gtest assertions, compares |expected| to |observed|. This is @@ -453,5 +527,70 @@ void ExpectMinidumpContextARM64(uint32_t expect_seed, } } +void ExpectMinidumpContextMIPS(uint32_t expect_seed, + const MinidumpContextMIPS* observed, + bool snapshot) { + MinidumpContextMIPS expected; + InitializeMinidumpContextMIPS(&expected, expect_seed); + + EXPECT_EQ(observed->context_flags, expected.context_flags); + + for (size_t index = 0; index < arraysize(expected.regs); ++index) { + EXPECT_EQ(observed->regs[index], expected.regs[index]); + } + + EXPECT_EQ(observed->mdlo, expected.mdlo); + EXPECT_EQ(observed->mdhi, expected.mdhi); + EXPECT_EQ(observed->epc, expected.epc); + EXPECT_EQ(observed->badvaddr, expected.badvaddr); + EXPECT_EQ(observed->status, expected.status); + EXPECT_EQ(observed->cause, expected.cause); + + for (size_t index = 0; index < arraysize(expected.fpregs.fregs); ++index) { + EXPECT_EQ(observed->fpregs.fregs[index]._fp_fregs, + expected.fpregs.fregs[index]._fp_fregs); + } + EXPECT_EQ(observed->fpcsr, expected.fpcsr); + EXPECT_EQ(observed->fir, expected.fir); + + for (size_t index = 0; index < 3; ++index) { + EXPECT_EQ(observed->hi[index], expected.hi[index]); + EXPECT_EQ(observed->lo[index], expected.lo[index]); + } + EXPECT_EQ(observed->dsp_control, expected.dsp_control); +} + +void ExpectMinidumpContextMIPS64(uint32_t expect_seed, + const MinidumpContextMIPS64* observed, + bool snapshot) { + MinidumpContextMIPS64 expected; + InitializeMinidumpContextMIPS64(&expected, expect_seed); + + EXPECT_EQ(observed->context_flags, expected.context_flags); + + for (size_t index = 0; index < arraysize(expected.regs); ++index) { + EXPECT_EQ(observed->regs[index], expected.regs[index]); + } + + EXPECT_EQ(observed->mdlo, expected.mdlo); + EXPECT_EQ(observed->mdhi, expected.mdhi); + EXPECT_EQ(observed->epc, expected.epc); + EXPECT_EQ(observed->badvaddr, expected.badvaddr); + EXPECT_EQ(observed->status, expected.status); + EXPECT_EQ(observed->cause, expected.cause); + + for (size_t index = 0; index < arraysize(expected.fpregs.dregs); ++index) { + EXPECT_EQ(observed->fpregs.dregs[index], expected.fpregs.dregs[index]); + } + EXPECT_EQ(observed->fpcsr, expected.fpcsr); + EXPECT_EQ(observed->fir, expected.fir); + + for (size_t index = 0; index < 3; ++index) { + EXPECT_EQ(observed->hi[index], expected.hi[index]); + EXPECT_EQ(observed->lo[index], expected.lo[index]); + } + EXPECT_EQ(observed->dsp_control, expected.dsp_control); +} + } // namespace test } // namespace crashpad diff --git a/minidump/test/minidump_context_test_util.h b/minidump/test/minidump_context_test_util.h index 64f79cde..080e04a0 100644 --- a/minidump/test/minidump_context_test_util.h +++ b/minidump/test/minidump_context_test_util.h @@ -44,6 +44,9 @@ void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context, void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed); void InitializeMinidumpContextARM64(MinidumpContextARM64* context, uint32_t seed); +void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, uint32_t seed); +void InitializeMinidumpContextMIPS64(MinidumpContextMIPS* context, + uint32_t seed); //! \} //! \brief Verifies, via gtest assertions, that a context structure contains @@ -76,6 +79,12 @@ void ExpectMinidumpContextARM(uint32_t expect_seed, void ExpectMinidumpContextARM64(uint32_t expect_seed, const MinidumpContextARM64* observed, bool snapshot); +void ExpectMinidumpContextMIPS(uint32_t expect_seed, + const MinidumpContextMIPS* observed, + bool snapshot); +void ExpectMinidumpContextMIPS64(uint32_t expect_seed, + const MinidumpContextMIPS64* observed, + bool snapshot); //! \} } // namespace test diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 6bafabb3..134df8b1 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -416,7 +416,8 @@ source_set("snapshot_test") { libs = [ "dl" ] } - if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { + if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) && + target_cpu != "mipsel" && target_cpu != "mips64el") { data_deps += [ ":crashpad_snapshot_test_both_dt_hash_styles" ] } @@ -477,7 +478,8 @@ crashpad_loadable_module("crashpad_snapshot_test_module_small") { deps += [ "../third_party/mini_chromium:base" ] } -if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { +if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) && + target_cpu != "mipsel" && target_cpu != "mips64el") { crashpad_loadable_module("crashpad_snapshot_test_both_dt_hash_styles") { testonly = true sources = [ diff --git a/snapshot/capture_memory.cc b/snapshot/capture_memory.cc index 4327fbda..98f400e8 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -106,6 +106,10 @@ void CaptureMemory::PointedToByContext(const CPUContext& context, MaybeCaptureMemoryAround(delegate, context.arm->regs[i]); } } +#elif defined(ARCH_CPU_MIPS_FAMILY) + for (size_t i = 0; i < arraysize(context.mipsel->regs); ++i) { + MaybeCaptureMemoryAround(delegate, context.mipsel->regs[i]); + } #else #error Port. #endif diff --git a/snapshot/cpu_architecture.h b/snapshot/cpu_architecture.h index 6116d4a1..811a7209 100644 --- a/snapshot/cpu_architecture.h +++ b/snapshot/cpu_architecture.h @@ -37,7 +37,13 @@ enum CPUArchitecture { kCPUArchitectureARM, //! \brief 64-bit ARM. - kCPUArchitectureARM64 + kCPUArchitectureARM64, + + //! \brief 32-bit MIPSEL. + kCPUArchitectureMIPSEL, + + //! \brief 64-bit MIPSEL. + kCPUArchitectureMIPS64EL }; } // namespace crashpad diff --git a/snapshot/cpu_context.cc b/snapshot/cpu_context.cc index 553a1a5d..4d7c1e5a 100644 --- a/snapshot/cpu_context.cc +++ b/snapshot/cpu_context.cc @@ -194,9 +194,11 @@ bool CPUContext::Is64Bit() const { switch (architecture) { case kCPUArchitectureX86_64: case kCPUArchitectureARM64: + case kCPUArchitectureMIPS64EL: return true; case kCPUArchitectureX86: case kCPUArchitectureARM: + case kCPUArchitectureMIPSEL: return false; default: NOTREACHED(); diff --git a/snapshot/cpu_context.h b/snapshot/cpu_context.h index b104217d..4dde9436 100644 --- a/snapshot/cpu_context.h +++ b/snapshot/cpu_context.h @@ -306,6 +306,52 @@ struct CPUContextARM64 { uint32_t fpcr; }; +//! \brief A context structure carrying MIPS CPU state. +struct CPUContextMIPS { + uint64_t regs[32]; + uint32_t mdlo; + uint32_t mdhi; + uint32_t cp0_epc; + uint32_t cp0_badvaddr; + uint32_t cp0_status; + uint32_t cp0_cause; + uint32_t hi[3]; + uint32_t lo[3]; + uint32_t dsp_control; + union { + double dregs[32]; + struct { + float _fp_fregs; + uint32_t _fp_pad; + } fregs[32]; + } fpregs; + uint32_t fpcsr; + uint32_t fir; +}; + +//! \brief A context structure carrying MIPS64 CPU state. +struct CPUContextMIPS64 { + uint64_t regs[32]; + uint64_t mdlo; + uint64_t mdhi; + uint64_t cp0_epc; + uint64_t cp0_badvaddr; + uint64_t cp0_status; + uint64_t cp0_cause; + uint64_t hi[3]; + uint64_t lo[3]; + uint64_t dsp_control; + union { + double dregs[32]; + struct { + float _fp_fregs; + uint32_t _fp_pad; + } fregs[32]; + } fpregs; + uint64_t fpcsr; + uint64_t fir; +}; + //! \brief A context structure capable of carrying the context of any supported //! CPU architecture. struct CPUContext { @@ -334,6 +380,8 @@ struct CPUContext { CPUContextX86_64* x86_64; CPUContextARM* arm; CPUContextARM64* arm64; + CPUContextMIPS* mipsel; + CPUContextMIPS64* mips64; }; }; diff --git a/snapshot/linux/cpu_context_linux.h b/snapshot/linux/cpu_context_linux.h index 4ca679a9..37fbc432 100644 --- a/snapshot/linux/cpu_context_linux.h +++ b/snapshot/linux/cpu_context_linux.h @@ -138,6 +138,42 @@ void InitializeCPUContextARM64_OnlyFPSIMD( #endif // ARCH_CPU_ARM_FAMILY || DOXYGEN +#if defined(ARCH_CPU_MIPS_FAMILY) || DOXYGEN + +//! \brief Initializes a CPUContextMIPS structure from native context +//! structures on Linux. +//! +//! This function has template specializations for MIPSEL and MIPS64EL +//! architecture contexts, using ContextTraits32 or ContextTraits64 as template +//! parameter, respectively. +//! +//! \param[in] thread_context The native thread context. +//! \param[in] float_context The native float context. +//! \param[out] context The CPUContextMIPS structure to initialize. +template +void InitializeCPUContextMIPS( + const typename Traits::SignalThreadContext& thread_context, + const typename Traits::SignalFloatContext& float_context, + typename Traits::CPUContext* context) { + static_assert(sizeof(context->regs) == sizeof(thread_context.regs), + "registers size mismatch"); + static_assert(sizeof(context->fpregs) == sizeof(float_context.fpregs), + "fp registers size mismatch"); + memcpy(&context->regs, &thread_context.regs, sizeof(context->regs)); + context->mdlo = thread_context.lo; + context->mdhi = thread_context.hi; + context->cp0_epc = thread_context.cp0_epc; + context->cp0_badvaddr = thread_context.cp0_badvaddr; + context->cp0_status = thread_context.cp0_status; + context->cp0_cause = thread_context.cp0_cause; + + memcpy(&context->fpregs, &float_context.fpregs, sizeof(context->fpregs)); + context->fpcsr = float_context.fpcsr; + context->fir = float_context.fpu_id; +}; + +#endif // ARCH_CPU_MIPS_FAMILY || DOXYGEN + } // namespace internal } // namespace crashpad diff --git a/snapshot/linux/exception_snapshot_linux.cc b/snapshot/linux/exception_snapshot_linux.cc index c57e072e..4256f942 100644 --- a/snapshot/linux/exception_snapshot_linux.cc +++ b/snapshot/linux/exception_snapshot_linux.cc @@ -268,6 +268,61 @@ bool ExceptionSnapshotLinux::ReadContext( } while (true); } +#elif defined(ARCH_CPU_MIPS_FAMILY) + +template +static bool ReadContext(ProcessReaderLinux* reader, + LinuxVMAddress context_address, + typename Traits::CPUContext* dest_context) { + ProcessMemory* memory = reader->Memory(); + + LinuxVMAddress gregs_address = context_address + + offsetof(UContext, mcontext) + + offsetof(typename Traits::MContext, gregs); + + typename Traits::SignalThreadContext thread_context; + if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) { + LOG(ERROR) << "Couldn't read gregs"; + return false; + } + + LinuxVMAddress fpregs_address = context_address + + offsetof(UContext, mcontext) + + offsetof(typename Traits::MContext, fpregs); + + typename Traits::SignalFloatContext fp_context; + if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) { + LOG(ERROR) << "Couldn't read fpregs"; + return false; + } + + InitializeCPUContextMIPS(thread_context, fp_context, dest_context); + + return true; +} + +template <> +bool ExceptionSnapshotLinux::ReadContext( + ProcessReaderLinux* reader, + LinuxVMAddress context_address) { + context_.architecture = kCPUArchitectureMIPSEL; + context_.mipsel = &context_union_.mipsel; + + return internal::ReadContext( + reader, context_address, context_.mipsel); +} + +template <> +bool ExceptionSnapshotLinux::ReadContext( + ProcessReaderLinux* reader, + LinuxVMAddress context_address) { + context_.architecture = kCPUArchitectureMIPS64EL; + context_.mips64 = &context_union_.mips64; + + return internal::ReadContext( + reader, context_address, context_.mips64); +} + #endif // ARCH_CPU_X86_FAMILY bool ExceptionSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, diff --git a/snapshot/linux/exception_snapshot_linux.h b/snapshot/linux/exception_snapshot_linux.h index 0dcead7b..ea0cd210 100644 --- a/snapshot/linux/exception_snapshot_linux.h +++ b/snapshot/linux/exception_snapshot_linux.h @@ -81,6 +81,9 @@ class ExceptionSnapshotLinux final : public ExceptionSnapshot { #elif defined(ARCH_CPU_ARM_FAMILY) CPUContextARM arm; CPUContextARM64 arm64; +#elif defined(ARCH_CPU_MIPS_FAMILY) + CPUContextMIPS mipsel; + CPUContextMIPS64 mips64; #endif } context_union_; CPUContext context_; diff --git a/snapshot/linux/exception_snapshot_linux_test.cc b/snapshot/linux/exception_snapshot_linux_test.cc index 5a0c6ae1..df9ad9e9 100644 --- a/snapshot/linux/exception_snapshot_linux_test.cc +++ b/snapshot/linux/exception_snapshot_linux_test.cc @@ -266,6 +266,36 @@ void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { sizeof(actual.arm64->fpsimd)), 0); } +#elif defined(ARCH_CPU_MIPS_FAMILY) +using NativeCPUContext = ucontext_t; + +void InitializeContext(NativeCPUContext* context) { + for (size_t reg = 0; reg < arraysize(context->uc_mcontext.gregs); ++reg) { + context->uc_mcontext.gregs[reg] = reg; + } + memset(&context->uc_mcontext.fpregs, 44, sizeof(context->uc_mcontext.fpregs)); +} + +void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { +#if defined(ARCH_CPU_MIPSEL) + EXPECT_EQ(actual.architecture, kCPUArchitectureMIPSEL); +#define CPU_ARCH_NAME mipsel +#elif defined(ARCH_CPU_MIPS64EL) + EXPECT_EQ(actual.architecture, kCPUArchitectureMIPS64EL); +#define CPU_ARCH_NAME mips64 +#endif + + for (size_t reg = 0; reg < arraysize(expected.uc_mcontext.gregs); ++reg) { + EXPECT_EQ(actual.CPU_ARCH_NAME->regs[reg], expected.uc_mcontext.gregs[reg]); + } + + EXPECT_EQ(memcmp(&actual.CPU_ARCH_NAME->fpregs, + &expected.uc_mcontext.fpregs, + sizeof(actual.CPU_ARCH_NAME->fpregs)), + 0); +#undef CPU_ARCH_NAME +} + #else #error Port. #endif diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index 9a5b092f..038d5cef 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -100,6 +100,9 @@ void ProcessReaderLinux::Thread::InitializeStack(ProcessReaderLinux* reader) { #elif defined(ARCH_CPU_ARM_FAMILY) stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.sp : thread_info.thread_context.t32.sp; +#elif defined(ARCH_CPU_MIPS_FAMILY) + stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.regs[29] + : thread_info.thread_context.t32.regs[29]; #else #error Port. #endif diff --git a/snapshot/linux/signal_context.h b/snapshot/linux/signal_context.h index 63202abe..11002468 100644 --- a/snapshot/linux/signal_context.h +++ b/snapshot/linux/signal_context.h @@ -41,8 +41,14 @@ union Sigval { template struct Siginfo { int32_t signo; +#ifdef ARCH_CPU_MIPS_FAMILY + // Attribute order for signo_t defined in kernel is different for MIPS. + int32_t code; + int32_t err; +#else int32_t err; int32_t code; +#endif typename Traits::UInteger32_64Only padding; union { @@ -301,6 +307,121 @@ static_assert(offsetof(UContext, reserved) == "reserved space offset mismtach"); #endif +#elif defined(ARCH_CPU_MIPS_FAMILY) + +struct MContext32 { + uint32_t regmask; + uint32_t status; + uint64_t pc; + uint64_t gregs[32]; + struct { + float _fp_fregs; + unsigned int _fp_pad; + } fpregs[32]; + uint32_t fp_owned; + uint32_t fpc_csr; + uint32_t fpc_eir; + uint32_t used_math; + uint32_t dsp; + uint64_t mdhi; + uint64_t mdlo; + uint32_t hi1; + uint32_t lo1; + uint32_t hi2; + uint32_t lo2; + uint32_t hi3; + uint32_t lo3; +}; + +struct MContext64 { + uint64_t gregs[32]; + double fpregs[32]; + uint64_t mdhi; + uint64_t hi1; + uint64_t hi2; + uint64_t hi3; + uint64_t mdlo; + uint64_t lo1; + uint64_t lo2; + uint64_t lo3; + uint64_t pc; + uint32_t fpc_csr; + uint32_t used_math; + uint32_t dsp; + uint32_t __glibc_reserved1; +}; + +struct SignalThreadContext32 { + uint64_t regs[32]; + uint32_t lo; + uint32_t hi; + uint32_t cp0_epc; + uint32_t cp0_badvaddr; + uint32_t cp0_status; + uint32_t cp0_cause; + + SignalThreadContext32() {} + explicit SignalThreadContext32( + const struct ThreadContext::t32_t& thread_context) { + for (size_t reg = 0; reg < 32; ++reg) { + regs[reg] = thread_context.regs[reg]; + } + lo = thread_context.lo; + hi = thread_context.hi; + cp0_epc = thread_context.cp0_epc; + cp0_badvaddr = thread_context.cp0_badvaddr; + cp0_status = thread_context.cp0_status; + cp0_cause = thread_context.cp0_cause; + } +}; + +struct ContextTraits32 : public Traits32 { + using MContext = MContext32; + using SignalThreadContext = SignalThreadContext32; + using SignalFloatContext = FloatContext::f32_t; + using CPUContext = CPUContextMIPS; +}; + +struct ContextTraits64 : public Traits64 { + using MContext = MContext64; + using SignalThreadContext = ThreadContext::t64_t; + using SignalFloatContext = FloatContext::f64_t; + using CPUContext = CPUContextMIPS64; +}; + +template +struct UContext { + typename Traits::ULong flags; + typename Traits::Address link; + SignalStack stack; + typename Traits::ULong_32Only alignment_padding_; + typename Traits::MContext mcontext; + Sigset sigmask; +}; + +#if defined(ARCH_CPU_MIPSEL) +static_assert(offsetof(UContext, mcontext) == + offsetof(ucontext_t, uc_mcontext), + "context offset mismatch"); +static_assert(offsetof(UContext, mcontext.gregs) == + offsetof(ucontext_t, uc_mcontext.gregs), + "context offset mismatch"); +static_assert(offsetof(UContext, mcontext.fpregs) == + offsetof(ucontext_t, uc_mcontext.fpregs), + "context offset mismatch"); + +#elif defined(ARCH_CPU_MIPS64EL) +static_assert(offsetof(UContext, mcontext) == + offsetof(ucontext_t, uc_mcontext), + "context offset mismtach"); +static_assert(offsetof(UContext, mcontext.gregs) == + offsetof(ucontext_t, uc_mcontext.gregs), + "context offset mismatch"); +static_assert(offsetof(UContext, mcontext.fpregs) == + offsetof(ucontext_t, uc_mcontext.fpregs), + "context offset mismatch"); +#endif + #else #error Port. #endif // ARCH_CPU_X86_FAMILY diff --git a/snapshot/linux/system_snapshot_linux.cc b/snapshot/linux/system_snapshot_linux.cc index 4c392888..8564d3d4 100644 --- a/snapshot/linux/system_snapshot_linux.cc +++ b/snapshot/linux/system_snapshot_linux.cc @@ -200,6 +200,9 @@ CPUArchitecture SystemSnapshotLinux::GetCPUArchitecture() const { #elif defined(ARCH_CPU_ARM_FAMILY) return process_reader_->Is64Bit() ? kCPUArchitectureARM64 : kCPUArchitectureARM; +#elif defined(ARCH_CPU_MIPS_FAMILY) + return process_reader_->Is64Bit() ? kCPUArchitectureMIPS64EL + : kCPUArchitectureMIPSEL; #else #error port to your architecture #endif @@ -212,6 +215,9 @@ uint32_t SystemSnapshotLinux::CPURevision() const { #elif defined(ARCH_CPU_ARM_FAMILY) // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30 return 0; +#elif defined(ARCH_CPU_MIPS_FAMILY) + // Not implementable on MIPS + return 0; #else #error port to your architecture #endif @@ -229,6 +235,9 @@ std::string SystemSnapshotLinux::CPUVendor() const { #elif defined(ARCH_CPU_ARM_FAMILY) // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30 return std::string(); +#elif defined(ARCH_CPU_MIPS_FAMILY) + // Not implementable on MIPS + return std::string(); #else #error port to your architecture #endif @@ -359,6 +368,9 @@ bool SystemSnapshotLinux::NXEnabled() const { #elif defined(ARCH_CPU_ARM_FAMILY) // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30 return false; +#elif defined(ARCH_CPU_MIPS_FAMILY) + // Not implementable on MIPS + return false; #else #error Port. #endif // ARCH_CPU_X86_FAMILY diff --git a/snapshot/linux/thread_snapshot_linux.cc b/snapshot/linux/thread_snapshot_linux.cc index 084ed73a..8ffbfe8b 100644 --- a/snapshot/linux/thread_snapshot_linux.cc +++ b/snapshot/linux/thread_snapshot_linux.cc @@ -69,6 +69,22 @@ bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, thread.thread_info.float_context.f32, context_.arm); } +#elif defined(ARCH_CPU_MIPS_FAMILY) + if (process_reader->Is64Bit()) { + context_.architecture = kCPUArchitectureMIPS64EL; + context_.mips64 = &context_union_.mips64; + InitializeCPUContextMIPS( + thread.thread_info.thread_context.t64, + thread.thread_info.float_context.f64, + context_.mips64); + } else { + context_.architecture = kCPUArchitectureMIPSEL; + context_.mipsel = &context_union_.mipsel; + InitializeCPUContextMIPS( + SignalThreadContext32(thread.thread_info.thread_context.t32), + thread.thread_info.float_context.f32, + context_.mipsel); + } #else #error Port. #endif diff --git a/snapshot/linux/thread_snapshot_linux.h b/snapshot/linux/thread_snapshot_linux.h index 8fc7e17e..17e471f3 100644 --- a/snapshot/linux/thread_snapshot_linux.h +++ b/snapshot/linux/thread_snapshot_linux.h @@ -65,6 +65,9 @@ class ThreadSnapshotLinux final : public ThreadSnapshot { #elif defined(ARCH_CPU_ARM_FAMILY) CPUContextARM arm; CPUContextARM64 arm64; +#elif defined(ARCH_CPU_MIPS_FAMILY) + CPUContextMIPS mipsel; + CPUContextMIPS64 mips64; #else #error Port. #endif // ARCH_CPU_X86_FAMILY diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index fc746f2c..b795d92f 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -52,7 +52,6 @@ 'target_name': 'crashpad_snapshot_test', 'type': 'executable', 'dependencies': [ - 'crashpad_snapshot_test_both_dt_hash_styles', 'crashpad_snapshot_test_lib', 'crashpad_snapshot_test_module', 'crashpad_snapshot_test_module_large', @@ -104,6 +103,10 @@ 'win/system_snapshot_win_test.cc', ], 'conditions': [ + # .gnu.hash is incompatible with the MIPS ABI + ['target_arch!="mips"', { + 'dependencies': ['crashpad_snapshot_test_both_dt_hash_styles'] + }], ['OS=="mac"', { 'dependencies': [ 'crashpad_snapshot_test_module_crashy_initializer', @@ -228,13 +231,17 @@ { 'target_name': 'crashpad_snapshot_test_both_dt_hash_styles', 'type': 'executable', - 'sources': [ - 'hash_types_test.cc', - ], - - 'ldflags': [ - # This makes `ld` emit both .hash and .gnu.hash sections. - '-Wl,--hash-style=both', + 'conditions': [ + # .gnu.hash is incompatible with the MIPS ABI + ['target_arch!="mips"', { + 'sources': [ + 'hash_types_test.cc', + ], + 'ldflags': [ + # This makes `ld` emit both .hash and .gnu.hash sections. + '-Wl,--hash-style=both', + ]}, + ] ], }, ], diff --git a/snapshot/test/test_cpu_context.cc b/snapshot/test/test_cpu_context.cc index 09a5e799..1e785af8 100644 --- a/snapshot/test/test_cpu_context.cc +++ b/snapshot/test/test_cpu_context.cc @@ -220,5 +220,77 @@ void InitializeCPUContextARM64(CPUContext* context, uint32_t seed) { arm64->fpcr = value++; } +void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed) { + context->architecture = kCPUArchitectureMIPSEL; + CPUContextMIPS* mipsel = context->mipsel; + + if (seed == 0) { + memset(mipsel, 0, sizeof(*mipsel)); + return; + } + + uint32_t value = seed; + + for (size_t index = 0; index < arraysize(mipsel->regs); ++index) { + mipsel->regs[index] = value++; + } + + mipsel->mdlo = value++; + mipsel->mdhi = value++; + mipsel->cp0_epc = value++; + mipsel->cp0_badvaddr = value++; + mipsel->cp0_status = value++; + mipsel->cp0_cause = value++; + + for (size_t index = 0; index < arraysize(mipsel->fpregs.fregs); ++index) { + mipsel->fpregs.fregs[index]._fp_fregs = static_cast(value++); + } + + mipsel->fpcsr = value++; + mipsel->fir = value++; + + for (size_t index = 0; index < 3; ++index) { + mipsel->hi[index] = value++; + mipsel->lo[index] = value++; + } + mipsel->dsp_control = value++; +} + +void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed) { + context->architecture = kCPUArchitectureMIPS64EL; + CPUContextMIPS64* mips64 = context->mips64; + + if (seed == 0) { + memset(mips64, 0, sizeof(*mips64)); + return; + } + + uint64_t value = seed; + + for (size_t index = 0; index < arraysize(mips64->regs); ++index) { + mips64->regs[index] = value++; + } + + mips64->mdlo = value++; + mips64->mdhi = value++; + mips64->cp0_epc = value++; + mips64->cp0_badvaddr = value++; + mips64->cp0_status = value++; + mips64->cp0_cause = value++; + + for (size_t index = 0; index < arraysize(mips64->fpregs.dregs); ++index) { + mips64->fpregs.dregs[index] = static_cast(value++); + } + + mips64->fpcsr = value++; + mips64->fir = value++; + + for (size_t index = 0; index < 3; ++index) { + mips64->hi[index] = value++; + mips64->lo[index] = value++; + } + mips64->dsp_control = value++; +} + } // namespace test } // namespace crashpad diff --git a/snapshot/test/test_cpu_context.h b/snapshot/test/test_cpu_context.h index 0b4b5376..ca1b6b7b 100644 --- a/snapshot/test/test_cpu_context.h +++ b/snapshot/test/test_cpu_context.h @@ -61,6 +61,8 @@ void InitializeCPUContextX86(CPUContext* context, uint32_t seed); void InitializeCPUContextX86_64(CPUContext* context, uint32_t seed); void InitializeCPUContextARM(CPUContext* context, uint32_t seed); void InitializeCPUContextARM64(CPUContext* context, uint32_t seed); +void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed); +void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed); //! \} } // namespace test diff --git a/test/linux/get_tls.cc b/test/linux/get_tls.cc index 47d041e4..452724de 100644 --- a/test/linux/get_tls.cc +++ b/test/linux/get_tls.cc @@ -35,6 +35,20 @@ LinuxVMAddress GetTLS() { tls = tls_32; #elif defined(ARCH_CPU_X86_64) asm("movq %%fs:0x0, %0" : "=r"(tls)); +#elif defined(ARCH_CPU_MIPSEL) + uint32_t tls_32; + asm("rdhwr $3,$29\n\t" + "move %0,$3\n\t" + : "=r"(tls_32) + : + : "$3"); + tls = tls_32; +#elif defined(ARCH_CPU_MIPS64EL) + asm("rdhwr $3,$29\n\t" + "move %0,$3\n\t" + : "=r"(tls) + : + : "$3"); #else #error Port. #endif // ARCH_CPU_ARMEL diff --git a/test/multiprocess_posix.cc b/test/multiprocess_posix.cc index 96b8ad26..cdb5385e 100644 --- a/test/multiprocess_posix.cc +++ b/test/multiprocess_posix.cc @@ -158,7 +158,7 @@ void Multiprocess::SetExpectedChildTermination(TerminationReason reason, } void Multiprocess::SetExpectedChildTerminationBuiltinTrap() { -#if defined(ARCH_CPU_ARM64) +#if defined(ARCH_CPU_ARM64) || defined(ARCH_CPU_MIPS_FAMILY) SetExpectedChildTermination(kTerminationSignal, SIGTRAP); #else SetExpectedChildTermination(kTerminationSignal, SIGILL); diff --git a/util/linux/auxiliary_vector_test.cc b/util/linux/auxiliary_vector_test.cc index 3a69ead1..add2d1e2 100644 --- a/util/linux/auxiliary_vector_test.cc +++ b/util/linux/auxiliary_vector_test.cc @@ -37,7 +37,12 @@ // TODO(jperaza): This symbol isn't defined when building in chromium for // Android. There may be another symbol to use. extern "C" { -extern void _start(); +#if defined(ARCH_CPU_MIPS_FAMILY) +#define START_SYMBOL __start +#else +#define START_SYMBOL _start +#endif +extern void START_SYMBOL(); } // extern "C" #endif @@ -70,7 +75,7 @@ void TestAgainstCloneOrSelf(pid_t pid) { #if !defined(OS_ANDROID) LinuxVMAddress entry_addr; ASSERT_TRUE(aux.GetValue(AT_ENTRY, &entry_addr)); - EXPECT_EQ(entry_addr, FromPointerCast(_start)); + EXPECT_EQ(entry_addr, FromPointerCast(START_SYMBOL)); #endif uid_t uid; diff --git a/util/linux/ptracer.cc b/util/linux/ptracer.cc index 63bee1e0..c6c92299 100644 --- a/util/linux/ptracer.cc +++ b/util/linux/ptracer.cc @@ -269,6 +269,131 @@ bool GetThreadArea64(pid_t tid, } return true; } +#elif defined(ARCH_CPU_MIPS_FAMILY) +// PTRACE_GETREGSET, introduced in Linux 2.6.34 (2225a122ae26), requires kernel +// support enabled by HAVE_ARCH_TRACEHOOK. This has been set for x86 (including +// x86_64) since Linux 2.6.28 (99bbc4b1e677a), but for MIPS only since +// Linux 3.13 (c0ff3c53d4f99). Older Linux kernels support PTRACE_GETREGS, +// and PTRACE_GETFPREGS instead, which don't allow checking the size of data +// copied. Also, PTRACE_GETREGS assumes register size of 64 bits even for 32 bit +// MIPS CPU (contrary to PTRACE_GETREGSET behavior), so we need buffer +// structure here. + +bool GetGeneralPurposeRegistersLegacy(pid_t tid, + ThreadContext* context, + bool can_log) { + ThreadContext context_buffer; + if (ptrace(PTRACE_GETREGS, tid, nullptr, &context_buffer.t64) != 0) { + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } +// Bitness of target process can't be determined through ptrace here, so we +// assume target process has the same as current process, making cross-bit +// ptrace unsupported on MIPS for kernels older than 3.13 +#if defined(ARCH_CPU_MIPSEL) +#define THREAD_CONTEXT_FIELD t32 +#elif defined(ARCH_CPU_MIPS64EL) +#define THREAD_CONTEXT_FIELD t64 +#endif + for (size_t reg = 0; reg < 32; ++reg) { + context->THREAD_CONTEXT_FIELD.regs[reg] = context_buffer.t64.regs[reg]; + } + context->THREAD_CONTEXT_FIELD.lo = context_buffer.t64.lo; + context->THREAD_CONTEXT_FIELD.hi = context_buffer.t64.hi; + context->THREAD_CONTEXT_FIELD.cp0_epc = context_buffer.t64.cp0_epc; + context->THREAD_CONTEXT_FIELD.cp0_badvaddr = context_buffer.t64.cp0_badvaddr; + context->THREAD_CONTEXT_FIELD.cp0_status = context_buffer.t64.cp0_status; + context->THREAD_CONTEXT_FIELD.cp0_cause = context_buffer.t64.cp0_cause; +#undef THREAD_CONTEXT_FIELD + return true; +} + +bool GetFloatingPointRegistersLegacy(pid_t tid, + FloatContext* context, + bool can_log) { + if (ptrace(PTRACE_GETFPREGS, tid, nullptr, &context->f32.fpregs) != 0) { + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + return true; +} + +bool GetFloatingPointRegisters32(pid_t tid, + FloatContext* context, + bool can_log) { + iovec iov; + iov.iov_base = &context->f32.fpregs; + iov.iov_len = sizeof(context->f32.fpregs); + if (ptrace(PTRACE_GETFPREGS, tid, nullptr, &context->f32.fpregs) != 0) { + switch (errno) { + case EINVAL: + // fp may not be present + break; + case EIO: + return GetFloatingPointRegistersLegacy(tid, context, can_log); + default: + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + } + return true; +} + +bool GetFloatingPointRegisters64(pid_t tid, + FloatContext* context, + bool can_log) { + iovec iov; + iov.iov_base = &context->f64.fpregs; + iov.iov_len = sizeof(context->f64.fpregs); + if (ptrace(PTRACE_GETFPREGS, tid, nullptr, &context->f64.fpregs) != 0) { + switch (errno) { + case EINVAL: + // fp may not be present + break; + case EIO: + return GetFloatingPointRegistersLegacy(tid, context, can_log); + default: + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + } + return true; +} + +bool GetThreadArea32(pid_t tid, + const ThreadContext& context, + LinuxVMAddress* address, + bool can_log) { +#if defined(ARCH_CPU_MIPSEL) + void* result; + if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &result) != 0) { + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + *address = FromPointerCast(result); + return true; +#else + return false; +#endif +} + +bool GetThreadArea64(pid_t tid, + const ThreadContext& context, + LinuxVMAddress* address, + bool can_log) { + void* result; +#if defined(ARCH_CPU_MIPSEL) + if (ptrace(PTRACE_GET_THREAD_AREA_3264, tid, nullptr, &result) != 0) { +#else + if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &result) != 0) { +#endif + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + *address = FromPointerCast(result); + return true; +} + #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -283,7 +408,7 @@ size_t GetGeneralPurposeRegistersAndLength(pid_t tid, PTRACE_GETREGSET, tid, reinterpret_cast(NT_PRSTATUS), &iov) != 0) { switch (errno) { -#if defined(ARCH_CPU_ARMEL) +#if defined(ARCH_CPU_ARMEL) || defined(ARCH_CPU_MIPS_FAMILY) case EIO: return GetGeneralPurposeRegistersLegacy(tid, context, can_log) ? sizeof(context->t32) diff --git a/util/linux/thread_info.h b/util/linux/thread_info.h index 91d0082f..5b55c24a 100644 --- a/util/linux/thread_info.h +++ b/util/linux/thread_info.h @@ -67,6 +67,18 @@ union ThreadContext { uint32_t pc; uint32_t cpsr; uint32_t orig_r0; +#elif defined(ARCH_CPU_MIPS_FAMILY) + // Reflects output format of static int gpr32_get(), defined in + // arch/mips/kernel/ptrace.c in kernel source + uint32_t padding0_[6]; + uint32_t regs[32]; + uint32_t lo; + uint32_t hi; + uint32_t cp0_epc; + uint32_t cp0_badvaddr; + uint32_t cp0_status; + uint32_t cp0_cause; + uint32_t padding1_; #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -110,6 +122,16 @@ union ThreadContext { uint64_t sp; uint64_t pc; uint64_t pstate; +#elif defined(ARCH_CPU_MIPS_FAMILY) + // Reflects output format of static int gpr64_get(), defined in + // arch/mips/kernel/ptrace.c in kernel source + uint64_t regs[32]; + uint64_t lo; + uint64_t hi; + uint64_t cp0_epc; + uint64_t cp0_badvaddr; + uint64_t cp0_status; + uint64_t cp0_cause; #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -119,15 +141,19 @@ union ThreadContext { using NativeThreadContext = user_regs_struct; #elif defined(ARCH_CPU_ARMEL) using NativeThreadContext = user_regs; +#elif defined(ARCH_CPU_MIPS_FAMILY) +// No appropriate NativeThreadsContext type available for MIPS #else #error Port. #endif // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64 +#if !defined(ARCH_CPU_MIPS_FAMILY) #if defined(ARCH_CPU_32_BITS) static_assert(sizeof(t32_t) == sizeof(NativeThreadContext), "Size mismatch"); #else // ARCH_CPU_64_BITS static_assert(sizeof(t64_t) == sizeof(NativeThreadContext), "Size mismatch"); #endif // ARCH_CPU_32_BITS +#endif // !ARCH_CPU_MIPS_FAMILY }; static_assert(std::is_standard_layout::value, "Not standard layout"); @@ -183,6 +209,15 @@ union FloatContext { bool have_fpregs; bool have_vfp; +#elif defined(ARCH_CPU_MIPS_FAMILY) + // Reflects data format filled by ptrace_getfpregs() in + // arch/mips/kernel/ptrace.c + struct { + float _fp_fregs; + unsigned int _fp_pad; + } fpregs[32]; + uint32_t fpcsr; + uint32_t fpu_id; #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -211,6 +246,12 @@ union FloatContext { uint32_t fpsr; uint32_t fpcr; uint8_t padding[8]; +#elif defined(ARCH_CPU_MIPS_FAMILY) + // Reflects data format filled by ptrace_getfpregs() in + // arch/mips/kernel/ptrace.c + double fpregs[32]; + uint32_t fpcsr; + uint32_t fpu_id; #else #error Port. #endif // ARCH_CPU_X86_FAMILY @@ -237,6 +278,8 @@ union FloatContext { #endif #elif defined(ARCH_CPU_ARM64) static_assert(sizeof(f64) == sizeof(user_fpsimd_struct), "Size mismatch"); +#elif defined(ARCH_CPU_MIPS_FAMILY) +// No appropriate floating point context native type for available MIPS. #else #error Port. #endif // ARCH_CPU_X86 diff --git a/util/misc/capture_context.h b/util/misc/capture_context.h index 73b80580..541589df 100644 --- a/util/misc/capture_context.h +++ b/util/misc/capture_context.h @@ -65,6 +65,7 @@ using NativeCPUContext = ucontext_t; //! Win | x86_64 | `%%rcx` //! macOS/Linux/Fuchsia | x86_64 | `%%rdi` //! Linux | ARM/ARM64 | `r0`/`x0` +//! Linux | MIPS/MIPS64 | `$a0` //! //! Additionally, the value `LR` on ARM/ARM64 will be the return address of //! this function. diff --git a/util/misc/capture_context_linux.S b/util/misc/capture_context_linux.S index b8d6238b..42999a90 100644 --- a/util/misc/capture_context_linux.S +++ b/util/misc/capture_context_linux.S @@ -28,7 +28,7 @@ .globl CAPTURECONTEXT_SYMBOL2 #if defined(__i386__) || defined(__x86_64__) .balign 16, 0x90 -#elif defined(__arm__) || defined(__aarch64__) +#elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) .balign 4, 0x0 #endif @@ -331,5 +331,94 @@ CAPTURECONTEXT_SYMBOL2: // TODO(jperaza): save floating-point registers. ret +#elif defined(__mips__) + .set noat +#if _MIPS_SIM == _ABIO32 +#define STORE sw +#define MCONTEXT_FPREG_SIZE 4 +#define MCONTEXT_PC_OFFSET 32 +#else +#define STORE sd +#define MCONTEXT_FPREG_SIZE 8 +#define MCONTEXT_PC_OFFSET 616 +#endif + +#define MCONTEXT_REG_SIZE 8 +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 + + // Value of register 0 is always 0. + // Registers 26 and 27 are reserved for kernel, and shouldn't be used. + STORE $1, (1 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $2, (2 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $3, (3 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $4, (4 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $5, (5 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $6, (6 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $7, (7 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $8, (8 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $9, (9 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $10, (10 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $11, (11 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $12, (12 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $13, (13 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $14, (14 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $15, (15 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $16, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $17, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $18, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $19, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $20, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $21, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $22, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $23, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0) + STORE $31, (MCONTEXT_PC_OFFSET)($a0) + +#ifdef __mips_hard_float + s.d $f0, (0 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f2, (2 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f4, (4 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f6, (6 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f8, (8 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f10, (10 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f12, (12 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f14, (14 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f16, (16 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f18, (18 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f20, (20 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f22, (22 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f24, (24 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f26, (26 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f28, (28 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f30, (30 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) +#if _MIPS_SIM != _ABIO32 + s.d $f1, (1 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f3, (3 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f5, (5 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f7, (7 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f9, (9 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f11, (11 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f13, (13 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f15, (15 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f17, (17 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f19, (19 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f21, (21 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f23, (23 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f25, (25 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f27, (27 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f29, (29 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) + s.d $f31, (31 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0) +#endif // _MIPS_SIM != _ABIO32 +#endif // __mips_hard_float + + jr $ra + + .set at #endif // __i386__ diff --git a/util/misc/capture_context_test.cc b/util/misc/capture_context_test.cc index deeea9e3..1117789d 100644 --- a/util/misc/capture_context_test.cc +++ b/util/misc/capture_context_test.cc @@ -49,7 +49,7 @@ void TestCaptureContext() { // reference program counter. uintptr_t pc = ProgramCounterFromContext(context_1); -#if !defined(ADDRESS_SANITIZER) +#if !defined(ADDRESS_SANITIZER) && !defined(ARCH_CPU_MIPS_FAMILY) // AddressSanitizer can cause enough code bloat that the “nearby” check would // likely fail. const uintptr_t kReferencePC = diff --git a/util/misc/capture_context_test_util_linux.cc b/util/misc/capture_context_test_util_linux.cc index 3ba13d85..9fc5db28 100644 --- a/util/misc/capture_context_test_util_linux.cc +++ b/util/misc/capture_context_test_util_linux.cc @@ -34,6 +34,8 @@ void SanityCheckContext(const NativeCPUContext& context) { EXPECT_EQ(context.uc_mcontext.arm_r0, FromPointerCast(&context)); #elif defined(ARCH_CPU_ARM64) EXPECT_EQ(context.uc_mcontext.regs[0], FromPointerCast(&context)); +#elif defined(ARCH_CPU_MIPS_FAMILY) + EXPECT_EQ(context.uc_mcontext.gregs[4], FromPointerCast(&context)); #endif } @@ -46,6 +48,8 @@ uintptr_t ProgramCounterFromContext(const NativeCPUContext& context) { return context.uc_mcontext.arm_pc; #elif defined(ARCH_CPU_ARM64) return context.uc_mcontext.pc; +#elif defined(ARCH_CPU_MIPS_FAMILY) + return context.uc_mcontext.pc; #endif } @@ -58,6 +62,8 @@ uintptr_t StackPointerFromContext(const NativeCPUContext& context) { return context.uc_mcontext.arm_sp; #elif defined(ARCH_CPU_ARM64) return context.uc_mcontext.sp; +#elif defined(ARCH_CPU_MIPS_FAMILY) + return context.uc_mcontext.gregs[29]; #endif } diff --git a/util/posix/symbolic_constants_posix.cc b/util/posix/symbolic_constants_posix.cc index c973c146..8008ffb6 100644 --- a/util/posix/symbolic_constants_posix.cc +++ b/util/posix/symbolic_constants_posix.cc @@ -65,6 +65,39 @@ constexpr const char* kSignalNames[] = { "USR1", "USR2", #elif defined(OS_LINUX) || defined(OS_ANDROID) +#if defined(ARCH_CPU_MIPS_FAMILY) + "HUP", + "INT", + "QUIT", + "ILL", + "TRAP", + "ABRT", + "EMT", + "FPE", + "KILL", + "BUS", + "SEGV", + "SYS", + "PIPE", + "ALRM", + "TERM", + "USR1", + "USR2", + "CHLD", + "PWR", + "WINCH", + "URG", + "IO", + "STOP", + "TSTP", + "CONT", + "TTIN", + "TTOU", + "VTALRM", + "PROF", + "XCPU", + "XFSZ", +#else // sed -Ene 's/^#define[[:space:]]SIG([[:alnum:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/ "\1",/p' // /usr/include/asm-generic/signal.h // and fix up by removing SIGIOT, SIGLOST, SIGUNUSED, and SIGRTMIN. @@ -99,6 +132,7 @@ constexpr const char* kSignalNames[] = { "IO", "PWR", "SYS", +#endif // defined(ARCH_CPU_MIPS_FAMILY) #endif }; #if defined(OS_LINUX) || defined(OS_ANDROID) diff --git a/util/posix/symbolic_constants_posix_test.cc b/util/posix/symbolic_constants_posix_test.cc index 8478b7bc..32c1d434 100644 --- a/util/posix/symbolic_constants_posix_test.cc +++ b/util/posix/symbolic_constants_posix_test.cc @@ -67,8 +67,10 @@ constexpr struct { {SIGINFO, "SIGINFO", "INFO"}, #elif defined(OS_LINUX) || defined(OS_ANDROID) {SIGPWR, "SIGPWR", "PWR"}, +#if !defined(ARCH_CPU_MIPS_FAMILY) {SIGSTKFLT, "SIGSTKFLT", "STKFLT"}, #endif +#endif }; // If |expect| is nullptr, the conversion is expected to fail. If |expect| is