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

     1  package native
     2  
     3  import (
     4  	"debug/elf"
     5  	"syscall"
     6  	"unsafe"
     7  
     8  	sys "golang.org/x/sys/unix"
     9  
    10  	"github.com/undoio/delve/pkg/dwarf/op"
    11  	"github.com/undoio/delve/pkg/proc"
    12  	"github.com/undoio/delve/pkg/proc/linutil"
    13  )
    14  
    15  const (
    16  	_AARCH64_GREGS_SIZE  = 34 * 8
    17  	_AARCH64_FPREGS_SIZE = 32*16 + 8
    18  	_NT_ARM_TLS          = 0x401 // used in PTRACE_GETREGSET on ARM64 to retrieve the value of TPIDR_EL0, see source/include/uapi/linux/elf.h and source/arch/arm64/kernel/ptrace.c
    19  )
    20  
    21  func ptraceGetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
    22  	iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _AARCH64_GREGS_SIZE}
    23  	_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
    24  	if err == syscall.Errno(0) {
    25  		err = nil
    26  	}
    27  	return
    28  }
    29  
    30  func ptraceGetTpidr_el0(pid int, tpidr_el0 *uint64) (err error) {
    31  	iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(tpidr_el0)), Len: uint64(unsafe.Sizeof(*tpidr_el0))}
    32  	_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid), uintptr(_NT_ARM_TLS), uintptr(unsafe.Pointer(&iov)), 0, 0)
    33  	if err == syscall.Errno(0) {
    34  		err = nil
    35  	}
    36  	return
    37  }
    38  
    39  func ptraceSetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
    40  	iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _AARCH64_GREGS_SIZE}
    41  	_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
    42  	if err == syscall.Errno(0) {
    43  		err = nil
    44  	}
    45  	return
    46  }
    47  
    48  // ptraceGetFpRegset returns floating point registers of the specified thread
    49  // using PTRACE.
    50  func ptraceGetFpRegset(tid int) (fpregset []byte, err error) {
    51  	var arm64_fpregs [_AARCH64_FPREGS_SIZE]byte
    52  	iov := sys.Iovec{Base: &arm64_fpregs[0], Len: _AARCH64_FPREGS_SIZE}
    53  	_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
    54  	if err != syscall.Errno(0) {
    55  		if err == syscall.ENODEV {
    56  			err = nil
    57  		}
    58  		return
    59  	} else {
    60  		err = nil
    61  	}
    62  
    63  	fpregset = arm64_fpregs[:iov.Len-8]
    64  	return fpregset, err
    65  }
    66  
    67  // setPC sets PC to the value specified by 'pc'.
    68  func (thread *nativeThread) setPC(pc uint64) error {
    69  	ir, err := registers(thread)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	r := ir.(*linutil.ARM64Registers)
    74  	r.Regs.Pc = pc
    75  	thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
    76  	return err
    77  }
    78  
    79  func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
    80  	ir, err := registers(thread)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	r := ir.(*linutil.ARM64Registers)
    85  	fpchanged, err := r.SetReg(regNum, reg)
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	thread.dbp.execPtraceFunc(func() {
    91  		err = ptraceSetGRegs(thread.ID, r.Regs)
    92  		if err != syscall.Errno(0) && err != nil {
    93  			return
    94  		}
    95  		if fpchanged && r.Fpregset != nil {
    96  			iov := sys.Iovec{Base: &r.Fpregset[0], Len: uint64(len(r.Fpregset))}
    97  			_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(thread.ID), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
    98  		}
    99  	})
   100  	if err == syscall.Errno(0) {
   101  		err = nil
   102  	}
   103  	return err
   104  }
   105  
   106  func registers(thread *nativeThread) (proc.Registers, error) {
   107  	var (
   108  		regs linutil.ARM64PtraceRegs
   109  		err  error
   110  	)
   111  	thread.dbp.execPtraceFunc(func() { err = ptraceGetGRegs(thread.ID, &regs) })
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	var tpidr_el0 uint64
   116  	if thread.dbp.iscgo {
   117  		thread.dbp.execPtraceFunc(func() { err = ptraceGetTpidr_el0(thread.ID, &tpidr_el0) })
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  	}
   122  	r := linutil.NewARM64Registers(&regs, thread.dbp.iscgo, tpidr_el0, func(r *linutil.ARM64Registers) error {
   123  		var floatLoadError error
   124  		r.Fpregs, r.Fpregset, floatLoadError = thread.fpRegisters()
   125  		return floatLoadError
   126  	})
   127  	return r, nil
   128  }