
Right now, if (*compositeMemory).WriteMemory needs to write a value to a register that's smaller than the full size of the register (say, a uint32 being passed as an argument), then (*AMD64Registers).SetReg can later fail a sanity check that ensures the passed DwarfRegister is a full size register. Fix this by reading the old value of the register and overwriting just the relevant parts with the new register. For the purposes of an argument, it would probably be fine to just pad with zeroes, but merging with the existing value is what gdb does. Fixes #2698
184 lines
4.4 KiB
Go
184 lines
4.4 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
|
|
ChangeFunc RegisterChangeFunc
|
|
|
|
FloatLoadError error // error produced when loading floating point registers
|
|
loadMoreCallback func()
|
|
}
|
|
|
|
type DwarfRegister struct {
|
|
Uint64Val uint64
|
|
Bytes []byte
|
|
}
|
|
|
|
type RegisterChangeFunc func(regNum uint64, reg *DwarfRegister) error
|
|
|
|
// 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}
|
|
}
|
|
|
|
// FillBytes fills the Bytes slice of reg using Uint64Val.
|
|
func (reg *DwarfRegister) FillBytes() {
|
|
if reg.Bytes != nil {
|
|
return
|
|
}
|
|
reg.Bytes = make([]byte, 8)
|
|
binary.LittleEndian.PutUint64(reg.Bytes, reg.Uint64Val)
|
|
}
|
|
|
|
// Overwrite takes the contents of reg1 and overwrites them with the contents
|
|
// of reg2 in little-endian order, returning a new register. The new register
|
|
// will always contain the complete contents of both registers, so if reg2 is
|
|
// larger than reg1, the final register will be reg2's size.
|
|
func (reg1 *DwarfRegister) Overwrite(reg2 *DwarfRegister) *DwarfRegister {
|
|
reg1.FillBytes()
|
|
reg2.FillBytes()
|
|
width := len(reg1.Bytes)
|
|
if len(reg2.Bytes) > len(reg1.Bytes) {
|
|
width = len(reg2.Bytes)
|
|
}
|
|
b := make([]byte, width)
|
|
copy(b, reg1.Bytes)
|
|
copy(b, reg2.Bytes)
|
|
return DwarfRegisterFromBytes(b)
|
|
}
|