Add ARM family minidump support

Bug: crashpad:30
Change-Id: I6784d42ba6c525c4e0b16dfdbbb4949c83e32fea
Reviewed-on: https://chromium-review.googlesource.com/888541
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Joshua Peraza 2018-01-30 12:41:09 -08:00 committed by Commit Bot
parent 693ff6d550
commit c9244d58df
8 changed files with 587 additions and 121 deletions

View File

@ -336,6 +336,102 @@ struct alignas(16) MinidumpContextAMD64 {
//! \}
};
//! \brief 32-bit ARM-specifc flags for MinidumpContextARM::context_flags.
enum MinidumpContextARMFlags : uint32_t {
//! \brief Identifies the context structure as 32-bit ARM.
kMinidumpContextARM = 0x40000000,
//! \brief Indicates the validity of integer regsiters.
//!
//! Regsiters `r0`-`r15` and `cpsr` are valid.
kMinidumpContextARMInteger = kMinidumpContextARM | 0x00000002,
//! \brief Inidicates the validity of VFP regsiters.
//!
//! Registers `d0`-`d31` and `fpscr` are valid.
kMinidumpContextARMVFP = kMinidumpContextARM | 0x00000004,
//! \brief Indicates the validity of all registers.
kMinidumpContextARMAll = kMinidumpContextARMInteger | kMinidumpContextARMVFP,
};
//! \brief A 32-bit ARM CPU context (register state) carried in a minidump file.
struct MinidumpContextARM {
//! \brief A bitfield composed of values of #MinidumpContextFlags and
//! #MinidumpContextARMFlags.
//!
//! This field identifies the context structure as a 32-bit ARM CPU context,
//! and indicates which other fields in the structure are valid.
uint32_t context_flags;
//! \brief General-purpose registers `r0`-`r15`.
uint32_t regs[11];
uint32_t fp; // r11
uint32_t ip; // r12
uint32_t sp; // r13
uint32_t lr; // r14
uint32_t pc; // r15
//! \brief Current program status register.
uint32_t cpsr;
//! \brief Floating-point status and control register.
uint32_t fpscr;
//! \brief VFP registers `d0`-`d31`.
uint64_t vfp[32];
//! \brief This space is unused. It is included for compatibility with
//! breakpad (which also doesn't use it).
uint32_t extra[8];
};
//! \brief 64-bit ARM-specifc flags for MinidumpContextARM64::context_flags.
enum MinidumpContextARM64Flags : uint32_t {
//! \brief Identifies the context structure as 64-bit ARM.
kMinidumpContextARM64 = 0x80000000,
//! \brief Indicates the validty of integer registers.
//!
//! Registers `x0`-`x31`, `pc`, and `cpsr`.
kMinidumpContextARM64Integer = kMinidumpContextARM64 | 0x00000002,
//! \brief Indicates the validity of fpsimd registers.
//!
//! Registers `v0`-`v31`, `fpsr`, and `fpcr` are valid.
kMinidumpContextARM64Fpsimd = kMinidumpContextARM64 | 0x00000004,
//! \brief Indicates the validity of all registers.
kMinidumpContextARM64All =
kMinidumpContextARM64Integer | kMinidumpContextARM64Fpsimd,
};
//! \brief A 64-bit ARM CPU context (register state) carried in a minidump file.
struct MinidumpContextARM64 {
uint64_t context_flags;
//! \brief General-purpose registers `x0`-`x30`.
uint64_t regs[31];
//! \brief Stack pointer or `x31`.
uint64_t sp;
//! \brief Program counter.
uint64_t pc;
//! \brief Current program status register.
uint32_t cpsr;
//! \brief Floating-point status register.
uint32_t fpsr;
//! \brief Floating-point control register.
uint32_t fpcr;
//! \brief NEON registers `v0`-`v31`.
uint128_struct fpsimd[32];
};
} // namespace crashpad
#endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_

View File

