Commit 8eafac3c authored by Joshua Peraza's avatar Joshua Peraza Committed by Commit Bot

Update Crashpad to 3a6c6012ba2b9ed662872ccaf7d276d56240943b

8edbc7439b2b codereview.settings: stop forcing squashing
64399c514ff2 Implement Exception context for minidump
6b5e30db285f Fix signed-unsigned-wchar build failure
efaebfc482b7 fuchsia: Capture from SP (+slop) to stack base, rather than
             entire stack
ec56fc6a38f0 linux: add Get/SetHandlerSocket()
3a6c6012ba2b linux: override exception thread ID

Change-Id: I2a9c12ec841ec053d7558a7e2d40dee0587fe1d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1762682Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Cr-Commit-Position: refs/heads/master@{#688718}
parent c9d6c403
...@@ -2,7 +2,7 @@ Name: Crashpad ...@@ -2,7 +2,7 @@ Name: Crashpad
Short Name: crashpad Short Name: crashpad
URL: https://crashpad.chromium.org/ URL: https://crashpad.chromium.org/
Version: unknown Version: unknown
Revision: 5a4c2f2b8359019f331eac260cb1443e07c3e9e1 Revision: 3a6c6012ba2b9ed662872ccaf7d276d56240943b
License: Apache 2.0 License: Apache 2.0
License File: crashpad/LICENSE License File: crashpad/LICENSE
Security Critical: yes Security Critical: yes
......
...@@ -24,7 +24,7 @@ deps = { ...@@ -24,7 +24,7 @@ deps = {
'3e50219fc4503f461b2176a9976891b28d80f9ab', '3e50219fc4503f461b2176a9976891b28d80f9ab',
'crashpad/third_party/gtest/gtest': 'crashpad/third_party/gtest/gtest':
Var('chromium_git') + '/external/github.com/google/googletest@' + Var('chromium_git') + '/external/github.com/google/googletest@' +
'da10da05c262af0a9e8fa91789a272a3dec67655', 'eb78ee170ac9eb21487f4d127720c060351fa8a2',
'crashpad/third_party/gyp/gyp': 'crashpad/third_party/gyp/gyp':
Var('chromium_git') + '/external/gyp@' + Var('chromium_git') + '/external/gyp@' +
'8bee09f4a57807136593ddc906b0b213c21f9014', '8bee09f4a57807136593ddc906b0b213c21f9014',
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/macros.h" #include "base/macros.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "util/file/file_io.h"
#include "util/misc/capture_context.h" #include "util/misc/capture_context.h"
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
...@@ -116,6 +117,30 @@ class CrashpadClient { ...@@ -116,6 +117,30 @@ class CrashpadClient {
bool restartable, bool restartable,
bool asynchronous_start); bool asynchronous_start);
#if defined(OS_ANDROID) || defined(OS_LINUX) || DOXYGEN
//! \brief Retrieve the socket and process ID for the handler.
//!
//! `StartHandler()` must have successfully been called before calling this
//! method.
//!
//! \param[out] sock The socket connected to the handler.
//! \param[out] pid The handler's process ID.
//! \return `true` on success. Otherwise `false` with a message logged.
static bool GetHandlerSocket(int* sock, pid_t* pid);
//! \brief Sets the socket to a presumably-running Crashpad handler process
//! which was started with StartHandler().
//!
//! This method installs a signal handler to request crash dumps on \a sock.
//!
//! \param[in] sock A socket connected to a Crashpad handler.
//! \param[in] pid The process ID of the handler, used to set the handler as
//! this process' ptracer. 0 indicates it is not necessary to set the
//! handler as this process' ptracer. -1 indicates that the handler's
//! process ID should be determined by communicating over the socket.
static bool SetHandlerSocket(ScopedFileHandle sock, pid_t pid);
#endif // OS_ANDROID || OS_LINUX || DOXYGEN
#if defined(OS_ANDROID) || DOXYGEN #if defined(OS_ANDROID) || DOXYGEN
//! \brief Installs a signal handler to execute `/system/bin/app_process` and //! \brief Installs a signal handler to execute `/system/bin/app_process` and
//! load a Java class in response to a crash. //! load a Java class in response to a crash.
......
...@@ -284,9 +284,19 @@ class RequestCrashDumpHandler : public SignalHandler { ...@@ -284,9 +284,19 @@ class RequestCrashDumpHandler : public SignalHandler {
return false; return false;
} }
sock_to_handler_.reset(sock.release()); sock_to_handler_.reset(sock.release());
handler_pid_ = pid;
return Install(); return Install();
} }
bool GetHandlerSocket(int* sock, pid_t* pid) {
if (!sock_to_handler_.is_valid()) {
return false;
}
*sock = sock_to_handler_.get();
*pid = handler_pid_;
return true;
}
void HandleCrashImpl() override { void HandleCrashImpl() override {
ExceptionHandlerProtocol::ClientInformation info = {}; ExceptionHandlerProtocol::ClientInformation info = {};
info.exception_information_address = info.exception_information_address =
...@@ -302,6 +312,7 @@ class RequestCrashDumpHandler : public SignalHandler { ...@@ -302,6 +312,7 @@ class RequestCrashDumpHandler : public SignalHandler {
~RequestCrashDumpHandler() = delete; ~RequestCrashDumpHandler() = delete;
ScopedFileHandle sock_to_handler_; ScopedFileHandle sock_to_handler_;
pid_t handler_pid_ = -1;
DISALLOW_COPY_AND_ASSIGN(RequestCrashDumpHandler); DISALLOW_COPY_AND_ASSIGN(RequestCrashDumpHandler);
}; };
...@@ -343,6 +354,20 @@ bool CrashpadClient::StartHandler( ...@@ -343,6 +354,20 @@ bool CrashpadClient::StartHandler(
return signal_handler->Initialize(std::move(client_sock), -1); return signal_handler->Initialize(std::move(client_sock), -1);
} }
#if defined(OS_ANDROID) || defined(OS_LINUX)
// static
bool CrashpadClient::GetHandlerSocket(int* sock, pid_t* pid) {
auto signal_handler = RequestCrashDumpHandler::Get();
return signal_handler->GetHandlerSocket(sock, pid);
}
// static
bool CrashpadClient::SetHandlerSocket(ScopedFileHandle sock, pid_t pid) {
auto signal_handler = RequestCrashDumpHandler::Get();
return signal_handler->Initialize(std::move(sock), pid);
}
#endif // OS_ANDROID || OS_LINUX
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
// static // static
......
...@@ -95,13 +95,18 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( ...@@ -95,13 +95,18 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
return false; return false;
} }
if (requesting_thread_id && requesting_thread_stack_address) { pid_t local_requesting_thread_id = -1;
*requesting_thread_id = process_snapshot.FindThreadWithStackAddress( if (requesting_thread_stack_address) {
local_requesting_thread_id = process_snapshot.FindThreadWithStackAddress(
requesting_thread_stack_address); requesting_thread_stack_address);
} }
if (!process_snapshot.InitializeException( if (requesting_thread_id) {
info.exception_information_address)) { *requesting_thread_id = local_requesting_thread_id;
}
if (!process_snapshot.InitializeException(info.exception_information_address,
local_requesting_thread_id)) {
Metrics::ExceptionCaptureResult( Metrics::ExceptionCaptureResult(
Metrics::CaptureResult::kExceptionInitializationFailed); Metrics::CaptureResult::kExceptionInitializationFailed);
return false; return false;
......
...@@ -42,6 +42,8 @@ static_library("snapshot") { ...@@ -42,6 +42,8 @@ static_library("snapshot") {
"minidump/memory_snapshot_minidump.h", "minidump/memory_snapshot_minidump.h",
"minidump/minidump_annotation_reader.cc", "minidump/minidump_annotation_reader.cc",
"minidump/minidump_annotation_reader.h", "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.cc",
"minidump/minidump_simple_string_dictionary_reader.h", "minidump/minidump_simple_string_dictionary_reader.h",
"minidump/minidump_stream.h", "minidump/minidump_stream.h",
......
...@@ -61,8 +61,22 @@ void GetStackRegions( ...@@ -61,8 +61,22 @@ void GetStackRegions(
<< "stack range is unexpectedly marked executable, continuing anyway"; << "stack range is unexpectedly marked executable, continuing anyway";
} }
// The stack covers [range_with_sp.base, range_with_sp.base +
// range_with_sp.size). The stack pointer (sp) can be anywhere in that range.
// It starts at the end of the range (range_with_sp.base + range_with_sp.size)
// and goes downwards until range_with_sp.base. Capture the part of the stack
// that is currently used: [sp, range_with_sp.base + range_with_sp.size).
// Capture up to kExtraCaptureSize additional bytes of stack, but only if
// present in the region that was already found.
constexpr uint64_t kExtraCaptureSize = 128;
const uint64_t start_address =
std::max(sp >= kExtraCaptureSize ? sp - kExtraCaptureSize : sp,
range_with_sp.base);
const size_t region_size =
range_with_sp.size - (start_address - range_with_sp.base);
stack_regions->push_back( stack_regions->push_back(
CheckedRange<zx_vaddr_t, size_t>(range_with_sp.base, range_with_sp.size)); CheckedRange<zx_vaddr_t, size_t>(start_address, region_size));
// TODO(scottmg): https://crashpad.chromium.org/bug/196, once the retrievable // TODO(scottmg): https://crashpad.chromium.org/bug/196, once the retrievable
// registers include FS and similar for ARM, retrieve the region for the // registers include FS and similar for ARM, retrieve the region for the
......
...@@ -174,7 +174,8 @@ class ThreadsChildTest : public MultiprocessExec { ...@@ -174,7 +174,8 @@ class ThreadsChildTest : public MultiprocessExec {
for (size_t i = 1; i < 6; ++i) { for (size_t i = 1; i < 6; ++i) {
ASSERT_GT(threads[i].stack_regions.size(), 0u); ASSERT_GT(threads[i].stack_regions.size(), 0u);
EXPECT_EQ(threads[i].stack_regions[0].size(), i * 4096u); EXPECT_GT(threads[i].stack_regions[0].size(), 0u);
EXPECT_LE(threads[i].stack_regions[0].size(), i * 4096u);
} }
} }
......
...@@ -64,7 +64,8 @@ pid_t ProcessSnapshotLinux::FindThreadWithStackAddress( ...@@ -64,7 +64,8 @@ pid_t ProcessSnapshotLinux::FindThreadWithStackAddress(
} }
bool ProcessSnapshotLinux::InitializeException( bool ProcessSnapshotLinux::InitializeException(
LinuxVMAddress exception_info_address) { LinuxVMAddress exception_info_address,
pid_t exception_thread_id) {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
DCHECK(!exception_); DCHECK(!exception_);
...@@ -75,6 +76,10 @@ bool ProcessSnapshotLinux::InitializeException( ...@@ -75,6 +76,10 @@ bool ProcessSnapshotLinux::InitializeException(
return false; return false;
} }
if (exception_thread_id >= 0) {
info.thread_id = exception_thread_id;
}
exception_.reset(new internal::ExceptionSnapshotLinux()); exception_.reset(new internal::ExceptionSnapshotLinux());
if (!exception_->Initialize(&process_reader_, if (!exception_->Initialize(&process_reader_,
info.siginfo_address, info.siginfo_address,
......
...@@ -70,7 +70,12 @@ class ProcessSnapshotLinux final : public ProcessSnapshot { ...@@ -70,7 +70,12 @@ class ProcessSnapshotLinux final : public ProcessSnapshot {
//! //!
//! \param[in] exception_info The address of an ExceptionInformation in the //! \param[in] exception_info The address of an ExceptionInformation in the
//! target process' address space. //! target process' address space.
bool InitializeException(LinuxVMAddress exception_info); //! \param[in] exception_thread_id The thread ID to assocaite the thread with.
//! Optional. If -1, the exception thread will be identified by the
//! ExceptionInformation struct which contains the thread ID in the target
//! process' namespace.
bool InitializeException(LinuxVMAddress exception_info,
pid_t exception_thread_id = -1);
//! \brief Sets the value to be returned by ReportID(). //! \brief Sets the value to be returned by ReportID().
//! //!
......
...@@ -22,16 +22,20 @@ namespace internal { ...@@ -22,16 +22,20 @@ namespace internal {
ExceptionSnapshotMinidump::ExceptionSnapshotMinidump() ExceptionSnapshotMinidump::ExceptionSnapshotMinidump()
: ExceptionSnapshot(), : ExceptionSnapshot(),
minidump_exception_stream_(), minidump_exception_stream_(),
context_(),
exception_information_(), exception_information_(),
initialized_() {} initialized_() {}
ExceptionSnapshotMinidump::~ExceptionSnapshotMinidump() {} ExceptionSnapshotMinidump::~ExceptionSnapshotMinidump() {}
bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader, bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
CPUArchitecture arch,
RVA minidump_exception_stream_rva) { RVA minidump_exception_stream_rva) {
DCHECK(initialized_.is_uninitialized()); DCHECK(initialized_.is_uninitialized());
initialized_.set_invalid(); initialized_.set_invalid();
std::vector<unsigned char> minidump_context;
if (!file_reader->SeekSet(minidump_exception_stream_rva)) { if (!file_reader->SeekSet(minidump_exception_stream_rva)) {
return false; return false;
} }
...@@ -48,14 +52,28 @@ bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader, ...@@ -48,14 +52,28 @@ bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
minidump_exception_stream_.ExceptionRecord.ExceptionInformation[i]); 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(); initialized_.set_valid();
return true; return true;
} }
const CPUContext* ExceptionSnapshotMinidump::Context() const { const CPUContext* ExceptionSnapshotMinidump::Context() const {
DCHECK(initialized_.is_valid()); DCHECK(initialized_.is_valid());
NOTREACHED(); // https://crashpad.chromium.org/bug/10 return context_.Get();
return nullptr;
} }
uint64_t ExceptionSnapshotMinidump::ThreadID() const { uint64_t ExceptionSnapshotMinidump::ThreadID() const {
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "snapshot/cpu_context.h" #include "snapshot/cpu_context.h"
#include "snapshot/exception_snapshot.h" #include "snapshot/exception_snapshot.h"
#include "snapshot/minidump/minidump_context_converter.h"
#include "util/file/file_reader.h" #include "util/file/file_reader.h"
#include "util/misc/initialization_state.h" #include "util/misc/initialization_state.h"
...@@ -37,12 +38,14 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot { ...@@ -37,12 +38,14 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot {
//! //!
//! \param[in] file_reader A file reader corresponding to a minidump file. //! \param[in] file_reader A file reader corresponding to a minidump file.
//! The file reader must support seeking. //! 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 //! \param[in] minidump_exception_stream_rva The file offset in \a file_reader
//! at which the MINIDUMP_EXCEPTION_STREAM structure is located. //! at which the MINIDUMP_EXCEPTION_STREAM structure is located.
//! //!
//! \return `true` if the snapshot could be created, `false` otherwise with //! \return `true` if the snapshot could be created, `false` otherwise with
//! an appropriate message logged. //! an appropriate message logged.
bool Initialize(FileReaderInterface* file_reader, bool Initialize(FileReaderInterface* file_reader,
CPUArchitecture arch,
RVA minidump_exception_stream_rva); RVA minidump_exception_stream_rva);
// ExceptionSnapshot: // ExceptionSnapshot:
...@@ -60,6 +63,7 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot { ...@@ -60,6 +63,7 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot {
private: private:
MINIDUMP_EXCEPTION_STREAM minidump_exception_stream_; MINIDUMP_EXCEPTION_STREAM minidump_exception_stream_;
MinidumpContextConverter context_;
std::vector<uint64_t> exception_information_; std::vector<uint64_t> exception_information_;
InitializationState initialized_; InitializationState initialized_;
......
// 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
// 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() { ...@@ -596,7 +596,8 @@ bool ProcessSnapshotMinidump::InitializeExceptionSnapshot() {
return false; 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; return false;
} }
......
...@@ -47,6 +47,43 @@ class ReadToVector : public crashpad::MemorySnapshot::Delegate { ...@@ -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) { TEST(ProcessSnapshotMinidump, EmptyFile) {
StringFile string_file; StringFile string_file;
ProcessSnapshotMinidump process_snapshot; ProcessSnapshotMinidump process_snapshot;
...@@ -799,38 +836,7 @@ TEST(ProcessSnapshotMinidump, ThreadContextARM64) { ...@@ -799,38 +836,7 @@ TEST(ProcessSnapshotMinidump, ThreadContextARM64) {
minidump_thread.ThreadId = 42; minidump_thread.ThreadId = 42;
minidump_thread.Teb = 24; minidump_thread.Teb = 24;
MinidumpContextARM64 minidump_context; MinidumpContextARM64 minidump_context = GetArm64MinidumpContext();
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.DataSize = sizeof(minidump_context);
minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet()); minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet());
...@@ -1314,10 +1320,35 @@ TEST(ProcessSnapshotMinidump, Exception) { ...@@ -1314,10 +1320,35 @@ TEST(ProcessSnapshotMinidump, Exception) {
minidump_exception.ExceptionInformation[0] = 51; minidump_exception.ExceptionInformation[0] = 51;
minidump_exception.ExceptionInformation[1] = 62; 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 minidump_exception_stream = {};
minidump_exception_stream.ThreadId = 5; minidump_exception_stream.ThreadId = 5;
minidump_exception_stream.ExceptionRecord = minidump_exception; 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_DIRECTORY minidump_exception_directory = {};
minidump_exception_directory.StreamType = kMinidumpStreamTypeException; minidump_exception_directory.StreamType = kMinidumpStreamTypeException;
minidump_exception_directory.Location.DataSize = minidump_exception_directory.Location.DataSize =
...@@ -1331,10 +1362,12 @@ TEST(ProcessSnapshotMinidump, Exception) { ...@@ -1331,10 +1362,12 @@ TEST(ProcessSnapshotMinidump, Exception) {
header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet());
ASSERT_TRUE(string_file.Write(&minidump_exception_directory, ASSERT_TRUE(string_file.Write(&minidump_exception_directory,
sizeof(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.Signature = MINIDUMP_SIGNATURE;
header.Version = MINIDUMP_VERSION; header.Version = MINIDUMP_VERSION;
header.NumberOfStreams = 1; header.NumberOfStreams = 2;
EXPECT_TRUE(string_file.SeekSet(0)); EXPECT_TRUE(string_file.SeekSet(0));
EXPECT_TRUE(string_file.Write(&header, sizeof(header))); EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
...@@ -1352,6 +1385,28 @@ TEST(ProcessSnapshotMinidump, Exception) { ...@@ -1352,6 +1385,28 @@ TEST(ProcessSnapshotMinidump, Exception) {
EXPECT_EQ(codes.size(), 2UL); EXPECT_EQ(codes.size(), 2UL);
EXPECT_EQ(codes[0], 51UL); EXPECT_EQ(codes[0], 51UL);
EXPECT_EQ(codes[1], 62UL); 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) { TEST(ProcessSnapshotMinidump, NoExceptionInMinidump) {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "minidump/minidump_extensions.h" #include "minidump/minidump_extensions.h"
#include "snapshot/cpu_context.h" #include "snapshot/cpu_context.h"
#include "snapshot/minidump/memory_snapshot_minidump.h" #include "snapshot/minidump/memory_snapshot_minidump.h"
#include "snapshot/minidump/minidump_context_converter.h"
#include "snapshot/thread_snapshot.h" #include "snapshot/thread_snapshot.h"
#include "util/file/file_reader.h" #include "util/file/file_reader.h"
#include "util/misc/initialization_state_dcheck.h" #include "util/misc/initialization_state_dcheck.h"
...@@ -44,7 +45,8 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { ...@@ -44,7 +45,8 @@ class ThreadSnapshotMinidump : public ThreadSnapshot {
//! //!
//! \return `true` if the snapshot could be created, `false` otherwise with //! \return `true` if the snapshot could be created, `false` otherwise with
//! an appropriate message logged. //! an appropriate message logged.
bool Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva, bool Initialize(FileReaderInterface* file_reader,
RVA minidump_thread_rva,
CPUArchitecture arch); CPUArchitecture arch);
const CPUContext* Context() const override; const CPUContext* Context() const override;
...@@ -65,8 +67,7 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { ...@@ -65,8 +67,7 @@ class ThreadSnapshotMinidump : public ThreadSnapshot {
bool InitializeContext(const std::vector<unsigned char>& minidump_context); bool InitializeContext(const std::vector<unsigned char>& minidump_context);
MINIDUMP_THREAD minidump_thread_; MINIDUMP_THREAD minidump_thread_;
CPUContext context_; MinidumpContextConverter context_;
std::vector<unsigned char> context_memory_;
MemorySnapshotMinidump stack_; MemorySnapshotMinidump stack_;
InitializationStateDcheck initialized_; InitializationStateDcheck initialized_;
......
...@@ -109,6 +109,8 @@ ...@@ -109,6 +109,8 @@
'memory_snapshot_generic.h', 'memory_snapshot_generic.h',
'minidump/minidump_annotation_reader.cc', 'minidump/minidump_annotation_reader.cc',
'minidump/minidump_annotation_reader.h', '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.cc',
'minidump/minidump_simple_string_dictionary_reader.h', 'minidump/minidump_simple_string_dictionary_reader.h',
'minidump/minidump_stream.h', 'minidump/minidump_stream.h',
......
...@@ -267,17 +267,6 @@ if (crashpad_is_in_chromium) { ...@@ -267,17 +267,6 @@ if (crashpad_is_in_chromium) {
config("gmock_private_config") { config("gmock_private_config") {
visibility = [ ":*" ] visibility = [ ":*" ]
include_dirs = [ "gtest/googlemock" ] include_dirs = [ "gtest/googlemock" ]
if (crashpad_is_clang && (crashpad_is_linux || crashpad_is_fuchsia)) {
cflags_cc = [
# This seems a bit questionable:
# https://github.com/google/googletest/blob/bf6df7eaee5cfaafe2655fab143f348eba98c9af/googlemock/include/gmock/internal/gmock-internal-utils.h#L109
# and causes a warning/error on recent clangs (Linux/Fuchsia currently
# have this, other platforms don't yet).
# Temporarily disable this warning for building gmock tests until
# internal CL 263406158 lands and rolls.
"-Wno-signed-unsigned-wchar",
]
}
} }
config("gmock_public_config") { config("gmock_public_config") {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment