123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- // Copyright 2017 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/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()
- : ExceptionSnapshot(),
- context_union_(),
- context_(),
- codes_(),
- thread_id_(0),
- exception_address_(0),
- signal_number_(0),
- signal_code_(0),
- initialized_() {}
- ExceptionSnapshotLinux::~ExceptionSnapshotLinux() {}
- #if defined(ARCH_CPU_X86_FAMILY)
- template <>
- bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
- ProcessReaderLinux* reader,
- LinuxVMAddress context_address) {
- UContext<ContextTraits32> ucontext;
- if (!reader->Memory()->Read(context_address, sizeof(ucontext), &ucontext)) {
- LOG(ERROR) << "Couldn't read ucontext";
- return false;
- }
- context_.architecture = kCPUArchitectureX86;
- context_.x86 = &context_union_.x86;
- if (!ucontext.mcontext.fpptr) {
- InitializeCPUContextX86_NoFloatingPoint(ucontext.mcontext.gprs,
- context_.x86);
- return true;
- }
- SignalFloatContext32 fprs;
- if (!reader->Memory()->Read(ucontext.mcontext.fpptr, sizeof(fprs), &fprs)) {
- LOG(ERROR) << "Couldn't read float context";
- return false;
- }
- if (fprs.magic == X86_FXSR_MAGIC) {
- InitializeCPUContextX86_NoFloatingPoint(ucontext.mcontext.gprs,
- context_.x86);
- if (!reader->Memory()->Read(
- ucontext.mcontext.fpptr + offsetof(SignalFloatContext32, fxsave),
- sizeof(CPUContextX86::Fxsave),
- &context_.x86->fxsave)) {
- LOG(ERROR) << "Couldn't read fxsave";
- return false;
- }
- } else if (fprs.magic == 0xffff) {
- InitializeCPUContextX86(ucontext.mcontext.gprs, fprs, context_.x86);
- } else {
- LOG(ERROR) << "unexpected magic 0x" << std::hex << fprs.magic;
- return false;
- }
- return true;
- }
- template <>
- bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
- ProcessReaderLinux* reader,
- LinuxVMAddress context_address) {
- UContext<ContextTraits64> ucontext;
- if (!reader->Memory()->Read(context_address, sizeof(ucontext), &ucontext)) {
- LOG(ERROR) << "Couldn't read ucontext";
- return false;
- }
- context_.architecture = kCPUArchitectureX86_64;
- context_.x86_64 = &context_union_.x86_64;
- if (!ucontext.mcontext.fpptr) {
- InitializeCPUContextX86_64_NoFloatingPoint(ucontext.mcontext.gprs,
- context_.x86_64);
- return true;
- }
- SignalFloatContext64 fprs;
- if (!reader->Memory()->Read(ucontext.mcontext.fpptr, sizeof(fprs), &fprs)) {
- LOG(ERROR) << "Couldn't read float context";
- return false;
- }
- InitializeCPUContextX86_64(ucontext.mcontext.gprs, fprs, context_.x86_64);
- return true;
- }
- #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_RISCV_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;
- }
- InitializeCPUContextRISCV<Traits>(thread_context, fp_context, dest_context);
- return true;
- }
- template <>
- bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
- ProcessReaderLinux* reader,
- LinuxVMAddress context_address) {
- context_.architecture = kCPUArchitectureRISCV;
- context_.riscv = &context_union_.riscv;
- return internal::ReadContext<ContextTraits32>(
- reader, context_address, context_.riscv);
- }
- template <>
- bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
- ProcessReaderLinux* reader,
- LinuxVMAddress context_address) {
- context_.architecture = kCPUArchitectureRISCV64;
- context_.riscv64 = &context_union_.riscv64;
- return internal::ReadContext<ContextTraits64>(
- reader, context_address, context_.riscv64);
- }
- #endif // ARCH_CPU_X86_FAMILY
- bool ExceptionSnapshotLinux::Initialize(
- ProcessReaderLinux* process_reader,
- LinuxVMAddress siginfo_address,
- LinuxVMAddress context_address,
- pid_t thread_id,
- uint32_t* gather_indirectly_referenced_memory_cap) {
- INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
- thread_id_ = thread_id;
- const ProcessReaderLinux::Thread* thread = nullptr;
- for (const auto& loop_thread : process_reader->Threads()) {
- if (thread_id == loop_thread.tid) {
- thread = &loop_thread;
- break;
- }
- }
- if (!thread) {
- // This is allowed until {ProcessReaderLinux::InitializeThreads()} is
- // improved to support target threads in the same thread group.
- LOG(WARNING) << "thread ID " << thread_id << " not found in process";
- }
- if (process_reader->Is64Bit()) {
- if (!ReadContext<ContextTraits64>(process_reader, context_address) ||
- !ReadSiginfo<Traits64>(process_reader, siginfo_address)) {
- return false;
- }
- } else {
- if (!ReadContext<ContextTraits32>(process_reader, context_address) ||
- !ReadSiginfo<Traits32>(process_reader, siginfo_address)) {
- return false;
- }
- }
- CaptureMemoryDelegateLinux capture_memory_delegate(
- process_reader,
- thread,
- &extra_memory_,
- gather_indirectly_referenced_memory_cap);
- CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
- INITIALIZATION_STATE_SET_VALID(initialized_);
- return true;
- }
- template <typename Traits>
- bool ExceptionSnapshotLinux::ReadSiginfo(ProcessReaderLinux* reader,
- LinuxVMAddress siginfo_address) {
- Siginfo<Traits> siginfo;
- if (!reader->Memory()->Read(siginfo_address, sizeof(siginfo), &siginfo)) {
- LOG(ERROR) << "Couldn't read siginfo";
- return false;
- }
- signal_number_ = siginfo.signo;
- signal_code_ = siginfo.code;
- uint64_t extra_code;
- #define PUSH_CODE(value) \
- do { \
- if (!ReinterpretBytes(value, &extra_code)) { \
- LOG(ERROR) << "bad code"; \
- return false; \
- } \
- codes_.push_back(extra_code); \
- } while (false)
- switch (siginfo.signo) {
- case SIGILL:
- case SIGFPE:
- case SIGSEGV:
- case SIGBUS:
- case SIGTRAP:
- exception_address_ = siginfo.address;
- break;
- case SIGPOLL: // SIGIO
- PUSH_CODE(siginfo.band);
- PUSH_CODE(siginfo.fd);
- break;
- case SIGSYS:
- exception_address_ = siginfo.call_address;
- PUSH_CODE(siginfo.syscall);
- PUSH_CODE(siginfo.arch);
- break;
- case SIGALRM:
- case SIGVTALRM:
- case SIGPROF:
- PUSH_CODE(siginfo.timerid);
- PUSH_CODE(siginfo.overrun);
- PUSH_CODE(siginfo.sigval.sigval);
- break;
- case SIGABRT:
- case SIGQUIT:
- case SIGXCPU:
- case SIGXFSZ:
- case SIGHUP:
- case SIGINT:
- case SIGPIPE:
- case SIGTERM:
- case SIGUSR1:
- case SIGUSR2:
- #if defined(SIGEMT)
- case SIGEMT:
- #endif // SIGEMT
- #if defined(SIGPWR)
- case SIGPWR:
- #endif // SIGPWR
- #if defined(SIGSTKFLT)
- case SIGSTKFLT:
- #endif // SIGSTKFLT
- PUSH_CODE(siginfo.pid);
- PUSH_CODE(siginfo.uid);
- PUSH_CODE(siginfo.sigval.sigval);
- break;
- case Signals::kSimulatedSigno:
- break;
- default:
- LOG(WARNING) << "Unhandled signal " << siginfo.signo;
- }
- return true;
- }
- const CPUContext* ExceptionSnapshotLinux::Context() const {
- INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return &context_;
- }
- uint64_t ExceptionSnapshotLinux::ThreadID() const {
- INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return thread_id_;
- }
- uint32_t ExceptionSnapshotLinux::Exception() const {
- INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return signal_number_;
- }
- uint32_t ExceptionSnapshotLinux::ExceptionInfo() const {
- INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return signal_code_;
- }
- uint64_t ExceptionSnapshotLinux::ExceptionAddress() const {
- INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return exception_address_;
- }
- const std::vector<uint64_t>& ExceptionSnapshotLinux::Codes() const {
- INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return codes_;
- }
- std::vector<const MemorySnapshot*> ExceptionSnapshotLinux::ExtraMemory() const {
- INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- std::vector<const MemorySnapshot*> result;
- result.reserve(extra_memory_.size());
- for (const auto& em : extra_memory_) {
- result.push_back(em.get());
- }
- return result;
- }
- } // namespace internal
- } // namespace crashpad
|