| // 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. | |
| #include "src/developer/debug/debug_agent/arch.h" | |
| // Notes on x64 architecture: | |
| // | |
| // Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B, 3C & 3D): | |
| // Chapter 17 holds the debug spefications: | |
| // https://software.intel.com/sites/default/files/managed/a4/60/325383-sdm-vol-2abcd.pdf | |
| // | |
| // Hardware Breakpoints/Watchpoints | |
| // ------------------------------------------------------------------------------------------------- | |
| // | |
| // Hardware breakpoints permits to stop a thread when it accesses an address setup in one of the | |
| // hw breakpoints registers. They will work independent whether the address in question is | |
| // read-only or not. | |
| // | |
| // Watchpoints are meant to throw an exception whenever the given address is read or written to, | |
| // depending on the configuration. | |
| // | |
| // DR0 to DR4 registers: There registers are the address to which the hw breakpoint/watchpoint | |
| // refers to. How it is interpreted depends on the associated configuration on the register DR7. | |
| // | |
| // DR6: Debug Status Register. | |
| // | |
| // This register is updated when the CPU encounters a #DB harware exception. This registers permits | |
| // users to interpret the result of an exception, such as if it was a single-step, hardware | |
| // breakpoint, etc. | |
| // | |
| // zircon/system/public/zircon/hw/debug/x86.h holds a good description of what each bit within the | |
| // register means. | |
| // | |
| // DR7: Debug Control Register. | |
| // | |
| // This register is used to establish the breakpoint conditions for the address breakpoint registers | |
| // (DR0-DR3) and to enable debug exceptions for each of them individually. | |
| // | |
| // The following fields are accepted by the user. All other fields are ignored (masked): | |
| // | |
| // - L0, L1, L2, L3: These defines whether breakpoint/watchpoint <n> is enabled or not. | |
| // | |
| // - LEN0, LEN1, LEN2, LEN3: Defines the "length" of the breakpoint/watchpoint. | |
| // 00: 1 byte. | |
| // 01: 2 byte. DRn must be 2 byte aligned. | |
| // 10: 8 byte. DRn must be 8 byte aligned. | |
| // 11: 4 byte. DRn must be 4 byte aligned. | |
| // p | |
| // - RW0, RW1, RW2, RW3: The "mode" of the registers. | |
| // 00: Only instruction execution (hw breakpoint). | |
| // 01: Only data write (write watchpoint). | |
| // 10: Dependant by CR4.DE. Not supported by Zircon. | |
| // - CR4.DE = 0: Undefined. | |
| // - CR4.DE = 1: Only on I/0 read/write. | |
| // 11: Only on data read/write (read/write watchpoint). | |
| namespace debug_agent { | |
| namespace arch { | |
| const BreakInstructionType kBreakInstruction = 0xCC; | |
| // An X86 exception is 1 byte and a breakpoint exception is triggered with RIP pointing to the | |
| // following instruction. | |
| const int64_t kExceptionOffsetForSoftwareBreakpoint = 1; | |
| ::debug::Arch GetCurrentArch() { return ::debug::Arch::kX64; } | |
| bool IsBreakpointInstruction(BreakInstructionType instruction) { | |
| // This handles the normal encoding of debug breakpoints (0xCC). It's also possible to cause an | |
| // interrupt 3 to happen using the opcode sequence 0xCD 0x03 but this has slightly different | |
| // semantics and no assemblers emit this. We can't easily check for that here since the | |
| // computation for the instruction address that is passed in assumes a 1-byte instruction. It | |
| // should be OK to ignore this case in practice. | |
| return instruction == kBreakInstruction; | |
| } | |
| uint64_t BreakpointInstructionForHardwareExceptionAddress(uint64_t exception_addr) { | |
| // x86 returns the instruction *about* to be executed when hitting the hw breakpoint. | |
| return exception_addr; | |
| } | |
| } // namespace arch | |
| } // namespace debug_agent |