mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
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:
parent
b6103e157c
commit
8d17d5b4cf
@ -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
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 thread’s 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user