proc/*: implement proc.(*compositeMemory).WriteMemory (#2271)

Delve represents registerized variables (fully or partially) using
compositeMemory, implementing proc.(*compositeMemory).WriteMemory is
necessary to make SetVariable and function calls work when Go will
switch to using the register calling convention in 1.17.

This commit also makes some refactoring by moving the code that
converts between register numbers and register names out of pkg/proc
into a different package.
This commit is contained in:
Alessandro Arzilli 2021-03-04 19:28:28 +01:00 committed by GitHub
parent 3088b8b579
commit 6a70d531bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 910 additions and 431 deletions

@ -1,20 +1,21 @@
Tests skipped by each supported backend:
* 386 skipped = 2.7% (4/147)
* 386 skipped = 2.7% (4/148)
* 1 broken
* 3 broken - cgo stacktraces
* arm64 skipped = 2.7% (4/147)
* arm64 skipped = 2.7% (4/148)
* 2 broken
* 1 broken - cgo stacktraces
* 1 broken - global variable symbolication
* darwin/lldb skipped = 0.68% (1/147)
* darwin/lldb skipped = 0.68% (1/148)
* 1 upstream issue
* freebsd skipped = 7.5% (11/147)
* freebsd skipped = 8.1% (12/148)
* 11 broken
* linux/386/pie skipped = 0.68% (1/147)
* 1 not implemented
* linux/386/pie skipped = 0.68% (1/148)
* 1 broken
* pie skipped = 0.68% (1/147)
* pie skipped = 0.68% (1/148)
* 1 upstream issue - https://github.com/golang/go/issues/29322
* windows skipped = 1.4% (2/147)
* windows skipped = 1.4% (2/148)
* 1 broken
* 1 upstream issue

@ -19,6 +19,7 @@ type DwarfRegisters struct {
SPRegNum uint64
BPRegNum uint64
LRRegNum uint64
ChangeFunc RegisterChangeFunc
FloatLoadError error // error produced when loading floating point registers
loadMoreCallback func()
@ -29,6 +30,8 @@ type DwarfRegister struct {
Bytes []byte
}
type RegisterChangeFunc func(regNum uint64, reg *DwarfRegister) error
// NewDwarfRegisters returns a new DwarfRegisters object.
func NewDwarfRegisters(staticBase uint64, regs []*DwarfRegister, byteOrder binary.ByteOrder, pcRegNum, spRegNum, bpRegNum, lrRegNum uint64) *DwarfRegisters {
return &DwarfRegisters{
@ -152,3 +155,12 @@ func DwarfRegisterFromBytes(bytes []byte) *DwarfRegister {
}
return &DwarfRegister{Uint64Val: v, Bytes: bytes}
}
// FillBytes fills the Bytes slice of reg using Uint64Val.
func (reg *DwarfRegister) FillBytes() {
if reg.Bytes != nil {
return
}
reg.Bytes = make([]byte, 8)
binary.LittleEndian.PutUint64(reg.Bytes, reg.Uint64Val)
}

136
pkg/dwarf/regnum/amd64.go Normal file

@ -0,0 +1,136 @@
package regnum
import (
"fmt"
"strings"
)
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
const (
AMD64_Rax = 0
AMD64_Rdx = 1
AMD64_Rcx = 2
AMD64_Rbx = 3
AMD64_Rsi = 4
AMD64_Rdi = 5
AMD64_Rbp = 6
AMD64_Rsp = 7
AMD64_R8 = 8
AMD64_R9 = 9
AMD64_R10 = 10
AMD64_R11 = 11
AMD64_R12 = 12
AMD64_R13 = 13
AMD64_R14 = 14
AMD64_R15 = 15
AMD64_Rip = 16
AMD64_XMM0 = 17 // XMM1 through XMM15 follow
AMD64_ST0 = 33 // ST(1) through ST(7) follow
AMD64_Rflags = 49
AMD64_Es = 50
AMD64_Cs = 51
AMD64_Ss = 52
AMD64_Ds = 53
AMD64_Fs = 54
AMD64_Gs = 55
AMD64_Fs_base = 58
AMD64_Gs_base = 59
AMD64_MXCSR = 64
AMD64_CW = 65
AMD64_SW = 66
)
var amd64DwarfToName = map[uint64]string{
AMD64_Rax: "Rax",
AMD64_Rdx: "Rdx",
AMD64_Rcx: "Rcx",
AMD64_Rbx: "Rbx",
AMD64_Rsi: "Rsi",
AMD64_Rdi: "Rdi",
AMD64_Rbp: "Rbp",
AMD64_Rsp: "Rsp",
AMD64_R8: "R8",
AMD64_R9: "R9",
AMD64_R10: "R10",
AMD64_R11: "R11",
AMD64_R12: "R12",
AMD64_R13: "R13",
AMD64_R14: "R14",
AMD64_R15: "R15",
AMD64_Rip: "Rip",
AMD64_XMM0: "XMM0",
AMD64_XMM0 + 1: "XMM1",
AMD64_XMM0 + 2: "XMM2",
AMD64_XMM0 + 3: "XMM3",
AMD64_XMM0 + 4: "XMM4",
AMD64_XMM0 + 5: "XMM5",
AMD64_XMM0 + 6: "XMM6",
AMD64_XMM0 + 7: "XMM7",
AMD64_XMM0 + 8: "XMM8",
AMD64_XMM0 + 9: "XMM9",
AMD64_XMM0 + 10: "XMM10",
AMD64_XMM0 + 11: "XMM11",
AMD64_XMM0 + 12: "XMM12",
AMD64_XMM0 + 13: "XMM13",
AMD64_XMM0 + 14: "XMM14",
AMD64_XMM0 + 15: "XMM15",
AMD64_ST0: "ST(0)",
AMD64_ST0 + 1: "ST(1)",
AMD64_ST0 + 2: "ST(2)",
AMD64_ST0 + 3: "ST(3)",
AMD64_ST0 + 4: "ST(4)",
AMD64_ST0 + 5: "ST(5)",
AMD64_ST0 + 6: "ST(6)",
AMD64_ST0 + 7: "ST(7)",
AMD64_Rflags: "Rflags",
AMD64_Es: "Es",
AMD64_Cs: "Cs",
AMD64_Ss: "Ss",
AMD64_Ds: "Ds",
AMD64_Fs: "Fs",
AMD64_Gs: "Gs",
AMD64_Fs_base: "Fs_base",
AMD64_Gs_base: "Gs_base",
AMD64_MXCSR: "MXCSR",
AMD64_CW: "CW",
AMD64_SW: "SW",
}
var AMD64NameToDwarf = func() map[string]int {
r := make(map[string]int)
for regNum, regName := range amd64DwarfToName {
r[strings.ToLower(regName)] = int(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 AMD64MaxRegNum() uint64 {
max := uint64(AMD64_Rip)
for i := range amd64DwarfToName {
if i > max {
max = i
}
}
return max
}
func AMD64ToName(num uint64) string {
name, ok := amd64DwarfToName[num]
if ok {
return name
}
return fmt.Sprintf("unknown%d", num)
}

35
pkg/dwarf/regnum/arm64.go Normal file

@ -0,0 +1,35 @@
package regnum
import (
"fmt"
)
// The mapping between hardware registers and DWARF registers is specified
// in the DWARF for the ARM® Architecture page 7,
// Table 1
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf
const (
ARM64_X0 = 0 // X1 through X30 follow
ARM64_BP = 29 // also X29
ARM64_LR = 30 // also X30
ARM64_SP = 31
ARM64_PC = 32
ARM64_V0 = 64 // V1 through V31 follow
)
func ARM64ToName(num uint64) string {
switch {
case num <= 30:
return fmt.Sprintf("X%d", num)
case num == ARM64_SP:
return "SP"
case num == ARM64_PC:
return "PC"
case num >= ARM64_V0 && num <= 95:
return fmt.Sprintf("V%d", num-64)
default:
return fmt.Sprintf("unknown%d", num)
}
}

102
pkg/dwarf/regnum/i386.go Normal file

@ -0,0 +1,102 @@
package regnum
import (
"fmt"
"strings"
)
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI Intel386 Architecture Processor Supplement page 25,
// table 2.14
// https://www.uclibc.org/docs/psABI-i386.pdf
const (
I386_Eax = 0
I386_Ecx = 1
I386_Edx = 2
I386_Ebx = 3
I386_Esp = 4
I386_Ebp = 5
I386_Esi = 6
I386_Edi = 7
I386_Eip = 8
I386_Eflags = 9
I386_ST0 = 11 // ST(1) through ST(7) follow
I386_XMM0 = 21 // XMM1 through XMM7 follow
I386_Es = 40
I386_Cs = 41
I386_Ss = 42
I386_Ds = 43
I386_Fs = 44
I386_Gs = 45
)
var i386DwarfToName = map[int]string{
I386_Eax: "Eax",
I386_Ecx: "Ecx",
I386_Edx: "Edx",
I386_Ebx: "Ebx",
I386_Esp: "Esp",
I386_Ebp: "Ebp",
I386_Esi: "Esi",
I386_Edi: "Edi",
I386_Eip: "Eip",
I386_Eflags: "Eflags",
I386_ST0: "ST(0)",
I386_ST0 + 1: "ST(1)",
I386_ST0 + 2: "ST(2)",
I386_ST0 + 3: "ST(3)",
I386_ST0 + 4: "ST(4)",
I386_ST0 + 5: "ST(5)",
I386_ST0 + 6: "ST(6)",
I386_ST0 + 7: "ST(7)",
I386_XMM0: "XMM0",
I386_XMM0 + 1: "XMM1",
I386_XMM0 + 2: "XMM2",
I386_XMM0 + 3: "XMM3",
I386_XMM0 + 4: "XMM4",
I386_XMM0 + 5: "XMM5",
I386_XMM0 + 6: "XMM6",
I386_XMM0 + 7: "XMM7",
I386_Es: "Es",
I386_Cs: "Cs",
I386_Ss: "Ss",
I386_Ds: "Ds",
I386_Fs: "Fs",
I386_Gs: "Gs",
}
var I386NameToDwarf = func() map[string]int {
r := make(map[string]int)
for regNum, regName := range i386DwarfToName {
r[strings.ToLower(regName)] = regNum
}
r["eflags"] = 9
r["st0"] = 11
r["st1"] = 12
r["st2"] = 13
r["st3"] = 14
r["st4"] = 15
r["st5"] = 16
r["st6"] = 17
r["st7"] = 18
return r
}()
func I386MaxRegNum() int {
max := int(I386_Eip)
for i := range i386DwarfToName {
if i > max {
max = i
}
}
return max
}
func I386ToName(num int) string {
name, ok := i386DwarfToName[num]
if ok {
return name
}
return fmt.Sprintf("unknown%d", num)
}

@ -10,12 +10,7 @@ import (
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
)
const (
amd64DwarfIPRegNum uint64 = 16
amd64DwarfSPRegNum uint64 = 7
amd64DwarfBPRegNum uint64 = 6
"github.com/go-delve/delve/pkg/dwarf/regnum"
)
var amd64BreakInstruction = []byte{0xCC}
@ -39,6 +34,10 @@ func AMD64Arch(goos string) *Arch {
DwarfRegisterToString: amd64DwarfRegisterToString,
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
asmDecode: amd64AsmDecode,
PCRegNum: regnum.AMD64_Rip,
SPRegNum: regnum.AMD64_Rsp,
BPRegNum: regnum.AMD64_Rbp,
ContextRegNum: regnum.AMD64_Rdx,
}
}
@ -68,24 +67,24 @@ func amd64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *Binary
// here).
return &frame.FrameContext{
RetAddrReg: amd64DwarfIPRegNum,
RetAddrReg: regnum.AMD64_Rip,
Regs: map[uint64]frame.DWRule{
amd64DwarfIPRegNum: {
regnum.AMD64_Rip: {
Rule: frame.RuleOffset,
Offset: int64(-a.PtrSize()),
},
amd64DwarfBPRegNum: {
regnum.AMD64_Rbp: {
Rule: frame.RuleOffset,
Offset: int64(-2 * a.PtrSize()),
},
amd64DwarfSPRegNum: {
regnum.AMD64_Rsp: {
Rule: frame.RuleValOffset,
Offset: 0,
},
},
CFA: frame.DWRule{
Rule: frame.RuleCFA,
Reg: amd64DwarfBPRegNum,
Reg: regnum.AMD64_Rbp,
Offset: int64(2 * a.PtrSize()),
},
}
@ -112,10 +111,10 @@ func amd64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *Binary
// so that we can use it to unwind the stack even when we encounter frames
// without descriptor entries.
// If there isn't a rule already we emit one.
if fctxt.Regs[amd64DwarfBPRegNum].Rule == frame.RuleUndefined {
fctxt.Regs[amd64DwarfBPRegNum] = frame.DWRule{
if fctxt.Regs[regnum.AMD64_Rbp].Rule == frame.RuleUndefined {
fctxt.Regs[regnum.AMD64_Rbp] = frame.DWRule{
Rule: frame.RuleFramePointer,
Reg: amd64DwarfBPRegNum,
Reg: regnum.AMD64_Rbp,
Offset: 0,
}
}
@ -244,110 +243,22 @@ func amd64SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
func amd64RegSize(regnum uint64) int {
func amd64RegSize(rn uint64) int {
// XMM registers
if regnum > amd64DwarfIPRegNum && regnum <= 32 {
if rn > regnum.AMD64_Rip && rn <= 32 {
return 16
}
// x87 registers
if regnum >= 33 && regnum <= 40 {
if rn >= 33 && rn <= 40 {
return 10
}
return 8
}
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
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",
20: "XMM3",
21: "XMM4",
22: "XMM5",
23: "XMM6",
24: "XMM7",
25: "XMM8",
26: "XMM9",
27: "XMM10",
28: "XMM11",
29: "XMM12",
30: "XMM13",
31: "XMM14",
32: "XMM15",
33: "ST(0)",
34: "ST(1)",
35: "ST(2)",
36: "ST(3)",
37: "ST(4)",
38: "ST(5)",
39: "ST(6)",
40: "ST(7)",
49: "Rflags",
50: "Es",
51: "Cs",
52: "Ss",
53: "Ds",
54: "Fs",
55: "Gs",
58: "Fs_base",
59: "Gs_base",
64: "MXCSR",
65: "CW",
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 amd64DwarfToName {
if i > max {
max = i
}
}
return max
}
func amd64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := initDwarfRegistersFromSlice(maxAmd64DwarfRegister(), regs, amd64NameToDwarf)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, amd64DwarfIPRegNum, amd64DwarfSPRegNum, amd64DwarfBPRegNum, 0)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, amd64NameToDwarf))
dregs := initDwarfRegistersFromSlice(int(regnum.AMD64MaxRegNum()), regs, regnum.AMD64NameToDwarf)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.AMD64_Rip, regnum.AMD64_Rsp, regnum.AMD64_Rbp, 0)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, regnum.AMD64NameToDwarf))
return *dr
}
@ -389,18 +300,19 @@ func loadMoreDwarfRegistersFromSliceFunc(dr *op.DwarfRegisters, regs Registers,
}
func amd64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
dregs := make([]*op.DwarfRegister, regnum.AMD64_Rip+1)
dregs[regnum.AMD64_Rip] = op.DwarfRegisterFromUint64(pc)
dregs[regnum.AMD64_Rsp] = op.DwarfRegisterFromUint64(sp)
dregs[regnum.AMD64_Rbp] = op.DwarfRegisterFromUint64(bp)
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, amd64DwarfIPRegNum, amd64DwarfSPRegNum, amd64DwarfBPRegNum, 0)
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.AMD64_Rip, regnum.AMD64_Rsp, regnum.AMD64_Rbp, 0)
}
func amd64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
name, ok := amd64DwarfToName[i]
if !ok {
name = fmt.Sprintf("unknown%d", i)
name = regnum.AMD64ToName(uint64(i))
if reg == nil {
return name, false, ""
}
switch n := strings.ToLower(name); n {

@ -74,6 +74,7 @@ func (xsave *AMD64Xstate) Decode() []proc.Register {
const (
_XSTATE_MAX_KNOWN_SIZE = 2969
_XSAVE_XMM_REGION_START = 160
_XSAVE_HEADER_START = 512
_XSAVE_HEADER_LEN = 64
_XSAVE_EXTENDED_REGION_START = 576
@ -129,3 +130,61 @@ func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate) er
return nil
}
func (xstate *AMD64Xstate) SetXmmRegister(n int, value []byte) error {
if n >= 16 {
return fmt.Errorf("setting register XMM%d not supported", n)
}
if len(value) > 64 {
return fmt.Errorf("value of register XMM%d too large (%d bytes)", n, len(value))
}
// Copy least significant 16 bytes to Xsave area
xmmval := value
if len(xmmval) > 16 {
xmmval = xmmval[:16]
}
rest := value[len(xmmval):]
xmmpos := _XSAVE_XMM_REGION_START + (n * 16)
if xmmpos >= len(xstate.Xsave) {
return fmt.Errorf("could not set XMM%d: not in XSAVE area", n)
}
copy(xstate.Xsave[xmmpos:], xmmval)
if len(rest) == 0 {
return nil
}
// Copy bytes [16, 32) to Xsave area
ymmval := rest
if len(ymmval) > 16 {
ymmval = ymmval[:16]
}
rest = rest[len(ymmval):]
ymmpos := _XSAVE_EXTENDED_REGION_START + (n * 16)
if ymmpos >= len(xstate.Xsave) {
return fmt.Errorf("could not set XMM%d: bytes 16..%d not in XSAVE area", n, 16+len(ymmval))
}
copy(xstate.Xsave[ymmpos:], ymmval)
if len(rest) == 0 {
return nil
}
// Copy bytes [32, 64) to Xsave area
zmmval := rest
zmmpos := _XSAVE_AVX512_ZMM_REGION_START + (n * 32)
if zmmpos >= len(xstate.Xsave) {
return fmt.Errorf("could not set XMM%d: bytes 32..%d not in XSAVE area", n, 32+len(zmmval))
}
copy(xstate.Xsave[zmmpos:], zmmval)
return nil
}

@ -17,6 +17,10 @@ type Arch struct {
breakInstrMovesPC bool
derefTLS bool
usesLR bool // architecture uses a link register, also called RA on some architectures
PCRegNum uint64
SPRegNum uint64
BPRegNum uint64
ContextRegNum uint64 // register used to pass a closure context when calling a function pointer
// asmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
// It assumes that the Loc and AtPC fields of asmInst have already been filled.
@ -34,7 +38,9 @@ type Arch struct {
// addrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
addrAndStackRegsToDwarfRegisters func(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
// DwarfRegisterToString returns the name and value representation of the given register.
// DwarfRegisterToString returns the name and value representation of the
// given register, the register value can be nil in which case only the
// register name will be returned.
DwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string)
// inhibitStepInto returns whether StepBreakpoint can be set at pc.
inhibitStepInto func(bi *BinaryInfo, pc uint64) bool

@ -8,16 +8,10 @@ import (
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"golang.org/x/arch/arm64/arm64asm"
)
const (
arm64DwarfIPRegNum uint64 = 32
arm64DwarfSPRegNum uint64 = 31
arm64DwarfLRRegNum uint64 = 30
arm64DwarfBPRegNum uint64 = 29
)
var arm64BreakInstruction = []byte{0x0, 0x0, 0x20, 0xd4}
// ARM64Arch returns an initialized ARM64
@ -40,6 +34,8 @@ func ARM64Arch(goos string) *Arch {
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
asmDecode: arm64AsmDecode,
usesLR: true,
PCRegNum: regnum.ARM64_PC,
SPRegNum: regnum.ARM64_SP,
}
}
@ -69,24 +65,24 @@ func arm64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *Binary
// here).
return &frame.FrameContext{
RetAddrReg: arm64DwarfIPRegNum,
RetAddrReg: regnum.ARM64_PC,
Regs: map[uint64]frame.DWRule{
arm64DwarfIPRegNum: frame.DWRule{
regnum.ARM64_PC: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-a.PtrSize()),
},
arm64DwarfBPRegNum: frame.DWRule{
regnum.ARM64_BP: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-2 * a.PtrSize()),
},
arm64DwarfSPRegNum: frame.DWRule{
regnum.ARM64_SP: frame.DWRule{
Rule: frame.RuleValOffset,
Offset: 0,
},
},
CFA: frame.DWRule{
Rule: frame.RuleCFA,
Reg: arm64DwarfBPRegNum,
Reg: regnum.ARM64_BP,
Offset: int64(2 * a.PtrSize()),
},
}
@ -113,17 +109,17 @@ func arm64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *Binary
// so that we can use it to unwind the stack even when we encounter frames
// without descriptor entries.
// If there isn't a rule already we emit one.
if fctxt.Regs[arm64DwarfBPRegNum].Rule == frame.RuleUndefined {
fctxt.Regs[arm64DwarfBPRegNum] = frame.DWRule{
if fctxt.Regs[regnum.ARM64_BP].Rule == frame.RuleUndefined {
fctxt.Regs[regnum.ARM64_BP] = frame.DWRule{
Rule: frame.RuleFramePointer,
Reg: arm64DwarfBPRegNum,
Reg: regnum.ARM64_BP,
Offset: 0,
}
}
if fctxt.Regs[arm64DwarfLRRegNum].Rule == frame.RuleUndefined {
fctxt.Regs[arm64DwarfLRRegNum] = frame.DWRule{
if fctxt.Regs[regnum.ARM64_LR].Rule == frame.RuleUndefined {
fctxt.Regs[regnum.ARM64_LR] = frame.DWRule{
Rule: frame.RuleFramePointer,
Reg: arm64DwarfLRRegNum,
Reg: regnum.ARM64_LR,
Offset: 0,
}
}
@ -317,8 +313,8 @@ var arm64NameToDwarf = func() map[string]int {
for i := 0; i <= 30; i++ {
r[fmt.Sprintf("x%d", i)] = i
}
r["pc"] = int(arm64DwarfIPRegNum)
r["lr"] = int(arm64DwarfLRRegNum)
r["pc"] = int(regnum.ARM64_PC)
r["lr"] = int(regnum.ARM64_LR)
r["sp"] = 31
for i := 0; i <= 31; i++ {
r[fmt.Sprintf("v%d", i)] = i + 64
@ -327,7 +323,7 @@ var arm64NameToDwarf = func() map[string]int {
}()
func maxArm64DwarfRegister() int {
max := int(arm64DwarfIPRegNum)
max := int(regnum.ARM64_PC)
for i := range arm64DwarfToHardware {
if i > max {
max = i
@ -339,11 +335,11 @@ func maxArm64DwarfRegister() int {
func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxArm64DwarfRegister()+1)
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(regs.SP())
dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(regs.BP())
dregs[regnum.ARM64_PC] = op.DwarfRegisterFromUint64(regs.PC())
dregs[regnum.ARM64_SP] = op.DwarfRegisterFromUint64(regs.SP())
dregs[regnum.ARM64_BP] = op.DwarfRegisterFromUint64(regs.BP())
if lr, err := regs.Get(int(arm64asm.X30)); err != nil {
dregs[arm64DwarfLRRegNum] = op.DwarfRegisterFromUint64(lr)
dregs[regnum.ARM64_LR] = op.DwarfRegisterFromUint64(lr)
}
for dwarfReg, asmReg := range arm64DwarfToHardware {
@ -353,34 +349,26 @@ func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfR
}
}
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, arm64DwarfIPRegNum, arm64DwarfSPRegNum, arm64DwarfBPRegNum, arm64DwarfLRRegNum)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.ARM64_PC, regnum.ARM64_SP, regnum.ARM64_BP, regnum.ARM64_LR)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, arm64NameToDwarf))
return *dr
}
func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, arm64DwarfIPRegNum+1)
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
dregs[arm64DwarfLRRegNum] = op.DwarfRegisterFromUint64(lr)
dregs := make([]*op.DwarfRegister, regnum.ARM64_PC+1)
dregs[regnum.ARM64_PC] = op.DwarfRegisterFromUint64(pc)
dregs[regnum.ARM64_SP] = op.DwarfRegisterFromUint64(sp)
dregs[regnum.ARM64_BP] = op.DwarfRegisterFromUint64(bp)
dregs[regnum.ARM64_LR] = op.DwarfRegisterFromUint64(lr)
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, arm64DwarfIPRegNum, arm64DwarfSPRegNum, arm64DwarfBPRegNum, arm64DwarfLRRegNum)
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.ARM64_PC, regnum.ARM64_SP, regnum.ARM64_BP, regnum.ARM64_LR)
}
func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
// see arm64DwarfToHardware table for explanation
switch {
case i <= 30:
name = fmt.Sprintf("X%d", i)
case i == 31:
name = "SP"
case i == 32:
name = "PC"
case i >= 64 && i <= 95:
name = fmt.Sprintf("V%d", i-64)
default:
name = fmt.Sprintf("unknown%d", i)
name = regnum.ARM64ToName(uint64(i))
if reg == nil {
return name, false, ""
}
if reg.Bytes != nil && name[0] == 'V' {

@ -6,6 +6,7 @@ import (
"io"
"github.com/go-delve/delve/pkg/elfwriter"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/proc"
)
@ -372,6 +373,12 @@ func (t *thread) SetDX(uint64) error {
return ErrChangeRegisterCore
}
// ChangeRegs will always return an error, you cannot
// change register values when debugging core files.
func (t *thread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
return ErrChangeRegisterCore
}
// Breakpoints will return all breakpoints for the process.
func (p *process) Breakpoints() *proc.BreakpointMap {
return &p.breakpoints

@ -1,6 +1,21 @@
package proc
import "github.com/go-delve/delve/pkg/dwarf/op"
// PackageVars returns bi.packageVars (for tests)
func (bi *BinaryInfo) PackageVars() []packageVar {
return bi.packageVars
}
func NewCompositeMemory(p *Target, pieces []op.Piece) (*compositeMemory, error) {
regs, err := p.CurrentThread().Registers()
if err != nil {
return nil, err
}
arch := p.BinInfo().Arch
dwarfregs := arch.RegistersToDwarfRegisters(0, regs)
dwarfregs.ChangeFunc = p.CurrentThread().SetReg
return newCompositeMemory(p.Memory(), arch, dwarfregs, pieces)
}

@ -77,8 +77,17 @@ func (mem *fakeMemory) ReadMemory(data []byte, addr uint64) (int, error) {
return len(data), nil
}
func (mem *fakeMemory) WriteMemory(uint64, []byte) (int, error) {
return 0, fmt.Errorf("not implemented")
func (mem *fakeMemory) WriteMemory(addr uint64, data []byte) (int, error) {
if uint64(addr) < mem.base {
return 0, fmt.Errorf("write out of bounds %d %#x", len(data), addr)
}
start := uint64(addr) - mem.base
end := uint64(len(data)) + start
if end > uint64(len(mem.data)) {
panic(fmt.Errorf("write out of bounds %d %#x", len(data), addr))
}
copy(mem.data[start:end], data)
return len(data), nil
}
func uintExprCheck(t *testing.T, scope *proc.EvalScope, expr string, tgt uint64) {
@ -93,13 +102,14 @@ func uintExprCheck(t *testing.T, scope *proc.EvalScope, expr string, tgt uint64)
}
}
func dwarfExprCheck(t *testing.T, mem proc.MemoryReadWriter, regs op.DwarfRegisters, bi *proc.BinaryInfo, testCases map[string]uint16, fn *proc.Function) *proc.EvalScope {
scope := &proc.EvalScope{Location: proc.Location{PC: 0x40100, Fn: fn}, Regs: regs, Mem: mem, BinInfo: bi}
func fakeScope(mem proc.MemoryReadWriter, regs op.DwarfRegisters, bi *proc.BinaryInfo, fn *proc.Function) *proc.EvalScope {
return &proc.EvalScope{Location: proc.Location{PC: 0x40100, Fn: fn}, Regs: regs, Mem: mem, BinInfo: bi}
}
func dwarfExprCheck(t *testing.T, scope *proc.EvalScope, testCases map[string]uint16) {
for name, value := range testCases {
uintExprCheck(t, scope, name, uint64(value))
}
return scope
}
func dwarfRegisters(bi *proc.BinaryInfo, regs *linutil.AMD64Registers) op.DwarfRegisters {
@ -137,7 +147,7 @@ func TestDwarfExprRegisters(t *testing.T) {
regs.Regs.Rax = uint64(testCases["a"])
regs.Regs.Rdx = uint64(testCases["c"])
dwarfExprCheck(t, mem, dwarfRegisters(bi, &regs), bi, testCases, mainfn)
dwarfExprCheck(t, fakeScope(mem, dwarfRegisters(bi, &regs), bi, mainfn), testCases)
}
func TestDwarfExprComposite(t *testing.T) {
@ -192,7 +202,17 @@ func TestDwarfExprComposite(t *testing.T) {
regs.Regs.Rcx = uint64(testCases["pair.k"])
regs.Regs.Rbx = uint64(testCases["n"])
scope := dwarfExprCheck(t, mem, dwarfRegisters(bi, &regs), bi, testCases, mainfn)
dwarfRegs := dwarfRegisters(bi, &regs)
var changeCalls []string
dwarfRegs.ChangeFunc = func(regNum uint64, reg *op.DwarfRegister) error {
t.Logf("SetReg(%d, %x)", regNum, reg.Bytes)
changeCalls = append(changeCalls, fmt.Sprintf("%d - %x", regNum, reg.Bytes))
return nil
}
scope := fakeScope(mem, dwarfRegs, bi, mainfn)
dwarfExprCheck(t, scope, testCases)
thevar, err := scope.EvalExpression("s", normalLoadConfig)
assertNoError(err, t, fmt.Sprintf("EvalExpression(%s)", "s"))
@ -203,6 +223,29 @@ func TestDwarfExprComposite(t *testing.T) {
t.Errorf("expected value %q got %q", stringVal, v)
}
}
// Test writes to composite memory
assertNoError(scope.SetVariable("n", "47"), t, "SetVariable(n, 47)")
assertNoError(scope.SetVariable("pair.k", "12"), t, "SetVariable(pair.k, 12)")
assertNoError(scope.SetVariable("pair.v", "13"), t, "SetVariable(pair.v, 13)")
for i := range changeCalls {
t.Logf("%q\n", changeCalls[i])
}
if len(changeCalls) != 2 {
t.Errorf("wrong number of calls to SetReg")
}
if changeCalls[0] != "3 - 2f00000000000000" {
t.Errorf("wrong call to SetReg (Rbx)")
}
if changeCalls[1] != "2 - 0c00" {
t.Errorf("wrong call to SetReg (Rcx)")
}
if mem.data[0x10] != 13 || mem.data[0x11] != 0x00 {
t.Errorf("memory was not written %v", mem.data[:2])
}
}
func TestDwarfExprLoclist(t *testing.T) {

@ -421,13 +421,13 @@ func callOP(bi *BinaryInfo, thread Thread, regs Registers, callAddr uint64) erro
sp := regs.SP()
// push PC on the stack
sp -= uint64(bi.Arch.PtrSize())
if err := thread.SetSP(sp); err != nil {
if err := setSP(thread, sp); err != nil {
return err
}
if err := writePointer(bi, thread.ProcessMemory(), sp, regs.PC()); err != nil {
return err
}
return thread.SetPC(callAddr)
return setPC(thread, callAddr)
}
// funcCallEvalFuncExpr evaluates expr.Fun and returns the function that we're trying to call.
@ -761,7 +761,7 @@ func funcCallStep(callScope *EvalScope, fncall *functionCallState, thread Thread
if fncall.closureAddr != 0 {
// When calling a function pointer we must set the DX register to the
// address of the function pointer itself.
thread.SetDX(fncall.closureAddr)
setClosureReg(thread, fncall.closureAddr)
}
cfa := regs.SP()
oldpc := regs.PC()
@ -770,8 +770,8 @@ func funcCallStep(callScope *EvalScope, fncall *functionCallState, thread Thread
err := funcCallEvalArgs(callScope, fncall, cfa)
if err != nil {
// rolling back the call, note: this works because we called regs.Copy() above
thread.SetSP(cfa)
thread.SetPC(oldpc)
setSP(thread, cfa)
setPC(thread, oldpc)
fncall.err = err
fncall.lateCallFailure = true
break
@ -784,10 +784,10 @@ func funcCallStep(callScope *EvalScope, fncall *functionCallState, thread Thread
if err := thread.RestoreRegisters(fncall.savedRegs); err != nil {
fncall.err = fmt.Errorf("could not restore registers: %v", err)
}
if err := thread.SetPC(pc); err != nil {
if err := setPC(thread, pc); err != nil {
fncall.err = fmt.Errorf("could not restore PC: %v", err)
}
if err := thread.SetSP(sp); err != nil {
if err := setSP(thread, sp); err != nil {
fncall.err = fmt.Errorf("could not restore SP: %v", err)
}
if err := stepInstructionOut(p, thread, debugCallFunctionName, debugCallFunctionName); err != nil {

@ -80,6 +80,7 @@ import (
"golang.org/x/arch/arm64/arm64asm"
"golang.org/x/arch/x86/x86asm"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/elfwriter"
"github.com/go-delve/delve/pkg/logflags"
"github.com/go-delve/delve/pkg/proc"
@ -1744,7 +1745,7 @@ func (t *gdbThread) SetCurrentBreakpoint(adjustPC bool) error {
pc := regs.PC()
if bp, ok := t.p.FindBreakpoint(pc); ok {
if t.regs.PC() != bp.Addr {
if err := t.SetPC(bp.Addr); err != nil {
if err := t.setPC(bp.Addr); err != nil {
return err
}
}
@ -1770,13 +1771,6 @@ func (regs *gdbRegisters) setPC(value uint64) {
func (regs *gdbRegisters) SP() uint64 {
return binary.LittleEndian.Uint64(regs.regs[regnameSP].value)
}
func (regs *gdbRegisters) setSP(value uint64) {
binary.LittleEndian.PutUint64(regs.regs[regnameSP].value, value)
}
func (regs *gdbRegisters) setDX(value uint64) {
binary.LittleEndian.PutUint64(regs.regs[regnameDX].value, value)
}
func (regs *gdbRegisters) BP() uint64 {
return binary.LittleEndian.Uint64(regs.regs[regnameBP].value)
@ -2180,7 +2174,7 @@ func (r *gdbRegisters) FloatLoadError() error {
}
// SetPC will set the value of the PC register to the given value.
func (t *gdbThread) SetPC(pc uint64) error {
func (t *gdbThread) setPC(pc uint64) error {
_, _ = t.Registers() // Registes must be loaded first
t.regs.setPC(pc)
if t.p.gcmdok {
@ -2190,30 +2184,26 @@ func (t *gdbThread) SetPC(pc uint64) error {
return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value)
}
// SetSP will set the value of the SP register to the given value.
func (t *gdbThread) SetSP(sp uint64) error {
_, _ = t.Registers() // Registes must be loaded first
t.regs.setSP(sp)
if t.p.gcmdok {
return t.p.conn.writeRegisters(t.strID, t.regs.buf)
// SetReg will change the value of a list of registers
func (t *gdbThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
regName, _, _ := t.p.bi.Arch.DwarfRegisterToString(int(regNum), nil)
regName = strings.ToLower(regName)
_, _ = t.Registers() // Registers must be loaded first
gdbreg, ok := t.regs.regs[regName]
if !ok && strings.HasPrefix(regName, "xmm") {
// XMMn and YMMn are the same amd64 register (in different sizes), if we
// don't find XMMn try YMMn instead.
gdbreg, ok = t.regs.regs["y"+regName[1:]]
}
reg := t.regs.regs[regnameSP]
return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value)
}
// SetDX will set the value of the DX register to the given value.
func (t *gdbThread) SetDX(dx uint64) error {
if t.p.bi.Arch.Name == "arm64" {
return fmt.Errorf("not supported")
if !ok {
return fmt.Errorf("could not set register %s: not found", regName)
}
_, _ = t.Registers() // Registes must be loaded first
t.regs.setDX(dx)
if t.p.gcmdok {
return t.p.conn.writeRegisters(t.strID, t.regs.buf)
reg.FillBytes()
if len(reg.Bytes) != len(gdbreg.value) {
return fmt.Errorf("could not set register %s: wrong size, expected %d got %d", regName, len(gdbreg.value), len(reg.Bytes))
}
reg := t.regs.regs[regnameDX]
return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value)
copy(gdbreg.value, reg.Bytes)
return t.p.conn.writeRegister(t.strID, gdbreg.regnum, gdbreg.value)
}
func (regs *gdbRegisters) Slice(floatingPoint bool) ([]proc.Register, error) {

@ -3,15 +3,11 @@ package proc
import (
"encoding/binary"
"fmt"
"strings"
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
"strings"
)
const (
i386DwarfIPRegNum uint64 = 8
i386DwarfSPRegNum uint64 = 4
i386DwarfBPRegNum uint64 = 5
"github.com/go-delve/delve/pkg/dwarf/regnum"
)
var i386BreakInstruction = []byte{0xCC}
@ -36,6 +32,8 @@ func I386Arch(goos string) *Arch {
DwarfRegisterToString: i386DwarfRegisterToString,
inhibitStepInto: i386InhibitStepInto,
asmDecode: i386AsmDecode,
PCRegNum: regnum.I386_Eip,
SPRegNum: regnum.I386_Esp,
}
}
@ -65,24 +63,24 @@ func i386FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryI
// here).
return &frame.FrameContext{
RetAddrReg: i386DwarfIPRegNum,
RetAddrReg: regnum.I386_Eip,
Regs: map[uint64]frame.DWRule{
i386DwarfIPRegNum: frame.DWRule{
regnum.I386_Eip: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-i.PtrSize()),
},
i386DwarfBPRegNum: frame.DWRule{
regnum.I386_Ebp: frame.DWRule{
Rule: frame.RuleOffset,
Offset: int64(-2 * i.PtrSize()),
},
i386DwarfSPRegNum: frame.DWRule{
regnum.I386_Esp: frame.DWRule{
Rule: frame.RuleValOffset,
Offset: 0,
},
},
CFA: frame.DWRule{
Rule: frame.RuleCFA,
Reg: i386DwarfBPRegNum,
Reg: regnum.I386_Ebp,
Offset: int64(2 * i.PtrSize()),
},
}
@ -103,10 +101,10 @@ func i386FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryI
// so that we can use it to unwind the stack even when we encounter frames
// without descriptor entries.
// If there isn't i rule already we emit one.
if fctxt.Regs[i386DwarfBPRegNum].Rule == frame.RuleUndefined {
fctxt.Regs[i386DwarfBPRegNum] = frame.DWRule{
if fctxt.Regs[regnum.I386_Ebp].Rule == frame.RuleUndefined {
fctxt.Regs[regnum.I386_Ebp] = frame.DWRule{
Rule: frame.RuleFramePointer,
Reg: i386DwarfBPRegNum,
Reg: regnum.I386_Ebp,
Offset: 0,
}
}
@ -186,94 +184,28 @@ func i386RegSize(regnum uint64) int {
return 4
}
// The mapping between hardware registers and DWARF registers is specified
// in the System V ABI Intel386 Architecture Processor Supplement page 25,
// table 2.14
// https://www.uclibc.org/docs/psABI-i386.pdf
var i386DwarfToName = map[int]string{
0: "Eax",
1: "Ecx",
2: "Edx",
3: "Ebx",
4: "Esp",
5: "Ebp",
6: "Esi",
7: "Edi",
8: "Eip",
9: "Eflags",
11: "ST(0)",
12: "ST(1)",
13: "ST(2)",
14: "ST(3)",
15: "ST(4)",
16: "ST(5)",
17: "ST(6)",
18: "ST(7)",
21: "XMM0",
22: "XMM1",
23: "XMM2",
24: "XMM3",
25: "XMM4",
26: "XMM5",
27: "XMM6",
28: "XMM7",
40: "Es",
41: "Cs",
42: "Ss",
43: "Ds",
44: "Fs",
45: "Gs",
}
var i386NameToDwarf = func() map[string]int {
r := make(map[string]int)
for regNum, regName := range i386DwarfToName {
r[strings.ToLower(regName)] = regNum
}
r["eflags"] = 9
r["st0"] = 11
r["st1"] = 12
r["st2"] = 13
r["st3"] = 14
r["st4"] = 15
r["st5"] = 16
r["st6"] = 17
r["st7"] = 18
return r
}()
func maxI386DwarfRegister() int {
max := int(i386DwarfIPRegNum)
for i := range i386DwarfToName {
if i > max {
max = i
}
}
return max
}
func i386RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := initDwarfRegistersFromSlice(maxI386DwarfRegister(), regs, i386NameToDwarf)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, i386DwarfIPRegNum, i386DwarfSPRegNum, i386DwarfBPRegNum, 0)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, i386NameToDwarf))
dregs := initDwarfRegistersFromSlice(regnum.I386MaxRegNum(), regs, regnum.I386NameToDwarf)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.I386_Eip, regnum.I386_Esp, regnum.I386_Ebp, 0)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, regnum.I386NameToDwarf))
return *dr
}
func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, i386DwarfIPRegNum+1)
dregs[i386DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
dregs[i386DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
dregs[i386DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
dregs := make([]*op.DwarfRegister, regnum.I386_Eip+1)
dregs[regnum.I386_Eip] = op.DwarfRegisterFromUint64(pc)
dregs[regnum.I386_Esp] = op.DwarfRegisterFromUint64(sp)
dregs[regnum.I386_Ebp] = op.DwarfRegisterFromUint64(bp)
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, i386DwarfIPRegNum, i386DwarfSPRegNum, i386DwarfBPRegNum, 0)
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.I386_Eip, regnum.I386_Esp, regnum.I386_Ebp, 0)
}
func i386DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
name, ok := i386DwarfToName[j]
if !ok {
name = fmt.Sprintf("unknown%d", j)
name = regnum.I386ToName(j)
if reg == nil {
return name, false, ""
}
switch n := strings.ToLower(name); n {

@ -1,8 +1,12 @@
package linutil
import (
"fmt"
"golang.org/x/arch/x86/x86asm"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/amd64util"
)
@ -307,3 +311,71 @@ func (r *AMD64Registers) Copy() (proc.Registers, error) {
}
return &rr, nil
}
func (r *AMD64Registers) SetReg(regNum uint64, reg *op.DwarfRegister) (bool, error) {
var p *uint64
switch regNum {
case regnum.AMD64_Rax:
p = &r.Regs.Rax
case regnum.AMD64_Rbx:
p = &r.Regs.Rbx
case regnum.AMD64_Rcx:
p = &r.Regs.Rcx
case regnum.AMD64_Rdx:
p = &r.Regs.Rdx
case regnum.AMD64_Rsi:
p = &r.Regs.Rsi
case regnum.AMD64_Rdi:
p = &r.Regs.Rdi
case regnum.AMD64_Rbp:
p = &r.Regs.Rbp
case regnum.AMD64_Rsp:
p = &r.Regs.Rsp
case regnum.AMD64_R8:
p = &r.Regs.R8
case regnum.AMD64_R9:
p = &r.Regs.R9
case regnum.AMD64_R10:
p = &r.Regs.R10
case regnum.AMD64_R11:
p = &r.Regs.R11
case regnum.AMD64_R12:
p = &r.Regs.R12
case regnum.AMD64_R13:
p = &r.Regs.R13
case regnum.AMD64_R14:
p = &r.Regs.R14
case regnum.AMD64_R15:
p = &r.Regs.R15
case regnum.AMD64_Rip:
p = &r.Regs.Rip
}
if p != nil {
if reg.Bytes != nil && len(reg.Bytes) != 8 {
return false, fmt.Errorf("wrong number of bytes for register %s (%d)", regnum.AMD64ToName(regNum), len(reg.Bytes))
}
*p = reg.Uint64Val
return false, nil
}
if r.loadFpRegs != nil {
err := r.loadFpRegs(r)
if err != nil {
return false, err
}
r.loadFpRegs = nil
}
if regNum < regnum.AMD64_XMM0 || regNum > regnum.AMD64_XMM0+15 {
return false, fmt.Errorf("can not set %s", regnum.AMD64ToName(regNum))
}
reg.FillBytes()
err := r.Fpregset.SetXmmRegister(int(regNum-regnum.AMD64_XMM0), reg.Bytes)
if err != nil {
return false, err
}
return true, nil
}

@ -89,27 +89,28 @@ const fakeAddress = 0xbeef0000
// memory.
type compositeMemory struct {
realmem MemoryReadWriter
arch *Arch
regs op.DwarfRegisters
pieces []op.Piece
data []byte
}
func newCompositeMemory(mem MemoryReadWriter, regs op.DwarfRegisters, pieces []op.Piece) (*compositeMemory, error) {
cmem := &compositeMemory{realmem: mem, regs: regs, pieces: pieces, data: []byte{}}
for _, piece := range pieces {
func newCompositeMemory(mem MemoryReadWriter, arch *Arch, regs op.DwarfRegisters, pieces []op.Piece) (*compositeMemory, error) {
cmem := &compositeMemory{realmem: mem, arch: arch, regs: regs, pieces: pieces, data: []byte{}}
for i := range pieces {
piece := &pieces[i]
if piece.IsRegister {
reg := regs.Bytes(piece.RegNum)
sz := piece.Size
if sz == 0 && len(pieces) == 1 {
sz = len(reg)
if piece.Size == 0 && len(pieces) == 1 {
piece.Size = len(reg)
}
if sz > len(reg) {
if piece.Size > len(reg) {
if regs.FloatLoadError != nil {
return nil, fmt.Errorf("could not read %d bytes from register %d (size: %d), also error loading floating point registers: %v", sz, piece.RegNum, len(reg), regs.FloatLoadError)
return nil, fmt.Errorf("could not read %d bytes from register %d (size: %d), also error loading floating point registers: %v", piece.Size, piece.RegNum, len(reg), regs.FloatLoadError)
}
return nil, fmt.Errorf("could not read %d bytes from register %d (size: %d)", sz, piece.RegNum, len(reg))
return nil, fmt.Errorf("could not read %d bytes from register %d (size: %d)", piece.Size, piece.RegNum, len(reg))
}
cmem.data = append(cmem.data, reg[:sz]...)
cmem.data = append(cmem.data, reg[:piece.Size]...)
} else {
buf := make([]byte, piece.Size)
mem.ReadMemory(buf, uint64(piece.Addr))
@ -129,8 +130,41 @@ func (mem *compositeMemory) ReadMemory(data []byte, addr uint64) (int, error) {
}
func (mem *compositeMemory) WriteMemory(addr uint64, data []byte) (int, error) {
//TODO(aarzilli): implement
return 0, errors.New("can't write composite memory")
addr -= fakeAddress
if addr >= uint64(len(mem.data)) || addr+uint64(len(data)) > uint64(len(mem.data)) {
return 0, errors.New("write out of bounds")
}
if mem.regs.ChangeFunc == nil {
return 0, errors.New("can not write registers")
}
copy(mem.data[addr:], data)
curAddr := uint64(0)
donesz := 0
for _, piece := range mem.pieces {
if curAddr < (addr+uint64(len(data))) && addr < (curAddr+uint64(piece.Size)) {
// changed memory interval overlaps current piece
pieceMem := mem.data[curAddr : curAddr+uint64(piece.Size)]
if piece.IsRegister {
err := mem.regs.ChangeFunc(piece.RegNum, op.DwarfRegisterFromBytes(pieceMem))
if err != nil {
return donesz, err
}
} else {
n, err := mem.realmem.WriteMemory(uint64(piece.Addr), pieceMem)
if err != nil {
return donesz + n, err
}
}
donesz += piece.Size
}
curAddr += uint64(piece.Size)
}
return len(data), nil
}
// DereferenceMemory returns a MemoryReadWriter that can read and write the

@ -6,6 +6,7 @@ import (
"errors"
"sync"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/proc"
)
@ -82,17 +83,12 @@ func (dbp *nativeProcess) EntryPoint() (uint64, error) {
}
// SetPC sets the value of the PC register.
func (t *nativeThread) SetPC(pc uint64) error {
func (t *nativeThread) setPC(pc uint64) error {
panic(ErrNativeBackendDisabled)
}
// SetSP sets the value of the SP register.
func (t *nativeThread) SetSP(sp uint64) error {
panic(ErrNativeBackendDisabled)
}
// SetDX sets the value of the DX register.
func (t *nativeThread) SetDX(dx uint64) error {
// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
panic(ErrNativeBackendDisabled)
}

@ -594,7 +594,7 @@ func (dbp *nativeProcess) stop(trapthread *nativeThread) (*nativeThread, error)
}
if !isHardcodedBreakpoint {
// phantom breakpoint hit
_ = th.SetPC(pc - uint64(len(dbp.BinInfo().Arch.BreakpointInstruction())))
_ = th.setPC(pc - uint64(len(dbp.BinInfo().Arch.BreakpointInstruction())))
th.os.setbp = false
if trapthread.ThreadID() == th.ThreadID() {
// Will switch to a different thread for trapthread because we don't

@ -325,7 +325,7 @@ func (dbp *nativeProcess) waitForDebugEvent(flags waitForDebugEventFlags) (threa
}
}
if !atbp {
thread.SetPC(uint64(exception.ExceptionRecord.ExceptionAddress))
thread.setPC(uint64(exception.ExceptionRecord.ExceptionAddress))
}
}

@ -5,13 +5,15 @@ import (
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/amd64util"
"github.com/go-delve/delve/pkg/proc/linutil"
)
// SetPC sets EIP to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error {
// setPC sets EIP to the value specified by 'pc'.
func (thread *nativeThread) setPC(pc uint64) error {
ir, err := registers(thread)
if err != nil {
return err
@ -22,29 +24,26 @@ func (thread *nativeThread) SetPC(pc uint64) error {
return err
}
// SetSP sets ESP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
ir, err := registers(thread)
if err != nil {
return err
}
r := ir.(*linutil.I386Registers)
r.Regs.Esp = int32(sp)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return
}
func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
if err != nil {
return err
switch regNum {
case regnum.I386_Eip:
r.Regs.Eip = int32(reg.Uint64Val)
case regnum.I386_Esp:
r.Regs.Esp = int32(reg.Uint64Val)
case regnum.I386_Edx:
r.Regs.Edx = int32(reg.Uint64Val)
default:
//TODO(aarzilli): when the register calling convention is adopted by Go on
// i386 this should be implemented.
return fmt.Errorf("changing register %d not implemented", regNum)
}
r := ir.(*linutil.I386Registers)
r.Regs.Edx = int32(dx)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return
return err
}
func registers(thread *nativeThread) (proc.Registers, error) {

@ -5,12 +5,13 @@ package native
// #include "threads_darwin.h"
import "C"
import (
"errors"
"fmt"
"unsafe"
"golang.org/x/arch/x86/x86asm"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
)
@ -111,7 +112,7 @@ func (r *Regs) GAddr() (uint64, bool) {
}
// SetPC sets the RIP register to the value specified by `pc`.
func (thread *nativeThread) SetPC(pc uint64) error {
func (thread *nativeThread) setPC(pc uint64) error {
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not set pc")
@ -119,13 +120,12 @@ func (thread *nativeThread) SetPC(pc uint64) error {
return nil
}
// SetSP sets the RSP register to the value specified by `pc`.
func (thread *nativeThread) SetSP(sp uint64) error {
return errors.New("not implemented")
}
func (thread *nativeThread) SetDX(dx uint64) error {
return errors.New("not implemented")
// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
if regNum != regnum.AMD64_Rip {
return fmt.Errorf("changing register %d not implemented", regNum)
}
return thread.setPC(reg.Uint64Val)
}
func (r *Regs) Get(n int) (uint64, error) {

@ -5,13 +5,15 @@ import (
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/amd64util"
"github.com/go-delve/delve/pkg/proc/fbsdutil"
)
// SetPC sets RIP to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error {
func (thread *nativeThread) setPC(pc uint64) error {
ir, err := registers(thread)
if err != nil {
return err
@ -22,27 +24,23 @@ func (thread *nativeThread) SetPC(pc uint64) error {
return err
}
// SetSP sets RSP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) (err error) {
ir, err := registers(thread)
if err != nil {
return err
}
r := ir.(*fbsdutil.AMD64Registers)
r.Regs.Rsp = int64(sp)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.Reg)(r.Regs)) })
return
}
func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
if err != nil {
return err
switch regNum {
case regnum.AMD64_Rip:
r.Regs.Rip = int64(reg.Uint64Val)
case regnum.AMD64_Rsp:
r.Regs.Rsp = int64(reg.Uint64Val)
case regnum.AMD64_Rdx:
r.Regs.Rdx = int64(reg.Uint64Val)
default:
return fmt.Errorf("changing register %d not implemented", regNum)
}
r := ir.(*fbsdutil.AMD64Registers)
r.Regs.Rdx = int64(dx)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.Reg)(r.Regs)) })
return
}

@ -2,16 +2,19 @@ package native
import (
"fmt"
"syscall"
"unsafe"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/amd64util"
"github.com/go-delve/delve/pkg/proc/linutil"
)
// SetPC sets RIP to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error {
func (thread *nativeThread) setPC(pc uint64) error {
ir, err := registers(thread)
if err != nil {
return err
@ -22,29 +25,31 @@ func (thread *nativeThread) SetPC(pc uint64) error {
return err
}
// SetSP sets RSP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
ir, err := registers(thread)
if err != nil {
return err
}
r := ir.(*linutil.AMD64Registers)
r.Regs.Rsp = sp
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return
}
func (thread *nativeThread) SetDX(dx uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
fpchanged, err := r.SetReg(regNum, reg)
if err != nil {
return err
}
r := ir.(*linutil.AMD64Registers)
r.Regs.Rdx = dx
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
thread.dbp.execPtraceFunc(func() {
err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs))
if err != nil {
return
}
if fpchanged && r.Fpregset != nil && r.Fpregset.Xsave != nil {
iov := sys.Iovec{Base: &r.Fpregset.Xsave[0], Len: uint64(len(r.Fpregset.Xsave))}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(thread.ID), _NT_X86_XSTATE, uintptr(unsafe.Pointer(&iov)), 0, 0)
if err == syscall.Errno(0) {
err = nil
}
}
})
return err
}
func registers(thread *nativeThread) (proc.Registers, error) {

@ -8,6 +8,8 @@ import (
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
)
@ -64,8 +66,8 @@ func ptraceGetFpRegset(tid int) (fpregset []byte, err error) {
return fpregset, err
}
// SetPC sets PC to the value specified by 'pc'.
func (thread *nativeThread) SetPC(pc uint64) error {
// setPC sets PC to the value specified by 'pc'.
func (thread *nativeThread) setPC(pc uint64) error {
ir, err := registers(thread)
if err != nil {
return err
@ -76,21 +78,26 @@ func (thread *nativeThread) SetPC(pc uint64) error {
return err
}
// SetSP sets RSP to the value specified by 'sp'
func (thread *nativeThread) SetSP(sp uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread)
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
ir, err := registers(thread)
if err != nil {
return err
}
r := ir.(*linutil.ARM64Registers)
r.Regs.Sp = sp
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
return
}
func (thread *nativeThread) SetDX(dx uint64) (err error) {
return fmt.Errorf("not supported")
switch regNum {
case regnum.ARM64_PC:
r.Regs.Pc = reg.Uint64Val
case regnum.ARM64_SP:
r.Regs.Sp = reg.Uint64Val
default:
//TODO(aarzilli): when the register calling convention is adopted by Go on
// arm64 this should be implemented.
return fmt.Errorf("changing register %d not implemented", regNum)
}
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
return err
}
func registers(thread *nativeThread) (proc.Registers, error) {

@ -4,12 +4,14 @@ import (
"fmt"
"unsafe"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/winutil"
)
// SetPC sets the RIP register to the value specified by `pc`.
func (thread *nativeThread) SetPC(pc uint64) error {
func (thread *nativeThread) setPC(pc uint64) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
@ -23,8 +25,8 @@ func (thread *nativeThread) SetPC(pc uint64) error {
return _SetThreadContext(thread.os.hThread, context)
}
// SetSP sets the RSP register to the value specified by `sp`.
func (thread *nativeThread) SetSP(sp uint64) error {
// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
@ -33,21 +35,60 @@ func (thread *nativeThread) SetSP(sp uint64) error {
return err
}
context.Rsp = sp
var p *uint64
return _SetThreadContext(thread.os.hThread, context)
}
func (thread *nativeThread) SetDX(dx uint64) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return err
switch regNum {
case regnum.AMD64_Rax:
p = &context.Rax
case regnum.AMD64_Rbx:
p = &context.Rbx
case regnum.AMD64_Rcx:
p = &context.Rcx
case regnum.AMD64_Rdx:
p = &context.Rdx
case regnum.AMD64_Rsi:
p = &context.Rsi
case regnum.AMD64_Rdi:
p = &context.Rdi
case regnum.AMD64_Rbp:
p = &context.Rbp
case regnum.AMD64_Rsp:
p = &context.Rsp
case regnum.AMD64_R8:
p = &context.R8
case regnum.AMD64_R9:
p = &context.R9
case regnum.AMD64_R10:
p = &context.R10
case regnum.AMD64_R11:
p = &context.R11
case regnum.AMD64_R12:
p = &context.R12
case regnum.AMD64_R13:
p = &context.R13
case regnum.AMD64_R14:
p = &context.R14
case regnum.AMD64_R15:
p = &context.R15
case regnum.AMD64_Rip:
p = &context.Rip
}
context.Rdx = dx
if p != nil {
if reg.Bytes != nil && len(reg.Bytes) != 8 {
return fmt.Errorf("wrong number of bytes for register %s (%d)", regnum.AMD64ToName(regNum), len(reg.Bytes))
}
*p = reg.Uint64Val
} else {
if regNum < regnum.AMD64_XMM0 || regNum > regnum.AMD64_XMM0+15 {
return fmt.Errorf("can not set register %s", regnum.AMD64ToName(regNum))
}
reg.FillBytes()
if len(reg.Bytes) > 16 {
return fmt.Errorf("too many bytes when setting register %s", regnum.AMD64ToName(regNum))
}
copy(context.FltSave.XmmRegisters[(regNum-regnum.AMD64_XMM0)*16:], reg.Bytes)
}
return _SetThreadContext(thread.os.hThread, context)
}

@ -122,7 +122,7 @@ func (t *nativeThread) SetCurrentBreakpoint(adjustPC bool) error {
if bp, ok := t.dbp.FindBreakpoint(pc, adjustPC); ok {
if adjustPC {
if err = t.SetPC(bp.Addr); err != nil {
if err = t.setPC(bp.Addr); err != nil {
return err
}
}

@ -2,6 +2,7 @@ package proc_test
import (
"bytes"
"encoding/binary"
"flag"
"fmt"
"go/ast"
@ -5169,3 +5170,72 @@ func TestDump(t *testing.T) {
}
})
}
func TestCompositeMemoryWrite(t *testing.T) {
if runtime.GOARCH != "amd64" {
t.Skip("only valid on amd64")
}
skipOn(t, "not implemented", "freebsd")
withTestProcess("fputest/", t, func(p *proc.Target, fixture protest.Fixture) {
getregs := func() (pc, rax, xmm1 uint64) {
regs, err := p.CurrentThread().Registers()
assertNoError(err, t, "Registers")
fmtregs, err := regs.Slice(true)
assertNoError(err, t, "register slice")
var xmm1buf []byte
for _, reg := range fmtregs {
switch strings.ToLower(reg.Name) {
case "rax":
rax = reg.Reg.Uint64Val
case "xmm1":
xmm1buf = reg.Reg.Bytes
}
}
xmm1 = binary.LittleEndian.Uint64(xmm1buf[:8])
return regs.PC(), rax, xmm1
}
getmem := func(mem proc.MemoryReader) uint64 {
buf := make([]byte, 8)
_, err := mem.ReadMemory(buf, 0xbeef0000)
assertNoError(err, t, "ReadMemory")
return binary.LittleEndian.Uint64(buf)
}
assertNoError(p.Continue(), t, "Continue()")
oldPc, oldRax, oldXmm1 := getregs()
t.Logf("PC %#x AX %#x XMM1 %#x", oldPc, oldRax, oldXmm1)
memRax, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, RegNum: 0, IsRegister: true}})
assertNoError(err, t, "NewCompositeMemory (rax)")
memXmm1, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, RegNum: 18, IsRegister: true}})
assertNoError(err, t, "NewCompositeMemory (xmm1)")
if memRax := getmem(memRax); memRax != oldRax {
t.Errorf("reading rax memory, expected %#x got %#x", oldRax, memRax)
}
if memXmm1 := getmem(memXmm1); memXmm1 != oldXmm1 {
t.Errorf("reading xmm1 memory, expected %#x got %#x", oldXmm1, memXmm1)
}
_, err = memRax.WriteMemory(0xbeef0000, []byte{0xef, 0xbe, 0x0d, 0xf0, 0xef, 0xbe, 0x0d, 0xf0})
assertNoError(err, t, "WriteMemory (rax)")
_, err = memXmm1.WriteMemory(0xbeef0000, []byte{0xef, 0xbe, 0x0d, 0xf0, 0xef, 0xbe, 0x0d, 0xf0})
assertNoError(err, t, "WriteMemory (xmm1)")
newPc, newRax, newXmm1 := getregs()
t.Logf("PC %#x AX %#x XMM1 %#x", newPc, newRax, newXmm1)
const tgt = 0xf00dbeeff00dbeef
if newRax != tgt {
t.Errorf("reading rax register, expected %#x, got %#x", uint64(tgt), newRax)
}
if newXmm1 != tgt {
t.Errorf("reading xmm1 register, expected %#x, got %#x", uint64(tgt), newXmm1)
}
})
}

@ -100,7 +100,9 @@ func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) {
return nil, err
}
so := thread.BinInfo().PCToImage(regs.PC())
it := newStackIterator(thread.BinInfo(), thread.ProcessMemory(), thread.BinInfo().Arch.RegistersToDwarfRegisters(so.StaticBase, regs), 0, nil, -1, nil, 0)
dwarfRegs := thread.BinInfo().Arch.RegistersToDwarfRegisters(so.StaticBase, regs)
dwarfRegs.ChangeFunc = thread.SetReg
it := newStackIterator(thread.BinInfo(), thread.ProcessMemory(), dwarfRegs, 0, nil, -1, nil, 0)
return it.stacktrace(depth)
}
return g.Stacktrace(depth, 0)
@ -119,9 +121,11 @@ func (g *G) stackIterator(opts StacktraceOptions) (*stackIterator, error) {
return nil, err
}
so := bi.PCToImage(regs.PC())
dwarfRegs := bi.Arch.RegistersToDwarfRegisters(so.StaticBase, regs)
dwarfRegs.ChangeFunc = g.Thread.SetReg
return newStackIterator(
bi, g.variable.mem,
bi.Arch.RegistersToDwarfRegisters(so.StaticBase, regs),
dwarfRegs,
g.stack.hi, stkbar, g.stkbarPos, g, opts), nil
}
so := g.variable.bi.PCToImage(g.PC)

@ -127,7 +127,7 @@ func (dbp *Target) Continue() error {
// In linux-arm64, PtraceSingleStep seems cannot step over BRK instruction
// (linux-arm64 feature or kernel bug maybe).
if !arch.BreakInstrMovesPC() {
curthread.SetPC(loc.PC + uint64(arch.BreakpointSize()))
setPC(curthread, loc.PC+uint64(arch.BreakpointSize()))
}
// Single-step current thread until we exit runtime.breakpoint and
// runtime.Breakpoint.
@ -145,7 +145,7 @@ func (dbp *Target) Continue() error {
bp := make([]byte, bpsize)
_, err = dbp.Memory().ReadMemory(bp, loc.PC)
if bytes.Equal(bp, arch.BreakpointInstruction()) {
curthread.SetPC(loc.PC + uint64(bpsize))
setPC(curthread, loc.PC+uint64(bpsize))
}
}
return conditionErrors(threads)

@ -2,6 +2,8 @@ package proc
import (
"errors"
"github.com/go-delve/delve/pkg/dwarf/op"
)
// Thread represents a thread.
@ -31,9 +33,10 @@ type Thread interface {
// Common returns the CommonThread structure for this thread
Common() *CommonThread
SetPC(uint64) error
SetSP(uint64) error
SetDX(uint64) error
// SetReg changes the value of the specified register. A minimal
// implementation of this interface can support just setting the PC
// register.
SetReg(uint64, *op.DwarfRegister) error
}
// Location represents the location of a thread.
@ -83,3 +86,15 @@ func topframe(g *G, thread Thread) (Stackframe, Stackframe, error) {
return frames[0], frames[1], nil
}
}
func setPC(thread Thread, newPC uint64) error {
return thread.SetReg(thread.BinInfo().Arch.PCRegNum, op.DwarfRegisterFromUint64(newPC))
}
func setSP(thread Thread, newSP uint64) error {
return thread.SetReg(thread.BinInfo().Arch.SPRegNum, op.DwarfRegisterFromUint64(newSP))
}
func setClosureReg(thread Thread, newClosureReg uint64) error {
return thread.SetReg(thread.BinInfo().Arch.ContextRegNum, op.DwarfRegisterFromUint64(newClosureReg))
}

@ -1147,7 +1147,7 @@ func extractVarInfoFromEntry(bi *BinaryInfo, image *Image, regs op.DwarfRegister
if pieces != nil {
addr = fakeAddress
var cmem *compositeMemory
cmem, err = newCompositeMemory(mem, regs, pieces)
cmem, err = newCompositeMemory(mem, bi.Arch, regs, pieces)
if cmem != nil {
mem = cmem
}