github.com/undoio/delve@v1.9.0/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  }