@ -73,6 +73,19 @@ MinidumpContextWriter::CreateFromSnapshot(const CPUContext* context_snapshot) {
break;
}
case kCPUArchitectureARM: {
context = std::make_unique<MinidumpContextARMWriter>();
reinterpret_cast<MinidumpContextARMWriter*>(context.get())
->InitializeFromSnapshot(context_snapshot->arm);
break;
}
case kCPUArchitectureARM64: {
context = std::make_unique<MinidumpContextARM64Writer>();
reinterpret_cast<MinidumpContextARM64Writer*>(context.get())
->InitializeFromSnapshot(context_snapshot->arm64);
}
default: {
LOG(ERROR) << "unknown context architecture "
<< context_snapshot->architecture;
@ -239,4 +252,90 @@ size_t MinidumpContextAMD64Writer::ContextSize() const {
return sizeof(context_);
}
MinidumpContextARMWriter::MinidumpContextARMWriter()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextARM;
}
MinidumpContextARMWriter::~MinidumpContextARMWriter() = default;
void MinidumpContextARMWriter::InitializeFromSnapshot(
const CPUContextARM* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextARM);
context_.context_flags = kMinidumpContextARMAll;
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
"GPRS size mismatch");
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
context_.fp = context_snapshot->fp;
context_.ip = context_snapshot->ip;
context_.sp = context_snapshot->sp;
context_.lr = context_snapshot->lr;
context_.pc = context_snapshot->pc;
context_.cpsr = context_snapshot->cpsr;
context_.fpscr = context_snapshot->vfp_regs.fpscr;
static_assert(sizeof(context_.vfp) == sizeof(context_snapshot->vfp_regs.vfp),
"VFP size mismatch");
memcpy(context_.vfp, context_snapshot->vfp_regs.vfp, sizeof(context_.vfp));
memset(context_.extra, 0, sizeof(context_.extra));
}
bool MinidumpContextARMWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextARMWriter::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
MinidumpContextARM64Writer::MinidumpContextARM64Writer()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextARM64;
}
MinidumpContextARM64Writer::~MinidumpContextARM64Writer() = default;
void MinidumpContextARM64Writer::InitializeFromSnapshot(
const CPUContextARM64* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextARM64);
context_.context_flags = kMinidumpContextARM64All;
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
"GPRs size mismatch");
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
context_.sp = context_snapshot->sp;
context_.pc = context_snapshot->pc;
if (context_snapshot->pstate >
std::numeric_limits<decltype(context_.cpsr)>::max()) {
LOG(WARNING) << "pstate truncation";
}
context_.cpsr =
static_cast<decltype(context_.cpsr)>(context_snapshot->pstate);
context_.fpsr = context_snapshot->fpsr;
context_.fpcr = context_snapshot->fpcr;
static_assert(sizeof(context_.fpsimd) == sizeof(context_snapshot->fpsimd),
"FPSIMD size mismatch");
memcpy(context_.fpsimd, context_snapshot->fpsimd, sizeof(context_.fpsimd));
}
bool MinidumpContextARM64Writer::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextARM64Writer::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
} // namespace crashpad

View File

@ -155,6 +155,86 @@ class MinidumpContextAMD64Writer final : public MinidumpContextWriter {
DISALLOW_COPY_AND_ASSIGN(MinidumpContextAMD64Writer);
};
//! \brief The writer for a MinidumpContextARM structure in a minidump file.
class MinidumpContextARMWriter final : public MinidumpContextWriter {
public:
MinidumpContextARMWriter();
~MinidumpContextARMWriter() override;
//! \brief Initializes the MinidumpContextARM 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 CPUContextARM* context_snapshot);
//! \brief Returns a pointer to the context structure that this object will
//! write.
//!
//! \attention This returns a non-`const` pointer to this objects 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.
MinidumpContextARM* context() { return &context_; }
protected:
// MinidumpWritable:
bool WriteObject(FileWriterInterface* file_writer) override;
// MinidumpContextWriter:
size_t ContextSize() const override;
private:
MinidumpContextARM context_;
DISALLOW_COPY_AND_ASSIGN(MinidumpContextARMWriter);
};
//! \brief The writer for a MinidumpContextARM64 structure in a minidump file.
class MinidumpContextARM64Writer final : public MinidumpContextWriter {
public:
MinidumpContextARM64Writer();
~MinidumpContextARM64Writer() override;
//! \brief Initializes the MinidumpContextARM64 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 CPUContextARM64* context_snapshot);
//! \brief Returns a pointer to the context structure that this object will
//! write.
//!
//! \attention This returns a non-`const` pointer to this objects 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.
MinidumpContextARM64* context() { return &context_; }
protected:
// MinidumpWritable:
bool WriteObject(FileWriterInterface* file_writer) override;
// MinidumpContextWriter:
size_t ContextSize() const override;
private:
MinidumpContextARM64 context_;
DISALLOW_COPY_AND_ASSIGN(MinidumpContextARM64Writer);
};
} // namespace crashpad
#endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_

