Decode Thread Context in minidump

We can now get the CPU state for threads from minidump snapshots.

Bug: crashpad:10
Change-Id: I6bef2b033f7b04fcfa64c114be94064f3e0ae775
Reviewed-on: https://chromium-review.googlesource.com/c/1285034
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Casey Dahlin 2018-10-16 12:23:21 -07:00 committed by Commit Bot
parent b6103e157c
commit 8d17d5b4cf
5 changed files with 623 additions and 8 deletions

View File

@ -30,6 +30,7 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump()
unloaded_modules_(),
crashpad_info_(),
system_snapshot_(),
arch_(CPUArchitecture::kCPUArchitectureUnknown),
annotations_simple_map_(),
file_reader_(nullptr),
process_id_(static_cast<pid_t>(-1)),
@ -88,8 +89,8 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) {
if (!InitializeCrashpadInfo() ||
!InitializeMiscInfo() ||
!InitializeModules() ||
!InitializeThreads() ||
!InitializeSystemSnapshot()) {
!InitializeSystemSnapshot() ||
!InitializeThreads()) {
return false;
}
@ -426,7 +427,7 @@ bool ProcessSnapshotMinidump::InitializeThreads() {
thread_index * sizeof(MINIDUMP_THREAD);
auto thread = std::make_unique<internal::ThreadSnapshotMinidump>();
if (!thread->Initialize(file_reader_, thread_rva)) {
if (!thread->Initialize(file_reader_, thread_rva, arch_)) {
return false;
}
@ -447,7 +448,12 @@ bool ProcessSnapshotMinidump::InitializeSystemSnapshot() {
return false;
}
return system_snapshot_.Initialize(file_reader_, stream_it->second->Rva);
if (!system_snapshot_.Initialize(file_reader_, stream_it->second->Rva)) {
return false;
}
arch_ = system_snapshot_.GetCPUArchitecture();
return true;
}
} // namespace crashpad

View File

@ -114,6 +114,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot {
std::vector<UnloadedModuleSnapshot> unloaded_modules_;
MinidumpCrashpadInfo crashpad_info_;
internal::SystemSnapshotMinidump system_snapshot_;
CPUArchitecture arch_;
std::map<std::string, std::string> annotations_simple_map_;
FileReaderInterface* file_reader_; // weak
pid_t process_id_;

View File

@ -21,6 +21,7 @@
#include <memory>
#include "gtest/gtest.h"
#include "minidump/minidump_context.h"
#include "snapshot/minidump/minidump_annotation_reader.h"
#include "snapshot/module_snapshot.h"
#include "util/file/string_file.h"
@ -571,6 +572,329 @@ TEST(ProcessSnapshotMinidump, System) {
EXPECT_EQ(build, "Snazzle");
}
TEST(ProcessSnapshotMinidump, ThreadContextARM64) {
StringFile string_file;
MINIDUMP_HEADER header = {};
EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
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_THREAD minidump_thread = {};
uint32_t minidump_thread_count = 1;
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;
}
minidump_thread.ThreadContext.DataSize = sizeof(minidump_context);
minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet());
EXPECT_TRUE(string_file.Write(&minidump_context, sizeof(minidump_context)));
MINIDUMP_DIRECTORY minidump_thread_list_directory = {};
minidump_thread_list_directory.StreamType = kMinidumpStreamTypeThreadList;
minidump_thread_list_directory.Location.DataSize =
sizeof(MINIDUMP_THREAD_LIST) +
minidump_thread_count * sizeof(MINIDUMP_THREAD);
minidump_thread_list_directory.Location.Rva =
static_cast<RVA>(string_file.SeekGet());
// Fields in MINIDUMP_THREAD_LIST.
EXPECT_TRUE(
string_file.Write(&minidump_thread_count, sizeof(minidump_thread_count)));
EXPECT_TRUE(string_file.Write(&minidump_thread, sizeof(minidump_thread)));
header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet());
ASSERT_TRUE(string_file.Write(&minidump_system_info_directory,
sizeof(minidump_system_info_directory)));
ASSERT_TRUE(string_file.Write(&minidump_thread_list_directory,
sizeof(minidump_thread_list_directory)));
header.Signature = MINIDUMP_SIGNATURE;
header.Version = MINIDUMP_VERSION;
header.NumberOfStreams = 2;
EXPECT_TRUE(string_file.SeekSet(0));
EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
ProcessSnapshotMinidump process_snapshot;
EXPECT_TRUE(process_snapshot.Initialize(&string_file));
std::vector<const ThreadSnapshot*> threads = process_snapshot.Threads();
ASSERT_EQ(threads.size(), minidump_thread_count);
const CPUContext* ctx_generic = threads[0]->Context();
ASSERT_EQ(ctx_generic->architecture, CPUArchitecture::kCPUArchitectureARM64);
const CPUContextARM64* ctx = ctx_generic->arm64;
EXPECT_EQ(ctx->pstate, 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, ThreadContextX86_64) {
StringFile string_file;
MINIDUMP_HEADER header = {};
EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
MINIDUMP_SYSTEM_INFO minidump_system_info = {};
minidump_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureAMD64;
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_THREAD minidump_thread = {};
uint32_t minidump_thread_count = 1;
minidump_thread.ThreadId = 42;
minidump_thread.Teb = 24;
MinidumpContextAMD64 minidump_context;
minidump_context.context_flags = kMinidumpContextAMD64Full;
minidump_context.mx_csr = 0;
minidump_context.cs = 1;
minidump_context.ds = 2;
minidump_context.es = 3;
minidump_context.fs = 4;
minidump_context.gs = 5;
minidump_context.ss = 6;
minidump_context.eflags = 7;
minidump_context.dr0 = 8;
minidump_context.dr1 = 9;
minidump_context.dr2 = 10;
minidump_context.dr3 = 11;
minidump_context.dr6 = 12;
minidump_context.dr7 = 13;
minidump_context.rax = 14;
minidump_context.rcx = 15;
minidump_context.rdx = 16;
minidump_context.rbx = 17;
minidump_context.rsp = 18;
minidump_context.rbp = 19;
minidump_context.rsi = 20;
minidump_context.rdi = 21;
minidump_context.r8 = 22;
minidump_context.r9 = 23;
minidump_context.r10 = 24;
minidump_context.r11 = 25;
minidump_context.r12 = 26;
minidump_context.r13 = 27;
minidump_context.r14 = 28;
minidump_context.r15 = 29;
minidump_context.rip = 30;
minidump_context.vector_control = 31;
minidump_context.debug_control = 32;
minidump_context.last_branch_to_rip = 33;
minidump_context.last_branch_from_rip = 34;
minidump_context.last_exception_to_rip = 35;
minidump_context.last_exception_from_rip = 36;
minidump_context.fxsave.fcw = 37;
minidump_context.fxsave.fsw = 38;
minidump_context.fxsave.ftw = 39;
minidump_context.fxsave.reserved_1 = 40;
minidump_context.fxsave.fop = 41;
minidump_context.fxsave.fpu_ip_64 = 42;
minidump_context.fxsave.fpu_dp_64 = 43;
for (size_t i = 0; i < arraysize(minidump_context.vector_register); i++) {
minidump_context.vector_register[i].lo = i * 2 + 44;
minidump_context.vector_register[i].hi = i * 2 + 45;
}
for (uint8_t i = 0; i < arraysize(minidump_context.fxsave.reserved_4); i++) {
minidump_context.fxsave.reserved_4[i] = i * 2 + 115;
minidump_context.fxsave.available[i] = i * 2 + 116;
}
for (size_t i = 0; i < arraysize(minidump_context.fxsave.st_mm); i++) {
for (uint8_t j = 0;
j < arraysize(minidump_context.fxsave.st_mm[0].mm_value);
j++) {
minidump_context.fxsave.st_mm[i].mm_value[j] = j + 1;
minidump_context.fxsave.st_mm[i].mm_reserved[j] = j + 1;
}
}
for (size_t i = 0; i < arraysize(minidump_context.fxsave.xmm); i++) {
for (uint8_t j = 0; j < arraysize(minidump_context.fxsave.xmm[0]); j++) {
minidump_context.fxsave.xmm[i][j] = j + 1;
}
}
minidump_thread.ThreadContext.DataSize = sizeof(minidump_context);
minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet());
EXPECT_TRUE(string_file.Write(&minidump_context, sizeof(minidump_context)));
MINIDUMP_DIRECTORY minidump_thread_list_directory = {};
minidump_thread_list_directory.StreamType = kMinidumpStreamTypeThreadList;
minidump_thread_list_directory.Location.DataSize =
sizeof(MINIDUMP_THREAD_LIST) +
minidump_thread_count * sizeof(MINIDUMP_THREAD);
minidump_thread_list_directory.Location.Rva =
static_cast<RVA>(string_file.SeekGet());
// Fields in MINIDUMP_THREAD_LIST.
EXPECT_TRUE(
string_file.Write(&minidump_thread_count, sizeof(minidump_thread_count)));
EXPECT_TRUE(string_file.Write(&minidump_thread, sizeof(minidump_thread)));
header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet());
ASSERT_TRUE(string_file.Write(&minidump_system_info_directory,
sizeof(minidump_system_info_directory)));
ASSERT_TRUE(string_file.Write(&minidump_thread_list_directory,
sizeof(minidump_thread_list_directory)));
header.Signature = MINIDUMP_SIGNATURE;
header.Version = MINIDUMP_VERSION;
header.NumberOfStreams = 2;
EXPECT_TRUE(string_file.SeekSet(0));
EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
ProcessSnapshotMinidump process_snapshot;
EXPECT_TRUE(process_snapshot.Initialize(&string_file));
std::vector<const ThreadSnapshot*> threads = process_snapshot.Threads();
ASSERT_EQ(threads.size(), minidump_thread_count);
const CPUContext* ctx_generic = threads[0]->Context();
ASSERT_EQ(ctx_generic->architecture, CPUArchitecture::kCPUArchitectureX86_64);
const CPUContextX86_64* ctx = ctx_generic->x86_64;
EXPECT_EQ(ctx->cs, 1);
EXPECT_EQ(ctx->fs, 4);
EXPECT_EQ(ctx->gs, 5);
EXPECT_EQ(ctx->rflags, 7UL);
EXPECT_EQ(ctx->dr0, 8UL);
EXPECT_EQ(ctx->dr1, 9U);
EXPECT_EQ(ctx->dr2, 10U);
EXPECT_EQ(ctx->dr3, 11U);
EXPECT_EQ(ctx->dr4, 12U);
EXPECT_EQ(ctx->dr5, 13U);
EXPECT_EQ(ctx->dr6, 12U);
EXPECT_EQ(ctx->dr7, 13U);
EXPECT_EQ(ctx->rax, 14U);
EXPECT_EQ(ctx->rcx, 15U);
EXPECT_EQ(ctx->rdx, 16U);
EXPECT_EQ(ctx->rbx, 17U);
EXPECT_EQ(ctx->rsp, 18U);
EXPECT_EQ(ctx->rbp, 19U);
EXPECT_EQ(ctx->rsi, 20U);
EXPECT_EQ(ctx->rdi, 21U);
EXPECT_EQ(ctx->r8, 22U);
EXPECT_EQ(ctx->r9, 23U);
EXPECT_EQ(ctx->r10, 24U);
EXPECT_EQ(ctx->r11, 25U);
EXPECT_EQ(ctx->r12, 26U);
EXPECT_EQ(ctx->r13, 27U);
EXPECT_EQ(ctx->r14, 28U);
EXPECT_EQ(ctx->r15, 29U);
EXPECT_EQ(ctx->rip, 30U);
EXPECT_EQ(ctx->fxsave.fcw, 37U);
EXPECT_EQ(ctx->fxsave.fsw, 38U);
EXPECT_EQ(ctx->fxsave.ftw, 39U);
EXPECT_EQ(ctx->fxsave.reserved_1, 40U);
EXPECT_EQ(ctx->fxsave.fop, 41U);
EXPECT_EQ(ctx->fxsave.fpu_ip_64, 42U);
EXPECT_EQ(ctx->fxsave.fpu_dp_64, 43U);
for (uint8_t i = 0; i < arraysize(ctx->fxsave.reserved_4); i++) {
EXPECT_EQ(ctx->fxsave.reserved_4[i], i * 2 + 115);
EXPECT_EQ(ctx->fxsave.available[i], i * 2 + 116);
}
for (size_t i = 0; i < arraysize(ctx->fxsave.st_mm); i++) {
for (uint8_t j = 0;
j < arraysize(ctx->fxsave.st_mm[0].mm_value);
j++) {
EXPECT_EQ(ctx->fxsave.st_mm[i].mm_value[j], j + 1);
EXPECT_EQ(ctx->fxsave.st_mm[i].mm_reserved[j], j + 1);
}
}
for (size_t i = 0; i < arraysize(ctx->fxsave.xmm); i++) {
for (uint8_t j = 0; j < arraysize(ctx->fxsave.xmm[0]); j++) {
EXPECT_EQ(ctx->fxsave.xmm[i][j], j + 1);
}
}
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -14,6 +14,10 @@
#include "snapshot/minidump/thread_snapshot_minidump.h"
#include <string.h>
#include "minidump/minidump_context.h"
namespace crashpad {
namespace internal {
@ -27,8 +31,13 @@ ThreadSnapshotMinidump::~ThreadSnapshotMinidump() {
}
bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
RVA minidump_thread_rva) {
RVA minidump_thread_rva,
CPUArchitecture arch) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
std::vector<unsigned char> minidump_context;
context_.architecture = arch;
if (!file_reader->SeekSet(minidump_thread_rva)) {
return false;
}
@ -37,10 +46,270 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
return false;
}
if (!file_reader->SeekSet(minidump_thread_.ThreadContext.Rva)) {
return false;
}
minidump_context.resize(minidump_thread_.ThreadContext.DataSize);
if (!file_reader->ReadExactly(minidump_context.data(),
minidump_context.size())) {
return false;
}
if (!InitializeContext(minidump_context)) {
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
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) {
LOG(WARNING) << "Snapshot X86 context support has no unit tests.";
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) {
LOG(WARNING) << "Snapshot ARM32 context support has no unit tests.";
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 < arraysize(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 < arraysize(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 < arraysize(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 < arraysize(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;
// Seems we don't get a full PSTATE but it looks like this assignment
// should give something useful at least.
context_.arm64->pstate = src->cpsr;
} else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) {
LOG(WARNING) << "Snapshot MIPS context support has no unit tests.";
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 < arraysize(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 < arraysize(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) {
LOG(WARNING) << "Snapshot MIPS64 context support has no unit tests.";
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 < arraysize(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 < arraysize(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;
@ -63,8 +332,7 @@ int ThreadSnapshotMinidump::Priority() const {
const CPUContext* ThreadSnapshotMinidump::Context() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
NOTREACHED(); // https://crashpad.chromium.org/bug/10
return nullptr;
return &context_;
}
const MemorySnapshot* ThreadSnapshotMinidump::Stack() const {

View File

@ -19,6 +19,7 @@
#include "minidump/minidump_extensions.h"
#include "snapshot/thread_snapshot.h"
#include "snapshot/cpu_context.h"
#include "util/file/file_reader.h"
#include "util/misc/initialization_state_dcheck.h"
@ -37,10 +38,13 @@ class ThreadSnapshotMinidump : public ThreadSnapshot {
//! The file reader must support seeking.
//! \param[in] minidump_thread_rva The file offset in \a file_reader at which
//! the threads MINIDUMP_THREAD structure is located.
//! \param[in] arch The architecture of the system this thread is running on.
//! Used to decode CPU Context.
//!
//! \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;
const MemorySnapshot* Stack() const override;
@ -51,8 +55,20 @@ class ThreadSnapshotMinidump : public ThreadSnapshot {
std::vector<const MemorySnapshot*> ExtraMemory() const override;
private:
//! \brief Initializes the CPU Context
//!
//! \param[in] minidump_context the raw bytes of the context data from the
//! minidump file.
//!
//! \return `true` if the context could be decoded without error.
bool InitializeContext(const std::vector<unsigned char>& minidump_context);
MINIDUMP_THREAD minidump_thread_;
CPUContext context_;
std::vector<unsigned char> context_memory_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotMinidump);
};
} // namespace internal