gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/amd64util/debugregs.go (about) 1 package amd64util 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 // DebugRegisters represents x86 debug registers described in the Intel 64 9 // and IA-32 Architectures Software Developer's Manual, Vol. 3B, section 10 // 17.2 11 type DebugRegisters struct { 12 pAddrs [4]*uint64 13 pDR6, pDR7 *uint64 14 Dirty bool 15 } 16 17 func NewDebugRegisters(pDR0, pDR1, pDR2, pDR3, pDR6, pDR7 *uint64) *DebugRegisters { 18 return &DebugRegisters{ 19 pAddrs: [4]*uint64{pDR0, pDR1, pDR2, pDR3}, 20 pDR6: pDR6, 21 pDR7: pDR7, 22 Dirty: false, 23 } 24 } 25 26 func lenrwBitsOffset(idx uint8) uint8 { 27 return 16 + idx*4 28 } 29 30 func enableBitOffset(idx uint8) uint8 { 31 return idx * 2 32 } 33 34 func (drs *DebugRegisters) breakpoint(idx uint8) (addr uint64, read, write bool, sz int) { 35 enable := *(drs.pDR7) & (1 << enableBitOffset(idx)) 36 if enable == 0 { 37 return 0, false, false, 0 38 } 39 40 addr = *(drs.pAddrs[idx]) 41 lenrw := (*(drs.pDR7) >> lenrwBitsOffset(idx)) & 0xf 42 write = (lenrw & 0x1) != 0 43 read = (lenrw & 0x2) != 0 44 switch lenrw >> 2 { 45 case 0x0: 46 sz = 1 47 case 0x1: 48 sz = 2 49 case 0x2: 50 sz = 8 // sic 51 case 0x3: 52 sz = 4 53 } 54 return addr, read, write, sz 55 } 56 57 // SetBreakpoint sets hardware breakpoint at index 'idx' to the specified 58 // address, read/write flags and size. 59 // If the breakpoint is already in use but the parameters match it does 60 // nothing. 61 func (drs *DebugRegisters) SetBreakpoint(idx uint8, addr uint64, read, write bool, sz int) error { 62 if int(idx) >= len(drs.pAddrs) { 63 return fmt.Errorf("hardware breakpoints exhausted") 64 } 65 curaddr, curread, curwrite, cursz := drs.breakpoint(idx) 66 if curaddr != 0 { 67 if (curaddr != addr) || (curread != read) || (curwrite != write) || (cursz != sz) { 68 return fmt.Errorf("hardware breakpoint %d already in use (address %#x)", idx, curaddr) 69 } 70 // hardware breakpoint already set 71 return nil 72 } 73 74 if read && !write { 75 return errors.New("break on read only not supported") 76 } 77 78 *(drs.pAddrs[idx]) = addr 79 var lenrw uint64 80 if write { 81 lenrw |= 0x1 82 } 83 if read { 84 lenrw |= 0x2 85 } 86 switch sz { 87 case 1: 88 // already ok 89 case 2: 90 lenrw |= 0x1 << 2 91 case 4: 92 lenrw |= 0x3 << 2 93 case 8: 94 lenrw |= 0x2 << 2 95 default: 96 return fmt.Errorf("data breakpoint of size %d not supported", sz) 97 } 98 *(drs.pDR7) &^= (0xf << lenrwBitsOffset(idx)) // clear old settings 99 *(drs.pDR7) |= lenrw << lenrwBitsOffset(idx) 100 *(drs.pDR7) |= 1 << enableBitOffset(idx) // enable 101 drs.Dirty = true 102 return nil 103 } 104 105 // ClearBreakpoint disables the hardware breakpoint at index 'idx'. If the 106 // breakpoint was already disabled it does nothing. 107 func (drs *DebugRegisters) ClearBreakpoint(idx uint8) { 108 if *(drs.pDR7)&(1<<enableBitOffset(idx)) == 0 { 109 return 110 } 111 *(drs.pDR7) &^= (1 << enableBitOffset(idx)) 112 drs.Dirty = true 113 } 114 115 // GetActiveBreakpoint returns the active hardware breakpoint and resets the 116 // condition flags. 117 func (drs *DebugRegisters) GetActiveBreakpoint() (ok bool, idx uint8) { 118 for idx := uint8(0); idx < 3; idx++ { 119 enable := *(drs.pDR7) & (1 << enableBitOffset(idx)) 120 if enable == 0 { 121 continue 122 } 123 if *(drs.pDR6)&(1<<idx) != 0 { 124 *drs.pDR6 &^= 0xf // it is our responsibility to clear the condition bits 125 drs.Dirty = true 126 return true, idx 127 } 128 } 129 return false, 0 130 }