// Copyright 2019 The Crashpad Authors. All rights reserved. // // 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 "snapshot/minidump/minidump_context_converter.h" #include #include "base/logging.h" #include "base/stl_util.h" #include "minidump/minidump_context.h" namespace crashpad { namespace internal { MinidumpContextConverter::MinidumpContextConverter() : initialized_() { context_.architecture = CPUArchitecture::kCPUArchitectureUnknown; } bool MinidumpContextConverter::Initialize( CPUArchitecture arch, const std::vector& minidump_context) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); if (minidump_context.size() == 0) { // Thread has no context. context_.architecture = CPUArchitecture::kCPUArchitectureUnknown; INITIALIZATION_STATE_SET_VALID(initialized_); return true; } context_.architecture = arch; if (context_.architecture == CPUArchitecture::kCPUArchitectureX86) { context_memory_.resize(sizeof(CPUContextX86)); context_.x86 = reinterpret_cast(context_memory_.data()); const MinidumpContextX86* src = reinterpret_cast(minidump_context.data()); if (minidump_context.size() < sizeof(MinidumpContextX86)) { return false; } if (!(src->context_flags & kMinidumpContextX86)) { return false; } if (src->context_flags & kMinidumpContextX86Extended) { context_.x86->fxsave = src->fxsave; } else if (src->context_flags & kMinidumpContextX86FloatingPoint) { CPUContextX86::FsaveToFxsave(src->fsave, &context_.x86->fxsave); } context_.x86->eax = src->eax; context_.x86->ebx = src->ebx; context_.x86->ecx = src->ecx; context_.x86->edx = src->edx; context_.x86->edi = src->edi; context_.x86->esi = src->esi; context_.x86->ebp = src->ebp; context_.x86->esp = src->esp; context_.x86->eip = src->eip; context_.x86->eflags = src->eflags; context_.x86->cs = static_cast(src->cs); context_.x86->ds = static_cast(src->ds); context_.x86->es = static_cast(src->es); context_.x86->fs = static_cast(src->fs); context_.x86->gs = static_cast(src->gs); context_.x86->ss = static_cast(src->ss); context_.x86->dr0 = src->dr0; context_.x86->dr1 = src->dr1; context_.x86->dr2 = src->dr2; context_.x86->dr3 = src->dr3; context_.x86->dr6 = src->dr6; context_.x86->dr7 = src->dr7; // Minidump passes no value for dr4/5. Our output context has space for // them. According to spec they're obsolete, but when present read as // aliases for dr6/7, so we'll do this. context_.x86->dr4 = src->dr6; context_.x86->dr5 = src->dr7; } else if (context_.architecture == CPUArchitecture::kCPUArchitectureX86_64) { context_memory_.resize(sizeof(CPUContextX86_64)); context_.x86_64 = reinterpret_cast(context_memory_.data()); const MinidumpContextAMD64* src = reinterpret_cast(minidump_context.data()); if (minidump_context.size() < sizeof(MinidumpContextAMD64)) { return false; } if (!(src->context_flags & kMinidumpContextAMD64)) { return false; } context_.x86_64->fxsave = src->fxsave; context_.x86_64->cs = src->cs; context_.x86_64->fs = src->fs; context_.x86_64->gs = src->gs; context_.x86_64->rflags = src->eflags; context_.x86_64->dr0 = src->dr0; context_.x86_64->dr1 = src->dr1; context_.x86_64->dr2 = src->dr2; context_.x86_64->dr3 = src->dr3; context_.x86_64->dr6 = src->dr6; context_.x86_64->dr7 = src->dr7; context_.x86_64->rax = src->rax; context_.x86_64->rcx = src->rcx; context_.x86_64->rdx = src->rdx; context_.x86_64->rbx = src->rbx; context_.x86_64->rsp = src->rsp; context_.x86_64->rbp = src->rbp; context_.x86_64->rsi = src->rsi; context_.x86_64->rdi = src->rdi; context_.x86_64->r8 = src->r8; context_.x86_64->r9 = src->r9; context_.x86_64->r10 = src->r10; context_.x86_64->r11 = src->r11; context_.x86_64->r12 = src->r12; context_.x86_64->r13 = src->r13; context_.x86_64->r14 = src->r14; context_.x86_64->r15 = src->r15; context_.x86_64->rip = src->rip; // See comments on x86 above. context_.x86_64->dr4 = src->dr6; context_.x86_64->dr5 = src->dr7; } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM) { context_memory_.resize(sizeof(CPUContextARM)); context_.arm = reinterpret_cast(context_memory_.data()); const MinidumpContextARM* src = reinterpret_cast(minidump_context.data()); if (minidump_context.size() < sizeof(MinidumpContextARM)) { return false; } if (!(src->context_flags & kMinidumpContextARM)) { return false; } for (size_t i = 0; i < base::size(src->regs); i++) { context_.arm->regs[i] = src->regs[i]; } context_.arm->fp = src->fp; context_.arm->ip = src->ip; context_.arm->sp = src->sp; context_.arm->lr = src->lr; context_.arm->pc = src->pc; context_.arm->cpsr = src->cpsr; context_.arm->vfp_regs.fpscr = src->fpscr; for (size_t i = 0; i < base::size(src->vfp); i++) { context_.arm->vfp_regs.vfp[i] = src->vfp[i]; } context_.arm->have_fpa_regs = false; context_.arm->have_vfp_regs = !!(src->context_flags & kMinidumpContextARMVFP); } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM64) { context_memory_.resize(sizeof(CPUContextARM64)); context_.arm64 = reinterpret_cast(context_memory_.data()); const MinidumpContextARM64* src = reinterpret_cast(minidump_context.data()); if (minidump_context.size() < sizeof(MinidumpContextARM64)) { return false; } if (!(src->context_flags & kMinidumpContextARM64)) { return false; } for (size_t i = 0; i < base::size(src->regs); i++) { context_.arm64->regs[i] = src->regs[i]; } context_.arm64->regs[29] = src->fp; context_.arm64->regs[30] = src->lr; for (size_t i = 0; i < base::size(src->fpsimd); i++) { context_.arm64->fpsimd[i] = src->fpsimd[i]; } context_.arm64->sp = src->sp; context_.arm64->pc = src->pc; context_.arm64->fpcr = src->fpcr; context_.arm64->fpsr = src->fpsr; context_.arm64->spsr = src->cpsr; } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) { context_memory_.resize(sizeof(CPUContextMIPS)); context_.mipsel = reinterpret_cast(context_memory_.data()); const MinidumpContextMIPS* src = reinterpret_cast(minidump_context.data()); if (minidump_context.size() < sizeof(MinidumpContextMIPS)) { return false; } if (!(src->context_flags & kMinidumpContextMIPS)) { return false; } for (size_t i = 0; i < base::size(src->regs); i++) { context_.mipsel->regs[i] = src->regs[i]; } context_.mipsel->mdhi = static_cast(src->mdhi); context_.mipsel->mdlo = static_cast(src->mdlo); context_.mipsel->dsp_control = src->dsp_control; for (size_t i = 0; i < base::size(src->hi); i++) { context_.mipsel->hi[i] = src->hi[i]; context_.mipsel->lo[i] = src->lo[i]; } context_.mipsel->cp0_epc = static_cast(src->epc); context_.mipsel->cp0_badvaddr = static_cast(src->badvaddr); context_.mipsel->cp0_status = src->status; context_.mipsel->cp0_cause = src->cause; context_.mipsel->fpcsr = src->fpcsr; context_.mipsel->fir = src->fir; memcpy(&context_.mipsel->fpregs, &src->fpregs, sizeof(src->fpregs)); } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPS64EL) { context_memory_.resize(sizeof(CPUContextMIPS64)); context_.mips64 = reinterpret_cast(context_memory_.data()); const MinidumpContextMIPS64* src = reinterpret_cast(minidump_context.data()); if (minidump_context.size() < sizeof(MinidumpContextMIPS64)) { return false; } if (!(src->context_flags & kMinidumpContextMIPS64)) { return false; } for (size_t i = 0; i < base::size(src->regs); i++) { context_.mips64->regs[i] = src->regs[i]; } context_.mips64->mdhi = src->mdhi; context_.mips64->mdlo = src->mdlo; context_.mips64->dsp_control = src->dsp_control; for (size_t i = 0; i < base::size(src->hi); i++) { context_.mips64->hi[i] = src->hi[i]; context_.mips64->lo[i] = src->lo[i]; } context_.mips64->cp0_epc = src->epc; context_.mips64->cp0_badvaddr = src->badvaddr; context_.mips64->cp0_status = src->status; context_.mips64->cp0_cause = src->cause; context_.mips64->fpcsr = src->fpcsr; context_.mips64->fir = src->fir; memcpy(&context_.mips64->fpregs, &src->fpregs, sizeof(src->fpregs)); } else { // Architecture is listed as "unknown". DLOG(ERROR) << "Unknown architecture"; } INITIALIZATION_STATE_SET_VALID(initialized_); return true; } } // namespace internal } // namespace crashpad