proc: only format registers value when it's necessary (#1860)

A significant amount of time is spent generating the string
representation for the proc.Registers object of each thread, since this
field is rarely used (only when the Registers API is called) it should
be generated on demand.

Also by changing the internal representation of proc.Register to be
closer to that of op.DwarfRegister it will help us implement #1838
(when Delve will need to be able to display the registers of an
internal frame, which we currently represent using op.DwarfRegister
objects).

Benchmark before:

BenchmarkConditionalBreakpoints-4   	       1	22292554301 ns/op

Benchmark after:

BenchmarkConditionalBreakpoints-4   	       1	17326345671 ns/op

Reduces conditional breakpoint latency from 2.2ms to 1.7ms.

Updates #1549, #1838
This commit is contained in:
Alessandro Arzilli
2020-02-12 22:31:48 +01:00
committed by GitHub
parent abb57ff017
commit b9d0ddd82c
13 changed files with 292 additions and 282 deletions

View File

@ -1,12 +1,15 @@
package proc
import (
"bytes"
"encoding/binary"
"fmt"
"math"
"os"
"strings"
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
"golang.org/x/arch/x86/x86asm"
)
// AMD64 represents the AMD64 CPU architecture.
@ -300,24 +303,24 @@ func (a *AMD64) RegSize(regnum uint64) int {
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
var amd64DwarfToHardware = map[int]x86asm.Reg{
0: x86asm.RAX,
1: x86asm.RDX,
2: x86asm.RCX,
3: x86asm.RBX,
4: x86asm.RSI,
5: x86asm.RDI,
8: x86asm.R8,
9: x86asm.R9,
10: x86asm.R10,
11: x86asm.R11,
12: x86asm.R12,
13: x86asm.R13,
14: x86asm.R14,
15: x86asm.R15,
}
var amd64DwarfToName = map[int]string{
0: "Rax",
1: "Rdx",
2: "Rcx",
3: "Rbx",
4: "Rsi",
5: "Rdi",
6: "Rbp",
7: "Rsp",
8: "R8",
9: "R9",
10: "R10",
11: "R11",
12: "R12",
13: "R13",
14: "R14",
15: "R15",
16: "Rip",
17: "XMM0",
18: "XMM1",
19: "XMM2",
@ -356,13 +359,25 @@ var amd64DwarfToName = map[int]string{
66: "SW",
}
var amd64NameToDwarf = func() map[string]int {
r := make(map[string]int)
for regNum, regName := range amd64DwarfToName {
r[strings.ToLower(regName)] = regNum
}
r["eflags"] = 49
r["st0"] = 33
r["st1"] = 34
r["st2"] = 35
r["st3"] = 36
r["st4"] = 37
r["st5"] = 38
r["st6"] = 39
r["st7"] = 40
return r
}()
func maxAmd64DwarfRegister() int {
max := int(amd64DwarfIPRegNum)
for i := range amd64DwarfToHardware {
if i > max {
max = i
}
}
for i := range amd64DwarfToName {
if i > max {
max = i
@ -376,22 +391,9 @@ func maxAmd64DwarfRegister() int {
func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1)
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(regs.SP())
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(regs.BP())
for dwarfReg, asmReg := range amd64DwarfToHardware {
v, err := regs.Get(int(asmReg))
if err == nil {
dregs[dwarfReg] = op.DwarfRegisterFromUint64(v)
}
}
for _, reg := range regs.Slice(true) {
for dwarfReg, regName := range amd64DwarfToName {
if regName == reg.Name {
dregs[dwarfReg] = op.DwarfRegisterFromBytes(reg.Bytes)
}
if dwarfReg, ok := amd64NameToDwarf[strings.ToLower(reg.Name)]; ok {
dregs[dwarfReg] = reg.Reg
}
}
@ -422,3 +424,132 @@ func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
BPRegNum: amd64DwarfBPRegNum,
}
}
func (a *AMD64) DwarfRegisterToString(name string, reg *op.DwarfRegister) string {
name = strings.ToLower(name)
switch name {
case "rflags":
return eflagsDescription.Describe(reg.Uint64Val, 64)
case "cw", "sw", "tw", "fop":
return fmt.Sprintf("%#04x", reg.Uint64Val)
case "mxcsr_mask":
return fmt.Sprintf("%#08x", reg.Uint64Val)
case "mxcsr":
return mxcsrDescription.Describe(reg.Uint64Val, 32)
default:
if reg.Bytes != nil && strings.HasPrefix(name, "xmm") {
return formatSSEReg(reg.Bytes)
} else if reg.Bytes != nil && strings.HasPrefix(name, "st(") {
return formatX87Reg(reg.Bytes)
} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) <= 8) {
return fmt.Sprintf("%#016x", reg.Uint64Val)
} else {
return fmt.Sprintf("%#x", reg.Bytes)
}
}
}
func formatSSEReg(xmm []byte) string {
buf := bytes.NewReader(xmm)
var out bytes.Buffer
var vi [16]uint8
for i := range vi {
binary.Read(buf, binary.LittleEndian, &vi[i])
}
fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
buf.Seek(0, os.SEEK_SET)
var v2 [2]float64
for i := range v2 {
binary.Read(buf, binary.LittleEndian, &v2[i])
}
fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
buf.Seek(0, os.SEEK_SET)
var v4 [4]float32
for i := range v4 {
binary.Read(buf, binary.LittleEndian, &v4[i])
}
fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
return out.String()
}
func formatX87Reg(b []byte) string {
if len(b) < 10 {
return fmt.Sprintf("%#x", b)
}
mantissa := binary.LittleEndian.Uint64(b[:8])
exponent := uint16(binary.LittleEndian.Uint16(b[8:]))
var f float64
fset := false
const (
_SIGNBIT = 1 << 15
_EXP_BIAS = (1 << 14) - 1 // 2^(n-1) - 1 = 16383
_SPECIALEXP = (1 << 15) - 1 // all bits set
_HIGHBIT = 1 << 63
_QUIETBIT = 1 << 62
)
sign := 1.0
if exponent&_SIGNBIT != 0 {
sign = -1.0
}
exponent &= ^uint16(_SIGNBIT)
NaN := math.NaN()
Inf := math.Inf(+1)
switch exponent {
case 0:
switch {
case mantissa == 0:
f = sign * 0.0
fset = true
case mantissa&_HIGHBIT != 0:
f = NaN
fset = true
}
case _SPECIALEXP:
switch {
case mantissa&_HIGHBIT == 0:
f = sign * Inf
fset = true
default:
f = NaN // signaling NaN
fset = true
}
default:
if mantissa&_HIGHBIT == 0 {
f = NaN
fset = true
}
}
if !fset {
significand := float64(mantissa) / (1 << 63)
f = sign * math.Ldexp(significand, int(exponent-_EXP_BIAS))
}
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, exponent)
binary.Write(&buf, binary.LittleEndian, mantissa)
return fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)
}

