From b9d0ddd82ca2a08bdbc703e91123d87d855d76ed Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Wed, 12 Feb 2020 22:31:48 +0100 Subject: [PATCH] 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 --- pkg/proc/amd64_arch.go | 207 ++++++++++++++++++---- pkg/proc/arch.go | 1 + pkg/proc/arm64_arch.go | 44 +++++ pkg/proc/core/core_test.go | 11 +- pkg/proc/fbsdutil/regs.go | 8 +- pkg/proc/gdbserial/gdbserver.go | 19 +- pkg/proc/linutil/regs_amd64_arch.go | 33 ++-- pkg/proc/linutil/regs_arm64_arch.go | 4 +- pkg/proc/native/registers_darwin_amd64.go | 27 ++- pkg/proc/registers.go | 181 +------------------ pkg/proc/winutil/regs.go | 33 ++-- service/api/conversions.go | 4 +- service/debugger/debugger.go | 2 +- 13 files changed, 292 insertions(+), 282 deletions(-) diff --git a/pkg/proc/amd64_arch.go b/pkg/proc/amd64_arch.go index b6fb445a..63ac7a3a 100644 --- a/pkg/proc/amd64_arch.go +++ b/pkg/proc/amd64_arch.go @@ -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) +} diff --git a/pkg/proc/arch.go b/pkg/proc/arch.go index e6490d22..3c27181e 100644 --- a/pkg/proc/arch.go +++ b/pkg/proc/arch.go @@ -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 ( diff --git a/pkg/proc/arm64_arch.go b/pkg/proc/arm64_arch.go index fad53a86..a0c5273d 100644 --- a/pkg/proc/arm64_arch.go +++ b/pkg/proc/arm64_arch.go @@ -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) +} diff --git a/pkg/proc/core/core_test.go b/pkg/proc/core/core_test.go index b5752043..9e6be602 100644 --- a/pkg/proc/core/core_test.go +++ b/pkg/proc/core/core_test.go @@ -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) } } } diff --git a/pkg/proc/fbsdutil/regs.go b/pkg/proc/fbsdutil/regs.go index eee30e3f..d00bec95 100644 --- a/pkg/proc/fbsdutil/regs.go +++ b/pkg/proc/fbsdutil/regs.go @@ -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...) } diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go index f73d7691..b1f7260e 100644 --- a/pkg/proc/gdbserial/gdbserver.go +++ b/pkg/proc/gdbserial/gdbserver.go @@ -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 diff --git a/pkg/proc/linutil/regs_amd64_arch.go b/pkg/proc/linutil/regs_amd64_arch.go index 1a708d1c..be1781bf 100644 --- a/pkg/proc/linutil/regs_amd64_arch.go +++ b/pkg/proc/linutil/regs_amd64_arch.go @@ -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]) } } diff --git a/pkg/proc/linutil/regs_arm64_arch.go b/pkg/proc/linutil/regs_arm64_arch.go index 6a06f8dc..4373822d 100644 --- a/pkg/proc/linutil/regs_arm64_arch.go +++ b/pkg/proc/linutil/regs_arm64_arch.go @@ -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 } diff --git a/pkg/proc/native/registers_darwin_amd64.go b/pkg/proc/native/registers_darwin_amd64.go index 86bfba20..070eb4df 100644 --- a/pkg/proc/native/registers_darwin_amd64.go +++ b/pkg/proc/native/registers_darwin_amd64.go @@ -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 diff --git a/pkg/proc/registers.go b/pkg/proc/registers.go index 2d884238..1bce1b19 100644 --- a/pkg/proc/registers.go +++ b/pkg/proc/registers.go @@ -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 diff --git a/pkg/proc/winutil/regs.go b/pkg/proc/winutil/regs.go index 46731e96..6ea2baa2 100644 --- a/pkg/proc/winutil/regs.go +++ b/pkg/proc/winutil/regs.go @@ -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 diff --git a/service/api/conversions.go b/service/api/conversions.go index b7dfc1ae..3cf1bd97 100644 --- a/service/api/conversions.go +++ b/service/api/conversions.go @@ -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 } diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index da6a64bc..c0a05f47 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -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 {