mirror of
https://github.com/go-delve/delve.git
synced 2025-11-03 13:57:33 +08:00
Some hw breakpoint fixes
Enable usage of dr1-dr3. Clear control bits when a breakpoint is disabled. Use DR_LEN_1 instead of DR_LEN_8 so breakpoint work on unaligned adresses. Fixes #51.
This commit is contained in:
@ -17,6 +17,7 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Represents a single breakpoint. Stores information on the break
|
// Represents a single breakpoint. Stores information on the break
|
||||||
@ -50,6 +51,15 @@ func PtracePokeUser(tid int, off, addr uintptr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PtracePeekUser(tid int, off uintptr) (uintptr, error) {
|
||||||
|
var x uintptr // XXX: this should not be necessary
|
||||||
|
ret, _, err := syscall.Syscall6(syscall.SYS_PTRACE, syscall.PTRACE_PEEKUSR, uintptr(tid), uintptr(off), uintptr(unsafe.Pointer(&x)), 0, 0)
|
||||||
|
if err != syscall.Errno(0) {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (dbp *DebuggedProcess) BreakpointExists(addr uint64) bool {
|
func (dbp *DebuggedProcess) BreakpointExists(addr uint64) bool {
|
||||||
for _, bp := range dbp.HWBreakPoints {
|
for _, bp := range dbp.HWBreakPoints {
|
||||||
if bp != nil && bp.Addr == addr {
|
if bp != nil && bp.Addr == addr {
|
||||||
@ -133,24 +143,49 @@ func (dbp *DebuggedProcess) newBreakpoint(fn, f string, l int, addr uint64, data
|
|||||||
// that we want to break at. There are only 4 debug registers
|
// that we want to break at. There are only 4 debug registers
|
||||||
// DR0-DR3. Debug register 7 is the control register.
|
// DR0-DR3. Debug register 7 is the control register.
|
||||||
func setHardwareBreakpoint(reg, tid int, addr uint64) error {
|
func setHardwareBreakpoint(reg, tid int, addr uint64) error {
|
||||||
if reg < 0 || reg > 7 {
|
if reg < 0 || reg > 3 {
|
||||||
return fmt.Errorf("invalid register value")
|
return fmt.Errorf("invalid register value")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
off = uintptr(C.offset(C.int(reg)))
|
dr7off = uintptr(C.offset(C.DR_CONTROL))
|
||||||
dr7 = uintptr(0x1 | C.DR_RW_EXECUTE | C.DR_LEN_8)
|
drxoff = uintptr(C.offset(C.int(reg)))
|
||||||
dr7addr = uintptr(C.offset(C.DR_CONTROL))
|
drxmask = uintptr((((1 << C.DR_CONTROL_SIZE) - 1) << uintptr(reg*C.DR_CONTROL_SIZE)) | (((1 << C.DR_ENABLE_SIZE) - 1) << uintptr(reg*C.DR_ENABLE_SIZE)))
|
||||||
|
drxenable = uintptr(0x1) << uintptr(reg*C.DR_ENABLE_SIZE)
|
||||||
|
drxctl = uintptr(C.DR_RW_EXECUTE|C.DR_LEN_1) << uintptr(reg*C.DR_CONTROL_SIZE)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Get current state
|
||||||
|
dr7, err := PtracePeekUser(tid, dr7off)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If addr == 0 we are expected to disable the breakpoint
|
||||||
|
if addr == 0 {
|
||||||
|
dr7 &= ^drxmask
|
||||||
|
return PtracePokeUser(tid, dr7off, dr7)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error out if dr`reg` is already used
|
||||||
|
if dr7&(0x3<<uint(reg*C.DR_ENABLE_SIZE)) != 0 {
|
||||||
|
return fmt.Errorf("dr%d already enabled", reg)
|
||||||
|
}
|
||||||
|
|
||||||
// Set the debug register `reg` with the address of the
|
// Set the debug register `reg` with the address of the
|
||||||
// instruction we want to trigger a debug exception.
|
// instruction we want to trigger a debug exception.
|
||||||
if err := PtracePokeUser(tid, off, uintptr(addr)); err != nil {
|
if err := PtracePokeUser(tid, drxoff, uintptr(addr)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear dr`reg` flags
|
||||||
|
dr7 &= ^drxmask
|
||||||
|
// Enable dr`reg`
|
||||||
|
dr7 |= (drxctl<<C.DR_CONTROL_SHIFT) | drxenable
|
||||||
|
|
||||||
// Set the debug control register. This
|
// Set the debug control register. This
|
||||||
// instructs the cpu to raise a debug
|
// instructs the cpu to raise a debug
|
||||||
// exception when hitting the address of
|
// exception when hitting the address of
|
||||||
// an instruction stored in dr0-dr3.
|
// an instruction stored in dr0-dr3.
|
||||||
return PtracePokeUser(tid, dr7addr, dr7)
|
return PtracePokeUser(tid, dr7off, dr7)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user