github.com/undoio/delve@v1.9.0/pkg/proc/native/threads_linux_amd64.go (about)

     1  package native
     2  
     3  import (
     4  	"syscall"
     5  	"unsafe"
     6  
     7  	sys "golang.org/x/sys/unix"
     8  
     9  	"github.com/undoio/delve/pkg/proc"
    10  	"github.com/undoio/delve/pkg/proc/amd64util"
    11  	"github.com/undoio/delve/pkg/proc/linutil"
    12  )
    13  
    14  func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
    15  	sr := savedRegs.(*linutil.AMD64Registers)
    16  
    17  	var restoreRegistersErr error
    18  	t.dbp.execPtraceFunc(func() {
    19  		oldRegs := (*sys.PtraceRegs)(sr.Regs)
    20  
    21  		var currentRegs sys.PtraceRegs
    22  		restoreRegistersErr = sys.PtraceGetRegs(t.ID, &currentRegs)
    23  		if restoreRegistersErr != nil {
    24  			return
    25  		}
    26  		// restoreRegisters is only supposed to restore CPU registers, not FS_BASE and GS_BASE
    27  		oldRegs.Fs_base = currentRegs.Fs_base
    28  		oldRegs.Gs_base = currentRegs.Gs_base
    29  
    30  		restoreRegistersErr = sys.PtraceSetRegs(t.ID, oldRegs)
    31  
    32  		if restoreRegistersErr != nil {
    33  			return
    34  		}
    35  		if sr.Fpregset.Xsave != nil {
    36  			iov := sys.Iovec{Base: &sr.Fpregset.Xsave[0], Len: uint64(len(sr.Fpregset.Xsave))}
    37  			_, _, restoreRegistersErr = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(t.ID), _NT_X86_XSTATE, uintptr(unsafe.Pointer(&iov)), 0, 0)
    38  			return
    39  		}
    40  
    41  		_, _, restoreRegistersErr = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETFPREGS, uintptr(t.ID), uintptr(0), uintptr(unsafe.Pointer(&sr.Fpregset.AMD64PtraceFpRegs)), 0, 0)
    42  	})
    43  	if restoreRegistersErr == syscall.Errno(0) {
    44  		restoreRegistersErr = nil
    45  	}
    46  	return restoreRegistersErr
    47  }
    48  
    49  const debugRegUserOffset = 848 // offset of debug registers in the user struct, see source/arch/x86/kernel/ptrace.c
    50  
    51  func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error {
    52  	var err error
    53  	t.dbp.execPtraceFunc(func() {
    54  		debugregs := make([]uint64, 8)
    55  
    56  		for i := range debugregs {
    57  			if i == 4 || i == 5 {
    58  				continue
    59  			}
    60  			_, _, err = sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_PEEKUSR, uintptr(t.ID), uintptr(debugRegUserOffset+uintptr(i)*unsafe.Sizeof(debugregs[0])), uintptr(unsafe.Pointer(&debugregs[i])), 0, 0)
    61  			if err != nil && err != syscall.Errno(0) {
    62  				return
    63  			}
    64  		}
    65  
    66  		drs := amd64util.NewDebugRegisters(&debugregs[0], &debugregs[1], &debugregs[2], &debugregs[3], &debugregs[6], &debugregs[7])
    67  
    68  		err = f(drs)
    69  
    70  		if drs.Dirty {
    71  			for i := range debugregs {
    72  				if i == 4 || i == 5 {
    73  					// Linux will return EIO for DR4 and DR5
    74  					continue
    75  				}
    76  				_, _, err = sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_POKEUSR, uintptr(t.ID), uintptr(debugRegUserOffset+uintptr(i)*unsafe.Sizeof(debugregs[0])), uintptr(debugregs[i]), 0, 0)
    77  				if err != nil && err != syscall.Errno(0) {
    78  					return
    79  				}
    80  			}
    81  		}
    82  	})
    83  	if err == syscall.Errno(0) || err == sys.ESRCH {
    84  		err = nil
    85  	}
    86  	return err
    87  }