280 lines
9.6 KiB
C++
280 lines
9.6 KiB
C++
// 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 <string.h>
|
|
|
|
#include <iterator>
|
|
|
|
#include "base/logging.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<unsigned char>& 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<CPUContextX86*>(context_memory_.data());
|
|
const MinidumpContextX86* src =
|
|
reinterpret_cast<const MinidumpContextX86*>(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<uint16_t>(src->cs);
|
|
context_.x86->ds = static_cast<uint16_t>(src->ds);
|
|
context_.x86->es = static_cast<uint16_t>(src->es);
|
|
context_.x86->fs = static_cast<uint16_t>(src->fs);
|
|
context_.x86->gs = static_cast<uint16_t>(src->gs);
|
|
context_.x86->ss = static_cast<uint16_t>(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<CPUContextX86_64*>(context_memory_.data());
|
|
const MinidumpContextAMD64* src =
|
|
reinterpret_cast<const MinidumpContextAMD64*>(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<CPUContextARM*>(context_memory_.data());
|
|
const MinidumpContextARM* src =
|
|
reinterpret_cast<const MinidumpContextARM*>(minidump_context.data());
|
|
if (minidump_context.size() < sizeof(MinidumpContextARM)) {
|
|
return false;
|
|
}
|
|
|
|
if (!(src->context_flags & kMinidumpContextARM)) {
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < std::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 < std::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<CPUContextARM64*>(context_memory_.data());
|
|
const MinidumpContextARM64* src =
|
|
reinterpret_cast<const MinidumpContextARM64*>(minidump_context.data());
|
|
if (minidump_context.size() < sizeof(MinidumpContextARM64)) {
|
|
return false;
|
|
}
|
|
|
|
if (!(src->context_flags & kMinidumpContextARM64)) {
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < std::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 < std::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<CPUContextMIPS*>(context_memory_.data());
|
|
const MinidumpContextMIPS* src =
|
|
reinterpret_cast<const MinidumpContextMIPS*>(minidump_context.data());
|
|
if (minidump_context.size() < sizeof(MinidumpContextMIPS)) {
|
|
return false;
|
|
}
|
|
|
|
if (!(src->context_flags & kMinidumpContextMIPS)) {
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < std::size(src->regs); i++) {
|
|
context_.mipsel->regs[i] = src->regs[i];
|
|
}
|
|
|
|
context_.mipsel->mdhi = static_cast<uint32_t>(src->mdhi);
|
|
context_.mipsel->mdlo = static_cast<uint32_t>(src->mdlo);
|
|
context_.mipsel->dsp_control = src->dsp_control;
|
|
|
|
for (size_t i = 0; i < std::size(src->hi); i++) {
|
|
context_.mipsel->hi[i] = src->hi[i];
|
|
context_.mipsel->lo[i] = src->lo[i];
|
|
}
|
|
|
|
context_.mipsel->cp0_epc = static_cast<uint32_t>(src->epc);
|
|
context_.mipsel->cp0_badvaddr = static_cast<uint32_t>(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<CPUContextMIPS64*>(context_memory_.data());
|
|
const MinidumpContextMIPS64* src =
|
|
reinterpret_cast<const MinidumpContextMIPS64*>(minidump_context.data());
|
|
if (minidump_context.size() < sizeof(MinidumpContextMIPS64)) {
|
|
return false;
|
|
}
|
|
|
|
if (!(src->context_flags & kMinidumpContextMIPS64)) {
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < std::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 < std::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
|