Implement Exception context for minidump

Bug: crashpad:10
Change-Id: I90d72d813da11d25c1ed13a51daacec9b0ad4a0f
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1753063
Commit-Queue: Casey Dahlin <sadmac@google.com>
Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Casey Dahlin 2019-08-13 15:14:20 -07:00 committed by Commit Bot
parent 8edbc7439b
commit 64399c514f
10 changed files with 450 additions and 288 deletions

View File

@ -42,6 +42,8 @@ static_library("snapshot") {
"minidump/memory_snapshot_minidump.h",
"minidump/minidump_annotation_reader.cc",
"minidump/minidump_annotation_reader.h",
"minidump/minidump_context_converter.cc",
"minidump/minidump_context_converter.h",
"minidump/minidump_simple_string_dictionary_reader.cc",
"minidump/minidump_simple_string_dictionary_reader.h",
"minidump/minidump_stream.h",

View File

@ -22,16 +22,20 @@ namespace internal {
ExceptionSnapshotMinidump::ExceptionSnapshotMinidump()
: ExceptionSnapshot(),
minidump_exception_stream_(),
context_(),
exception_information_(),
initialized_() {}
ExceptionSnapshotMinidump::~ExceptionSnapshotMinidump() {}
bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
CPUArchitecture arch,
RVA minidump_exception_stream_rva) {
DCHECK(initialized_.is_uninitialized());
initialized_.set_invalid();
std::vector<unsigned char> minidump_context;
if (!file_reader->SeekSet(minidump_exception_stream_rva)) {
return false;
}
@ -48,14 +52,28 @@ bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
minidump_exception_stream_.ExceptionRecord.ExceptionInformation[i]);
}
if (!file_reader->SeekSet(minidump_exception_stream_.ThreadContext.Rva)) {
return false;
}
minidump_context.resize(minidump_exception_stream_.ThreadContext.DataSize);
if (!file_reader->ReadExactly(minidump_context.data(),
minidump_context.size())) {
return false;
}
if (!context_.Initialize(arch, minidump_context)) {
return false;
}
initialized_.set_valid();
return true;
}
const CPUContext* ExceptionSnapshotMinidump::Context() const {
DCHECK(initialized_.is_valid());
NOTREACHED(); // https://crashpad.chromium.org/bug/10
return nullptr;
return context_.Get();
}
uint64_t ExceptionSnapshotMinidump::ThreadID() const {

View File

@ -21,6 +21,7 @@
#include "build/build_config.h"
#include "snapshot/cpu_context.h"
#include "snapshot/exception_snapshot.h"
#include "snapshot/minidump/minidump_context_converter.h"
#include "util/file/file_reader.h"
#include "util/misc/initialization_state.h"
@ -37,12 +38,14 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot {
//!
//! \param[in] file_reader A file reader corresponding to a minidump file.
//! The file reader must support seeking.
//! \param[in] arch The CPU architecture of this snapshot.
//! \param[in] minidump_exception_stream_rva The file offset in \a file_reader
//! at which the MINIDUMP_EXCEPTION_STREAM structure is located.
//!
//! \return `true` if the snapshot could be created, `false` otherwise with
//! an appropriate message logged.
bool Initialize(FileReaderInterface* file_reader,
CPUArchitecture arch,
RVA minidump_exception_stream_rva);
// ExceptionSnapshot:
@ -60,6 +63,7 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot {
private:
MINIDUMP_EXCEPTION_STREAM minidump_exception_stream_;
MinidumpContextConverter context_;
std::vector<uint64_t> exception_information_;
InitializationState initialized_;

View File

@ -0,0 +1,275 @@
// 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 "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<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 < 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<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 < 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<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 < base::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 < 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<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 < 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

View File

@ -0,0 +1,47 @@
// 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.
#ifndef CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_CONTEXT_CONVERTER_H_
#define CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_CONTEXT_CONVERTER_H_
#include <vector>
#include "snapshot/cpu_context.h"
#include "util/misc/initialization_state.h"
#include "util/misc/initialization_state_dcheck.h"
namespace crashpad {
namespace internal {
class MinidumpContextConverter {
public:
MinidumpContextConverter();
bool Initialize(CPUArchitecture arch,
const std::vector<unsigned char>& minidump_context);
const CPUContext* Get() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return &context_;
}
private:
CPUContext context_;
std::vector<unsigned char> context_memory_;
InitializationStateDcheck initialized_;
};
} // namespace internal
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_CONTEXT_CONVERTER_H_

View File

@ -596,7 +596,8 @@ bool ProcessSnapshotMinidump::InitializeExceptionSnapshot() {
return false;
}
if (!exception_snapshot_.Initialize(file_reader_, stream_it->second->Rva)) {
if (!exception_snapshot_.Initialize(
file_reader_, arch_, stream_it->second->Rva)) {
return false;
}

View File

@ -47,6 +47,43 @@ class ReadToVector : public crashpad::MemorySnapshot::Delegate {
}
};
MinidumpContextARM64 GetArm64MinidumpContext() {
MinidumpContextARM64 minidump_context;
minidump_context.context_flags = kMinidumpContextARM64Full;
minidump_context.cpsr = 0;
for (int i = 0; i < 29; i++) {
minidump_context.regs[i] = i + 1;
}
minidump_context.fp = 30;
minidump_context.lr = 31;
minidump_context.sp = 32;
minidump_context.pc = 33;
for (int i = 0; i < 32; i++) {
minidump_context.fpsimd[i].lo = i * 2 + 34;
minidump_context.fpsimd[i].hi = i * 2 + 35;
}
minidump_context.fpcr = 98;
minidump_context.fpsr = 99;
for (int i = 0; i < 8; i++) {
minidump_context.bcr[i] = i * 2 + 100;
minidump_context.bvr[i] = i * 2 + 101;
}
for (int i = 0; i < 2; i++) {
minidump_context.wcr[i] = i * 2 + 115;
minidump_context.wvr[i] = i * 2 + 116;
}
return minidump_context;
}
TEST(ProcessSnapshotMinidump, EmptyFile) {
StringFile string_file;
ProcessSnapshotMinidump process_snapshot;
@ -799,38 +836,7 @@ TEST(ProcessSnapshotMinidump, ThreadContextARM64) {
minidump_thread.ThreadId = 42;
minidump_thread.Teb = 24;
MinidumpContextARM64 minidump_context;
minidump_context.context_flags = kMinidumpContextARM64Full;
minidump_context.cpsr = 0;
for (int i = 0; i < 29; i++) {
minidump_context.regs[i] = i + 1;
}
minidump_context.fp = 30;
minidump_context.lr = 31;
minidump_context.sp = 32;
minidump_context.pc = 33;
for (int i = 0; i < 32; i++) {
minidump_context.fpsimd[i].lo = i * 2 + 34;
minidump_context.fpsimd[i].hi = i * 2 + 35;
}
minidump_context.fpcr = 98;
minidump_context.fpsr = 99;
for (int i = 0; i < 8; i++) {
minidump_context.bcr[i] = i * 2 + 100;
minidump_context.bvr[i] = i * 2 + 101;
}
for (int i = 0; i < 2; i++) {
minidump_context.wcr[i] = i * 2 + 115;
minidump_context.wvr[i] = i * 2 + 116;
}
MinidumpContextARM64 minidump_context = GetArm64MinidumpContext();
minidump_thread.ThreadContext.DataSize = sizeof(minidump_context);
minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet());
@ -1314,10 +1320,35 @@ TEST(ProcessSnapshotMinidump, Exception) {
minidump_exception.ExceptionInformation[0] = 51;
minidump_exception.ExceptionInformation[1] = 62;
MINIDUMP_SYSTEM_INFO minidump_system_info = {};
minidump_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureARM64;
minidump_system_info.ProductType = kMinidumpOSTypeServer;
minidump_system_info.PlatformId = kMinidumpOSFuchsia;
minidump_system_info.CSDVersionRva = WriteString(&string_file, "");
MINIDUMP_DIRECTORY minidump_system_info_directory = {};
minidump_system_info_directory.StreamType = kMinidumpStreamTypeSystemInfo;
minidump_system_info_directory.Location.DataSize =
sizeof(MINIDUMP_SYSTEM_INFO);
minidump_system_info_directory.Location.Rva =
static_cast<RVA>(string_file.SeekGet());
ASSERT_TRUE(
string_file.Write(&minidump_system_info, sizeof(minidump_system_info)));
MINIDUMP_EXCEPTION_STREAM minidump_exception_stream = {};
minidump_exception_stream.ThreadId = 5;
minidump_exception_stream.ExceptionRecord = minidump_exception;
MinidumpContextARM64 minidump_context = GetArm64MinidumpContext();
minidump_exception_stream.ThreadContext.DataSize = sizeof(minidump_context);
minidump_exception_stream.ThreadContext.Rva =
static_cast<RVA>(string_file.SeekGet());
ASSERT_TRUE(string_file.Write(&minidump_context, sizeof(minidump_context)));
MINIDUMP_DIRECTORY minidump_exception_directory = {};
minidump_exception_directory.StreamType = kMinidumpStreamTypeException;
minidump_exception_directory.Location.DataSize =
@ -1331,10 +1362,12 @@ TEST(ProcessSnapshotMinidump, Exception) {
header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet());
ASSERT_TRUE(string_file.Write(&minidump_exception_directory,
sizeof(minidump_exception_directory)));
ASSERT_TRUE(string_file.Write(&minidump_system_info_directory,
sizeof(minidump_system_info_directory)));
header.Signature = MINIDUMP_SIGNATURE;
header.Version = MINIDUMP_VERSION;
header.NumberOfStreams = 1;
header.NumberOfStreams = 2;
EXPECT_TRUE(string_file.SeekSet(0));
EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
@ -1352,6 +1385,28 @@ TEST(ProcessSnapshotMinidump, Exception) {
EXPECT_EQ(codes.size(), 2UL);
EXPECT_EQ(codes[0], 51UL);
EXPECT_EQ(codes[1], 62UL);
const CPUContext* ctx_generic = s->Context();
ASSERT_EQ(ctx_generic->architecture, CPUArchitecture::kCPUArchitectureARM64);
const CPUContextARM64* ctx = ctx_generic->arm64;
EXPECT_EQ(ctx->spsr, 0UL);
for (unsigned int i = 0; i < 31; i++) {
EXPECT_EQ(ctx->regs[i], i + 1);
}
EXPECT_EQ(ctx->sp, 32UL);
EXPECT_EQ(ctx->pc, 33UL);
EXPECT_EQ(ctx->fpcr, 98UL);
EXPECT_EQ(ctx->fpsr, 99UL);
for (unsigned int i = 0; i < 32; i++) {
EXPECT_EQ(ctx->fpsimd[i].lo, i * 2 + 34);
EXPECT_EQ(ctx->fpsimd[i].hi, i * 2 + 35);
}
}
TEST(ProcessSnapshotMinidump, NoExceptionInMinidump) {

View File

@ -27,13 +27,10 @@ ThreadSnapshotMinidump::ThreadSnapshotMinidump()
: ThreadSnapshot(),
minidump_thread_(),
context_(),
context_memory_(),
stack_(),
initialized_() {
}
initialized_() {}
ThreadSnapshotMinidump::~ThreadSnapshotMinidump() {
}
ThreadSnapshotMinidump::~ThreadSnapshotMinidump() {}
bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
RVA minidump_thread_rva,
@ -41,8 +38,6 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
std::vector<unsigned char> minidump_context;
context_.architecture = arch;
if (!file_reader->SeekSet(minidump_thread_rva)) {
return false;
}
@ -62,12 +57,12 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
return false;
}
if (!InitializeContext(minidump_context)) {
if (!context_.Initialize(arch, minidump_context)) {
return false;
}
RVA stack_info_location = minidump_thread_rva +
offsetof(MINIDUMP_THREAD, Stack);
RVA stack_info_location =
minidump_thread_rva + offsetof(MINIDUMP_THREAD, Stack);
if (!stack_.Initialize(file_reader, stack_info_location)) {
return false;
@ -77,244 +72,6 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
return true;
}
bool ThreadSnapshotMinidump::InitializeContext(
const std::vector<unsigned char>& minidump_context) {
if (minidump_context.size() == 0) {
// Thread has no context.
context_.architecture = CPUArchitecture::kCPUArchitectureUnknown;
return true;
}
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 < 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<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 < 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<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 < base::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 < 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<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 < 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));
}
// If we fell through, Architecture is listed as "unknown".
return true;
}
uint64_t ThreadSnapshotMinidump::ThreadID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return minidump_thread_.ThreadId;
@ -337,7 +94,7 @@ int ThreadSnapshotMinidump::Priority() const {
const CPUContext* ThreadSnapshotMinidump::Context() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return &context_;
return context_.Get();
}
const MemorySnapshot* ThreadSnapshotMinidump::Stack() const {

View File

@ -20,6 +20,7 @@
#include "minidump/minidump_extensions.h"
#include "snapshot/cpu_context.h"
#include "snapshot/minidump/memory_snapshot_minidump.h"
#include "snapshot/minidump/minidump_context_converter.h"
#include "snapshot/thread_snapshot.h"
#include "util/file/file_reader.h"
#include "util/misc/initialization_state_dcheck.h"
@ -44,7 +45,8 @@ class ThreadSnapshotMinidump : public ThreadSnapshot {
//!
//! \return `true` if the snapshot could be created, `false` otherwise with
//! an appropriate message logged.
bool Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva,
bool Initialize(FileReaderInterface* file_reader,
RVA minidump_thread_rva,
CPUArchitecture arch);
const CPUContext* Context() const override;
@ -65,8 +67,7 @@ class ThreadSnapshotMinidump : public ThreadSnapshot {
bool InitializeContext(const std::vector<unsigned char>& minidump_context);
MINIDUMP_THREAD minidump_thread_;
CPUContext context_;
std::vector<unsigned char> context_memory_;
MinidumpContextConverter context_;
MemorySnapshotMinidump stack_;
InitializationStateDcheck initialized_;

View File

@ -109,6 +109,8 @@
'memory_snapshot_generic.h',
'minidump/minidump_annotation_reader.cc',
'minidump/minidump_annotation_reader.h',
'minidump/minidump_context_converter.cc',
'minidump/minidump_context_converter.h',
'minidump/minidump_simple_string_dictionary_reader.cc',
'minidump/minidump_simple_string_dictionary_reader.h',
'minidump/minidump_stream.h',