View File

@ -21,6 +21,7 @@ type Arch interface {
RegSize(uint64) int
RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters
AddrAndStackRegsToDwarfRegisters(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
DwarfRegisterToString(string, *op.DwarfRegister) string
}
const (

View File

@ -1,7 +1,10 @@
package proc
import (
"bytes"
"encoding/binary"
"fmt"
"os"
"strings"
"github.com/go-delve/delve/pkg/dwarf/frame"
@ -406,3 +409,44 @@ func (a *ARM64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
LRRegNum: arm64DwarfLRRegNum,
}
}
func (a *ARM64) DwarfRegisterToString(name string, reg *op.DwarfRegister) string {
if reg.Bytes != nil && (name[0] == 'v' || name[0] == 'V') {
buf := bytes.NewReader(reg.Bytes)
var out bytes.Buffer
var vi [16]uint8
for i := range vi {
binary.Read(buf, binary.LittleEndian, &vi[i])
}
fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
buf.Seek(0, os.SEEK_SET)
var v2 [2]float64
for i := range v2 {
binary.Read(buf, binary.LittleEndian, &v2[i])
}
fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
buf.Seek(0, os.SEEK_SET)
var v4 [4]float32
for i := range v4 {
binary.Read(buf, binary.LittleEndian, &v4[i])
}
fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
return out.String()
} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) < 16) {
return fmt.Sprintf("%#016x", reg.Uint64Val)
}
return fmt.Sprintf("%#x", reg.Bytes)
}

