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
This commit is contained in:
Alessandro Arzilli 2020-05-13 20:56:50 +02:00 committed by GitHub
parent f96663a243
commit 200994bc8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 364 additions and 250 deletions

@ -12,13 +12,16 @@ type DwarfRegisters struct {
CFA int64 CFA int64
FrameBase int64 FrameBase int64
ObjBase int64 ObjBase int64
Regs []*DwarfRegister regs []*DwarfRegister
ByteOrder binary.ByteOrder ByteOrder binary.ByteOrder
PCRegNum uint64 PCRegNum uint64
SPRegNum uint64 SPRegNum uint64
BPRegNum uint64 BPRegNum uint64
LRRegNum uint64 LRRegNum uint64
FloatLoadError error // error produced when loading floating point registers
loadMoreCallback func()
} }
type DwarfRegister struct { type DwarfRegister struct {
@ -26,13 +29,38 @@ type DwarfRegister struct {
Bytes []byte 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. // Uint64Val returns the uint64 value of register idx.
func (regs *DwarfRegisters) Uint64Val(idx uint64) uint64 { func (regs *DwarfRegisters) Uint64Val(idx uint64) uint64 {
reg := regs.Reg(idx) reg := regs.Reg(idx)
if reg == nil { if reg == nil {
return 0 return 0
} }
return regs.Regs[idx].Uint64Val return regs.regs[idx].Uint64Val
} }
// Bytes returns the bytes value of register idx, nil if the register is not // Bytes returns the bytes value of register idx, nil if the register is not
@ -50,12 +78,26 @@ func (regs *DwarfRegisters) Bytes(idx uint64) []byte {
return reg.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. // Reg returns register idx or nil if the register is not defined.
func (regs *DwarfRegisters) Reg(idx uint64) *DwarfRegister { func (regs *DwarfRegisters) Reg(idx uint64) *DwarfRegister {
if idx >= uint64(len(regs.Regs)) { if idx >= uint64(len(regs.regs)) {
return nil regs.loadMore()
if idx >= uint64(len(regs.regs)) {
return nil
}
} }
return regs.Regs[idx] if regs.regs[idx] == nil {
regs.loadMore()
}
return regs.regs[idx]
} }
func (regs *DwarfRegisters) PC() uint64 { func (regs *DwarfRegisters) PC() uint64 {
@ -72,12 +114,20 @@ func (regs *DwarfRegisters) BP() uint64 {
// AddReg adds register idx to regs. // AddReg adds register idx to regs.
func (regs *DwarfRegisters) AddReg(idx uint64, reg *DwarfRegister) { func (regs *DwarfRegisters) AddReg(idx uint64, reg *DwarfRegister) {
if idx >= uint64(len(regs.Regs)) { if idx >= uint64(len(regs.regs)) {
newRegs := make([]*DwarfRegister, idx+1) newRegs := make([]*DwarfRegister, idx+1)
copy(newRegs, regs.Regs) copy(newRegs, regs.regs)
regs.Regs = newRegs 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
} }
regs.Regs[idx] = reg
} }
func DwarfRegisterFromUint64(v uint64) *DwarfRegister { func DwarfRegisterFromUint64(v uint64) *DwarfRegister {

@ -345,21 +345,32 @@ func maxAmd64DwarfRegister() int {
} }
func amd64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters { func amd64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1) dregs := initDwarfRegistersFromSlice(maxAmd64DwarfRegister(), regs, amd64NameToDwarf)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, amd64DwarfIPRegNum, amd64DwarfSPRegNum, amd64DwarfBPRegNum, 0)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, amd64NameToDwarf))
return *dr
}
for _, reg := range regs.Slice(true) { func initDwarfRegistersFromSlice(maxRegs int, regs Registers, nameToDwarf map[string]int) []*op.DwarfRegister {
if dwarfReg, ok := amd64NameToDwarf[strings.ToLower(reg.Name)]; ok { dregs := make([]*op.DwarfRegister, maxRegs+1)
regslice, _ := regs.Slice(false)
for _, reg := range regslice {
if dwarfReg, ok := nameToDwarf[strings.ToLower(reg.Name)]; ok {
dregs[dwarfReg] = reg.Reg dregs[dwarfReg] = reg.Reg
} }
} }
return dregs
}
return op.DwarfRegisters{ func loadMoreDwarfRegistersFromSliceFunc(dr *op.DwarfRegisters, regs Registers, nameToDwarf map[string]int) func() {
StaticBase: staticBase, return func() {
Regs: dregs, regslice, err := regs.Slice(true)
ByteOrder: binary.LittleEndian, dr.FloatLoadError = err
PCRegNum: amd64DwarfIPRegNum, for _, reg := range regslice {
SPRegNum: amd64DwarfSPRegNum, if dwarfReg, ok := nameToDwarf[strings.ToLower(reg.Name)]; ok {
BPRegNum: amd64DwarfBPRegNum, dr.AddReg(uint64(dwarfReg), reg.Reg)
}
}
} }
} }
@ -369,14 +380,7 @@ func amd64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp) dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp) dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
return op.DwarfRegisters{ return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, amd64DwarfIPRegNum, amd64DwarfSPRegNum, amd64DwarfBPRegNum, 0)
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: amd64DwarfIPRegNum,
SPRegNum: amd64DwarfSPRegNum,
BPRegNum: amd64DwarfBPRegNum,
}
} }
func amd64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) { func amd64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {

@ -312,6 +312,20 @@ var arm64DwarfToHardware = map[int]arm64asm.Reg{
95: arm64asm.V31, 95: arm64asm.V31,
} }
var arm64NameToDwarf = func() map[string]int {
r := make(map[string]int)
for i := 0; i <= 30; i++ {
r[fmt.Sprintf("x%d", i)] = i
}
r["pc"] = int(arm64DwarfIPRegNum)
r["lr"] = int(arm64DwarfLRRegNum)
r["sp"] = 31
for i := 0; i <= 31; i++ {
r[fmt.Sprintf("v%d", i)] = i + 64
}
return r
}()
func maxArm64DwarfRegister() int { func maxArm64DwarfRegister() int {
max := int(arm64DwarfIPRegNum) max := int(arm64DwarfIPRegNum)
for i := range arm64DwarfToHardware { for i := range arm64DwarfToHardware {
@ -339,15 +353,9 @@ func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfR
} }
} }
return op.DwarfRegisters{ dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, arm64DwarfIPRegNum, arm64DwarfSPRegNum, arm64DwarfBPRegNum, arm64DwarfLRRegNum)
StaticBase: staticBase, dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, arm64NameToDwarf))
Regs: dregs, return *dr
ByteOrder: binary.LittleEndian,
PCRegNum: arm64DwarfIPRegNum,
SPRegNum: arm64DwarfSPRegNum,
BPRegNum: arm64DwarfBPRegNum,
LRRegNum: arm64DwarfLRRegNum,
}
} }
func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters { func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
@ -357,15 +365,7 @@ func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op
dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp) dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
dregs[arm64DwarfLRRegNum] = op.DwarfRegisterFromUint64(lr) dregs[arm64DwarfLRRegNum] = op.DwarfRegisterFromUint64(lr)
return op.DwarfRegisters{ return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, arm64DwarfIPRegNum, arm64DwarfSPRegNum, arm64DwarfBPRegNum, arm64DwarfLRRegNum)
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: arm64DwarfIPRegNum,
SPRegNum: arm64DwarfSPRegNum,
BPRegNum: arm64DwarfBPRegNum,
LRRegNum: arm64DwarfLRRegNum,
}
} }
func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) { func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {

@ -170,7 +170,7 @@ type thread struct {
} }
type osThread interface { type osThread interface {
registers(floatingPoint bool) (proc.Registers, error) registers() (proc.Registers, error)
pid() int pid() int
} }
@ -281,7 +281,7 @@ func (t *thread) WriteMemory(addr uintptr, data []byte) (int, error) {
// Location returns the location of this thread based on // Location returns the location of this thread based on
// the value of the instruction pointer register. // the value of the instruction pointer register.
func (t *thread) Location() (*proc.Location, error) { func (t *thread) Location() (*proc.Location, error) {
regs, err := t.th.registers(false) regs, err := t.th.registers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -303,8 +303,8 @@ func (t *thread) ThreadID() int {
} }
// Registers returns the current value of the registers for this thread. // Registers returns the current value of the registers for this thread.
func (t *thread) Registers(floatingPoint bool) (proc.Registers, error) { func (t *thread) Registers() (proc.Registers, error) {
return t.th.registers(floatingPoint) return t.th.registers()
} }
// RestoreRegisters will only return an error for core files, // RestoreRegisters will only return an error for core files,

@ -187,7 +187,9 @@ func withCoreFile(t *testing.T, name, args string) *proc.Target {
func logRegisters(t *testing.T, regs proc.Registers, arch *proc.Arch) { func logRegisters(t *testing.T, regs proc.Registers, arch *proc.Arch) {
dregs := arch.RegistersToDwarfRegisters(0, regs) dregs := arch.RegistersToDwarfRegisters(0, regs)
for i, reg := range dregs.Regs { dregs.Reg(^uint64(0))
for i := 0; i < dregs.CurrentSize(); i++ {
reg := dregs.Reg(uint64(i))
if reg == nil { if reg == nil {
continue continue
} }
@ -250,7 +252,7 @@ func TestCore(t *testing.T) {
t.Errorf("main.msg = %q, want %q", msg.Value, "BOOM!") t.Errorf("main.msg = %q, want %q", msg.Value, "BOOM!")
} }
regs, err := p.CurrentThread().Registers(true) regs, err := p.CurrentThread().Registers()
if err != nil { if err != nil {
t.Fatalf("Couldn't get current thread registers: %v", err) t.Fatalf("Couldn't get current thread registers: %v", err)
} }
@ -286,7 +288,7 @@ func TestCoreFpRegisters(t *testing.T) {
continue continue
} }
if frames[i].Current.Fn.Name == "main.main" { if frames[i].Current.Fn.Name == "main.main" {
regs, err = thread.Registers(true) regs, err = thread.Registers()
if err != nil { if err != nil {
t.Fatalf("Could not get registers for thread %x, %v", thread.ThreadID(), err) t.Fatalf("Could not get registers for thread %x, %v", thread.ThreadID(), err)
} }
@ -326,7 +328,9 @@ func TestCoreFpRegisters(t *testing.T) {
for _, regtest := range regtests { for _, regtest := range regtests {
found := false found := false
for i, reg := range dregs.Regs { dregs.Reg(^uint64(0))
for i := 0; i < dregs.CurrentSize(); i++ {
reg := dregs.Reg(uint64(i))
regname, _, regval := arch.DwarfRegisterToString(i, reg) regname, _, regval := arch.DwarfRegisterToString(i, reg)
if reg != nil && regname == regtest.name { if reg != nil && regname == regtest.name {
found = true found = true

@ -154,21 +154,17 @@ type linuxARM64Thread struct {
t *linuxPrStatusARM64 t *linuxPrStatusARM64
} }
func (t *linuxAMD64Thread) registers(floatingPoint bool) (proc.Registers, error) { func (t *linuxAMD64Thread) registers() (proc.Registers, error) {
var r linutil.AMD64Registers var r linutil.AMD64Registers
r.Regs = t.regs.Regs r.Regs = t.regs.Regs
if floatingPoint { r.Fpregs = t.regs.Fpregs
r.Fpregs = t.regs.Fpregs
}
return &r, nil return &r, nil
} }
func (t *linuxARM64Thread) registers(floatingPoint bool) (proc.Registers, error) { func (t *linuxARM64Thread) registers() (proc.Registers, error) {
var r linutil.ARM64Registers var r linutil.ARM64Registers
r.Regs = t.regs.Regs r.Regs = t.regs.Regs
if floatingPoint { r.Fpregs = t.regs.Fpregs
r.Fpregs = t.regs.Fpregs
}
return &r, nil return &r, nil
} }

@ -54,6 +54,6 @@ func (th *windowsAMD64Thread) pid() int {
return int(th.th.ID) return int(th.th.ID)
} }
func (th *windowsAMD64Thread) registers(floatingPoint bool) (proc.Registers, error) { func (th *windowsAMD64Thread) registers() (proc.Registers, error) {
return winutil.NewAMD64Registers(&th.th.Context, th.th.TEB, floatingPoint), nil return winutil.NewAMD64Registers(&th.th.Context, th.th.TEB), nil
} }

@ -232,7 +232,7 @@ func TestDwarfExprLoclist(t *testing.T) {
uintExprCheck(t, scope, "a", before) uintExprCheck(t, scope, "a", before)
scope.PC = 0x40800 scope.PC = 0x40800
scope.Regs.Regs[scope.Regs.PCRegNum].Uint64Val = scope.PC scope.Regs.Reg(scope.Regs.PCRegNum).Uint64Val = scope.PC
uintExprCheck(t, scope, "a", after) uintExprCheck(t, scope, "a", after)
} }

@ -14,6 +14,12 @@ type AMD64Registers struct {
Fpregs []proc.Register Fpregs []proc.Register
Fpregset *AMD64Xstate Fpregset *AMD64Xstate
Fsbase uint64 Fsbase uint64
loadFpRegs func(*AMD64Registers) error
}
func NewAMD64Registers(regs *AMD64PtraceRegs, fsbase uint64, loadFpRegs func(*AMD64Registers) error) *AMD64Registers {
return &AMD64Registers{Regs: regs, Fsbase: fsbase, loadFpRegs: loadFpRegs}
} }
// AMD64PtraceRegs is the struct used by the freebsd kernel to return the // AMD64PtraceRegs is the struct used by the freebsd kernel to return the
@ -49,7 +55,7 @@ type AMD64PtraceRegs struct {
} }
// Slice returns the registers as a list of (name, value) pairs. // Slice returns the registers as a list of (name, value) pairs.
func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register { func (r *AMD64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs64 = []struct { var regs64 = []struct {
k string k string
v int64 v int64
@ -112,10 +118,15 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
// x86 called this register "Eflags". amd64 extended it and renamed it // x86 called this register "Eflags". amd64 extended it and renamed it
// "Rflags", but Linux still uses the old name. // "Rflags", but Linux still uses the old name.
out = proc.AppendUint64Register(out, "Rflags", uint64(r.Regs.Rflags)) out = proc.AppendUint64Register(out, "Rflags", uint64(r.Regs.Rflags))
var floatLoadError error
if floatingPoint { if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...) out = append(out, r.Fpregs...)
} }
return out return out, floatLoadError
} }
// PC returns the value of RIP register. // PC returns the value of RIP register.
@ -302,7 +313,14 @@ func (r *AMD64Registers) Get(n int) (uint64, error) {
} }
// Copy returns a copy of these registers that is guarenteed not to change. // Copy returns a copy of these registers that is guarenteed not to change.
func (r *AMD64Registers) Copy() proc.Registers { func (r *AMD64Registers) Copy() (proc.Registers, error) {
if r.loadFpRegs != nil {
err := r.loadFpRegs(r)
r.loadFpRegs = nil
if err != nil {
return nil, err
}
}
var rr AMD64Registers var rr AMD64Registers
rr.Regs = &AMD64PtraceRegs{} rr.Regs = &AMD64PtraceRegs{}
rr.Fpregset = &AMD64Xstate{} rr.Fpregset = &AMD64Xstate{}
@ -314,7 +332,7 @@ func (r *AMD64Registers) Copy() proc.Registers {
rr.Fpregs = make([]proc.Register, len(r.Fpregs)) rr.Fpregs = make([]proc.Register, len(r.Fpregs))
copy(rr.Fpregs, r.Fpregs) copy(rr.Fpregs, r.Fpregs)
} }
return &rr return &rr, nil
} }
type AMD64Xstate linutil.AMD64Xstate type AMD64Xstate linutil.AMD64Xstate

@ -252,11 +252,14 @@ func evalFunctionCall(scope *EvalScope, node *ast.CallExpr) (*Variable, error) {
} }
// check that there are at least 256 bytes free on the stack // check that there are at least 256 bytes free on the stack
regs, err := scope.g.Thread.Registers(true) regs, err := scope.g.Thread.Registers()
if err != nil {
return nil, err
}
regs, err = regs.Copy()
if err != nil { if err != nil {
return nil, err return nil, err
} }
regs = regs.Copy()
if regs.SP()-256 <= scope.g.stack.lo { if regs.SP()-256 <= scope.g.stack.lo {
return nil, errNotEnoughStack return nil, errNotEnoughStack
} }
@ -293,18 +296,13 @@ func evalFunctionCall(scope *EvalScope, node *ast.CallExpr) (*Variable, error) {
scope.g = scope.callCtx.doContinue() scope.g = scope.callCtx.doContinue()
// adjust the value of registers inside scope // adjust the value of registers inside scope
for regnum := range scope.Regs.Regs { pcreg, bpreg, spreg := scope.Regs.Reg(scope.Regs.PCRegNum), scope.Regs.Reg(scope.Regs.BPRegNum), scope.Regs.Reg(scope.Regs.SPRegNum)
switch uint64(regnum) { scope.Regs.ClearRegisters()
case scope.Regs.PCRegNum, scope.Regs.SPRegNum, scope.Regs.BPRegNum: scope.Regs.AddReg(scope.Regs.PCRegNum, pcreg)
// leave these alone scope.Regs.AddReg(scope.Regs.BPRegNum, bpreg)
default: scope.Regs.AddReg(scope.Regs.SPRegNum, spreg)
// every other register is dirty and unrecoverable scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(spoff + int64(scope.g.stack.hi))
scope.Regs.Regs[regnum] = nil scope.Regs.Reg(scope.Regs.BPRegNum).Uint64Val = uint64(bpoff + int64(scope.g.stack.hi))
}
}
scope.Regs.Regs[scope.Regs.SPRegNum].Uint64Val = uint64(spoff + int64(scope.g.stack.hi))
scope.Regs.Regs[scope.Regs.BPRegNum].Uint64Val = uint64(bpoff + int64(scope.g.stack.hi))
scope.Regs.FrameBase = fboff + int64(scope.g.stack.hi) scope.Regs.FrameBase = fboff + int64(scope.g.stack.hi)
scope.Regs.CFA = scope.frameOffset + int64(scope.g.stack.hi) scope.Regs.CFA = scope.frameOffset + int64(scope.g.stack.hi)
@ -655,12 +653,16 @@ func funcCallStep(callScope *EvalScope, fncall *functionCallState) bool {
bi := p.BinInfo() bi := p.BinInfo()
thread := callScope.g.Thread thread := callScope.g.Thread
regs, err := thread.Registers(false) regs, err := thread.Registers()
if err != nil {
fncall.err = err
return true
}
regs, err = regs.Copy()
if err != nil { if err != nil {
fncall.err = err fncall.err = err
return true return true
} }
regs = regs.Copy()
rax, _ := regs.Get(int(x86asm.RAX)) rax, _ := regs.Get(int(x86asm.RAX))
@ -823,7 +825,7 @@ func fakeFunctionEntryScope(scope *EvalScope, fn *Function, cfa int64, sp uint64
scope.File, scope.Line, _ = scope.BinInfo.PCToLine(fn.Entry) scope.File, scope.Line, _ = scope.BinInfo.PCToLine(fn.Entry)
scope.Regs.CFA = cfa scope.Regs.CFA = cfa
scope.Regs.Regs[scope.Regs.SPRegNum].Uint64Val = sp scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = sp
fn.cu.image.dwarfReader.Seek(fn.offset) fn.cu.image.dwarfReader.Seek(fn.offset)
e, err := fn.cu.image.dwarfReader.Next() e, err := fn.cu.image.dwarfReader.Next()

@ -1286,7 +1286,7 @@ func (t *gdbThread) WriteMemory(addr uintptr, data []byte) (written int, err err
// Location returns the current location of this thread. // Location returns the current location of this thread.
func (t *gdbThread) Location() (*proc.Location, error) { func (t *gdbThread) Location() (*proc.Location, error) {
regs, err := t.Registers(false) regs, err := t.Registers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1311,7 +1311,7 @@ func (t *gdbThread) ThreadID() int {
} }
// Registers returns the CPU registers for this thread. // Registers returns the CPU registers for this thread.
func (t *gdbThread) Registers(floatingPoint bool) (proc.Registers, error) { func (t *gdbThread) Registers() (proc.Registers, error) {
if t.regs.regs == nil { if t.regs.regs == nil {
if err := t.reloadRegisters(); err != nil { if err := t.reloadRegisters(); err != nil {
return nil, err return nil, err
@ -1358,7 +1358,7 @@ func (t *gdbThread) StepInstruction() error {
// Blocked returns true if the thread is blocked in runtime or kernel code. // Blocked returns true if the thread is blocked in runtime or kernel code.
func (t *gdbThread) Blocked() bool { func (t *gdbThread) Blocked() bool {
regs, err := t.Registers(false) regs, err := t.Registers()
if err != nil { if err != nil {
return false return false
} }
@ -1639,7 +1639,7 @@ func (t *gdbThread) SetCurrentBreakpoint(adjustPC bool) error {
// adjustPC is ignored, it is the stub's responsibiility to set the PC // adjustPC is ignored, it is the stub's responsibiility to set the PC
// address correctly after hitting a breakpoint. // address correctly after hitting a breakpoint.
t.clearBreakpointState() t.clearBreakpointState()
regs, err := t.Registers(false) regs, err := t.Registers()
if err != nil { if err != nil {
return err return err
} }
@ -1865,6 +1865,10 @@ func (regs *gdbRegisters) Get(n int) (uint64, error) {
return 0, proc.ErrUnknownRegister return 0, proc.ErrUnknownRegister
} }
func (r *gdbRegisters) FloatLoadError() error {
return nil
}
// SetPC will set the value of the PC register to the given value. // SetPC will set the value of the PC register to the given value.
func (t *gdbThread) SetPC(pc uint64) error { func (t *gdbThread) SetPC(pc uint64) error {
t.regs.setPC(pc) t.regs.setPC(pc)
@ -1895,7 +1899,7 @@ func (t *gdbThread) SetDX(dx uint64) error {
return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value) return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value)
} }
func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register { func (regs *gdbRegisters) Slice(floatingPoint bool) ([]proc.Register, error) {
r := make([]proc.Register, 0, len(regs.regsInfo)) r := make([]proc.Register, 0, len(regs.regsInfo))
for _, reginfo := range regs.regsInfo { for _, reginfo := range regs.regsInfo {
if reginfo.Group == "float" && !floatingPoint { if reginfo.Group == "float" && !floatingPoint {
@ -1941,12 +1945,12 @@ func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register {
r = proc.AppendBytesRegister(r, strings.ToUpper(reginfo.Name), value[16:]) r = proc.AppendBytesRegister(r, strings.ToUpper(reginfo.Name), value[16:])
} }
} }
return r return r, nil
} }
func (regs *gdbRegisters) Copy() proc.Registers { func (regs *gdbRegisters) Copy() (proc.Registers, error) {
savedRegs := &gdbRegisters{} savedRegs := &gdbRegisters{}
savedRegs.init(regs.regsInfo) savedRegs.init(regs.regsInfo)
copy(savedRegs.buf, regs.buf) copy(savedRegs.buf, regs.buf)
return savedRegs return savedRegs, nil
} }

@ -253,22 +253,11 @@ func maxI386DwarfRegister() int {
} }
func i386RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters { func i386RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxI386DwarfRegister()+1) dregs := initDwarfRegistersFromSlice(maxI386DwarfRegister(), regs, i386NameToDwarf)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, i386DwarfIPRegNum, i386DwarfSPRegNum, i386DwarfBPRegNum, 0)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, i386NameToDwarf))
for _, reg := range regs.Slice(true) { return *dr
if dwarfReg, ok := i386NameToDwarf[strings.ToLower(reg.Name)]; ok {
dregs[dwarfReg] = reg.Reg
}
}
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: i386DwarfIPRegNum,
SPRegNum: i386DwarfSPRegNum,
BPRegNum: i386DwarfBPRegNum,
}
} }
func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters { func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
@ -277,14 +266,7 @@ func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.
dregs[i386DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp) dregs[i386DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[i386DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp) dregs[i386DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
return op.DwarfRegisters{ return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, i386DwarfIPRegNum, i386DwarfSPRegNum, i386DwarfBPRegNum, 0)
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: i386DwarfIPRegNum,
SPRegNum: i386DwarfSPRegNum,
BPRegNum: i386DwarfBPRegNum,
}
} }
func i386DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) { func i386DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
@ -301,9 +283,9 @@ func i386DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string, float
return name, true, fmt.Sprintf("%#04x", reg.Uint64Val) return name, true, fmt.Sprintf("%#04x", reg.Uint64Val)
default: default:
if reg.Bytes != nil && strings.HasPrefix(name, "xmm") { if reg.Bytes != nil && strings.HasPrefix(n, "xmm") {
return name, true, formatSSEReg(reg.Bytes) return name, true, formatSSEReg(reg.Bytes)
} else if reg.Bytes != nil && strings.HasPrefix(name, "st(") { } else if reg.Bytes != nil && strings.HasPrefix(n, "st(") {
return name, true, formatX87Reg(reg.Bytes) return name, true, formatX87Reg(reg.Bytes)
} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) <= 8) { } else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) <= 8) {
return name, false, fmt.Sprintf("%#016x", reg.Uint64Val) return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)

@ -16,6 +16,12 @@ type AMD64Registers struct {
Regs *AMD64PtraceRegs Regs *AMD64PtraceRegs
Fpregs []proc.Register Fpregs []proc.Register
Fpregset *AMD64Xstate Fpregset *AMD64Xstate
loadFpRegs func(*AMD64Registers) error
}
func NewAMD64Registers(regs *AMD64PtraceRegs, loadFpRegs func(*AMD64Registers) error) *AMD64Registers {
return &AMD64Registers{Regs: regs, loadFpRegs: loadFpRegs}
} }
// AMD64PtraceRegs is the struct used by the linux kernel to return the // AMD64PtraceRegs is the struct used by the linux kernel to return the
@ -51,7 +57,7 @@ type AMD64PtraceRegs struct {
} }
// Slice returns the registers as a list of (name, value) pairs. // Slice returns the registers as a list of (name, value) pairs.
func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register { func (r *AMD64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs = []struct { var regs = []struct {
k string k string
v uint64 v uint64
@ -88,10 +94,15 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
for _, reg := range regs { for _, reg := range regs {
out = proc.AppendUint64Register(out, reg.k, reg.v) out = proc.AppendUint64Register(out, reg.k, reg.v)
} }
var floatLoadError error
if floatingPoint { if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...) out = append(out, r.Fpregs...)
} }
return out return out, floatLoadError
} }
// PC returns the value of RIP register. // PC returns the value of RIP register.
@ -278,7 +289,14 @@ func (r *AMD64Registers) Get(n int) (uint64, error) {
} }
// Copy returns a copy of these registers that is guarenteed not to change. // Copy returns a copy of these registers that is guarenteed not to change.
func (r *AMD64Registers) Copy() proc.Registers { func (r *AMD64Registers) Copy() (proc.Registers, error) {
if r.loadFpRegs != nil {
err := r.loadFpRegs(r)
r.loadFpRegs = nil
if err != nil {
return nil, err
}
}
var rr AMD64Registers var rr AMD64Registers
rr.Regs = &AMD64PtraceRegs{} rr.Regs = &AMD64PtraceRegs{}
rr.Fpregset = &AMD64Xstate{} rr.Fpregset = &AMD64Xstate{}
@ -290,7 +308,7 @@ func (r *AMD64Registers) Copy() proc.Registers {
rr.Fpregs = make([]proc.Register, len(r.Fpregs)) rr.Fpregs = make([]proc.Register, len(r.Fpregs))
copy(rr.Fpregs, r.Fpregs) copy(rr.Fpregs, r.Fpregs)
} }
return &rr return &rr, nil
} }
// AMD64PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h // AMD64PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h

@ -12,6 +12,12 @@ type ARM64Registers struct {
Regs *ARM64PtraceRegs //general-purpose registers Regs *ARM64PtraceRegs //general-purpose registers
Fpregs []proc.Register //Formatted floating point registers Fpregs []proc.Register //Formatted floating point registers
Fpregset []byte //holding all floating point register values Fpregset []byte //holding all floating point register values
loadFpRegs func(*ARM64Registers) error
}
func NewARM64Registers(regs *ARM64PtraceRegs, loadFpRegs func(*ARM64Registers) error) *ARM64Registers {
return &ARM64Registers{Regs: regs, loadFpRegs: loadFpRegs}
} }
// ARM64PtraceRegs is the struct used by the linux kernel to return the // ARM64PtraceRegs is the struct used by the linux kernel to return the
@ -25,7 +31,7 @@ type ARM64PtraceRegs struct {
} }
// Slice returns the registers as a list of (name, value) pairs. // Slice returns the registers as a list of (name, value) pairs.
func (r *ARM64Registers) Slice(floatingPoint bool) []proc.Register { func (r *ARM64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs64 = []struct { var regs64 = []struct {
k string k string
v uint64 v uint64
@ -69,8 +75,15 @@ func (r *ARM64Registers) Slice(floatingPoint bool) []proc.Register {
for _, reg := range regs64 { for _, reg := range regs64 {
out = proc.AppendUint64Register(out, reg.k, reg.v) out = proc.AppendUint64Register(out, reg.k, reg.v)
} }
out = append(out, r.Fpregs...) var floatLoadError error
return out if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...)
}
return out, floatLoadError
} }
// PC returns the value of RIP register. // PC returns the value of RIP register.
@ -110,7 +123,14 @@ func (r *ARM64Registers) Get(n int) (uint64, error) {
} }
// Copy returns a copy of these registers that is guarenteed not to change. // Copy returns a copy of these registers that is guarenteed not to change.
func (r *ARM64Registers) Copy() proc.Registers { func (r *ARM64Registers) Copy() (proc.Registers, error) {
if r.loadFpRegs != nil {
err := r.loadFpRegs(r)
r.loadFpRegs = nil
if err != nil {
return nil, err
}
}
var rr ARM64Registers var rr ARM64Registers
rr.Regs = &ARM64PtraceRegs{} rr.Regs = &ARM64PtraceRegs{}
*(rr.Regs) = *(r.Regs) *(rr.Regs) = *(r.Regs)
@ -122,7 +142,7 @@ func (r *ARM64Registers) Copy() proc.Registers {
rr.Fpregset = make([]byte, len(r.Fpregset)) rr.Fpregset = make([]byte, len(r.Fpregset))
copy(rr.Fpregset, r.Fpregset) copy(rr.Fpregset, r.Fpregset)
} }
return &rr return &rr, nil
} }
type ARM64PtraceFpRegs struct { type ARM64PtraceFpRegs struct {

@ -15,6 +15,12 @@ type I386Registers struct {
Fpregs []proc.Register Fpregs []proc.Register
Fpregset *I386Xstate Fpregset *I386Xstate
Tls uint64 Tls uint64
loadFpRegs func(*I386Registers) error
}
func NewI386Registers(regs *I386PtraceRegs, loadFpRegs func(*I386Registers) error) *I386Registers {
return &I386Registers{Regs: regs, Fpregs: nil, Fpregset: nil, Tls: 0, loadFpRegs: loadFpRegs}
} }
// I386PtraceRegs is the struct used by the linux kernel to return the // I386PtraceRegs is the struct used by the linux kernel to return the
@ -40,7 +46,7 @@ type I386PtraceRegs struct {
} }
// Slice returns the registers as a list of (name, value) pairs. // Slice returns the registers as a list of (name, value) pairs.
func (r *I386Registers) Slice(floatingPoint bool) []proc.Register { func (r *I386Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs = []struct { var regs = []struct {
k string k string
v int32 v int32
@ -67,10 +73,15 @@ func (r *I386Registers) Slice(floatingPoint bool) []proc.Register {
for _, reg := range regs { for _, reg := range regs {
out = proc.AppendUint64Register(out, reg.k, uint64(uint32(reg.v))) out = proc.AppendUint64Register(out, reg.k, uint64(uint32(reg.v)))
} }
var floatLoadError error
if floatingPoint { if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...) out = append(out, r.Fpregs...)
} }
return out return out, floatLoadError
} }
// PC returns the value of EIP register. // PC returns the value of EIP register.
@ -178,7 +189,14 @@ func (r *I386Registers) Get(n int) (uint64, error) {
} }
// Copy returns a copy of these registers that is guarenteed not to change. // Copy returns a copy of these registers that is guarenteed not to change.
func (r *I386Registers) Copy() proc.Registers { func (r *I386Registers) Copy() (proc.Registers, error) {
if r.loadFpRegs != nil {
err := r.loadFpRegs(r)
r.loadFpRegs = nil
if err != nil {
return nil, err
}
}
var rr I386Registers var rr I386Registers
rr.Regs = &I386PtraceRegs{} rr.Regs = &I386PtraceRegs{}
rr.Fpregset = &I386Xstate{} rr.Fpregset = &I386Xstate{}
@ -190,7 +208,7 @@ func (r *I386Registers) Copy() proc.Registers {
rr.Fpregs = make([]proc.Register, len(r.Fpregs)) rr.Fpregs = make([]proc.Register, len(r.Fpregs))
copy(rr.Fpregs, r.Fpregs) copy(rr.Fpregs, r.Fpregs)
} }
return &rr return &rr, nil
} }
// I386PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h // I386PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h

@ -104,6 +104,9 @@ func newCompositeMemory(mem MemoryReadWriter, regs op.DwarfRegisters, pieces []o
sz = len(reg) sz = len(reg)
} }
if sz > len(reg) { if sz > len(reg) {
if regs.FloatLoadError != nil {
return nil, fmt.Errorf("could not read %d bytes from register %d (size: %d), also error loading floating point registers: %v", sz, piece.RegNum, len(reg), regs.FloatLoadError)
}
return nil, fmt.Errorf("could not read %d bytes from register %d (size: %d)", sz, piece.RegNum, len(reg)) return nil, fmt.Errorf("could not read %d bytes from register %d (size: %d)", sz, piece.RegNum, len(reg))
} }
cmem.data = append(cmem.data, reg[:sz]...) cmem.data = append(cmem.data, reg[:sz]...)

@ -39,7 +39,7 @@ func killProcess(pid int) error {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread) (proc.Registers, error) {
panic(ErrNativeBackendDisabled) panic(ErrNativeBackendDisabled)
} }

@ -11,7 +11,7 @@ import (
// SetPC sets EIP to the value specified by 'pc'. // SetPC sets EIP to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -24,7 +24,7 @@ func (thread *nativeThread) SetPC(pc uint64) error {
// SetSP sets ESP to the value specified by 'sp' // SetSP sets ESP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -36,7 +36,7 @@ func (thread *nativeThread) SetSP(sp uint64) (err error) {
func (thread *nativeThread) SetDX(dx uint64) (err error) { func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -46,7 +46,7 @@ func (thread *nativeThread) SetDX(dx uint64) (err error) {
return return
} }
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread) (proc.Registers, error) {
var ( var (
regs linutil.I386PtraceRegs regs linutil.I386PtraceRegs
err error err error
@ -55,15 +55,13 @@ func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &linutil.I386Registers{&regs, nil, nil, 0} r := linutil.NewI386Registers(&regs, func(r *linutil.I386Registers) error {
if floatingPoint {
var fpregset linutil.I386Xstate var fpregset linutil.I386Xstate
r.Fpregs, fpregset, err = thread.fpRegisters() var floatLoadError error
r.Fpregs, fpregset, floatLoadError = thread.fpRegisters()
r.Fpregset = &fpregset r.Fpregset = &fpregset
if err != nil { return floatLoadError
return nil, err })
}
}
thread.dbp.execPtraceFunc(func() { thread.dbp.execPtraceFunc(func() {
tls, _ := ptraceGetTls(regs.Xgs, thread.ThreadID()) tls, _ := ptraceGetTls(regs.Xgs, thread.ThreadID())
r.Tls = uint64(tls) r.Tls = uint64(tls)

@ -41,7 +41,7 @@ type Regs struct {
fpregs []proc.Register fpregs []proc.Register
} }
func (r *Regs) Slice(floatingPoint bool) []proc.Register { func (r *Regs) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs = []struct { var regs = []struct {
k string k string
v uint64 v uint64
@ -80,7 +80,7 @@ func (r *Regs) Slice(floatingPoint bool) []proc.Register {
if floatingPoint { if floatingPoint {
out = append(out, r.fpregs...) out = append(out, r.fpregs...)
} }
return out return out, nil
} }
// PC returns the current program counter // PC returns the current program counter
@ -285,7 +285,7 @@ func (r *Regs) Get(n int) (uint64, error) {
return 0, proc.ErrUnknownRegister return 0, proc.ErrUnknownRegister
} }
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread) (proc.Registers, error) {
var state C.x86_thread_state64_t var state C.x86_thread_state64_t
var identity C.thread_identifier_info_data_t var identity C.thread_identifier_info_data_t
kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state) kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state)
@ -333,37 +333,36 @@ func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error)
gsBase: uint64(identity.thread_handle), gsBase: uint64(identity.thread_handle),
} }
if floatingPoint { // https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/thread_status.h?txt
// https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/thread_status.h?txt var fpstate C.x86_float_state64_t
var fpstate C.x86_float_state64_t kret = C.get_fpu_registers(C.mach_port_name_t(thread.os.threadAct), &fpstate)
kret = C.get_fpu_registers(C.mach_port_name_t(thread.os.threadAct), &fpstate) if kret != C.KERN_SUCCESS {
if kret != C.KERN_SUCCESS { return nil, fmt.Errorf("could not get floating point registers")
return nil, fmt.Errorf("could not get floating point registers")
}
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "CW", uint64(*((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw)))))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "SW", uint64(*((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw)))))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "TW", uint64(fpstate.__fpu_ftw))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FOP", uint64(fpstate.__fpu_fop))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp))
for i, st := range []*C.char{&fpstate.__fpu_stmm0.__mmst_reg[0], &fpstate.__fpu_stmm1.__mmst_reg[0], &fpstate.__fpu_stmm2.__mmst_reg[0], &fpstate.__fpu_stmm3.__mmst_reg[0], &fpstate.__fpu_stmm4.__mmst_reg[0], &fpstate.__fpu_stmm5.__mmst_reg[0], &fpstate.__fpu_stmm6.__mmst_reg[0], &fpstate.__fpu_stmm7.__mmst_reg[0]} {
stb := C.GoBytes(unsafe.Pointer(st), 10)
regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("ST(%d)", i), stb)
}
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "MXCSR_MASK", uint64(fpstate.__fpu_mxcsrmask))
for i, xmm := range []*C.char{&fpstate.__fpu_xmm0.__xmm_reg[0], &fpstate.__fpu_xmm1.__xmm_reg[0], &fpstate.__fpu_xmm2.__xmm_reg[0], &fpstate.__fpu_xmm3.__xmm_reg[0], &fpstate.__fpu_xmm4.__xmm_reg[0], &fpstate.__fpu_xmm5.__xmm_reg[0], &fpstate.__fpu_xmm6.__xmm_reg[0], &fpstate.__fpu_xmm7.__xmm_reg[0], &fpstate.__fpu_xmm8.__xmm_reg[0], &fpstate.__fpu_xmm9.__xmm_reg[0], &fpstate.__fpu_xmm10.__xmm_reg[0], &fpstate.__fpu_xmm11.__xmm_reg[0], &fpstate.__fpu_xmm12.__xmm_reg[0], &fpstate.__fpu_xmm13.__xmm_reg[0], &fpstate.__fpu_xmm14.__xmm_reg[0], &fpstate.__fpu_xmm15.__xmm_reg[0]} {
regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
}
} }
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "CW", uint64(*((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw)))))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "SW", uint64(*((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw)))))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "TW", uint64(fpstate.__fpu_ftw))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FOP", uint64(fpstate.__fpu_fop))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp))
for i, st := range []*C.char{&fpstate.__fpu_stmm0.__mmst_reg[0], &fpstate.__fpu_stmm1.__mmst_reg[0], &fpstate.__fpu_stmm2.__mmst_reg[0], &fpstate.__fpu_stmm3.__mmst_reg[0], &fpstate.__fpu_stmm4.__mmst_reg[0], &fpstate.__fpu_stmm5.__mmst_reg[0], &fpstate.__fpu_stmm6.__mmst_reg[0], &fpstate.__fpu_stmm7.__mmst_reg[0]} {
stb := C.GoBytes(unsafe.Pointer(st), 10)
regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("ST(%d)", i), stb)
}
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr))
regs.fpregs = proc.AppendUint64Register(regs.fpregs, "MXCSR_MASK", uint64(fpstate.__fpu_mxcsrmask))
for i, xmm := range []*C.char{&fpstate.__fpu_xmm0.__xmm_reg[0], &fpstate.__fpu_xmm1.__xmm_reg[0], &fpstate.__fpu_xmm2.__xmm_reg[0], &fpstate.__fpu_xmm3.__xmm_reg[0], &fpstate.__fpu_xmm4.__xmm_reg[0], &fpstate.__fpu_xmm5.__xmm_reg[0], &fpstate.__fpu_xmm6.__xmm_reg[0], &fpstate.__fpu_xmm7.__xmm_reg[0], &fpstate.__fpu_xmm8.__xmm_reg[0], &fpstate.__fpu_xmm9.__xmm_reg[0], &fpstate.__fpu_xmm10.__xmm_reg[0], &fpstate.__fpu_xmm11.__xmm_reg[0], &fpstate.__fpu_xmm12.__xmm_reg[0], &fpstate.__fpu_xmm13.__xmm_reg[0], &fpstate.__fpu_xmm14.__xmm_reg[0], &fpstate.__fpu_xmm15.__xmm_reg[0]} {
regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
}
return regs, nil return regs, nil
} }
func (r *Regs) Copy() proc.Registers { func (r *Regs) Copy() (proc.Registers, error) {
//TODO(aarzilli): implement this to support function calls //TODO(aarzilli): implement this to support function calls
return nil return nil, nil
} }

