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
FrameBase int64
ObjBase int64
Regs []*DwarfRegister
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 {
@ -26,13 +29,38 @@ type DwarfRegister struct {
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
return regs.regs[idx].Uint64Val
}
// 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
}
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)) {
return nil
if idx >= uint64(len(regs.regs)) {
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 {
@ -72,12 +114,20 @@ func (regs *DwarfRegisters) BP() uint64 {
// AddReg adds register idx to regs.
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)
copy(newRegs, regs.Regs)
regs.Regs = newRegs
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
}
regs.Regs[idx] = reg
}
func DwarfRegisterFromUint64(v uint64) *DwarfRegister {

@ -345,21 +345,32 @@ func maxAmd64DwarfRegister() int {
}
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) {
if dwarfReg, ok := amd64NameToDwarf[strings.ToLower(reg.Name)]; ok {
func initDwarfRegistersFromSlice(maxRegs int, regs Registers, nameToDwarf map[string]int) []*op.DwarfRegister {
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
}
}
return dregs
}
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: amd64DwarfIPRegNum,
SPRegNum: amd64DwarfSPRegNum,
BPRegNum: amd64DwarfBPRegNum,
func loadMoreDwarfRegistersFromSliceFunc(dr *op.DwarfRegisters, regs Registers, nameToDwarf map[string]int) func() {
return func() {
regslice, err := regs.Slice(true)
dr.FloatLoadError = err
for _, reg := range regslice {
if dwarfReg, ok := nameToDwarf[strings.ToLower(reg.Name)]; ok {
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[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: amd64DwarfIPRegNum,
SPRegNum: amd64DwarfSPRegNum,
BPRegNum: amd64DwarfBPRegNum,
}
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, amd64DwarfIPRegNum, amd64DwarfSPRegNum, amd64DwarfBPRegNum, 0)
}
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,
}
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 {
max := int(arm64DwarfIPRegNum)
for i := range arm64DwarfToHardware {
@ -339,15 +353,9 @@ func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfR
}
}
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: arm64DwarfIPRegNum,
SPRegNum: arm64DwarfSPRegNum,
BPRegNum: arm64DwarfBPRegNum,
LRRegNum: arm64DwarfLRRegNum,
}
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, arm64DwarfIPRegNum, arm64DwarfSPRegNum, arm64DwarfBPRegNum, arm64DwarfLRRegNum)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, arm64NameToDwarf))
return *dr
}
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[arm64DwarfLRRegNum] = op.DwarfRegisterFromUint64(lr)
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: arm64DwarfIPRegNum,
SPRegNum: arm64DwarfSPRegNum,
BPRegNum: arm64DwarfBPRegNum,
LRRegNum: arm64DwarfLRRegNum,
}
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, arm64DwarfIPRegNum, arm64DwarfSPRegNum, arm64DwarfBPRegNum, arm64DwarfLRRegNum)
}
func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {

@ -170,7 +170,7 @@ type thread struct {
}
type osThread interface {
registers(floatingPoint bool) (proc.Registers, error)
registers() (proc.Registers, error)
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
// the value of the instruction pointer register.
func (t *thread) Location() (*proc.Location, error) {
regs, err := t.th.registers(false)
regs, err := t.th.registers()
if err != nil {
return nil, err
}
@ -303,8 +303,8 @@ func (t *thread) ThreadID() int {
}
// Registers returns the current value of the registers for this thread.
func (t *thread) Registers(floatingPoint bool) (proc.Registers, error) {
return t.th.registers(floatingPoint)
func (t *thread) Registers() (proc.Registers, error) {
return t.th.registers()
}
// 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) {
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 {
continue
}
@ -250,7 +252,7 @@ func TestCore(t *testing.T) {
t.Errorf("main.msg = %q, want %q", msg.Value, "BOOM!")
}
regs, err := p.CurrentThread().Registers(true)
regs, err := p.CurrentThread().Registers()
if err != nil {
t.Fatalf("Couldn't get current thread registers: %v", err)
}
@ -286,7 +288,7 @@ func TestCoreFpRegisters(t *testing.T) {
continue
}
if frames[i].Current.Fn.Name == "main.main" {
regs, err = thread.Registers(true)
regs, err = thread.Registers()
if err != nil {
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 {
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)
if reg != nil && regname == regtest.name {
found = true

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

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

@ -232,7 +232,7 @@ func TestDwarfExprLoclist(t *testing.T) {
uintExprCheck(t, scope, "a", before)
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)
}

@ -14,6 +14,12 @@ type AMD64Registers struct {
Fpregs []proc.Register
Fpregset *AMD64Xstate
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
@ -49,7 +55,7 @@ type AMD64PtraceRegs struct {
}
// 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 {
k string
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
// "Rflags", but Linux still uses the old name.
out = proc.AppendUint64Register(out, "Rflags", uint64(r.Regs.Rflags))
var floatLoadError error
if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...)
}
return out
return out, floatLoadError
}
// 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.
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
rr.Regs = &AMD64PtraceRegs{}
rr.Fpregset = &AMD64Xstate{}
@ -314,7 +332,7 @@ func (r *AMD64Registers) Copy() proc.Registers {
rr.Fpregs = make([]proc.Register, len(r.Fpregs))
copy(rr.Fpregs, r.Fpregs)
}
return &rr
return &rr, nil
}
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
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 {
return nil, err
}
regs = regs.Copy()
if regs.SP()-256 <= scope.g.stack.lo {
return nil, errNotEnoughStack
}
@ -293,18 +296,13 @@ func evalFunctionCall(scope *EvalScope, node *ast.CallExpr) (*Variable, error) {
scope.g = scope.callCtx.doContinue()
// adjust the value of registers inside scope
for regnum := range scope.Regs.Regs {
switch uint64(regnum) {
case scope.Regs.PCRegNum, scope.Regs.SPRegNum, scope.Regs.BPRegNum:
// leave these alone
default:
// every other register is dirty and unrecoverable
scope.Regs.Regs[regnum] = nil
}
}
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))
pcreg, bpreg, spreg := scope.Regs.Reg(scope.Regs.PCRegNum), scope.Regs.Reg(scope.Regs.BPRegNum), scope.Regs.Reg(scope.Regs.SPRegNum)
scope.Regs.ClearRegisters()
scope.Regs.AddReg(scope.Regs.PCRegNum, pcreg)
scope.Regs.AddReg(scope.Regs.BPRegNum, bpreg)
scope.Regs.AddReg(scope.Regs.SPRegNum, spreg)
scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(spoff + int64(scope.g.stack.hi))
scope.Regs.Reg(scope.Regs.BPRegNum).Uint64Val = uint64(bpoff + int64(scope.g.stack.hi))
scope.Regs.FrameBase = fboff + 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()
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 {
fncall.err = err
return true
}
regs = regs.Copy()
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.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)
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.
func (t *gdbThread) Location() (*proc.Location, error) {
regs, err := t.Registers(false)
regs, err := t.Registers()
if err != nil {
return nil, err
}
@ -1311,7 +1311,7 @@ func (t *gdbThread) ThreadID() int {
}
// 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 err := t.reloadRegisters(); err != nil {
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.
func (t *gdbThread) Blocked() bool {
regs, err := t.Registers(false)
regs, err := t.Registers()
if err != nil {
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
// address correctly after hitting a breakpoint.
t.clearBreakpointState()
regs, err := t.Registers(false)
regs, err := t.Registers()
if err != nil {
return err
}
@ -1865,6 +1865,10 @@ func (regs *gdbRegisters) Get(n int) (uint64, error) {
return 0, proc.ErrUnknownRegister
}
func (r *gdbRegisters) FloatLoadError() error {
return nil
}
// SetPC will set the value of the PC register to the given value.
func (t *gdbThread) SetPC(pc uint64) error {
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)
}
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))
for _, reginfo := range regs.regsInfo {
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:])
}
}
return r
return r, nil
}
func (regs *gdbRegisters) Copy() proc.Registers {
func (regs *gdbRegisters) Copy() (proc.Registers, error) {
savedRegs := &gdbRegisters{}
savedRegs.init(regs.regsInfo)
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 {
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) {
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,
}
return *dr
}
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[i386DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
return op.DwarfRegisters{
StaticBase: staticBase,
Regs: dregs,
ByteOrder: binary.LittleEndian,
PCRegNum: i386DwarfIPRegNum,
SPRegNum: i386DwarfSPRegNum,
BPRegNum: i386DwarfBPRegNum,
}
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, i386DwarfIPRegNum, i386DwarfSPRegNum, i386DwarfBPRegNum, 0)
}
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)
default:
if reg.Bytes != nil && strings.HasPrefix(name, "xmm") {
if reg.Bytes != nil && strings.HasPrefix(n, "xmm") {
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)
} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) <= 8) {
return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)

