// Copyright 2018 The Crashpad Authors // // 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/fuchsia/exception_snapshot_fuchsia.h" #include "base/numerics/safe_conversions.h" #include "snapshot/fuchsia/cpu_context_fuchsia.h" #include "snapshot/fuchsia/process_reader_fuchsia.h" namespace crashpad { namespace internal { ExceptionSnapshotFuchsia::ExceptionSnapshotFuchsia() = default; ExceptionSnapshotFuchsia::~ExceptionSnapshotFuchsia() = default; bool ExceptionSnapshotFuchsia::Initialize( ProcessReaderFuchsia* process_reader, zx_koid_t thread_id, const zx_exception_report_t& exception_report) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); exception_ = exception_report.header.type; thread_id_ = thread_id; // TODO(scottmg): Not sure whether these values for exception_info_ are // helpful or correct. Other values in the structures are stored below into // Codes() in case they are useful. #if defined(ARCH_CPU_X86_64) DCHECK(base::IsValueInRangeForNumericType( exception_report.context.arch.u.x86_64.err_code)); exception_info_ = exception_report.context.arch.u.x86_64.err_code; #elif defined(ARCH_CPU_ARM64) exception_info_ = exception_report.context.arch.u.arm_64.esr; #elif defined(ARCH_CPU_RISCV64) exception_info_ = exception_report.context.arch.u.riscv_64.cause; #endif codes_.push_back(exception_); codes_.push_back(exception_info_); #if defined(ARCH_CPU_X86_64) codes_.push_back(exception_report.context.arch.u.x86_64.vector); codes_.push_back(exception_report.context.arch.u.x86_64.cr2); #elif defined(ARCH_CPU_ARM64) codes_.push_back(exception_report.context.arch.u.arm_64.far); #elif defined(ARCH_CPU_RISCV64) codes_.push_back(exception_report.context.arch.u.riscv_64.tval); #endif const auto threads = process_reader->Threads(); const auto& t = std::find_if(threads.begin(), threads.end(), [thread_id](const ProcessReaderFuchsia::Thread& thread) { return thread.id == thread_id; }); if (t == threads.end()) { // If no threads have been read, then context_ can't be initalized, and the // exception snapshot can't be considered initialized_. return false; } #if defined(ARCH_CPU_X86_64) context_.architecture = kCPUArchitectureX86_64; context_.x86_64 = &context_arch_; // TODO(fxbug.dev/5496): Add vector context. InitializeCPUContextX86_64( t->general_registers, t->fp_registers, context_.x86_64); #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_arch_; InitializeCPUContextARM64( t->general_registers, t->vector_registers, context_.arm64); #elif defined(ARCH_CPU_RISCV64) context_.architecture = kCPUArchitectureRISCV64; context_.riscv64 = &context_arch_; InitializeCPUContextRISCV64( t->general_registers, t->fp_registers, context_.riscv64); #else #error Port. #endif if (context_.InstructionPointer() != 0 && (exception_ == ZX_EXCP_UNDEFINED_INSTRUCTION || exception_ == ZX_EXCP_SW_BREAKPOINT || exception_ == ZX_EXCP_HW_BREAKPOINT)) { exception_address_ = context_.InstructionPointer(); } else { #if defined(ARCH_CPU_X86_64) exception_address_ = exception_report.context.arch.u.x86_64.cr2; #elif defined(ARCH_CPU_ARM64) exception_address_ = exception_report.context.arch.u.arm_64.far; #elif defined(ARCH_CPU_RISCV64) exception_address_ = exception_report.context.arch.u.riscv_64.tval; #else #error Port. #endif } INITIALIZATION_STATE_SET_VALID(initialized_); return true; } const CPUContext* ExceptionSnapshotFuchsia::Context() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return &context_; } uint64_t ExceptionSnapshotFuchsia::ThreadID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return thread_id_; } uint32_t ExceptionSnapshotFuchsia::Exception() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return exception_; } uint32_t ExceptionSnapshotFuchsia::ExceptionInfo() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return exception_info_; } uint64_t ExceptionSnapshotFuchsia::ExceptionAddress() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return exception_address_; } const std::vector& ExceptionSnapshotFuchsia::Codes() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return codes_; } std::vector ExceptionSnapshotFuchsia::ExtraMemory() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return std::vector(); } } // namespace internal } // namespace crashpad