@ -11,7 +11,7 @@ import (
// SetPC sets RIP to the value specified by 'pc'. // SetPC sets RIP to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -24,7 +24,7 @@ func (thread *nativeThread) SetPC(pc uint64) error {
// SetSP sets RSP to the value specified by 'sp' // SetSP sets RSP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -36,7 +36,7 @@ func (thread *nativeThread) SetSP(sp uint64) (err error) {
func (thread *nativeThread) SetDX(dx uint64) (err error) { func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -46,7 +46,7 @@ func (thread *nativeThread) SetDX(dx uint64) (err error) {
return return
} }
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread) (proc.Registers, error) {
var ( var (
regs fbsdutil.AMD64PtraceRegs regs fbsdutil.AMD64PtraceRegs
err error err error
@ -60,15 +60,13 @@ func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &fbsdutil.AMD64Registers{&regs, nil, nil, uint64(fsbase)} r := fbsdutil.NewAMD64Registers(&regs, uint64(fsbase), func(r *fbsdutil.AMD64Registers) error {
if floatingPoint {
var fpregset fbsdutil.AMD64Xstate var fpregset fbsdutil.AMD64Xstate
r.Fpregs, fpregset, err = thread.fpRegisters() var floatLoadError error
r.Fpregs, fpregset, floatLoadError = thread.fpRegisters()
r.Fpregset = &fpregset r.Fpregset = &fpregset
if err != nil { return floatLoadError
return nil, err })
}
}
return r, nil return r, nil
} }

@ -11,7 +11,7 @@ import (
// SetPC sets RIP to the value specified by 'pc'. // SetPC sets RIP to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -24,7 +24,7 @@ func (thread *nativeThread) SetPC(pc uint64) error {
// SetSP sets RSP to the value specified by 'sp' // SetSP sets RSP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -36,7 +36,7 @@ func (thread *nativeThread) SetSP(sp uint64) (err error) {
func (thread *nativeThread) SetDX(dx uint64) (err error) { func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -46,7 +46,7 @@ func (thread *nativeThread) SetDX(dx uint64) (err error) {
return return
} }
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread) (proc.Registers, error) {
var ( var (
regs linutil.AMD64PtraceRegs regs linutil.AMD64PtraceRegs
err error err error
@ -55,15 +55,13 @@ func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &linutil.AMD64Registers{Regs: &regs} r := linutil.NewAMD64Registers(&regs, func(r *linutil.AMD64Registers) error {
if floatingPoint {
var fpregset linutil.AMD64Xstate var fpregset linutil.AMD64Xstate
r.Fpregs, fpregset, err = thread.fpRegisters() var floatLoadError error
r.Fpregs, fpregset, floatLoadError = thread.fpRegisters()
r.Fpregset = &fpregset r.Fpregset = &fpregset
if err != nil { return floatLoadError
return nil, err })
}
}
return r, nil return r, nil
} }

@ -56,7 +56,7 @@ func ptraceGetFpRegset(tid int) (fpregset []byte, err error) {
// SetPC sets PC to the value specified by 'pc'. // SetPC sets PC to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error { func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false) ir, err := registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -69,7 +69,7 @@ func (thread *nativeThread) SetPC(pc uint64) error {
// SetSP sets RSP to the value specified by 'sp' // SetSP sets RSP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) { func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers var ir proc.Registers
ir, err = registers(thread, false) ir, err = registers(thread)
if err != nil { if err != nil {
return err return err
} }
@ -83,7 +83,7 @@ func (thread *nativeThread) SetDX(dx uint64) (err error) {
return fmt.Errorf("not supported") return fmt.Errorf("not supported")
} }
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread) (proc.Registers, error) {
var ( var (
regs linutil.ARM64PtraceRegs regs linutil.ARM64PtraceRegs
err error err error
@ -92,12 +92,10 @@ func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &linutil.ARM64Registers{&regs, nil, nil} r := linutil.NewARM64Registers(&regs, func(r *linutil.ARM64Registers) error {
if floatingPoint { var floatLoadError error
r.Fpregs, r.Fpregset, err = thread.fpRegisters() r.Fpregs, r.Fpregset, floatLoadError = thread.fpRegisters()
if err != nil { return floatLoadError
return nil, err })
}
}
return r, nil return r, nil
} }

@ -52,7 +52,7 @@ func (thread *nativeThread) SetDX(dx uint64) error {
return _SetThreadContext(thread.os.hThread, context) return _SetThreadContext(thread.os.hThread, context)
} }
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) { func registers(thread *nativeThread) (proc.Registers, error) {
context := winutil.NewCONTEXT() context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL context.ContextFlags = _CONTEXT_ALL
@ -67,5 +67,5 @@ func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error)
return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status) return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status)
} }
return winutil.NewAMD64Registers(context, uint64(threadInfo.TebBaseAddress), floatingPoint), nil return winutil.NewAMD64Registers(context, uint64(threadInfo.TebBaseAddress)), nil
} }

