
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
155 lines
3.5 KiB
Go
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}
|
|
}
|