634 lines
22 KiB
C++
634 lines
22 KiB
C++
// Copyright 2014 The Crashpad Authors
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
#include "minidump/minidump_context_writer.h"
|
||
|
||
#include <windows.h>
|
||
#include <dbghelp.h>
|
||
#include <stdint.h>
|
||
#include <string.h>
|
||
|
||
#include "base/compiler_specific.h"
|
||
#include "base/logging.h"
|
||
#include "build/build_config.h"
|
||
#include "snapshot/cpu_context.h"
|
||
#include "util/file/file_writer.h"
|
||
#include "util/stdlib/aligned_allocator.h"
|
||
|
||
namespace crashpad {
|
||
|
||
namespace {
|
||
|
||
// Sanity-check complex structures to ensure interoperability.
|
||
static_assert(sizeof(MinidumpContextX86) == 716, "MinidumpContextX86 size");
|
||
static_assert(sizeof(MinidumpContextAMD64) == 1232,
|
||
"MinidumpContextAMD64 size");
|
||
|
||
// These structures can also be checked against definitions in the Windows SDK.
|
||
#if BUILDFLAG(IS_WIN)
|
||
#if defined(ARCH_CPU_X86_FAMILY)
|
||
static_assert(sizeof(MinidumpContextX86) == sizeof(WOW64_CONTEXT),
|
||
"WOW64_CONTEXT size");
|
||
#if defined(ARCH_CPU_X86)
|
||
static_assert(sizeof(MinidumpContextX86) == sizeof(CONTEXT), "CONTEXT size");
|
||
#elif defined(ARCH_CPU_X86_64)
|
||
static_assert(sizeof(MinidumpContextAMD64) == sizeof(CONTEXT), "CONTEXT size");
|
||
#endif
|
||
#endif // ARCH_CPU_X86_FAMILY
|
||
#endif // BUILDFLAG(IS_WIN)
|
||
|
||
} // namespace
|
||
|
||
MinidumpContextWriter::~MinidumpContextWriter() {
|
||
}
|
||
|
||
// static
|
||
std::unique_ptr<MinidumpContextWriter>
|
||
MinidumpContextWriter::CreateFromSnapshot(const CPUContext* context_snapshot) {
|
||
std::unique_ptr<MinidumpContextWriter> context;
|
||
|
||
switch (context_snapshot->architecture) {
|
||
case kCPUArchitectureX86: {
|
||
MinidumpContextX86Writer* context_x86 = new MinidumpContextX86Writer();
|
||
context.reset(context_x86);
|
||
context_x86->InitializeFromSnapshot(context_snapshot->x86);
|
||
break;
|
||
}
|
||
|
||
case kCPUArchitectureX86_64: {
|
||
MinidumpContextAMD64Writer* context_amd64 =
|
||
new MinidumpContextAMD64Writer();
|
||
context.reset(context_amd64);
|
||
context_amd64->InitializeFromSnapshot(context_snapshot->x86_64);
|
||
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);
|
||
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;
|
||
}
|
||
|
||
case kCPUArchitectureRISCV64: {
|
||
context = std::make_unique<MinidumpContextRISCV64Writer>();
|
||
reinterpret_cast<MinidumpContextRISCV64Writer*>(context.get())
|
||
->InitializeFromSnapshot(context_snapshot->riscv64);
|
||
break;
|
||
}
|
||
|
||
default: {
|
||
LOG(ERROR) << "unknown context architecture "
|
||
<< context_snapshot->architecture;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return context;
|
||
}
|
||
|
||
size_t MinidumpContextWriter::SizeOfObject() {
|
||
DCHECK_GE(state(), kStateFrozen);
|
||
|
||
return ContextSize();
|
||
}
|
||
|
||
size_t MinidumpContextWriter::FreezeAndGetSizeOfObject() {
|
||
Freeze();
|
||
return SizeOfObject();
|
||
}
|
||
|
||
MinidumpContextX86Writer::MinidumpContextX86Writer()
|
||
: MinidumpContextWriter(), context_() {
|
||
context_.context_flags = kMinidumpContextX86;
|
||
}
|
||
|
||
MinidumpContextX86Writer::~MinidumpContextX86Writer() {
|
||
}
|
||
|
||
void MinidumpContextX86Writer::InitializeFromSnapshot(
|
||
const CPUContextX86* context_snapshot) {
|
||
DCHECK_EQ(state(), kStateMutable);
|
||
DCHECK_EQ(context_.context_flags, kMinidumpContextX86);
|
||
|
||
context_.context_flags = kMinidumpContextX86All;
|
||
|
||
context_.dr0 = context_snapshot->dr0;
|
||
context_.dr1 = context_snapshot->dr1;
|
||
context_.dr2 = context_snapshot->dr2;
|
||
context_.dr3 = context_snapshot->dr3;
|
||
context_.dr6 = context_snapshot->dr6;
|
||
context_.dr7 = context_snapshot->dr7;
|
||
|
||
// The contents of context_.fsave effectively alias everything in
|
||
// context_.fxsave that’s related to x87 FPU state. context_.fsave doesn’t
|
||
// carry state specific to SSE (or later), such as mxcsr and the xmm
|
||
// registers.
|
||
CPUContextX86::FxsaveToFsave(context_snapshot->fxsave, &context_.fsave);
|
||
|
||
context_.gs = context_snapshot->gs;
|
||
context_.fs = context_snapshot->fs;
|
||
context_.es = context_snapshot->es;
|
||
context_.ds = context_snapshot->ds;
|
||
context_.edi = context_snapshot->edi;
|
||
context_.esi = context_snapshot->esi;
|
||
context_.ebx = context_snapshot->ebx;
|
||
context_.edx = context_snapshot->edx;
|
||
context_.ecx = context_snapshot->ecx;
|
||
context_.eax = context_snapshot->eax;
|
||
context_.ebp = context_snapshot->ebp;
|
||
context_.eip = context_snapshot->eip;
|
||
context_.cs = context_snapshot->cs;
|
||
context_.eflags = context_snapshot->eflags;
|
||
context_.esp = context_snapshot->esp;
|
||
context_.ss = context_snapshot->ss;
|
||
|
||
// This is effectively a memcpy() of a big structure.
|
||
context_.fxsave = context_snapshot->fxsave;
|
||
}
|
||
|
||
bool MinidumpContextX86Writer::WriteObject(FileWriterInterface* file_writer) {
|
||
DCHECK_EQ(state(), kStateWritable);
|
||
|
||
return file_writer->Write(&context_, sizeof(context_));
|
||
}
|
||
|
||
size_t MinidumpContextX86Writer::ContextSize() const {
|
||
DCHECK_GE(state(), kStateFrozen);
|
||
|
||
return sizeof(context_);
|
||
}
|
||
|
||
static_assert(alignof(MinidumpContextAMD64) >= 16,
|
||
"MinidumpContextAMD64 alignment");
|
||
static_assert(alignof(MinidumpContextAMD64Writer) >=
|
||
alignof(MinidumpContextAMD64),
|
||
"MinidumpContextAMD64Writer alignment");
|
||
|
||
MinidumpContextAMD64Writer::MinidumpContextAMD64Writer()
|
||
: MinidumpContextWriter(), context_() {
|
||
context_.context_flags = kMinidumpContextAMD64;
|
||
}
|
||
|
||
MinidumpContextAMD64Writer::~MinidumpContextAMD64Writer() {
|
||
}
|
||
|
||
// static
|
||
void* MinidumpContextAMD64Writer::operator new(size_t size) {
|
||
// MinidumpContextAMD64 requests an alignment of 16, which can be larger than
|
||
// what standard new provides. This may trigger MSVC warning C4316. As a
|
||
// workaround to this language deficiency, provide a custom allocation
|
||
// function to allocate a block meeting the alignment requirement.
|
||
return AlignedAllocate(alignof(MinidumpContextAMD64Writer), size);
|
||
}
|
||
|
||
// static
|
||
void MinidumpContextAMD64Writer::operator delete(void* pointer) {
|
||
return AlignedFree(pointer);
|
||
}
|
||
|
||
void MinidumpContextAMD64Writer::InitializeFromSnapshot(
|
||
const CPUContextX86_64* context_snapshot) {
|
||
DCHECK_EQ(state(), kStateMutable);
|
||
DCHECK_EQ(context_.context_flags, kMinidumpContextAMD64);
|
||
|
||
if (context_snapshot->xstate.enabled_features != 0) {
|
||
// Extended context.
|
||
context_.context_flags =
|
||
kMinidumpContextAMD64All | kMinidumpContextAMD64Xstate;
|
||
} else {
|
||
// Fixed size context - no xsave components.
|
||
context_.context_flags = kMinidumpContextAMD64All;
|
||
}
|
||
|
||
context_.mx_csr = context_snapshot->fxsave.mxcsr;
|
||
context_.cs = context_snapshot->cs;
|
||
context_.fs = context_snapshot->fs;
|
||
context_.gs = context_snapshot->gs;
|
||
// The top 32 bits of rflags are reserved/unused.
|
||
context_.eflags = static_cast<uint32_t>(context_snapshot->rflags);
|
||
context_.dr0 = context_snapshot->dr0;
|
||
context_.dr1 = context_snapshot->dr1;
|
||
context_.dr2 = context_snapshot->dr2;
|
||
context_.dr3 = context_snapshot->dr3;
|
||
context_.dr6 = context_snapshot->dr6;
|
||
context_.dr7 = context_snapshot->dr7;
|
||
context_.rax = context_snapshot->rax;
|
||
context_.rcx = context_snapshot->rcx;
|
||
context_.rdx = context_snapshot->rdx;
|
||
context_.rbx = context_snapshot->rbx;
|
||
context_.rsp = context_snapshot->rsp;
|
||
context_.rbp = context_snapshot->rbp;
|
||
context_.rsi = context_snapshot->rsi;
|
||
context_.rdi = context_snapshot->rdi;
|
||
context_.r8 = context_snapshot->r8;
|
||
context_.r9 = context_snapshot->r9;
|
||
context_.r10 = context_snapshot->r10;
|
||
context_.r11 = context_snapshot->r11;
|
||
context_.r12 = context_snapshot->r12;
|
||
context_.r13 = context_snapshot->r13;
|
||
context_.r14 = context_snapshot->r14;
|
||
context_.r15 = context_snapshot->r15;
|
||
context_.rip = context_snapshot->rip;
|
||
|
||
// This is effectively a memcpy() of a big structure.
|
||
context_.fxsave = context_snapshot->fxsave;
|
||
|
||
// If XSave features are being recorded store in xsave_entries in xcomp_bv
|
||
// order. We will not see features we do not support as we provide flags
|
||
// to the OS when first obtaining a snapshot.
|
||
if (context_snapshot->xstate.enabled_features & XSTATE_MASK_CET_U) {
|
||
auto cet_u = std::make_unique<MinidumpXSaveAMD64CetU>();
|
||
cet_u->InitializeFromSnapshot(context_snapshot);
|
||
xsave_entries_.push_back(std::move(cet_u));
|
||
}
|
||
}
|
||
|
||
size_t MinidumpContextAMD64Writer::Alignment() {
|
||
DCHECK_GE(state(), kStateFrozen);
|
||
|
||
// Match the alignment of MinidumpContextAMD64.
|
||
return 16;
|
||
}
|
||
|
||
bool MinidumpContextAMD64Writer::WriteObject(FileWriterInterface* file_writer) {
|
||
DCHECK_EQ(state(), kStateWritable);
|
||
// Note: all sizes here come from our constants, not from untrustworthy data.
|
||
std::vector<unsigned char> data(ContextSize());
|
||
unsigned char* const buf = data.data();
|
||
|
||
// CONTEXT always comes first.
|
||
DCHECK_LE(sizeof(context_), data.size());
|
||
memcpy(buf, &context_, sizeof(context_));
|
||
|
||
if (xsave_entries_.size() > 0) {
|
||
MinidumpContextExHeader context_ex = {{0, 0}, {0, 0}, {0, 0}};
|
||
MinidumpXSaveAreaHeader xsave_header = {0, 0, {}};
|
||
|
||
// CONTEXT_EX goes directly after the CONTEXT. |offset| is relative to
|
||
// &CONTEXT_EX.
|
||
context_ex.all.offset = -static_cast<int32_t>(sizeof(context_));
|
||
context_ex.all.size = static_cast<uint32_t>(ContextSize());
|
||
context_ex.legacy.offset = context_ex.all.offset;
|
||
context_ex.legacy.size = sizeof(context_);
|
||
// Then... there is a gap.
|
||
//
|
||
// In the compacted format the XSave area header goes just before
|
||
// the first xsave entry. It has a total size given by the header
|
||
// + (padded) sizes of all the entries.
|
||
context_ex.xstate.offset = static_cast<int32_t>(
|
||
kMinidumpAMD64XSaveOffset - sizeof(MinidumpXSaveAreaHeader) -
|
||
sizeof(context_));
|
||
context_ex.xstate.size =
|
||
static_cast<uint32_t>(sizeof(MinidumpXSaveAreaHeader) + ContextSize() -
|
||
kMinidumpAMD64XSaveOffset);
|
||
|
||
// Store CONTEXT_EX now it is complete.
|
||
DCHECK_LE(sizeof(context_) + sizeof(context_ex), data.size());
|
||
memcpy(&buf[sizeof(context_)], &context_ex, sizeof(context_ex));
|
||
|
||
// Calculate flags for xsave header & write entries (they will be
|
||
// *after* the xsave header).
|
||
size_t cursor = kMinidumpAMD64XSaveOffset;
|
||
for (auto const& entry : xsave_entries_) {
|
||
xsave_header.mask |= 1ull << entry->XCompBVBit();
|
||
DCHECK_LE(cursor + entry->Size(), data.size());
|
||
entry->Copy(&buf[cursor]);
|
||
cursor += entry->Size();
|
||
}
|
||
|
||
xsave_header.compaction_mask =
|
||
xsave_header.mask | XSTATE_COMPACTION_ENABLE_MASK;
|
||
|
||
// Store xsave header at its calculated offset. It is before the entries
|
||
// above, but we need to add the |mask| bits before writing it.
|
||
DCHECK_LE(
|
||
context_ex.xstate.offset + sizeof(context_) + sizeof(xsave_header),
|
||
data.size());
|
||
memcpy(&buf[context_ex.xstate.offset + sizeof(context_)],
|
||
&xsave_header,
|
||
sizeof(xsave_header));
|
||
}
|
||
|
||
if (!file_writer->Write(data.data(), data.size()))
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
size_t MinidumpContextAMD64Writer::ContextSize() const {
|
||
DCHECK_GE(state(), kStateFrozen);
|
||
if (xsave_entries_.size() == 0) {
|
||
return sizeof(context_);
|
||
} else {
|
||
DCHECK_EQ(context_.context_flags,
|
||
kMinidumpContextAMD64All | kMinidumpContextAMD64Xstate);
|
||
DCHECK(xsave_entries_.size() != 0);
|
||
size_t size = kMinidumpAMD64XSaveOffset;
|
||
for (auto& entry : xsave_entries_) {
|
||
size += entry->Size();
|
||
}
|
||
return size;
|
||
}
|
||
}
|
||
|
||
bool MinidumpXSaveAMD64CetU::InitializeFromSnapshot(
|
||
const CPUContextX86_64* context_snapshot) {
|
||
#ifdef SENTRY_DISABLED
|
||
DCHECK_EQ(context_snapshot->xstate.cet_u.cetmsr, 1ull);
|
||
#else
|
||
// TODO(supervacuus): this DCHECK led to multiple user inquiries because it
|
||
// ends up killing the crashpad_handler (when using a DEBUG build) which in
|
||
// turn keeps the crashpad client waiting indefinitely.
|
||
//
|
||
// It seems that crashpad devs put a DCHECK here because they already check
|
||
// at the call-site that the CET_U flag is enabled in the XSAVE feature set.
|
||
// However, that this flag is set, only means that the CET_U registers in
|
||
// XSAVE are valid, not necessarily that the SH_STK_EN bit is set.
|
||
//
|
||
// I couldn't find anything in the Intel (SDM 13.1) or AMD (PR 11.5.2,
|
||
// 18.11/12/13) CET/SS spec that would signal that SH_STK_EN(=cetmsr[0])
|
||
// cannot be 0 at this point. Ideally, if SH_STK_EN is not set, then SSP
|
||
// should be set to 0 too (which means both are in their initial state). But
|
||
// even that should not lead to fatally exit the crashpad_handler (even in
|
||
// DEBUG), but rather produce a log and result in something that can be
|
||
// analysed in the backend.
|
||
//
|
||
// Any validation based on these register contents must check SH_STK_EN
|
||
// anyway or check SSP for !NULL and as a valid base like it is done here:
|
||
// https://chromium.googlesource.com/crashpad/crashpad/+/6278690abe6ef0dda047e67dc1d0c49ce7af3811/snapshot/win/thread_snapshot_win.cc#130
|
||
if (!(context_snapshot->xstate.cet_u.cetmsr & 1ull)) {
|
||
LOG(WARNING) << "CET MSR enabled flag is not set ("
|
||
<< context_snapshot->xstate.cet_u.cetmsr
|
||
<< "); SSP = "
|
||
<< context_snapshot->xstate.cet_u.ssp;
|
||
}
|
||
#endif
|
||
cet_u_.cetmsr = context_snapshot->xstate.cet_u.cetmsr;
|
||
cet_u_.ssp = context_snapshot->xstate.cet_u.ssp;
|
||
return true;
|
||
}
|
||
|
||
bool MinidumpXSaveAMD64CetU::Copy(void* dst) const {
|
||
memcpy(dst, &cet_u_, sizeof(cet_u_));
|
||
return true;
|
||
}
|
||
|
||
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 = kMinidumpContextARM64Full;
|
||
|
||
static_assert(
|
||
sizeof(context_.regs) == sizeof(context_snapshot->regs) -
|
||
2 * sizeof(context_snapshot->regs[0]),
|
||
"GPRs size mismatch");
|
||
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
|
||
context_.fp = context_snapshot->regs[29];
|
||
context_.lr = context_snapshot->regs[30];
|
||
context_.sp = context_snapshot->sp;
|
||
context_.pc = context_snapshot->pc;
|
||
context_.cpsr = context_snapshot->spsr;
|
||
|
||
static_assert(sizeof(context_.fpsimd) == sizeof(context_snapshot->fpsimd),
|
||
"FPSIMD size mismatch");
|
||
memcpy(context_.fpsimd, context_snapshot->fpsimd, sizeof(context_.fpsimd));
|
||
context_.fpcr = context_snapshot->fpcr;
|
||
context_.fpsr = context_snapshot->fpsr;
|
||
|
||
memset(context_.bcr, 0, sizeof(context_.bcr));
|
||
memset(context_.bvr, 0, sizeof(context_.bvr));
|
||
memset(context_.wcr, 0, sizeof(context_.wcr));
|
||
memset(context_.wvr, 0, sizeof(context_.wvr));
|
||
}
|
||
|
||
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_);
|
||
}
|
||
|
||
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_);
|
||
}
|
||
|
||
MinidumpContextRISCV64Writer::MinidumpContextRISCV64Writer()
|
||
: MinidumpContextWriter(), context_() {
|
||
context_.context_flags = kMinidumpContextRISCV64;
|
||
context_.version = MinidumpContextRISCV64::kVersion;
|
||
}
|
||
|
||
MinidumpContextRISCV64Writer::~MinidumpContextRISCV64Writer() = default;
|
||
|
||
void MinidumpContextRISCV64Writer::InitializeFromSnapshot(
|
||
const CPUContextRISCV64* context_snapshot) {
|
||
DCHECK_EQ(state(), kStateMutable);
|
||
DCHECK_EQ(context_.context_flags, kMinidumpContextRISCV64);
|
||
|
||
context_.context_flags = kMinidumpContextRISCV64All;
|
||
context_.version = MinidumpContextRISCV64::kVersion;
|
||
context_.pc = context_snapshot->pc;
|
||
|
||
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
|
||
"GPRs size mismatch");
|
||
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
|
||
|
||
static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs),
|
||
"FPRs size mismatch");
|
||
memcpy(context_.fpregs, context_snapshot->fpregs, sizeof(context_.fpregs));
|
||
context_.fcsr = context_snapshot->fcsr;
|
||
}
|
||
|
||
bool MinidumpContextRISCV64Writer::WriteObject(
|
||
FileWriterInterface* file_writer) {
|
||
DCHECK_EQ(state(), kStateWritable);
|
||
return file_writer->Write(&context_, sizeof(context_));
|
||
}
|
||
|
||
size_t MinidumpContextRISCV64Writer::ContextSize() const {
|
||
DCHECK_GE(state(), kStateFrozen);
|
||
return sizeof(context_);
|
||
}
|
||
|
||
} // namespace crashpad
|