View File

@ -244,8 +244,9 @@ func TestCore(t *testing.T) {
t.Fatalf("Couldn't get current thread registers: %v", err)
}
regslice := regs.Slice(true)
arch := p.BinInfo().Arch
for _, reg := range regslice {
t.Logf("%s = %s", reg.Name, reg.Value)
t.Logf("%s = %s", reg.Name, arch.DwarfRegisterToString(reg.Name, reg.Reg))
}
}
@ -312,8 +313,9 @@ func TestCoreFpRegisters(t *testing.T) {
{"XMM8", "0x4059999a404ccccd4059999a404ccccd"},
}
arch := p.BinInfo().Arch
for _, reg := range regs.Slice(true) {
t.Logf("%s = %s", reg.Name, reg.Value)
t.Logf("%s = %s", reg.Name, arch.DwarfRegisterToString(reg.Name, reg.Reg))
}
for _, regtest := range regtests {
@ -321,8 +323,9 @@ func TestCoreFpRegisters(t *testing.T) {
for _, reg := range regs.Slice(true) {
if reg.Name == regtest.name {
found = true
if !strings.HasPrefix(reg.Value, regtest.value) {
t.Fatalf("register %s expected %q got %q", reg.Name, regtest.value, reg.Value)
regval := arch.DwarfRegisterToString(reg.Name, reg.Reg)
if !strings.HasPrefix(regval, regtest.value) {
t.Fatalf("register %s expected %q got %q", reg.Name, regtest.value, regval)
}
}
}

View File

@ -101,17 +101,17 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
// FreeBSD defines the registers as signed, but Linux defines
// them as unsigned. Of course, a register doesn't really have
// a concept of signedness. Cast to what Delve expects.
out = proc.AppendQwordReg(out, reg.k, uint64(reg.v))
out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
}
for _, reg := range regs32 {
out = proc.AppendDwordReg(out, reg.k, reg.v)
out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
}
for _, reg := range regs16 {
out = proc.AppendWordReg(out, reg.k, reg.v)
out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
}
// x86 called this register "Eflags". amd64 extended it and renamed it
// "Rflags", but Linux still uses the old name.
out = proc.AppendEflagReg(out, "Rflags", uint64(r.Regs.Rflags))
out = proc.AppendUint64Register(out, "Rflags", uint64(r.Regs.Rflags))
if floatingPoint {
out = append(out, r.Fpregs...)
}

View File

@ -1903,15 +1903,15 @@ func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register {
}
switch {
case reginfo.Name == "eflags":
r = proc.AppendEflagReg(r, reginfo.Name, uint64(binary.LittleEndian.Uint32(regs.regs[reginfo.Name].value)))
r = proc.AppendBytesRegister(r, "Rflags", regs.regs[reginfo.Name].value)
case reginfo.Name == "mxcsr":
r = proc.AppendMxcsrReg(r, reginfo.Name, uint64(binary.LittleEndian.Uint32(regs.regs[reginfo.Name].value)))
r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
case reginfo.Bitsize == 16:
r = proc.AppendWordReg(r, reginfo.Name, binary.LittleEndian.Uint16(regs.regs[reginfo.Name].value))
r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
case reginfo.Bitsize == 32:
r = proc.AppendDwordReg(r, reginfo.Name, binary.LittleEndian.Uint32(regs.regs[reginfo.Name].value))
r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
case reginfo.Bitsize == 64:
r = proc.AppendQwordReg(r, reginfo.Name, binary.LittleEndian.Uint64(regs.regs[reginfo.Name].value))
r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
case reginfo.Bitsize == 80:
if !floatingPoint {
continue
@ -1923,12 +1923,11 @@ func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register {
break
}
}
value := regs.regs[reginfo.Name].value
r = proc.AppendX87Reg(r, idx, binary.LittleEndian.Uint16(value[8:]), binary.LittleEndian.Uint64(value[:8]))
r = proc.AppendBytesRegister(r, fmt.Sprintf("ST(%d)", idx), regs.regs[reginfo.Name].value)
case reginfo.Bitsize == 128:
if floatingPoint {
r = proc.AppendSSEReg(r, strings.ToUpper(reginfo.Name), regs.regs[reginfo.Name].value)
r = proc.AppendBytesRegister(r, strings.ToUpper(reginfo.Name), regs.regs[reginfo.Name].value)
}
case reginfo.Bitsize == 256:
@ -1938,8 +1937,8 @@ func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register {
value := regs.regs[reginfo.Name].value
xmmName := "x" + reginfo.Name[1:]
r = proc.AppendSSEReg(r, strings.ToUpper(xmmName), value[:16])
r = proc.AppendSSEReg(r, strings.ToUpper(reginfo.Name), value[16:])
r = proc.AppendBytesRegister(r, strings.ToUpper(xmmName), value[:16])
r = proc.AppendBytesRegister(r, strings.ToUpper(reginfo.Name), value[16:])
}
}
return r

View File

@ -75,7 +75,7 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
{"R15", r.Regs.R15},
{"Orig_rax", r.Regs.Orig_rax},
{"Cs", r.Regs.Cs},
{"Eflags", r.Regs.Eflags},
{"Rflags", r.Regs.Eflags},
{"Ss", r.Regs.Ss},
{"Fs_base", r.Regs.Fs_base},
{"Gs_base", r.Regs.Gs_base},
@ -86,11 +86,7 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
}
out := make([]proc.Register, 0, len(regs)+len(r.Fpregs))
for _, reg := range regs {
if reg.k == "Eflags" {
out = proc.AppendEflagReg(out, reg.k, reg.v)
} else {
out = proc.AppendQwordReg(out, reg.k, reg.v)
}
out = proc.AppendUint64Register(out, reg.k, reg.v)
}
if floatingPoint {
out = append(out, r.Fpregs...)
@ -325,25 +321,28 @@ type AMD64Xstate struct {
// Decode decodes an XSAVE area to a list of name/value pairs of registers.
func (xsave *AMD64Xstate) Decode() (regs []proc.Register) {
// x87 registers
regs = proc.AppendWordReg(regs, "CW", xsave.Cwd)
regs = proc.AppendWordReg(regs, "SW", xsave.Swd)
regs = proc.AppendWordReg(regs, "TW", xsave.Ftw)
regs = proc.AppendWordReg(regs, "FOP", xsave.Fop)
regs = proc.AppendQwordReg(regs, "FIP", xsave.Rip)
regs = proc.AppendQwordReg(regs, "FDP", xsave.Rdp)
regs = proc.AppendUint64Register(regs, "CW", uint64(xsave.Cwd))
regs = proc.AppendUint64Register(regs, "SW", uint64(xsave.Swd))
regs = proc.AppendUint64Register(regs, "TW", uint64(xsave.Ftw))
regs = proc.AppendUint64Register(regs, "FOP", uint64(xsave.Fop))
regs = proc.AppendUint64Register(regs, "FIP", xsave.Rip)
regs = proc.AppendUint64Register(regs, "FDP", xsave.Rdp)
for i := 0; i < len(xsave.StSpace); i += 4 {
regs = proc.AppendX87Reg(regs, i/4, uint16(xsave.StSpace[i+2]), uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
binary.Write(&buf, binary.LittleEndian, uint16(xsave.StSpace[i+2]))
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ST(%d)", i/4), buf.Bytes())
}
// SSE registers
regs = proc.AppendMxcsrReg(regs, "MXCSR", uint64(xsave.Mxcsr))
regs = proc.AppendDwordReg(regs, "MXCSR_MASK", xsave.MxcrMask)
regs = proc.AppendUint64Register(regs, "MXCSR", uint64(xsave.Mxcsr))
regs = proc.AppendUint64Register(regs, "MXCSR_MASK", uint64(xsave.MxcrMask))
for i := 0; i < len(xsave.XmmSpace); i += 16 {
regs = proc.AppendSSEReg(regs, fmt.Sprintf("XMM%d", i/16), xsave.XmmSpace[i:i+16])
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("XMM%d", i/16), xsave.XmmSpace[i:i+16])
if xsave.AvxState {
regs = proc.AppendSSEReg(regs, fmt.Sprintf("YMM%d", i/16), xsave.YmmSpace[i:i+16])
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("YMM%d", i/16), xsave.YmmSpace[i:i+16])
}
}

View File

@ -67,7 +67,7 @@ func (r *ARM64Registers) Slice(floatingPoint bool) []proc.Register {
}
out := make([]proc.Register, 0, len(regs64)+len(r.Fpregs))
for _, reg := range regs64 {
out = proc.AppendQwordReg(out, reg.k, reg.v)
out = proc.AppendUint64Register(out, reg.k, reg.v)
}
out = append(out, r.Fpregs...)
return out
@ -128,7 +128,7 @@ func (r *ARM64Registers) Copy() proc.Registers {
// Decode decodes an XSAVE area to a list of name/value pairs of registers.
func Decode(fpregs []byte) (regs []proc.Register) {
for i := 0; i < len(fpregs); i += 16 {
regs = proc.AppendFPReg(regs, fmt.Sprintf("V%d", i/16), fpregs[i:i+16])
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("V%d", i/16), fpregs[i:i+16])
}
return
}

View File

@ -5,7 +5,6 @@ package native
// #include "threads_darwin.h"
import "C"
import (
"encoding/binary"
"errors"
"fmt"
"unsafe"
@ -73,9 +72,9 @@ func (r *Regs) Slice(floatingPoint bool) []proc.Register {
out := make([]proc.Register, 0, len(regs)+len(r.fpregs))
for _, reg := range regs {
if reg.k == "Rflags" {
out = proc.AppendEflagReg(out, reg.k, reg.v)
out = proc.AppendUint64Register(out, reg.k, reg.v)
} else {
out = proc.AppendQwordReg(out, reg.k, reg.v)
out = proc.AppendUint64Register(out, reg.k, reg.v)
}
}
if floatingPoint {
@ -342,25 +341,23 @@ func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
return nil, fmt.Errorf("could not get floating point registers")
}
regs.fpregs = proc.AppendWordReg(regs.fpregs, "CW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw))))
regs.fpregs = proc.AppendWordReg(regs.fpregs, "SW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw))))
regs.fpregs = proc.AppendWordReg(regs.fpregs, "TW", uint16(fpstate.__fpu_ftw))
regs.fpregs = proc.AppendWordReg(regs.fpregs, "FOP", uint16(fpstate.__fpu_fop))
regs.fpregs = proc.AppendQwordReg(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip))
regs.fpregs = proc.AppendQwordReg(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp))
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)
mantissa := binary.LittleEndian.Uint64(stb[:8])
exponent := binary.LittleEndian.Uint16(stb[8:])
regs.fpregs = proc.AppendX87Reg(regs.fpregs, i, exponent, mantissa)
regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("ST(%d)", i), stb)
}
regs.fpregs = proc.AppendMxcsrReg(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr))
regs.fpregs = proc.AppendDwordReg(regs.fpregs, "MXCSR_MASK", uint32(fpstate.__fpu_mxcsrmask))
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.AppendSSEReg(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
}
}
return regs, nil

