delve/pkg/proc/native/register_linux_386.go
Alessandro Arzilli 200994bc8f
proc/*: only load floating point registers when needed (#1981)
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
2020-05-13 11:56:50 -07:00

90 lines
2.3 KiB
Go

package native
import (
"fmt"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
)
// SetPC sets EIP 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.I386Registers)
r.Regs.Eip = int32(pc)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return err
}
// SetSP sets ESP 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.I386Registers)
r.Regs.Esp = int32(sp)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return
}
func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
if err != nil {
return err
}
r := ir.(*linutil.I386Registers)
r.Regs.Edx = int32(dx)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return
}
func registers(thread *nativeThread) (proc.Registers, error) {
var (
regs linutil.I386PtraceRegs
err error
)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(thread.ID, (*sys.PtraceRegs)(&regs)) })
if err != nil {
return nil, err
}
r := linutil.NewI386Registers(&regs, func(r *linutil.I386Registers) error {
var fpregset linutil.I386Xstate
var floatLoadError error
r.Fpregs, fpregset, floatLoadError = thread.fpRegisters()
r.Fpregset = &fpregset
return floatLoadError
})
thread.dbp.execPtraceFunc(func() {
tls, _ := ptraceGetTls(regs.Xgs, thread.ThreadID())
r.Tls = uint64(tls)
})
return r, nil
}
const (
_X86_XSTATE_MAX_SIZE = 2688
_NT_X86_XSTATE = 0x202
_XSAVE_HEADER_START = 512
_XSAVE_HEADER_LEN = 64
_XSAVE_EXTENDED_REGION_START = 576
_XSAVE_SSE_REGION_LEN = 416
)
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs linutil.I386Xstate, err error) {
thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
regs = fpregs.Decode()
if err != nil {
err = fmt.Errorf("could not get floating point registers: %v", err.Error())
}
return
}