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:
parent
3088b8b579
commit
6a70d531bb
@ -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
|
||||
|
@ -14,11 +14,12 @@ type DwarfRegisters struct {
|
||||
ObjBase int64
|
||||
regs []*DwarfRegister
|
||||
|
||||
ByteOrder binary.ByteOrder
|
||||
PCRegNum uint64
|
||||
SPRegNum uint64
|
||||
BPRegNum uint64
|
||||
LRRegNum uint64
|
||||
ByteOrder binary.ByteOrder
|
||||
PCRegNum uint64
|
||||
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
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
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
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, ®s), bi, testCases, mainfn)
|
||||
dwarfExprCheck(t, fakeScope(mem, dwarfRegisters(bi, ®s), 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, ®s), bi, testCases, mainfn)
|
||||
dwarfRegs := dwarfRegisters(bi, ®s)
|
||||
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)) })
|
||||
return
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user