From 8d17d5b4cf33f225cc13c865e9e7499272a5de02 Mon Sep 17 00:00:00 2001 From: Casey Dahlin Date: Tue, 16 Oct 2018 12:23:21 -0700 Subject: [PATCH] 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 Reviewed-by: Scott Graham --- .../minidump/process_snapshot_minidump.cc | 14 +- snapshot/minidump/process_snapshot_minidump.h | 1 + .../process_snapshot_minidump_test.cc | 324 ++++++++++++++++++ snapshot/minidump/thread_snapshot_minidump.cc | 274 ++++++++++++++- snapshot/minidump/thread_snapshot_minidump.h | 18 +- 5 files changed, 623 insertions(+), 8 deletions(-) diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index f50c6520..a9bd0f04 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -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(-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(); - 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 diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 105c5d27..2ef23a68 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -114,6 +114,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector unloaded_modules_; MinidumpCrashpadInfo crashpad_info_; internal::SystemSnapshotMinidump system_snapshot_; + CPUArchitecture arch_; std::map annotations_simple_map_; FileReaderInterface* file_reader_; // weak pid_t process_id_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 9212dacb..b710f028 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -21,6 +21,7 @@ #include #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(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(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(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(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 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(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(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(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(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 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 diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index 9bf2b718..458586d3 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -14,6 +14,10 @@ #include "snapshot/minidump/thread_snapshot_minidump.h" +#include + +#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 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& 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(context_memory_.data()); + const MinidumpContextX86* src = + reinterpret_cast(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextX86)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextX86)) { + return false; + } + + if (src->context_flags & kMinidumpContextX86Extended) { + context_.x86->fxsave = src->fxsave; + } else if (src->context_flags & kMinidumpContextX86FloatingPoint) { + CPUContextX86::FsaveToFxsave(src->fsave, &context_.x86->fxsave); + } + + context_.x86->eax = src->eax; + context_.x86->ebx = src->ebx; + context_.x86->ecx = src->ecx; + context_.x86->edx = src->edx; + context_.x86->edi = src->edi; + context_.x86->esi = src->esi; + context_.x86->ebp = src->ebp; + context_.x86->esp = src->esp; + context_.x86->eip = src->eip; + context_.x86->eflags = src->eflags; + context_.x86->cs = static_cast(src->cs); + context_.x86->ds = static_cast(src->ds); + context_.x86->es = static_cast(src->es); + context_.x86->fs = static_cast(src->fs); + context_.x86->gs = static_cast(src->gs); + context_.x86->ss = static_cast(src->ss); + context_.x86->dr0 = src->dr0; + context_.x86->dr1 = src->dr1; + context_.x86->dr2 = src->dr2; + context_.x86->dr3 = src->dr3; + context_.x86->dr6 = src->dr6; + context_.x86->dr7 = src->dr7; + + // Minidump passes no value for dr4/5. Our output context has space for + // them. According to spec they're obsolete, but when present read as + // aliases for dr6/7, so we'll do this. + context_.x86->dr4 = src->dr6; + context_.x86->dr5 = src->dr7; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureX86_64) { + context_memory_.resize(sizeof(CPUContextX86_64)); + context_.x86_64 = + reinterpret_cast(context_memory_.data()); + const MinidumpContextAMD64* src = + reinterpret_cast(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextAMD64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextAMD64)) { + return false; + } + + context_.x86_64->fxsave = src->fxsave; + context_.x86_64->cs = src->cs; + context_.x86_64->fs = src->fs; + context_.x86_64->gs = src->gs; + context_.x86_64->rflags = src->eflags; + context_.x86_64->dr0 = src->dr0; + context_.x86_64->dr1 = src->dr1; + context_.x86_64->dr2 = src->dr2; + context_.x86_64->dr3 = src->dr3; + context_.x86_64->dr6 = src->dr6; + context_.x86_64->dr7 = src->dr7; + context_.x86_64->rax = src->rax; + context_.x86_64->rcx = src->rcx; + context_.x86_64->rdx = src->rdx; + context_.x86_64->rbx = src->rbx; + context_.x86_64->rsp = src->rsp; + context_.x86_64->rbp = src->rbp; + context_.x86_64->rsi = src->rsi; + context_.x86_64->rdi = src->rdi; + context_.x86_64->r8 = src->r8; + context_.x86_64->r9 = src->r9; + context_.x86_64->r10 = src->r10; + context_.x86_64->r11 = src->r11; + context_.x86_64->r12 = src->r12; + context_.x86_64->r13 = src->r13; + context_.x86_64->r14 = src->r14; + context_.x86_64->r15 = src->r15; + context_.x86_64->rip = src->rip; + + // See comments on x86 above. + context_.x86_64->dr4 = src->dr6; + context_.x86_64->dr5 = src->dr7; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM) { + LOG(WARNING) << "Snapshot ARM32 context support has no unit tests."; + context_memory_.resize(sizeof(CPUContextARM)); + context_.arm = reinterpret_cast(context_memory_.data()); + const MinidumpContextARM* src = + reinterpret_cast(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextARM)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextARM)) { + return false; + } + + for (size_t i = 0; i < 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(context_memory_.data()); + const MinidumpContextARM64* src = + reinterpret_cast(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextARM64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextARM64)) { + return false; + } + + for (size_t i = 0; i < 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(context_memory_.data()); + const MinidumpContextMIPS* src = + reinterpret_cast(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextMIPS)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextMIPS)) { + return false; + } + + for (size_t i = 0; i < arraysize(src->regs); i++) { + context_.mipsel->regs[i] = src->regs[i]; + } + + context_.mipsel->mdhi = static_cast(src->mdhi); + context_.mipsel->mdlo = static_cast(src->mdlo); + context_.mipsel->dsp_control = src->dsp_control; + + for (size_t i = 0; i < arraysize(src->hi); i++) { + context_.mipsel->hi[i] = src->hi[i]; + context_.mipsel->lo[i] = src->lo[i]; + } + + context_.mipsel->cp0_epc = static_cast(src->epc); + context_.mipsel->cp0_badvaddr = static_cast(src->badvaddr); + context_.mipsel->cp0_status = src->status; + context_.mipsel->cp0_cause = src->cause; + context_.mipsel->fpcsr = src->fpcsr; + context_.mipsel->fir = src->fir; + + memcpy(&context_.mipsel->fpregs, &src->fpregs, sizeof(src->fpregs)); + } else if (context_.architecture == + CPUArchitecture::kCPUArchitectureMIPS64EL) { + LOG(WARNING) << "Snapshot MIPS64 context support has no unit tests."; + context_memory_.resize(sizeof(CPUContextMIPS64)); + context_.mips64 = + reinterpret_cast(context_memory_.data()); + const MinidumpContextMIPS64* src = + reinterpret_cast(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextMIPS64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextMIPS64)) { + return false; + } + + for (size_t i = 0; i < 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 { diff --git a/snapshot/minidump/thread_snapshot_minidump.h b/snapshot/minidump/thread_snapshot_minidump.h index 18a17b28..338f2341 100644 --- a/snapshot/minidump/thread_snapshot_minidump.h +++ b/snapshot/minidump/thread_snapshot_minidump.h @@ -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 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& minidump_context); + MINIDUMP_THREAD minidump_thread_; + CPUContext context_; + std::vector context_memory_; InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotMinidump); }; } // namespace internal