blob: 1d409728657e45e64f50ca9de95c9c983fc046dc [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 ARM64 architecture:
//
// Information was obtained from the ArmĀ® Architecture Reference Manual Armv8, for Armv8-A
// architecture profile:
//
// https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile
//
// In order to obtain information about the registers below, the easiest way to do it is to do
// search (ctrl-f) in the browser and the hit will probably will a link that you can press into
// the corresponding definition (eg. search for "dbgwcr" and then click on the link).
//
// See zircon/system/public/hw/debug/arm64.h for more detailed information.
//
// Hardware Breakpoints
// -------------------------------------------------------------------------------------------------
//
// 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.
// ARMv8 assures at least 2 hardware breakpoints.
//
// DBGBVR<n>: HW Breakpoint Value Register.
//
// This register defines the value of the hw breakpoint <n> within the system. How that value is
// interpreted depends on the correspondent value of DBGBCR<n>.
//
// DBGBCR<n>: HW Breakpoint Control Register.
//
// Control register for HW breakpoints. There is one for each HW breakpoint present within the
// system. They go numbering by DBGBCR0, DBGBCR1, ... until the value defined in ID_AADFR0_EL1.
//
// For each control register, there is an equivalent DBGBVR<n> that holds the address the thread
// will compare against.
//
// The only register bit that needs to be set by the user is E (Bit 1). The other bits are opaque
// and should be handled by the kernel.
//
// Watchpoints
// -------------------------------------------------------------------------------------------------
//
// Watchpoints permits to stop a thread when it read/writes to a particular address in memory.
// This will work even if the address is read-only memory (for a read, of course).
// ARMv8 assures at least 2 watchpoints.
//
// DBGWVR<n>: Watchpoint Value Register.
//
// This register defines the value of the watchpoint <n> within the system. How that value is
// interpreted depends on the correspondent value of DBGWCR<n>.
//
// DBGWCR<n>: Watchpoint Control Register.
//
// Control register for watchpoints. There is one for each watchpoint present within the system.
// They go numbering by DBGWCR0, DBGWCR1, ... until the value defined ID_AAFR0_EL1.
// For each control register, there is an equivalent DBGWCR<n> that holds the address the thread
// will compare against. How this address is interpreted depends upon the configuration of the
// associated control register.
//
// The following are the bits that are most important,
//
// - E (Bit 1): Defines whether the watchpoint is enabled or not.
//
// - LSC (bits 3-4): Defines how the watchpoint works:
// 01: Read from address.
// 10: Write to address.
// 11: Read/Write to address.
//
// - BAS (Bits 5-12): Defines which bytes are to be "matched" starting from the one defined in the
// value register. Each bit defines what bytes to match onto:
//
// 0bxxxx'xxx1: Match DBGWVR<n> + 0
// 0bxxxx'xx1x: Match DBGWVR<n> + 1
// 0bxxxx'x1xx: Match DBGWVR<n> + 2
// 0bxxxx'1xxx: Match DBGWVR<n> + 3
// 0bxxx1'xxxx: Match DBGWVR<n> + 4
// 0bxx1x'xxxx: Match DBGWVR<n> + 5
// 0bx1xx'xxxx: Match DBGWVR<n> + 6
// 0b1xxx'xxxx: Match DBGWVR<n> + 7
//
// These bits must be set contiguosly (there cannot be gaps between the first
// set bit and the last). Having DBGWVR not be 4-bytes aligned is deprecated.
namespace debug_agent {
namespace arch {
// "BRK 0" instruction.
// - Low 5 bits = 0.
// - High 11 bits = 11010100001
// - In between 16 bits is the argument to the BRK instruction (in this case zero).
const BreakInstructionType kBreakInstruction = 0xd4200000;
// ARM reports the exception for the exception instruction itself.
const int64_t kExceptionOffsetForSoftwareBreakpoint = 0;
::debug::Arch GetCurrentArch() { return ::debug::Arch::kArm64; }
bool IsBreakpointInstruction(BreakInstructionType instruction) {
// The BRK instruction could have any number associated with it, even though we only write "BRK
// 0", so check for the low 5 and high 11 bytes as described above.
constexpr BreakInstructionType kMask = 0b11111111111000000000000000011111;
return (instruction & kMask) == kBreakInstruction;
}
uint64_t BreakpointInstructionForHardwareExceptionAddress(uint64_t exception_addr) {
// arm64 will return the address of the instruction *about* to be executed.
return exception_addr;
}
} // namespace arch
} // namespace debug_agent