mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
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 <jperaza@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
3072b4059f
commit
cb41ba7471
1
AUTHORS
1
AUTHORS
@ -11,3 +11,4 @@ Intel Corporation
|
||||
Opera Software ASA
|
||||
Vewd Software AS
|
||||
LG Electronics, Inc.
|
||||
MIPS Technologies, Inc.
|
||||
|
@ -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__)
|
||||
|
||||
|
@ -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_
|
||||
|
@ -87,6 +87,20 @@ MinidumpContextWriter::CreateFromSnapshot(const CPUContext* context_snapshot) {
|
||||
break;
|
||||
}
|
||||
|
||||
case kCPUArchitectureMIPSEL: {
|
||||
context = std::make_unique<MinidumpContextMIPSWriter>();
|
||||
reinterpret_cast<MinidumpContextMIPSWriter*>(context.get())
|
||||
->InitializeFromSnapshot(context_snapshot->mipsel);
|
||||
break;
|
||||
}
|
||||
|
||||
case kCPUArchitectureMIPS64EL: {
|
||||
context = std::make_unique<MinidumpContextMIPS64Writer>();
|
||||
reinterpret_cast<MinidumpContextMIPS64Writer*>(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
|
||||
|
@ -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_
|
||||
|
@ -183,6 +183,36 @@ TEST(MinidumpContextWriter, ARM64_FromSnapshot) {
|
||||
context, ExpectMinidumpContextARM64, kSeed);
|
||||
}
|
||||
|
||||
TEST(MinidumpContextWriter, MIPS_Zeros) {
|
||||
EmptyContextTest<MinidumpContextMIPSWriter, MinidumpContextMIPS>(
|
||||
ExpectMinidumpContextMIPS);
|
||||
}
|
||||
|
||||
TEST(MinidumpContextWriter, MIPS64_Zeros) {
|
||||
EmptyContextTest<MinidumpContextMIPS64Writer, MinidumpContextMIPS64>(
|
||||
ExpectMinidumpContextMIPS64);
|
||||
}
|
||||
|
||||
TEST(MinidumpContextWriter, MIPS_FromSnapshot) {
|
||||
constexpr uint32_t kSeed = 32;
|
||||
CPUContextMIPS context_mips;
|
||||
CPUContext context;
|
||||
context.mipsel = &context_mips;
|
||||
InitializeCPUContextMIPS(&context, kSeed);
|
||||
FromSnapshotTest<MinidumpContextMIPSWriter, MinidumpContextMIPS>(
|
||||
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<MinidumpContextMIPS64Writer, MinidumpContextMIPS64>(
|
||||
context, ExpectMinidumpContextMIPS64, kSeed);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -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
|
||||
|
@ -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<float>(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<double>(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
|
||||
|
@ -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
|
||||
|
@ -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 = [
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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 <typename Traits>
|
||||
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
|
||||
|
||||
|
@ -268,6 +268,61 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
|
||||
} while (true);
|
||||
}
|
||||
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
|
||||
template <typename Traits>
|
||||
static bool ReadContext(ProcessReaderLinux* reader,
|
||||
LinuxVMAddress context_address,
|
||||
typename Traits::CPUContext* dest_context) {
|
||||
ProcessMemory* memory = reader->Memory();
|
||||
|
||||
LinuxVMAddress gregs_address = context_address +
|
||||
offsetof(UContext<Traits>, 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<Traits>, 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<Traits>(thread_context, fp_context, dest_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
|
||||
ProcessReaderLinux* reader,
|
||||
LinuxVMAddress context_address) {
|
||||
context_.architecture = kCPUArchitectureMIPSEL;
|
||||
context_.mipsel = &context_union_.mipsel;
|
||||
|
||||
return internal::ReadContext<ContextTraits32>(
|
||||
reader, context_address, context_.mipsel);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
|
||||
ProcessReaderLinux* reader,
|
||||
LinuxVMAddress context_address) {
|
||||
context_.architecture = kCPUArchitectureMIPS64EL;
|
||||
context_.mips64 = &context_union_.mips64;
|
||||
|
||||
return internal::ReadContext<ContextTraits64>(
|
||||
reader, context_address, context_.mips64);
|
||||
}
|
||||
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
||||
bool ExceptionSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -41,8 +41,14 @@ union Sigval {
|
||||
template <class Traits>
|
||||
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<ContextTraits64>, 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 <typename Traits>
|
||||
struct UContext {
|
||||
typename Traits::ULong flags;
|
||||
typename Traits::Address link;
|
||||
SignalStack<Traits> stack;
|
||||
typename Traits::ULong_32Only alignment_padding_;
|
||||
typename Traits::MContext mcontext;
|
||||
Sigset<Traits> sigmask;
|
||||
};
|
||||
|
||||
#if defined(ARCH_CPU_MIPSEL)
|
||||
static_assert(offsetof(UContext<ContextTraits32>, mcontext) ==
|
||||
offsetof(ucontext_t, uc_mcontext),
|
||||
"context offset mismatch");
|
||||
static_assert(offsetof(UContext<ContextTraits32>, mcontext.gregs) ==
|
||||
offsetof(ucontext_t, uc_mcontext.gregs),
|
||||
"context offset mismatch");
|
||||
static_assert(offsetof(UContext<ContextTraits32>, mcontext.fpregs) ==
|
||||
offsetof(ucontext_t, uc_mcontext.fpregs),
|
||||
"context offset mismatch");
|
||||
|
||||
#elif defined(ARCH_CPU_MIPS64EL)
|
||||
static_assert(offsetof(UContext<ContextTraits64>, mcontext) ==
|
||||
offsetof(ucontext_t, uc_mcontext),
|
||||
"context offset mismtach");
|
||||
static_assert(offsetof(UContext<ContextTraits64>, mcontext.gregs) ==
|
||||
offsetof(ucontext_t, uc_mcontext.gregs),
|
||||
"context offset mismatch");
|
||||
static_assert(offsetof(UContext<ContextTraits64>, mcontext.fpregs) ==
|
||||
offsetof(ucontext_t, uc_mcontext.fpregs),
|
||||
"context offset mismatch");
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
@ -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
|
||||
|
@ -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<ContextTraits64>(
|
||||
thread.thread_info.thread_context.t64,
|
||||
thread.thread_info.float_context.f64,
|
||||
context_.mips64);
|
||||
} else {
|
||||
context_.architecture = kCPUArchitectureMIPSEL;
|
||||
context_.mipsel = &context_union_.mipsel;
|
||||
InitializeCPUContextMIPS<ContextTraits32>(
|
||||
SignalThreadContext32(thread.thread_info.thread_context.t32),
|
||||
thread.thread_info.float_context.f32,
|
||||
context_.mipsel);
|
||||
}
|
||||
#else
|
||||
#error Port.
|
||||
#endif
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
'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',
|
||||
]},
|
||||
]
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -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<float>(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<double>(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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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<LinuxVMAddress>(_start));
|
||||
EXPECT_EQ(entry_addr, FromPointerCast<LinuxVMAddress>(START_SYMBOL));
|
||||
#endif
|
||||
|
||||
uid_t uid;
|
||||
|
@ -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<LinuxVMAddress>(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<LinuxVMAddress>(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<void*>(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)
|
||||
|
@ -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<ThreadContext>::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
|
||||
|
@ -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.
|
||||
|
@ -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__
|
||||
|
@ -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 =
|
||||
|
@ -34,6 +34,8 @@ void SanityCheckContext(const NativeCPUContext& context) {
|
||||
EXPECT_EQ(context.uc_mcontext.arm_r0, FromPointerCast<uintptr_t>(&context));
|
||||
#elif defined(ARCH_CPU_ARM64)
|
||||
EXPECT_EQ(context.uc_mcontext.regs[0], FromPointerCast<uintptr_t>(&context));
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
EXPECT_EQ(context.uc_mcontext.gregs[4], FromPointerCast<uintptr_t>(&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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user