View File

@ -28,6 +28,20 @@ namespace crashpad {
namespace test {
namespace {
template <typename Writer, typename Context>
void EmptyContextTest(void (*expect_context)(uint32_t, const Context*, bool)) {
Writer context_writer;
StringFile string_file;
EXPECT_TRUE(context_writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(), sizeof(Context));
const Context* observed =
MinidumpWritableAtRVA<Context>(string_file.string(), 0);
ASSERT_TRUE(observed);
expect_context(0, observed, false);
}
TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
StringFile string_file;
@ -36,16 +50,8 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
// context.
SCOPED_TRACE("zero");
MinidumpContextX86Writer context_writer;
EXPECT_TRUE(context_writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(), sizeof(MinidumpContextX86));
const MinidumpContextX86* observed =
MinidumpWritableAtRVA<MinidumpContextX86>(string_file.string(), 0);
ASSERT_TRUE(observed);
ExpectMinidumpContextX86(0, observed, false);
EmptyContextTest<MinidumpContextX86Writer, MinidumpContextX86>(
ExpectMinidumpContextX86);
}
{
@ -85,16 +91,8 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
// context.
SCOPED_TRACE("zero");
MinidumpContextAMD64Writer context_writer;
EXPECT_TRUE(context_writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(), sizeof(MinidumpContextAMD64));
const MinidumpContextAMD64* observed =
MinidumpWritableAtRVA<MinidumpContextAMD64>(string_file.string(), 0);
ASSERT_TRUE(observed);
ExpectMinidumpContextAMD64(0, observed, false);
EmptyContextTest<MinidumpContextAMD64Writer, MinidumpContextAMD64>(
ExpectMinidumpContextAMD64);
}
{
@ -117,48 +115,72 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
}
}
TEST(MinidumpContextWriter, CreateFromSnapshot_X86) {
constexpr uint32_t kSeed = 32;
CPUContextX86 context_snapshot_x86;
CPUContext context_snapshot;
context_snapshot.x86 = &context_snapshot_x86;
InitializeCPUContextX86(&context_snapshot, kSeed);
template <typename Writer, typename Context>
void FromSnapshotTest(const CPUContext& snapshot_context,
void (*expect_context)(uint32_t, const Context*, bool),
uint32_t seed) {
std::unique_ptr<MinidumpContextWriter> context_writer =
MinidumpContextWriter::CreateFromSnapshot(&context_snapshot);
MinidumpContextWriter::CreateFromSnapshot(&snapshot_context);
ASSERT_TRUE(context_writer);
StringFile string_file;
ASSERT_TRUE(context_writer->WriteEverything(&string_file));
const MinidumpContextX86* observed =
MinidumpWritableAtRVA<MinidumpContextX86>(string_file.string(), 0);
const Context* observed =
MinidumpWritableAtRVA<Context>(string_file.string(), 0);
ASSERT_TRUE(observed);
ExpectMinidumpContextX86(kSeed, observed, true);
expect_context(seed, observed, true);
}
TEST(MinidumpContextWriter, CreateFromSnapshot_AMD64) {
TEST(MinidumpContextWriter, X86_FromSnapshot) {
constexpr uint32_t kSeed = 32;
CPUContextX86 context_x86;
CPUContext context;
context.x86 = &context_x86;
InitializeCPUContextX86(&context, kSeed);
FromSnapshotTest<MinidumpContextX86Writer, MinidumpContextX86>(
context, ExpectMinidumpContextX86, kSeed);
}
TEST(MinidumpContextWriter, AMD64_FromSnapshot) {
constexpr uint32_t kSeed = 64;
CPUContextX86_64 context_x86_64;
CPUContext context;
context.x86_64 = &context_x86_64;
InitializeCPUContextX86_64(&context, kSeed);
FromSnapshotTest<MinidumpContextAMD64Writer, MinidumpContextAMD64>(
context, ExpectMinidumpContextAMD64, kSeed);
}
CPUContextX86_64 context_snapshot_x86_64;
CPUContext context_snapshot;
context_snapshot.x86_64 = &context_snapshot_x86_64;
InitializeCPUContextX86_64(&context_snapshot, kSeed);
TEST(MinidumpContextWriter, ARM_Zeros) {
EmptyContextTest<MinidumpContextARMWriter, MinidumpContextARM>(
ExpectMinidumpContextARM);
}
std::unique_ptr<MinidumpContextWriter> context_writer =
MinidumpContextWriter::CreateFromSnapshot(&context_snapshot);
ASSERT_TRUE(context_writer);
TEST(MinidumpContextWRiter, ARM64_Zeros) {
EmptyContextTest<MinidumpContextARM64Writer, MinidumpContextARM64>(
ExpectMinidumpContextARM64);
}
StringFile string_file;
ASSERT_TRUE(context_writer->WriteEverything(&string_file));
TEST(MinidumpContextWriter, ARM_FromSnapshot) {
constexpr uint32_t kSeed = 32;
CPUContextARM context_arm;
CPUContext context;
context.arm = &context_arm;
InitializeCPUContextARM(&context, kSeed);
FromSnapshotTest<MinidumpContextARMWriter, MinidumpContextARM>(
context, ExpectMinidumpContextARM, kSeed);
}
const MinidumpContextAMD64* observed =
MinidumpWritableAtRVA<MinidumpContextAMD64>(string_file.string(), 0);
ASSERT_TRUE(observed);
ExpectMinidumpContextAMD64(kSeed, observed, true);
TEST(MinidumpContextWriter, ARM64_FromSnapshot) {
constexpr uint32_t kSeed = 64;
CPUContextARM64 context_arm64;
CPUContext context;
context.arm64 = &context_arm64;
InitializeCPUContextARM64(&context, kSeed);
FromSnapshotTest<MinidumpContextARM64Writer, MinidumpContextARM64>(
context, ExpectMinidumpContextARM64, kSeed);
}
} // namespace

View File

@ -140,6 +140,61 @@ void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context,
context->last_exception_from_rip = value++;
}
void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed) {
if (seed == 0) {
memset(context, 0, sizeof(*context));
context->context_flags = kMinidumpContextARM;
return;
}
context->context_flags = kMinidumpContextARMAll;
uint32_t value = seed;
for (size_t index = 0; index < arraysize(context->regs); ++index) {
context->regs[index] = value++;
}
context->fp = value++;
context->ip = value++;
context->ip = value++;
context->sp = value++;
context->lr = value++;
context->pc = value++;
context->cpsr = value++;
for (size_t index = 0; index < arraysize(context->vfp); ++index) {
context->vfp[index] = value++;
}
context->fpscr = value++;
}
void InitializeMinidumpContextARM64(MinidumpContextARM64* context,
uint32_t seed) {
if (seed == 0) {
memset(context, 0, sizeof(*context));
context->context_flags = kMinidumpContextARM64;
return;
}
context->context_flags = kMinidumpContextARM64All;
uint32_t value = seed;
for (size_t index = 0; index < arraysize(context->regs); ++index) {
context->regs[index] = value++;
}
context->sp = value++;
context->pc = value++;
context->cpsr = value++;
for (size_t index = 0; index < arraysize(context->fpsimd); ++index) {
context->fpsimd[index].lo = value++;
context->fpsimd[index].hi = value++;
}
context->fpsr = value++;
context->fpcr = value++;
}
namespace {
// Using gtest assertions, compares |expected| to |observed|. This is
@ -350,5 +405,53 @@ void ExpectMinidumpContextAMD64(
}
}
void ExpectMinidumpContextARM(uint32_t expect_seed,
const MinidumpContextARM* observed,
bool snapshot) {
MinidumpContextARM expected;
InitializeMinidumpContextARM(&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->fp, expected.fp);
EXPECT_EQ(observed->ip, expected.ip);
EXPECT_EQ(observed->sp, expected.sp);
EXPECT_EQ(observed->lr, expected.lr);
EXPECT_EQ(observed->pc, expected.pc);
EXPECT_EQ(observed->cpsr, expected.cpsr);
EXPECT_EQ(observed->fpscr, expected.fpscr);
for (size_t index = 0; index < arraysize(expected.vfp); ++index) {
EXPECT_EQ(observed->vfp[index], expected.vfp[index]);
}
for (size_t index = 0; index < arraysize(expected.extra); ++index) {
EXPECT_EQ(observed->extra[index], snapshot ? 0 : expected.extra[index]);
}
}
void ExpectMinidumpContextARM64(uint32_t expect_seed,
const MinidumpContextARM64* observed,
bool snapshot) {
MinidumpContextARM64 expected;
InitializeMinidumpContextARM64(&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->cpsr, expected.cpsr);
EXPECT_EQ(observed->fpsr, expected.fpsr);
EXPECT_EQ(observed->fpcr, expected.fpcr);
for (size_t index = 0; index < arraysize(expected.fpsimd); ++index) {
EXPECT_EQ(observed->fpsimd[index].lo, expected.fpsimd[index].lo);
EXPECT_EQ(observed->fpsimd[index].hi, expected.fpsimd[index].hi);
}
}
} // namespace test
} // namespace crashpad

