#include "snapshot/linux/exception_snapshot_linux.h"
#include <signal.h>
#include "base/logging.h"
#include "snapshot/linux/capture_memory_delegate_linux.h"
#include "snapshot/linux/cpu_context_linux.h"
#include "snapshot/linux/process_reader_linux.h"
#include "snapshot/linux/signal_context.h"
#include "util/linux/traits.h"
#include "util/misc/reinterpret_bytes.h"
#include "util/numeric/safe_assignment.h"
#include "util/posix/signals.h"
namespace crashpad {
namespace internal {
ExceptionSnapshotLinux::ExceptionSnapshotLinux()
: … { … }
ExceptionSnapshotLinux::~ExceptionSnapshotLinux() { … }
#if defined(ARCH_CPU_X86_FAMILY)
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
ProcessReaderLinux* reader,
LinuxVMAddress context_address) { … }
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
ProcessReaderLinux* reader,
LinuxVMAddress context_address) { … }
#elif defined(ARCH_CPU_ARM_FAMILY)
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
ProcessReaderLinux* reader,
LinuxVMAddress context_address) {
context_.architecture = kCPUArchitectureARM;
context_.arm = &context_union_.arm;
CPUContextARM* dest_context = context_.arm;
const ProcessMemory* memory = reader->Memory();
LinuxVMAddress gprs_address =
context_address + offsetof(UContext<ContextTraits32>, mcontext32) +
offsetof(ContextTraits32::MContext32, gprs);
SignalThreadContext32 thread_context;
if (!memory->Read(gprs_address, sizeof(thread_context), &thread_context)) {
LOG(ERROR) << "Couldn't read gprs";
return false;
}
InitializeCPUContextARM_NoFloatingPoint(thread_context, dest_context);
LinuxVMAddress reserved_address =
context_address + offsetof(UContext<ContextTraits32>, reserved);
if ((reserved_address & 7) != 0) {
LOG(ERROR) << "invalid alignment 0x" << std::hex << reserved_address;
return false;
}
constexpr VMSize kMaxContextSpace = 1024;
ProcessMemoryRange range;
if (!range.Initialize(memory, false, reserved_address, kMaxContextSpace)) {
return false;
}
do {
CoprocessorContextHead head;
if (!range.Read(reserved_address, sizeof(head), &head)) {
LOG(ERROR) << "missing context terminator";
return false;
}
reserved_address += sizeof(head);
switch (head.magic) {
case VFP_MAGIC:
if (head.size != sizeof(SignalVFPContext) + sizeof(head)) {
LOG(ERROR) << "unexpected vfp context size " << head.size;
return false;
}
static_assert(
sizeof(SignalVFPContext::vfp) == sizeof(dest_context->vfp_regs),
"vfp context size mismatch");
if (!range.Read(reserved_address + offsetof(SignalVFPContext, vfp),
sizeof(dest_context->vfp_regs),
&dest_context->vfp_regs)) {
LOG(ERROR) << "Couldn't read vfp";
return false;
}
dest_context->have_vfp_regs = true;
return true;
case CRUNCH_MAGIC:
case IWMMXT_MAGIC:
case DUMMY_MAGIC:
reserved_address += head.size - sizeof(head);
continue;
case 0:
return true;
default:
LOG(ERROR) << "invalid magic number 0x" << std::hex << head.magic;
return false;
}
} while (true);
}
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
ProcessReaderLinux* reader,
LinuxVMAddress context_address) {
context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_union_.arm64;
CPUContextARM64* dest_context = context_.arm64;
const ProcessMemory* memory = reader->Memory();
LinuxVMAddress gprs_address =
context_address + offsetof(UContext<ContextTraits64>, mcontext64) +
offsetof(ContextTraits64::MContext64, gprs);
ThreadContext::t64_t thread_context;
if (!memory->Read(gprs_address, sizeof(thread_context), &thread_context)) {
LOG(ERROR) << "Couldn't read gprs";
return false;
}
InitializeCPUContextARM64_NoFloatingPoint(thread_context, dest_context);
LinuxVMAddress reserved_address =
context_address + offsetof(UContext<ContextTraits64>, reserved);
if ((reserved_address & 15) != 0) {
LOG(ERROR) << "invalid alignment 0x" << std::hex << reserved_address;
return false;
}
constexpr VMSize kMaxContextSpace = 4096;
ProcessMemoryRange range;
if (!range.Initialize(memory, true, reserved_address, kMaxContextSpace)) {
return false;
}
do {
CoprocessorContextHead head;
if (!range.Read(reserved_address, sizeof(head), &head)) {
LOG(ERROR) << "missing context terminator";
return false;
}
reserved_address += sizeof(head);
switch (head.magic) {
case FPSIMD_MAGIC:
if (head.size != sizeof(SignalFPSIMDContext) + sizeof(head)) {
LOG(ERROR) << "unexpected fpsimd context size " << head.size;
return false;
}
SignalFPSIMDContext fpsimd;
if (!range.Read(reserved_address, sizeof(fpsimd), &fpsimd)) {
LOG(ERROR) << "Couldn't read fpsimd " << head.size;
return false;
}
InitializeCPUContextARM64_OnlyFPSIMD(fpsimd, dest_context);
return true;
case ESR_MAGIC:
case EXTRA_MAGIC:
reserved_address += head.size - sizeof(head);
continue;
case 0:
LOG(WARNING) << "fpsimd not found";
return true;
default:
LOG(ERROR) << "invalid magic number 0x" << std::hex << head.magic;
return false;
}
} while (true);
}
#elif defined(ARCH_CPU_MIPS_FAMILY)
template <typename Traits>
static bool ReadContext(ProcessReaderLinux* reader,
LinuxVMAddress context_address,
typename Traits::CPUContext* dest_context) {
const ProcessMemory* memory = reader->Memory();
LinuxVMAddress gregs_address = context_address +
offsetof(UContext<Traits>, mcontext) +
offsetof(typename Traits::MContext, gregs);
typename Traits::SignalThreadContext thread_context;
if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) {
LOG(ERROR) << "Couldn't read gregs";
return false;
}
LinuxVMAddress fpregs_address = context_address +
offsetof(UContext<Traits>, mcontext) +
offsetof(typename Traits::MContext, fpregs);
typename Traits::SignalFloatContext fp_context;
if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) {
LOG(ERROR) << "Couldn't read fpregs";
return false;
}
InitializeCPUContextMIPS<Traits>(thread_context, fp_context, dest_context);
return true;
}
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
ProcessReaderLinux* reader,
LinuxVMAddress context_address) {
context_.architecture = kCPUArchitectureMIPSEL;
context_.mipsel = &context_union_.mipsel;
return internal::ReadContext<ContextTraits32>(
reader, context_address, context_.mipsel);
}
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
ProcessReaderLinux* reader,
LinuxVMAddress context_address) {
context_.architecture = kCPUArchitectureMIPS64EL;
context_.mips64 = &context_union_.mips64;
return internal::ReadContext<ContextTraits64>(
reader, context_address, context_.mips64);
}
#elif defined(ARCH_CPU_RISCV64)
static bool ReadContext(ProcessReaderLinux* reader,
LinuxVMAddress context_address,
typename ContextTraits64::CPUContext* dest_context) {
const ProcessMemory* memory = reader->Memory();
LinuxVMAddress gregs_address = context_address +
offsetof(UContext<ContextTraits64>, mcontext) +
offsetof(MContext64, regs);
typename ContextTraits64::SignalThreadContext thread_context;
if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) {
LOG(ERROR) << "Couldn't read gregs";
return false;
}
LinuxVMAddress fpregs_address =
context_address + offsetof(UContext<ContextTraits64>, mcontext) +
offsetof(MContext64, fpregs);
typename ContextTraits64::SignalFloatContext fp_context;
if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) {
LOG(ERROR) << "Couldn't read fpregs";
return false;
}
InitializeCPUContextRISCV64(thread_context, fp_context, dest_context);
return true;
}
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
ProcessReaderLinux* reader,
LinuxVMAddress context_address) {
context_.architecture = kCPUArchitectureRISCV64;
context_.riscv64 = &context_union_.riscv64;
return internal::ReadContext(reader, context_address, context_.riscv64);
}
#endif
bool ExceptionSnapshotLinux::Initialize(
ProcessReaderLinux* process_reader,
LinuxVMAddress siginfo_address,
LinuxVMAddress context_address,
pid_t thread_id,
uint32_t* gather_indirectly_referenced_memory_cap) { … }
template <typename Traits>
bool ExceptionSnapshotLinux::ReadSiginfo(ProcessReaderLinux* reader,
LinuxVMAddress siginfo_address) { … }
const CPUContext* ExceptionSnapshotLinux::Context() const { … }
uint64_t ExceptionSnapshotLinux::ThreadID() const { … }
uint32_t ExceptionSnapshotLinux::Exception() const { … }
uint32_t ExceptionSnapshotLinux::ExceptionInfo() const { … }
uint64_t ExceptionSnapshotLinux::ExceptionAddress() const { … }
const std::vector<uint64_t>& ExceptionSnapshotLinux::Codes() const { … }
std::vector<const MemorySnapshot*> ExceptionSnapshotLinux::ExtraMemory() const { … }
}
}