| // 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/check_op.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) { |
| // Exception records do not carry CET registers but we have to provide the |
| // same shaped context for threads and exception contexts, so both 0 (no ssp |
| // present) and 1 (ssp present) are expected. |
| DCHECK(context_snapshot->xstate.cet_u.cetmsr == 0ull || |
| context_snapshot->xstate.cet_u.cetmsr == 1ull); |
| 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 |