View File

@ -41,6 +41,9 @@ namespace test {
void InitializeMinidumpContextX86(MinidumpContextX86* context, uint32_t seed);
void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context,
uint32_t seed);
void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed);
void InitializeMinidumpContextARM64(MinidumpContextARM64* context,
uint32_t seed);
//! \}
//! \brief Verifies, via gtest assertions, that a context structure contains
@ -67,6 +70,12 @@ void ExpectMinidumpContextX86(
uint32_t expect_seed, const MinidumpContextX86* observed, bool snapshot);
void ExpectMinidumpContextAMD64(
uint32_t expect_seed, const MinidumpContextAMD64* observed, bool snapshot);
void ExpectMinidumpContextARM(uint32_t expect_seed,
const MinidumpContextARM* observed,
bool snapshot);
void ExpectMinidumpContextARM64(uint32_t expect_seed,
const MinidumpContextARM64* observed,
bool snapshot);
//! \}
} // namespace test

View File

@ -22,6 +22,68 @@
namespace crashpad {
namespace test {
namespace {
// This is templatized because the CPUContextX86::Fxsave and
// CPUContextX86_64::Fxsave are nearly identical but have different sizes for
// the members |xmm|, |reserved_4|, and |available|.
template <typename FxsaveType>
void InitializeCPUContextFxsave(FxsaveType* fxsave, uint32_t* seed) {
uint32_t value = *seed;
fxsave->fcw = static_cast<uint16_t>(value++);
fxsave->fsw = static_cast<uint16_t>(value++);
fxsave->ftw = static_cast<uint8_t>(value++);
fxsave->reserved_1 = static_cast<uint8_t>(value++);
fxsave->fop = static_cast<uint16_t>(value++);
fxsave->fpu_ip = value++;
fxsave->fpu_cs = static_cast<uint16_t>(value++);
fxsave->reserved_2 = static_cast<uint16_t>(value++);
fxsave->fpu_dp = value++;
fxsave->fpu_ds = static_cast<uint16_t>(value++);
fxsave->reserved_3 = static_cast<uint16_t>(value++);
fxsave->mxcsr = value++;
fxsave->mxcsr_mask = value++;
for (size_t st_mm_index = 0; st_mm_index < arraysize(fxsave->st_mm);
++st_mm_index) {
for (size_t byte = 0; byte < arraysize(fxsave->st_mm[st_mm_index].st);
++byte) {
fxsave->st_mm[st_mm_index].st[byte] = static_cast<uint8_t>(value++);
}
for (size_t byte = 0;
byte < arraysize(fxsave->st_mm[st_mm_index].st_reserved);
++byte) {
fxsave->st_mm[st_mm_index].st_reserved[byte] =
static_cast<uint8_t>(value);
}
}
for (size_t xmm_index = 0; xmm_index < arraysize(fxsave->xmm); ++xmm_index) {
for (size_t byte = 0; byte < arraysize(fxsave->xmm[xmm_index]); ++byte) {
fxsave->xmm[xmm_index][byte] = static_cast<uint8_t>(value++);
}
}
for (size_t byte = 0; byte < arraysize(fxsave->reserved_4); ++byte) {
fxsave->reserved_4[byte] = static_cast<uint8_t>(value++);
}
for (size_t byte = 0; byte < arraysize(fxsave->available); ++byte) {
fxsave->available[byte] = static_cast<uint8_t>(value++);
}
*seed = value;
}
} // namespace
void InitializeCPUContextX86Fxsave(CPUContextX86::Fxsave* fxsave,
uint32_t* seed) {
return InitializeCPUContextFxsave(fxsave, seed);
}
void InitializeCPUContextX86_64Fxsave(CPUContextX86_64::Fxsave* fxsave,
uint32_t* seed) {
return InitializeCPUContextFxsave(fxsave, seed);
}
void InitializeCPUContextX86(CPUContext* context, uint32_t seed) {
context->architecture = kCPUArchitectureX86;
@ -101,68 +163,61 @@ void InitializeCPUContextX86_64(CPUContext* context, uint32_t seed) {
context->x86_64->dr7 = value++;
}
namespace {
void InitializeCPUContextARM(CPUContext* context, uint32_t seed) {
context->architecture = kCPUArchitectureARM;
CPUContextARM* arm = context->arm;
// This is templatized because the CPUContextX86::Fxsave and
// CPUContextX86_64::Fxsave are nearly identical but have different sizes for
// the members |xmm|, |reserved_4|, and |available|.
template <typename FxsaveType>
void InitializeCPUContextFxsave(FxsaveType* fxsave, uint32_t* seed) {
uint32_t value = *seed;
fxsave->fcw = static_cast<uint16_t>(value++);
fxsave->fsw = static_cast<uint16_t>(value++);
fxsave->ftw = static_cast<uint8_t>(value++);
fxsave->reserved_1 = static_cast<uint8_t>(value++);
fxsave->fop = static_cast<uint16_t>(value++);
fxsave->fpu_ip = value++;
fxsave->fpu_cs = static_cast<uint16_t>(value++);
fxsave->reserved_2 = static_cast<uint16_t>(value++);
fxsave->fpu_dp = value++;
fxsave->fpu_ds = static_cast<uint16_t>(value++);
fxsave->reserved_3 = static_cast<uint16_t>(value++);
fxsave->mxcsr = value++;
fxsave->mxcsr_mask = value++;
for (size_t st_mm_index = 0;
st_mm_index < arraysize(fxsave->st_mm);
++st_mm_index) {
for (size_t byte = 0;
byte < arraysize(fxsave->st_mm[st_mm_index].st);
++byte) {
fxsave->st_mm[st_mm_index].st[byte] = static_cast<uint8_t>(value++);
}
for (size_t byte = 0;
byte < arraysize(fxsave->st_mm[st_mm_index].st_reserved);
++byte) {
fxsave->st_mm[st_mm_index].st_reserved[byte] =
static_cast<uint8_t>(value);
}
}
for (size_t xmm_index = 0; xmm_index < arraysize(fxsave->xmm); ++xmm_index) {
for (size_t byte = 0; byte < arraysize(fxsave->xmm[xmm_index]); ++byte) {
fxsave->xmm[xmm_index][byte] = static_cast<uint8_t>(value++);
}
}
for (size_t byte = 0; byte < arraysize(fxsave->reserved_4); ++byte) {
fxsave->reserved_4[byte] = static_cast<uint8_t>(value++);
}
for (size_t byte = 0; byte < arraysize(fxsave->available); ++byte) {
fxsave->available[byte] = static_cast<uint8_t>(value++);
if (seed == 0) {
memset(arm, 0, sizeof(*arm));
return;
}
*seed = value;
uint32_t value = seed;
for (size_t index = 0; index < arraysize(arm->regs); ++index) {
arm->regs[index] = value++;
}
arm->fp = value++;
arm->ip = value++;
arm->ip = value++;
arm->sp = value++;
arm->lr = value++;
arm->pc = value++;
arm->cpsr = value++;
for (size_t index = 0; index < arraysize(arm->vfp_regs.vfp); ++index) {
arm->vfp_regs.vfp[index] = value++;
}
arm->vfp_regs.fpscr = value++;
arm->have_fpa_regs = false;
arm->have_vfp_regs = true;
}
} // namespace
void InitializeCPUContextARM64(CPUContext* context, uint32_t seed) {
context->architecture = kCPUArchitectureARM64;
CPUContextARM64* arm64 = context->arm64;
void InitializeCPUContextX86Fxsave(CPUContextX86::Fxsave* fxsave,
uint32_t* seed) {
return InitializeCPUContextFxsave(fxsave, seed);
}
if (seed == 0) {
memset(arm64, 0, sizeof(*arm64));
return;
}
void InitializeCPUContextX86_64Fxsave(CPUContextX86_64::Fxsave* fxsave,
uint32_t* seed) {
return InitializeCPUContextFxsave(fxsave, seed);
uint32_t value = seed;
for (size_t index = 0; index < arraysize(arm64->regs); ++index) {
arm64->regs[index] = value++;
}
arm64->sp = value++;
arm64->pc = value++;
arm64->pstate = value++;
for (size_t index = 0; index < arraysize(arm64->fpsimd); ++index) {
arm64->fpsimd[index].lo = value++;
arm64->fpsimd[index].hi = value++;
}
arm64->fpsr = value++;
arm64->fpcr = value++;
}
} // namespace test

View File

@ -22,6 +22,25 @@
namespace crashpad {
namespace test {
//! \brief Initializes an `fxsave` context substructure for testing.
//!
//! \param[out] fxsave The structure to initialize.
//! \param[in,out] seed The seed value. Initializing two `fxsave` structures of
//! the same type with identical seed values should produce identical
//! structures. Initialization with a different seed value should produce
//! a different `fxsave` structure. If \a seed is `0`, \a fxsave is zeroed
//! out entirely. If \a seed is nonzero, \a fxsave will be populated
//! entirely with nonzero values. \a seed will be updated by this function
//! to allow the caller to perform subsequent initialization of the context
//! structure containing \a fxsave.
//!
//! \{
void InitializeCPUContextX86Fxsave(CPUContextX86::Fxsave* fxsave,
uint32_t* seed);
void InitializeCPUContextX86_64Fxsave(CPUContextX86_64::Fxsave* fxsave,
uint32_t* seed);
//! \}
//! \brief Initializes a context structure for testing.
//!
//! Initialization is compatible with the initialization used by minidump
@ -40,25 +59,8 @@ namespace test {
//! \{
void InitializeCPUContextX86(CPUContext* context, uint32_t seed);
void InitializeCPUContextX86_64(CPUContext* context, uint32_t seed);
//! \}
//! \brief Initializes an `fxsave` context substructure for testing.
//!
//! \param[out] fxsave The structure to initialize.
//! \param[in,out] seed The seed value. Initializing two `fxsave` structures of
//! the same type with identical seed values should produce identical
//! structures. Initialization with a different seed value should produce
//! a different `fxsave` structure. If \a seed is `0`, \a fxsave is zeroed
//! out entirely. If \a seed is nonzero, \a fxsave will be populated
//! entirely with nonzero values. \a seed will be updated by this function
//! to allow the caller to perform subsequent initialization of the context
//! structure containing \a fxsave.
//!
//! \{
void InitializeCPUContextX86Fxsave(
CPUContextX86::Fxsave* fxsave, uint32_t* seed);
void InitializeCPUContextX86_64Fxsave(
CPUContextX86_64::Fxsave* fxsave, uint32_t* seed);
void InitializeCPUContextARM(CPUContext* context, uint32_t seed);
void InitializeCPUContextARM64(CPUContext* context, uint32_t seed);
//! \}
} // namespace test