@ -16,6 +16,12 @@ type AMD64Registers struct {
Regs *AMD64PtraceRegs
Fpregs []proc.Register
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
@ -51,7 +57,7 @@ type AMD64PtraceRegs struct {
}
// 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 {
k string
v uint64
@ -88,10 +94,15 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
for _, reg := range regs {
out = proc.AppendUint64Register(out, reg.k, reg.v)
}
var floatLoadError error
if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...)
}
return out
return out, floatLoadError
}
// 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.
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
rr.Regs = &AMD64PtraceRegs{}
rr.Fpregset = &AMD64Xstate{}
@ -290,7 +308,7 @@ func (r *AMD64Registers) Copy() proc.Registers {
rr.Fpregs = make([]proc.Register, len(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

@ -12,6 +12,12 @@ type ARM64Registers struct {
Regs *ARM64PtraceRegs //general-purpose registers
Fpregs []proc.Register //Formatted floating point registers
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
@ -25,7 +31,7 @@ type ARM64PtraceRegs struct {
}
// 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 {
k string
v uint64
@ -69,8 +75,15 @@ func (r *ARM64Registers) Slice(floatingPoint bool) []proc.Register {
for _, reg := range regs64 {
out = proc.AppendUint64Register(out, reg.k, reg.v)
}
out = append(out, r.Fpregs...)
return out
var floatLoadError error
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.
@ -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.
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
rr.Regs = &ARM64PtraceRegs{}
*(rr.Regs) = *(r.Regs)
@ -122,7 +142,7 @@ func (r *ARM64Registers) Copy() proc.Registers {
rr.Fpregset = make([]byte, len(r.Fpregset))
copy(rr.Fpregset, r.Fpregset)
}
return &rr
return &rr, nil
}
type ARM64PtraceFpRegs struct {

@ -15,6 +15,12 @@ type I386Registers struct {
Fpregs []proc.Register
Fpregset *I386Xstate
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
@ -40,7 +46,7 @@ type I386PtraceRegs struct {
}
// 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 {
k string
v int32
@ -67,10 +73,15 @@ func (r *I386Registers) Slice(floatingPoint bool) []proc.Register {
for _, reg := range regs {
out = proc.AppendUint64Register(out, reg.k, uint64(uint32(reg.v)))
}
var floatLoadError error
if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...)
}
return out
return out, floatLoadError
}
// 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.
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
rr.Regs = &I386PtraceRegs{}
rr.Fpregset = &I386Xstate{}
@ -190,7 +208,7 @@ func (r *I386Registers) Copy() proc.Registers {
rr.Fpregs = make([]proc.Register, len(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

@ -104,6 +104,9 @@ func newCompositeMemory(mem MemoryReadWriter, regs op.DwarfRegisters, pieces []o
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))
}
cmem.data = append(cmem.data, reg[:sz]...)

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

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

@ -41,7 +41,7 @@ type Regs struct {
fpregs []proc.Register
}
func (r *Regs) Slice(floatingPoint bool) []proc.Register {
func (r *Regs) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs = []struct {
k string
v uint64
@ -80,7 +80,7 @@ func (r *Regs) Slice(floatingPoint bool) []proc.Register {
if floatingPoint {
out = append(out, r.fpregs...)
}
return out
return out, nil
}
// PC returns the current program counter
@ -285,7 +285,7 @@ func (r *Regs) Get(n int) (uint64, error) {
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 identity C.thread_identifier_info_data_t
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),
}
if floatingPoint {
// https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/thread_status.h?txt
var fpstate C.x86_float_state64_t
kret = C.get_fpu_registers(C.mach_port_name_t(thread.os.threadAct), &fpstate)
if kret != C.KERN_SUCCESS {
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))
}
// https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/thread_status.h?txt
var fpstate C.x86_float_state64_t
kret = C.get_fpu_registers(C.mach_port_name_t(thread.os.threadAct), &fpstate)
if kret != C.KERN_SUCCESS {
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))
}
return regs, nil
}
func (r *Regs) Copy() proc.Registers {
func (r *Regs) Copy() (proc.Registers, error) {
//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'.
func (thread *nativeThread) SetPC(pc uint64) error {
ir, err := registers(thread, false)
ir, err := registers(thread)
if err != nil {
return err
}
@ -24,7 +24,7 @@ func (thread *nativeThread) SetPC(pc uint64) error {
// SetSP sets RSP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread, false)
ir, err = registers(thread)
if err != nil {
return err
}
@ -36,7 +36,7 @@ func (thread *nativeThread) SetSP(sp uint64) (err error) {
func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread, false)
ir, err = registers(thread)
if err != nil {
return err
}
@ -46,7 +46,7 @@ func (thread *nativeThread) SetDX(dx uint64) (err error) {
return
}
func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error) {
func registers(thread *nativeThread) (proc.Registers, error) {
var (
regs fbsdutil.AMD64PtraceRegs
err error
@ -60,15 +60,13 @@ func registers(thread *nativeThread, floatingPoint bool) (proc.Registers, error)
if err != nil {
return nil, err
}
r := &fbsdutil.AMD64Registers{&regs, nil, nil, uint64(fsbase)}
if floatingPoint {
r := fbsdutil.NewAMD64Registers(&regs, uint64(fsbase), func(r *fbsdutil.AMD64Registers) error {
var fpregset fbsdutil.AMD64Xstate
r.Fpregs, fpregset, err = thread.fpRegisters()
var floatLoadError error
r.Fpregs, fpregset, floatLoadError = thread.fpRegisters()
r.Fpregset = &fpregset
if err != nil {
return nil, err
}
}
return floatLoadError
})
return r, nil
}

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

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

@ -52,7 +52,7 @@ func (thread *nativeThread) SetDX(dx uint64) error {
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.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 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.
func (t *nativeThread) Registers(floatingPoint bool) (proc.Registers, error) {
return registers(t, floatingPoint)
func (t *nativeThread) Registers() (proc.Registers, error) {
return registers(t)
}
// 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.
func (t *nativeThread) PC() (uint64, error) {
regs, err := t.Registers(false)
regs, err := t.Registers()
if err != nil {
return 0, err
}

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

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

@ -114,7 +114,7 @@ func (t *nativeThread) resume() error {
func (t *nativeThread) Blocked() bool {
// TODO: Probably incorrect - what are the runtime functions that
// indicate blocking on Windows?
regs, err := t.Registers(false)
regs, err := t.Registers()
if err != nil {
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 {
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
if err != nil {
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 {
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
if err != nil {
t.Fatal(err)
}
@ -280,7 +280,7 @@ func TestBreakpoint(t *testing.T) {
bp := setFunctionBreakpoint(p, t, "main.helloworld")
assertNoError(p.Continue(), t, "Continue()")
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers")
pc := regs.PC()
@ -302,7 +302,7 @@ func TestBreakpointInSeparateGoRoutine(t *testing.T) {
assertNoError(p.Continue(), t, "Continue")
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers")
pc := regs.PC()
@ -409,7 +409,7 @@ func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *te
if traceTestseq2 {
t.Logf("initial breakpoint %v", bp)
}
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers")
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)
regs, _ = p.CurrentThread().Registers(false)
regs, _ = p.CurrentThread().Registers()
pc := regs.PC()
if traceTestseq2 {
@ -710,7 +710,7 @@ func TestRuntimeBreakpoint(t *testing.T) {
if err != nil {
t.Fatal(err)
}
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers")
pc := regs.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()")
pc := regs.PC()
pcAfterPrologue := findFunctionLocation(p, t, "main.changeMe")
@ -2502,7 +2502,7 @@ func TestStepOnCallPtrInstr(t *testing.T) {
if ln != 10 {
break
}
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers()")
pc := regs.PC()
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) {
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)
assertNoError(err, t, "Disassemble")
found := false
@ -4168,7 +4168,7 @@ func TestIssue1374(t *testing.T) {
assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "getNum()", normalLoadConfig, true), t, "Call")
err := p.Continue()
if _, isexited := err.(proc.ErrProcessExited); !isexited {
regs, _ := p.CurrentThread().Registers(false)
regs, _ := p.CurrentThread().Registers()
f, l, _ := p.BinInfo().PCToLine(regs.PC())
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() (uint64, bool)
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
// when the registers of the associated thread change.
Copy() Registers
Copy() (Registers, error)
}
// Register represents a CPU register.

@ -95,7 +95,7 @@ func (frame *Stackframe) FramePointerOffset() int64 {
func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) {
g, _ := GetG(thread)
if g == nil {
regs, err := thread.Registers(true)
regs, err := thread.Registers()
if err != nil {
return nil, err
}
@ -114,7 +114,7 @@ func (g *G) stackIterator(opts StacktraceOptions) (*stackIterator, error) {
bi := g.variable.bi
if g.Thread != nil {
regs, err := g.Thread.Registers(true)
regs, err := g.Thread.Registers()
if err != nil {
return nil, err
}
@ -456,8 +456,8 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
}
if it.bi.Arch.Name == "arm64" {
if ret == 0 && it.regs.Regs[it.regs.LRRegNum] != nil {
ret = it.regs.Regs[it.regs.LRRegNum].Uint64Val
if ret == 0 && it.regs.Reg(it.regs.LRRegNum) != nil {
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
// CALL.
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.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) {
regs, err := thread.Registers(false)
regs, err := thread.Registers()
if err != nil {
return nil, err
}
@ -474,7 +474,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
var regs Registers
if selg != nil && selg.Thread != nil {
thread = selg.Thread
regs, err = selg.Thread.Registers(false)
regs, err = selg.Thread.Registers()
if err != nil {
return err
}

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

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

@ -41,7 +41,7 @@ type AMD64Registers struct {
// NewAMD64Registers creates a new AMD64Registers struct from a CONTEXT
// 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{
rax: uint64(context.Rax),
rbx: uint64(context.Rbx),
@ -67,16 +67,14 @@ func NewAMD64Registers(context *CONTEXT, TebBaseAddress uint64, floatingPoint bo
tls: TebBaseAddress,
}
if floatingPoint {
regs.fltSave = &context.FltSave
}
regs.fltSave = &context.FltSave
regs.Context = context
return regs
}
// 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 {
k string
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])
}
}
return out
return out, nil
}
// 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.
func (r *AMD64Registers) Copy() proc.Registers {
func (r *AMD64Registers) Copy() (proc.Registers, error) {
var rr AMD64Registers
rr = *r
rr.Context = NewCONTEXT()
*(rr.Context) = *(r.Context)
rr.fltSave = &rr.Context.FltSave
return &rr
return &rr, nil
}
// 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.
func ConvertRegisters(in op.DwarfRegisters, arch *proc.Arch, floatingPoint bool) (out []Register) {
out = make([]Register, 0, len(in.Regs))
for i := range in.Regs {
if floatingPoint {
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))
if reg == nil {
continue

@ -350,7 +350,7 @@ func (d *Debugger) FunctionReturnLocations(fnName string) ([]uint64, error) {
var mem proc.MemoryReadWriter = p.CurrentThread()
if g != nil && g.Thread != nil {
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)
if err != nil {
@ -1159,13 +1159,16 @@ func (d *Debugger) Registers(threadID int, scope *api.EvalScope, floatingPoint b
if !found {
return nil, fmt.Errorf("couldn't find thread %d", threadID)
}
regs, err := thread.Registers(floatingPoint)
regs, err := thread.Registers()
if err != nil {
return nil, err
}
dregs = d.target.BinInfo().Arch.RegistersToDwarfRegisters(0, regs)
}
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
// because the DWARF register numbering for AMD64 is weird.
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 {
curthread = g.Thread
}
regs, _ := curthread.Registers(false)
regs, _ := curthread.Registers()
insts, err := proc.Disassemble(curthread, regs, d.target.Breakpoints(), d.target.BinInfo(), addr1, addr2)
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) {
regs, err := p.CurrentThread().Registers(false)
regs, err := p.CurrentThread().Registers()
if err != nil {
t.Fatalf("Registers error: %v", err)
}