delve/pkg/dwarf/op/regs.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

155 lines
3.5 KiB
Go

package op
import (
"bytes"
"encoding/binary"
)
// DwarfRegisters holds the value of stack program registers.
type DwarfRegisters struct {
StaticBase uint64
CFA int64
FrameBase int64
ObjBase int64
regs []*DwarfRegister
ByteOrder binary.ByteOrder
PCRegNum uint64
SPRegNum uint64
BPRegNum uint64
LRRegNum uint64
FloatLoadError error // error produced when loading floating point registers
loadMoreCallback func()
}
type DwarfRegister struct {
Uint64Val uint64
Bytes []byte
}
// NewDwarfRegisters returns a new DwarfRegisters object.
func NewDwarfRegisters(staticBase uint64, regs []*DwarfRegister, byteOrder binary.ByteOrder, pcRegNum, spRegNum, bpRegNum, lrRegNum uint64) *DwarfRegisters {
return &DwarfRegisters{
StaticBase: staticBase,
regs: regs,
ByteOrder: byteOrder,
PCRegNum: pcRegNum,
SPRegNum: spRegNum,
BPRegNum: bpRegNum,
LRRegNum: lrRegNum,
}
}
// SetLoadMoreCallback sets a callback function that will be called the
// first time the user of regs tries to access an undefined register.
func (regs *DwarfRegisters) SetLoadMoreCallback(fn func()) {
regs.loadMoreCallback = fn
}
// CurrentSize returns the current number of known registers. This number might be
// wrong if loadMoreCallback has been set.
func (regs *DwarfRegisters) CurrentSize() int {
return len(regs.regs)
}
// Uint64Val returns the uint64 value of register idx.
func (regs *DwarfRegisters) Uint64Val(idx uint64) uint64 {
reg := regs.Reg(idx)
if reg == nil {
return 0
}
return regs.regs[idx].Uint64Val
}
// Bytes returns the bytes value of register idx, nil if the register is not
// defined.
func (regs *DwarfRegisters) Bytes(idx uint64) []byte {
reg := regs.Reg(idx)
if reg == nil {
return nil
}
if reg.Bytes == nil {
var buf bytes.Buffer
binary.Write(&buf, regs.ByteOrder, reg.Uint64Val)
reg.Bytes = buf.Bytes()
}
return reg.Bytes
}
func (regs *DwarfRegisters) loadMore() {
if regs.loadMoreCallback == nil {
return
}
regs.loadMoreCallback()
regs.loadMoreCallback = nil
}
// Reg returns register idx or nil if the register is not defined.
func (regs *DwarfRegisters) Reg(idx uint64) *DwarfRegister {
if idx >= uint64(len(regs.regs)) {
regs.loadMore()
if idx >= uint64(len(regs.regs)) {
return nil
}
}
if regs.regs[idx] == nil {
regs.loadMore()
}
return regs.regs[idx]
}
func (regs *DwarfRegisters) PC() uint64 {
return regs.Uint64Val(regs.PCRegNum)
}
func (regs *DwarfRegisters) SP() uint64 {
return regs.Uint64Val(regs.SPRegNum)
}
func (regs *DwarfRegisters) BP() uint64 {
return regs.Uint64Val(regs.BPRegNum)
}
// AddReg adds register idx to regs.
func (regs *DwarfRegisters) AddReg(idx uint64, reg *DwarfRegister) {
if idx >= uint64(len(regs.regs)) {
newRegs := make([]*DwarfRegister, idx+1)
copy(newRegs, regs.regs)
regs.regs = newRegs
}
regs.regs[idx] = reg
}
// ClearRegisters clears all registers.
func (regs *DwarfRegisters) ClearRegisters() {
regs.loadMoreCallback = nil
for regnum := range regs.regs {
regs.regs[regnum] = nil
}
}
func DwarfRegisterFromUint64(v uint64) *DwarfRegister {
return &DwarfRegister{Uint64Val: v}
}
func DwarfRegisterFromBytes(bytes []byte) *DwarfRegister {
var v uint64
switch len(bytes) {
case 1:
v = uint64(bytes[0])
case 2:
x := binary.LittleEndian.Uint16(bytes)
v = uint64(x)
case 4:
x := binary.LittleEndian.Uint32(bytes)
v = uint64(x)
default:
if len(bytes) >= 8 {
v = binary.LittleEndian.Uint64(bytes[:8])
}
}
return &DwarfRegister{Uint64Val: v, Bytes: bytes}
}