blob: ae5e196e1ffcc748f5400845d5bfd7058f83906e [file] [log] [blame]
// 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