View File

@ -1,13 +1,12 @@
package proc
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math"
"os"
"strings"
"github.com/go-delve/delve/pkg/dwarf/op"
)
// Registers is an interface for a generic register type. The
@ -30,180 +29,16 @@ type Registers interface {
// Register represents a CPU register.
type Register struct {
Name string
Bytes []byte
Value string
Name string
Reg *op.DwarfRegister
}
// AppendWordReg appends a word (16 bit) register to regs.
func AppendWordReg(regs []Register, name string, value uint16) []Register {
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, value)
return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#04x", value)})
func AppendUint64Register(regs []Register, name string, value uint64) []Register {
return append(regs, Register{name, op.DwarfRegisterFromUint64(value)})
}
// AppendDwordReg appends a double word (32 bit) register to regs.
func AppendDwordReg(regs []Register, name string, value uint32) []Register {
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, value)
return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#08x", value)})
}
// AppendQwordReg appends a quad word (64 bit) register to regs.
func AppendQwordReg(regs []Register, name string, value uint64) []Register {
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, value)
return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#016x", value)})
}
func appendFlagReg(regs []Register, name string, value uint64, descr flagRegisterDescr, size int) []Register {
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, value)
return append(regs, Register{name, buf.Bytes()[:size], descr.Describe(value, size)})
}
// AppendEflagReg appends EFLAG register to regs.
func AppendEflagReg(regs []Register, name string, value uint64) []Register {
return appendFlagReg(regs, name, value, eflagsDescription, 64)
}
// AppendMxcsrReg appends MXCSR register to regs.
func AppendMxcsrReg(regs []Register, name string, value uint64) []Register {
return appendFlagReg(regs, name, value, mxcsrDescription, 32)
}
// AppendX87Reg appends a 80 bit float register to regs.
func AppendX87Reg(regs []Register, index int, exponent uint16, mantissa uint64) []Register {
var f float64
fset := false
const (
_SIGNBIT = 1 << 15
_EXP_BIAS = (1 << 14) - 1 // 2^(n-1) - 1 = 16383
_SPECIALEXP = (1 << 15) - 1 // all bits set
_HIGHBIT = 1 << 63
_QUIETBIT = 1 << 62
)
sign := 1.0
if exponent&_SIGNBIT != 0 {
sign = -1.0
}
exponent &= ^uint16(_SIGNBIT)
NaN := math.NaN()
Inf := math.Inf(+1)
switch exponent {
case 0:
switch {
case mantissa == 0:
f = sign * 0.0
fset = true
case mantissa&_HIGHBIT != 0:
f = NaN
fset = true
}
case _SPECIALEXP:
switch {
case mantissa&_HIGHBIT == 0:
f = sign * Inf
fset = true
default:
f = NaN // signaling NaN
fset = true
}
default:
if mantissa&_HIGHBIT == 0 {
f = NaN
fset = true
}
}
if !fset {
significand := float64(mantissa) / (1 << 63)
f = sign * math.Ldexp(significand, int(exponent-_EXP_BIAS))
}
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, exponent)
binary.Write(&buf, binary.LittleEndian, mantissa)
return append(regs, Register{fmt.Sprintf("ST(%d)", index), buf.Bytes(), fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)})
}
// AppendSSEReg appends a 256 bit SSE register to regs.
func AppendSSEReg(regs []Register, name string, xmm []byte) []Register {
buf := bytes.NewReader(xmm)
var out bytes.Buffer
var vi [16]uint8
for i := range vi {
binary.Read(buf, binary.LittleEndian, &vi[i])
}
fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
buf.Seek(0, os.SEEK_SET)
var v2 [2]float64
for i := range v2 {
binary.Read(buf, binary.LittleEndian, &v2[i])
}
fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
buf.Seek(0, os.SEEK_SET)
var v4 [4]float32
for i := range v4 {
binary.Read(buf, binary.LittleEndian, &v4[i])
}
fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
return append(regs, Register{name, xmm, out.String()})
}
// AppendFPReg appends a 128 bit FP register to regs.
func AppendFPReg(regs []Register, name string, reg_value []byte) []Register {
buf := bytes.NewReader(reg_value)
var out bytes.Buffer
var vi [16]uint8
for i := range vi {
binary.Read(buf, binary.LittleEndian, &vi[i])
}
fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
buf.Seek(0, os.SEEK_SET)
var v2 [2]float64
for i := range v2 {
binary.Read(buf, binary.LittleEndian, &v2[i])
}
fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
buf.Seek(0, os.SEEK_SET)
var v4 [4]float32
for i := range v4 {
binary.Read(buf, binary.LittleEndian, &v4[i])
}
fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
return append(regs, Register{name, reg_value, out.String()})
func AppendBytesRegister(regs []Register, name string, value []byte) []Register {
return append(regs, Register{name, op.DwarfRegisterFromBytes(value)})
}
// ErrUnknownRegister is returned when the value of an unknown

View File

@ -1,6 +1,8 @@
package winutil
import (
"bytes"
"encoding/binary"
"fmt"
"unsafe"
@ -96,7 +98,7 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
{"R13", r.r13},
{"R14", r.r14},
{"R15", r.r15},
{"Eflags", r.eflags},
{"Rflags", r.eflags},
{"Cs", r.cs},
{"Fs", r.fs},
{"Gs", r.gs},
@ -108,29 +110,28 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
}
out := make([]proc.Register, 0, outlen)
for _, reg := range regs {
if reg.k == "Eflags" {
out = proc.AppendEflagReg(out, reg.k, reg.v)
} else {
out = proc.AppendQwordReg(out, reg.k, reg.v)
}
out = proc.AppendUint64Register(out, reg.k, reg.v)
}
if r.fltSave != nil && floatingPoint {
out = proc.AppendWordReg(out, "CW", r.fltSave.ControlWord)
out = proc.AppendWordReg(out, "SW", r.fltSave.StatusWord)
out = proc.AppendWordReg(out, "TW", uint16(r.fltSave.TagWord))
out = proc.AppendWordReg(out, "FOP", r.fltSave.ErrorOpcode)
out = proc.AppendQwordReg(out, "FIP", uint64(r.fltSave.ErrorSelector)<<32|uint64(r.fltSave.ErrorOffset))
out = proc.AppendQwordReg(out, "FDP", uint64(r.fltSave.DataSelector)<<32|uint64(r.fltSave.DataOffset))
out = proc.AppendUint64Register(out, "CW", uint64(r.fltSave.ControlWord))
out = proc.AppendUint64Register(out, "SW", uint64(r.fltSave.StatusWord))
out = proc.AppendUint64Register(out, "TW", uint64(uint16(r.fltSave.TagWord)))
out = proc.AppendUint64Register(out, "FOP", uint64(r.fltSave.ErrorOpcode))
out = proc.AppendUint64Register(out, "FIP", uint64(r.fltSave.ErrorSelector)<<32|uint64(r.fltSave.ErrorOffset))
out = proc.AppendUint64Register(out, "FDP", uint64(r.fltSave.DataSelector)<<32|uint64(r.fltSave.DataOffset))
for i := range r.fltSave.FloatRegisters {
out = proc.AppendX87Reg(out, i, uint16(r.fltSave.FloatRegisters[i].High), r.fltSave.FloatRegisters[i].Low)
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, r.fltSave.FloatRegisters[i].Low)
binary.Write(&buf, binary.LittleEndian, r.fltSave.FloatRegisters[i].High)
out = proc.AppendBytesRegister(out, fmt.Sprintf("ST(%d)", i), buf.Bytes())
}
out = proc.AppendMxcsrReg(out, "MXCSR", uint64(r.fltSave.MxCsr))
out = proc.AppendDwordReg(out, "MXCSR_MASK", r.fltSave.MxCsr_Mask)
out = proc.AppendUint64Register(out, "MXCSR", uint64(r.fltSave.MxCsr))
out = proc.AppendUint64Register(out, "MXCSR_MASK", uint64(r.fltSave.MxCsr_Mask))
for i := 0; i < len(r.fltSave.XmmRegisters); i += 16 {
out = proc.AppendSSEReg(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

View File

@ -328,10 +328,10 @@ func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig {
}
// ConvertRegisters converts proc.Register to api.Register for a slice.
func ConvertRegisters(in []proc.Register) (out []Register) {
func ConvertRegisters(in []proc.Register, arch proc.Arch) (out []Register) {
out = make([]Register, len(in))
for i := range in {
out[i] = Register{in[i].Name, in[i].Value}
out[i] = Register{in[i].Name, arch.DwarfRegisterToString(in[i].Name, in[i].Reg)}
}
return
}

View File

@ -961,7 +961,7 @@ func (d *Debugger) Registers(threadID int, floatingPoint bool) (api.Registers, e
if err != nil {
return nil, err
}
return api.ConvertRegisters(regs.Slice(floatingPoint)), err
return api.ConvertRegisters(regs.Slice(floatingPoint), d.target.BinInfo().Arch), err
}
func convertVars(pv []*proc.Variable) []api.Variable {