
Changes implementations of proc.Registers interface and the op.DwarfRegisters struct so that floating point registers can be loaded only when they are needed. Removes the floatingPoint parameter from proc.Thread.Registers. This accomplishes three things: 1. it simplifies the proc.Thread.Registers interface 2. it makes it impossible to accidentally create a broken set of saved registers or of op.DwarfRegisters by accidentally calling Registers(false) 3. it improves general performance of Delve by avoiding to load floating point registers as much as possible Floating point registers are loaded under two circumstances: 1. When the Slice method is called with floatingPoint == true 2. When the Copy method is called Benchmark before: BenchmarkConditionalBreakpoints-4 1 4327350142 ns/op Benchmark after: BenchmarkConditionalBreakpoints-4 1 3852642917 ns/op Updates #1549
102 lines
2.7 KiB
Go
102 lines
2.7 KiB
Go
package native
|
|
|
|
import (
|
|
"debug/elf"
|
|
"fmt"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
sys "golang.org/x/sys/unix"
|
|
|
|
"github.com/go-delve/delve/pkg/proc"
|
|
"github.com/go-delve/delve/pkg/proc/linutil"
|
|
)
|
|
|
|
const (
|
|
_AARCH64_GREGS_SIZE = 34 * 8
|
|
_AARCH64_FPREGS_SIZE = 32*16 + 8
|
|
)
|
|
|
|
func ptraceGetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
|
|
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _AARCH64_GREGS_SIZE}
|
|
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
|
if err == syscall.Errno(0) {
|
|
err = nil
|
|
}
|
|
return
|
|
}
|
|
|
|
func ptraceSetGRegs(pid int, regs *linutil.ARM64PtraceRegs) (err error) {
|
|
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _AARCH64_GREGS_SIZE}
|
|
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
|
if err == syscall.Errno(0) {
|
|
err = nil
|
|
}
|
|
return
|
|
}
|
|
|
|
// ptraceGetFpRegset returns floating point registers of the specified thread
|
|
// using PTRACE.
|
|
func ptraceGetFpRegset(tid int) (fpregset []byte, err error) {
|
|
var arm64_fpregs [_AARCH64_FPREGS_SIZE]byte
|
|
iov := sys.Iovec{Base: &arm64_fpregs[0], Len: _AARCH64_FPREGS_SIZE}
|
|
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
|
if err != syscall.Errno(0) {
|
|
if err == syscall.ENODEV {
|
|
err = nil
|
|
}
|
|
return
|
|
} else {
|
|
err = nil
|
|
}
|
|
|
|
fpregset = arm64_fpregs[:iov.Len-8]
|
|
return fpregset, err
|
|
}
|
|
|
|
// SetPC sets PC to the value specified by 'pc'.
|
|
func (thread *nativeThread) SetPC(pc uint64) error {
|
|
ir, err := registers(thread)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r := ir.(*linutil.ARM64Registers)
|
|
r.Regs.Pc = pc
|
|
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
|
|
return err
|
|
}
|
|
|
|
// SetSP sets RSP to the value specified by 'sp'
|
|
func (thread *nativeThread) SetSP(sp uint64) (err error) {
|
|
var ir proc.Registers
|
|
ir, err = registers(thread)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r := ir.(*linutil.ARM64Registers)
|
|
r.Regs.Sp = sp
|
|
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
|
|
return
|
|
}
|
|
|
|
func (thread *nativeThread) SetDX(dx uint64) (err error) {
|
|
return fmt.Errorf("not supported")
|
|
}
|
|
|
|
func registers(thread *nativeThread) (proc.Registers, error) {
|
|
var (
|
|
regs linutil.ARM64PtraceRegs
|
|
err error
|
|
)
|
|
thread.dbp.execPtraceFunc(func() { err = ptraceGetGRegs(thread.ID, ®s) })
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r := linutil.NewARM64Registers(®s, func(r *linutil.ARM64Registers) error {
|
|
var floatLoadError error
|
|
r.Fpregs, r.Fpregset, floatLoadError = thread.fpRegisters()
|
|
return floatLoadError
|
|
})
|
|
return r, nil
|
|
}
|