| // Copyright 2018 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef SRC_DEVELOPER_DEBUG_DEBUG_AGENT_ARCH_H_ | |
| #define SRC_DEVELOPER_DEBUG_DEBUG_AGENT_ARCH_H_ | |
| #include <lib/zx/process.h> | |
| #include <lib/zx/thread.h> | |
| #include <zircon/syscalls/debug.h> | |
| #include <zircon/syscalls/exception.h> | |
| #include "src/developer/debug/debug_agent/arch_types.h" | |
| #include "src/developer/debug/ipc/protocol.h" | |
| namespace debug_agent { | |
| class DebuggedThread; | |
| class ThreadHandle; | |
| namespace arch { | |
| // This file contains architecture-specific low-level helper functions. It is like zircon_utils but | |
| // the functions will have different implementations depending on CPU architecture. | |
| // | |
| // The functions here should be very low-level and are designed for the real (*_zircon.cc) | |
| // implementations of the the various primitives. Cross-platform code should use interfaces like | |
| // ThreadHandle for anything that might need mocking out. | |
| // Our canonical breakpoint instruction for the current architecture. This is what we'll write for | |
| // software breakpoints. Some platforms may have alternate encodings for software breakpoints, so to | |
| // check if something is a breakpoint instruction, use arch::IsBreakpointInstruction() rather than | |
| // checking for equality with this value. | |
| extern const BreakInstructionType kBreakInstruction; | |
| // Distance offset from a software breakpoint instruction that the exception will be reported as | |
| // thron at. Architectures differ about what address is reported for a software breakpoint | |
| // exception. | |
| // | |
| // * To convert from a software breakpoint address to the exception address, add this. | |
| // * To convert from an exception address to the breakpoint instruction address, subtract this. | |
| extern const int64_t kExceptionOffsetForSoftwareBreakpoint; | |
| debug_ipc::Arch GetCurrentArch(); | |
| // Returns the number of hardware breakpoints and watchpoints on the current system. | |
| uint32_t GetHardwareBreakpointCount(); | |
| uint32_t GetHardwareWatchpointCount(); | |
| // Converts the given register structure to a vector of debug_ipc registers. | |
| void SaveGeneralRegs(const zx_thread_state_general_regs& input, | |
| std::vector<debug_ipc::Register>& out); | |
| // The registers in the given category are appended to the given output vector. | |
| zx_status_t ReadRegisters(const zx::thread& thread, const debug_ipc::RegisterCategory& cat, | |
| std::vector<debug_ipc::Register>& out); | |
| // The registers must all be in the same category. | |
| zx_status_t WriteRegisters(zx::thread& thread, const debug_ipc::RegisterCategory& cat, | |
| const std::vector<debug_ipc::Register>& registers); | |
| // Given the current register value in |regs|, applies to it the new updated values for the | |
| // registers listed in |updates|. | |
| zx_status_t WriteGeneralRegisters(const std::vector<debug_ipc::Register>& updates, | |
| zx_thread_state_general_regs_t* regs); | |
| zx_status_t WriteFloatingPointRegisters(const std::vector<debug_ipc::Register>& update, | |
| zx_thread_state_fp_regs_t* regs); | |
| zx_status_t WriteVectorRegisters(const std::vector<debug_ipc::Register>& update, | |
| zx_thread_state_vector_regs_t* regs); | |
| zx_status_t WriteDebugRegisters(const std::vector<debug_ipc::Register>& update, | |
| zx_thread_state_debug_regs_t* regs); | |
| // Writes the register data to the given output variable, checking that the register data is | |
| // the same size as the output. | |
| template <typename RegType> | |
| zx_status_t WriteRegisterValue(const debug_ipc::Register& reg, RegType* dest) { | |
| if (reg.data.size() != sizeof(RegType)) | |
| return ZX_ERR_INVALID_ARGS; | |
| memcpy(dest, reg.data.data(), sizeof(RegType)); | |
| return ZX_OK; | |
| } | |
| // Converts a Zircon exception type to a debug_ipc one. Some exception types require querying the | |
| // thread's debug registers. If needed, the given thread will be used for that. | |
| debug_ipc::ExceptionType DecodeExceptionType(const zx::thread& thread, uint32_t exception_type); | |
| // Converts an architecture-specific exception record to a cross-platform one. | |
| debug_ipc::ExceptionRecord FillExceptionRecord(const zx_exception_report_t& in); | |
| // Returns the instruction following the one causing the given software exception. | |
| uint64_t NextInstructionForSoftwareExceptionAddress(uint64_t exception_addr); | |
| // Returns true if the given opcode is a breakpoint instruction. This checked for equality with | |
| // kBreakInstruction and also checks other possible breakpoint encodings for the current platform. | |
| bool IsBreakpointInstruction(BreakInstructionType instruction); | |
| // Returns the address of the instruction that hit the exception from the address reported by the | |
| // exception. | |
| uint64_t BreakpointInstructionForHardwareExceptionAddress(uint64_t exception_addr); | |
| } // namespace arch | |
| } // namespace debug_agent | |
| #endif // SRC_DEVELOPER_DEBUG_DEBUG_AGENT_ARCH_H_ |