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 {