mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
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:
parent
8edbc7439b
commit
64399c514f
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -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_;
|
||||
|
||||
|
275
snapshot/minidump/minidump_context_converter.cc
Normal file
275
snapshot/minidump/minidump_context_converter.cc
Normal 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
|
47
snapshot/minidump/minidump_context_converter.h
Normal file
47
snapshot/minidump/minidump_context_converter.h
Normal 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_
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user