@ -157,8 +157,8 @@ func (t *nativeThread) ClearBreakpoint(bp *proc.Breakpoint) error {
} }
// Registers obtains register values from the debugged process. // Registers obtains register values from the debugged process.
func (t *nativeThread) Registers(floatingPoint bool) (proc.Registers, error) { func (t *nativeThread) Registers() (proc.Registers, error) {
return registers(t, floatingPoint) return registers(t)
} }
// RestoreRegisters will set the value of the CPU registers to those // RestoreRegisters will set the value of the CPU registers to those
@ -169,7 +169,7 @@ func (t *nativeThread) RestoreRegisters(savedRegs proc.Registers) error {
// PC returns the current program counter value for this thread. // PC returns the current program counter value for this thread.
func (t *nativeThread) PC() (uint64, error) { func (t *nativeThread) PC() (uint64, error) {
regs, err := t.Registers(false) regs, err := t.Registers()
if err != nil { if err != nil {
return 0, err return 0, err
} }

@ -87,7 +87,7 @@ func (t *nativeThread) resume() error {
func (t *nativeThread) Blocked() bool { func (t *nativeThread) Blocked() bool {
// TODO(dp) cache the func pc to remove this lookup // TODO(dp) cache the func pc to remove this lookup
regs, err := t.Registers(false) regs, err := t.Registers()
if err != nil { if err != nil {
return false return false
} }

@ -72,7 +72,7 @@ func (t *nativeThread) singleStep() (err error) {
} }
func (t *nativeThread) Blocked() bool { func (t *nativeThread) Blocked() bool {
regs, err := t.Registers(false) regs, err := t.Registers()
if err != nil { if err != nil {
return false return false
} }

@ -114,7 +114,7 @@ func (t *nativeThread) resume() error {
func (t *nativeThread) Blocked() bool { func (t *nativeThread) Blocked() bool {
// TODO: Probably incorrect - what are the runtime functions that // TODO: Probably incorrect - what are the runtime functions that
// indicate blocking on Windows? // indicate blocking on Windows?
regs, err := t.Registers(false) regs, err := t.Registers()
if err != nil { if err != nil {
return false return false
} }

@ -90,7 +90,7 @@ func withTestProcessArgs(name string, t testing.TB, wd string, args []string, bu
} }
func getRegisters(p *proc.Target, t *testing.T) proc.Registers { func getRegisters(p *proc.Target, t *testing.T) proc.Registers {
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
if err != nil { if err != nil {
t.Fatal("Registers():", err) t.Fatal("Registers():", err)
} }
@ -113,7 +113,7 @@ func assertNoError(err error, t testing.TB, s string) {
} }
func currentPC(p *proc.Target, t *testing.T) uint64 { func currentPC(p *proc.Target, t *testing.T) uint64 {
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -280,7 +280,7 @@ func TestBreakpoint(t *testing.T) {
bp := setFunctionBreakpoint(p, t, "main.helloworld") bp := setFunctionBreakpoint(p, t, "main.helloworld")
assertNoError(p.Continue(), t, "Continue()") assertNoError(p.Continue(), t, "Continue()")
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers") assertNoError(err, t, "Registers")
pc := regs.PC() pc := regs.PC()
@ -302,7 +302,7 @@ func TestBreakpointInSeparateGoRoutine(t *testing.T) {
assertNoError(p.Continue(), t, "Continue") assertNoError(p.Continue(), t, "Continue")
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers") assertNoError(err, t, "Registers")
pc := regs.PC() pc := regs.PC()
@ -409,7 +409,7 @@ func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *te
if traceTestseq2 { if traceTestseq2 {
t.Logf("initial breakpoint %v", bp) t.Logf("initial breakpoint %v", bp)
} }
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers") assertNoError(err, t, "Registers")
f, ln := currentLineNumber(p, t) f, ln := currentLineNumber(p, t)
@ -474,7 +474,7 @@ func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *te
} }
f, ln = currentLineNumber(p, t) f, ln = currentLineNumber(p, t)
regs, _ = p.CurrentThread().Registers(false) regs, _ = p.CurrentThread().Registers()
pc := regs.PC() pc := regs.PC()
if traceTestseq2 { if traceTestseq2 {
@ -710,7 +710,7 @@ func TestRuntimeBreakpoint(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers") assertNoError(err, t, "Registers")
pc := regs.PC() pc := regs.PC()
f, l, _ := p.BinInfo().PCToLine(pc) f, l, _ := p.BinInfo().PCToLine(pc)
@ -1770,7 +1770,7 @@ func TestIssue332_Part2(t *testing.T) {
} }
} }
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers()") assertNoError(err, t, "Registers()")
pc := regs.PC() pc := regs.PC()
pcAfterPrologue := findFunctionLocation(p, t, "main.changeMe") pcAfterPrologue := findFunctionLocation(p, t, "main.changeMe")
@ -2502,7 +2502,7 @@ func TestStepOnCallPtrInstr(t *testing.T) {
if ln != 10 { if ln != 10 {
break break
} }
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers()") assertNoError(err, t, "Registers()")
pc := regs.PC() pc := regs.PC()
text, err := proc.Disassemble(p.CurrentThread(), regs, p.Breakpoints(), p.BinInfo(), pc, pc+uint64(p.BinInfo().Arch.MaxInstructionLength())) text, err := proc.Disassemble(p.CurrentThread(), regs, p.Breakpoints(), p.BinInfo(), pc, pc+uint64(p.BinInfo().Arch.MaxInstructionLength()))
@ -3611,7 +3611,7 @@ func TestDisassembleGlobalVars(t *testing.T) {
} }
withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) { withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) {
mainfn := p.BinInfo().LookupFunc["main.main"] mainfn := p.BinInfo().LookupFunc["main.main"]
regs, _ := p.CurrentThread().Registers(false) regs, _ := p.CurrentThread().Registers()
text, err := proc.Disassemble(p.CurrentThread(), regs, p.Breakpoints(), p.BinInfo(), mainfn.Entry, mainfn.End) text, err := proc.Disassemble(p.CurrentThread(), regs, p.Breakpoints(), p.BinInfo(), mainfn.Entry, mainfn.End)
assertNoError(err, t, "Disassemble") assertNoError(err, t, "Disassemble")
found := false found := false
@ -4168,7 +4168,7 @@ func TestIssue1374(t *testing.T) {
assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "getNum()", normalLoadConfig, true), t, "Call") assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "getNum()", normalLoadConfig, true), t, "Call")
err := p.Continue() err := p.Continue()
if _, isexited := err.(proc.ErrProcessExited); !isexited { if _, isexited := err.(proc.ErrProcessExited); !isexited {
regs, _ := p.CurrentThread().Registers(false) regs, _ := p.CurrentThread().Registers()
f, l, _ := p.BinInfo().PCToLine(regs.PC()) f, l, _ := p.BinInfo().PCToLine(regs.PC())
t.Fatalf("expected process exited error got %v at %s:%d", err, f, l) t.Fatalf("expected process exited error got %v at %s:%d", err, f, l)
} }

@ -21,10 +21,10 @@ type Registers interface {
// GAddr returns the address of the G variable if it is known, 0 and false otherwise // GAddr returns the address of the G variable if it is known, 0 and false otherwise
GAddr() (uint64, bool) GAddr() (uint64, bool)
Get(int) (uint64, error) Get(int) (uint64, error)
Slice(floatingPoint bool) []Register Slice(floatingPoint bool) ([]Register, error)
// Copy returns a copy of the registers that is guaranteed not to change // Copy returns a copy of the registers that is guaranteed not to change
// when the registers of the associated thread change. // when the registers of the associated thread change.
Copy() Registers Copy() (Registers, error)
} }
// Register represents a CPU register. // Register represents a CPU register.

@ -95,7 +95,7 @@ func (frame *Stackframe) FramePointerOffset() int64 {
func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) { func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) {
g, _ := GetG(thread) g, _ := GetG(thread)
if g == nil { if g == nil {
regs, err := thread.Registers(true) regs, err := thread.Registers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -114,7 +114,7 @@ func (g *G) stackIterator(opts StacktraceOptions) (*stackIterator, error) {
bi := g.variable.bi bi := g.variable.bi
if g.Thread != nil { if g.Thread != nil {
regs, err := g.Thread.Registers(true) regs, err := g.Thread.Registers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -456,8 +456,8 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
} }
if it.bi.Arch.Name == "arm64" { if it.bi.Arch.Name == "arm64" {
if ret == 0 && it.regs.Regs[it.regs.LRRegNum] != nil { if ret == 0 && it.regs.Reg(it.regs.LRRegNum) != nil {
ret = it.regs.Regs[it.regs.LRRegNum].Uint64Val ret = it.regs.Reg(it.regs.LRRegNum).Uint64Val
} }
} }
@ -666,7 +666,7 @@ func (d *Defer) EvalScope(thread Thread) (*EvalScope, error) {
// the space occupied by pushing the return address on the stack during the // the space occupied by pushing the return address on the stack during the
// CALL. // CALL.
scope.Regs.CFA = (int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize) scope.Regs.CFA = (int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize)
scope.Regs.Regs[scope.Regs.SPRegNum].Uint64Val = uint64(scope.Regs.CFA - int64(bi.Arch.PtrSize())) scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(scope.Regs.CFA - int64(bi.Arch.PtrSize()))
rdr := scope.Fn.cu.image.dwarfReader rdr := scope.Fn.cu.image.dwarfReader
rdr.Seek(scope.Fn.offset) rdr.Seek(scope.Fn.offset)

@ -230,7 +230,7 @@ func pickCurrentThread(dbp *Target, trapthread Thread, threads []Thread) error {
} }
func disassembleCurrentInstruction(p Process, thread Thread) ([]AsmInstruction, error) { func disassembleCurrentInstruction(p Process, thread Thread) ([]AsmInstruction, error) {
regs, err := thread.Registers(false) regs, err := thread.Registers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -474,7 +474,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
var regs Registers var regs Registers
if selg != nil && selg.Thread != nil { if selg != nil && selg.Thread != nil {
thread = selg.Thread thread = selg.Thread
regs, err = selg.Thread.Registers(false) regs, err = selg.Thread.Registers()
if err != nil { if err != nil {
return err return err
} }

@ -19,7 +19,7 @@ type Thread interface {
// SetPC/SetSP/etc. // SetPC/SetSP/etc.
// To insure that the the returned variable won't change call the Copy // To insure that the the returned variable won't change call the Copy
// method of Registers. // method of Registers.
Registers(floatingPoint bool) (Registers, error) Registers() (Registers, error)
// RestoreRegisters restores saved registers // RestoreRegisters restores saved registers
RestoreRegisters(Registers) error RestoreRegisters(Registers) error

@ -422,7 +422,7 @@ func FindGoroutine(dbp *Target, gid int) (*G, error) {
} }
func getGVariable(thread Thread) (*Variable, error) { func getGVariable(thread Thread) (*Variable, error) {
regs, err := thread.Registers(false) regs, err := thread.Registers()
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -41,7 +41,7 @@ type AMD64Registers struct {
// NewAMD64Registers creates a new AMD64Registers struct from a CONTEXT // NewAMD64Registers creates a new AMD64Registers struct from a CONTEXT
// struct and the TEB base address of the thread. // struct and the TEB base address of the thread.
func NewAMD64Registers(context *CONTEXT, TebBaseAddress uint64, floatingPoint bool) *AMD64Registers { func NewAMD64Registers(context *CONTEXT, TebBaseAddress uint64) *AMD64Registers {
regs := &AMD64Registers{ regs := &AMD64Registers{
rax: uint64(context.Rax), rax: uint64(context.Rax),
rbx: uint64(context.Rbx), rbx: uint64(context.Rbx),
@ -67,16 +67,14 @@ func NewAMD64Registers(context *CONTEXT, TebBaseAddress uint64, floatingPoint bo
tls: TebBaseAddress, tls: TebBaseAddress,
} }
if floatingPoint { regs.fltSave = &context.FltSave
regs.fltSave = &context.FltSave
}
regs.Context = context regs.Context = context
return regs return regs
} }
// Slice returns the registers as a list of (name, value) pairs. // Slice returns the registers as a list of (name, value) pairs.
func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register { func (r *AMD64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs = []struct { var regs = []struct {
k string k string
v uint64 v uint64
@ -134,7 +132,7 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
out = proc.AppendBytesRegister(out, fmt.Sprintf("XMM%d", i/16), r.fltSave.XmmRegisters[i:i+16]) out = proc.AppendBytesRegister(out, fmt.Sprintf("XMM%d", i/16), r.fltSave.XmmRegisters[i:i+16])
} }
} }
return out return out, nil
} }
// PC returns the current program counter // PC returns the current program counter
@ -325,13 +323,13 @@ func (r *AMD64Registers) Get(n int) (uint64, error) {
} }
// Copy returns a copy of these registers that is guarenteed not to change. // Copy returns a copy of these registers that is guarenteed not to change.
func (r *AMD64Registers) Copy() proc.Registers { func (r *AMD64Registers) Copy() (proc.Registers, error) {
var rr AMD64Registers var rr AMD64Registers
rr = *r rr = *r
rr.Context = NewCONTEXT() rr.Context = NewCONTEXT()
*(rr.Context) = *(r.Context) *(rr.Context) = *(r.Context)
rr.fltSave = &rr.Context.FltSave rr.fltSave = &rr.Context.FltSave
return &rr return &rr, nil
} }
// M128A tracks the _M128A windows struct. // M128A tracks the _M128A windows struct.

@ -330,8 +330,11 @@ func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig {
// ConvertRegisters converts proc.Register to api.Register for a slice. // ConvertRegisters converts proc.Register to api.Register for a slice.
func ConvertRegisters(in op.DwarfRegisters, arch *proc.Arch, floatingPoint bool) (out []Register) { func ConvertRegisters(in op.DwarfRegisters, arch *proc.Arch, floatingPoint bool) (out []Register) {
out = make([]Register, 0, len(in.Regs)) if floatingPoint {
for i := range in.Regs { in.Reg(^uint64(0)) // force loading all registers
}
out = make([]Register, 0, in.CurrentSize())
for i := 0; i < in.CurrentSize(); i++ {
reg := in.Reg(uint64(i)) reg := in.Reg(uint64(i))
if reg == nil { if reg == nil {
continue continue

@ -350,7 +350,7 @@ func (d *Debugger) FunctionReturnLocations(fnName string) ([]uint64, error) {
var mem proc.MemoryReadWriter = p.CurrentThread() var mem proc.MemoryReadWriter = p.CurrentThread()
if g != nil && g.Thread != nil { if g != nil && g.Thread != nil {
mem = g.Thread mem = g.Thread
regs, _ = g.Thread.Registers(false) regs, _ = g.Thread.Registers()
} }
instructions, err := proc.Disassemble(mem, regs, p.Breakpoints(), p.BinInfo(), fn.Entry, fn.End) instructions, err := proc.Disassemble(mem, regs, p.Breakpoints(), p.BinInfo(), fn.Entry, fn.End)
if err != nil { if err != nil {
@ -1159,13 +1159,16 @@ func (d *Debugger) Registers(threadID int, scope *api.EvalScope, floatingPoint b
if !found { if !found {
return nil, fmt.Errorf("couldn't find thread %d", threadID) return nil, fmt.Errorf("couldn't find thread %d", threadID)
} }
regs, err := thread.Registers(floatingPoint) regs, err := thread.Registers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
dregs = d.target.BinInfo().Arch.RegistersToDwarfRegisters(0, regs) dregs = d.target.BinInfo().Arch.RegistersToDwarfRegisters(0, regs)
} }
r := api.ConvertRegisters(dregs, d.target.BinInfo().Arch, floatingPoint) r := api.ConvertRegisters(dregs, d.target.BinInfo().Arch, floatingPoint)
if floatingPoint && dregs.FloatLoadError != nil {
return nil, dregs.FloatLoadError
}
// Sort the registers in a canonical order we prefer, this is mostly // Sort the registers in a canonical order we prefer, this is mostly
// because the DWARF register numbering for AMD64 is weird. // because the DWARF register numbering for AMD64 is weird.
sort.Slice(r, func(i, j int) bool { sort.Slice(r, func(i, j int) bool {
@ -1488,7 +1491,7 @@ func (d *Debugger) Disassemble(goroutineID int, addr1, addr2 uint64, flavour api
if g != nil && g.Thread != nil { if g != nil && g.Thread != nil {
curthread = g.Thread curthread = g.Thread
} }
regs, _ := curthread.Registers(false) regs, _ := curthread.Registers()
insts, err := proc.Disassemble(curthread, regs, d.target.Breakpoints(), d.target.BinInfo(), addr1, addr2) insts, err := proc.Disassemble(curthread, regs, d.target.Breakpoints(), d.target.BinInfo(), addr1, addr2)
if err != nil { if err != nil {

@ -1439,7 +1439,7 @@ func setFileBreakpoint(p *proc.Target, t *testing.T, fixture protest.Fixture, li
} }
func currentLocation(p *proc.Target, t *testing.T) (pc uint64, f string, ln int, fn *proc.Function) { func currentLocation(p *proc.Target, t *testing.T) (pc uint64, f string, ln int, fn *proc.Function) {
regs, err := p.CurrentThread().Registers(false) regs, err := p.CurrentThread().Registers()
if err != nil { if err != nil {
t.Fatalf("Registers error: %v", err) t.Fatalf("Registers error: %v", err)
} }