| // 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" |
| #include "src/developer/debug/shared/register_info.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; |
| |
| // The size of the breakpoint instruction. In theory it could be different from |
| // sizeof(BreakInstructionType) but in practice they are the same for all architectures. |
| constexpr size_t kBreakInstructionSize = sizeof(BreakInstructionType); |
| |
| // Distance offset from a software breakpoint instruction that the exception will be reported as |
| // thrown 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::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::RegisterValue>& out); |
| |
| // The registers in the given category are appended to the given output vector. |
| zx_status_t ReadRegisters(const zx::thread& thread, const debug::RegisterCategory& cat, |
| std::vector<debug::RegisterValue>& out); |
| |
| // The registers must all be in the same category. |
| zx_status_t WriteRegisters(zx::thread& thread, const debug::RegisterCategory& cat, |
| const std::vector<debug::RegisterValue>& 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::RegisterValue>& updates, |
| zx_thread_state_general_regs_t* regs); |
| zx_status_t WriteFloatingPointRegisters(const std::vector<debug::RegisterValue>& update, |
| zx_thread_state_fp_regs_t* regs); |
| zx_status_t WriteVectorRegisters(const std::vector<debug::RegisterValue>& update, |
| zx_thread_state_vector_regs_t* regs); |
| zx_status_t WriteDebugRegisters(const std::vector<debug::RegisterValue>& 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::RegisterValue& 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 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_ |