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:
|
Tests skipped by each supported backend:
|
||||||
|
|
||||||
* 386 skipped = 2.7% (4/147)
|
* 386 skipped = 2.7% (4/148)
|
||||||
* 1 broken
|
* 1 broken
|
||||||
* 3 broken - cgo stacktraces
|
* 3 broken - cgo stacktraces
|
||||||
* arm64 skipped = 2.7% (4/147)
|
* arm64 skipped = 2.7% (4/148)
|
||||||
* 2 broken
|
* 2 broken
|
||||||
* 1 broken - cgo stacktraces
|
* 1 broken - cgo stacktraces
|
||||||
* 1 broken - global variable symbolication
|
* 1 broken - global variable symbolication
|
||||||
* darwin/lldb skipped = 0.68% (1/147)
|
* darwin/lldb skipped = 0.68% (1/148)
|
||||||
* 1 upstream issue
|
* 1 upstream issue
|
||||||
* freebsd skipped = 7.5% (11/147)
|
* freebsd skipped = 8.1% (12/148)
|
||||||
* 11 broken
|
* 11 broken
|
||||||
* linux/386/pie skipped = 0.68% (1/147)
|
* 1 not implemented
|
||||||
|
* linux/386/pie skipped = 0.68% (1/148)
|
||||||
* 1 broken
|
* 1 broken
|
||||||
* pie skipped = 0.68% (1/147)
|
* pie skipped = 0.68% (1/148)
|
||||||
* 1 upstream issue - https://github.com/golang/go/issues/29322
|
* 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 broken
|
||||||
* 1 upstream issue
|
* 1 upstream issue
|
||||||
|
@ -14,11 +14,12 @@ type DwarfRegisters struct {
|
|||||||
ObjBase int64
|
ObjBase int64
|
||||||
regs []*DwarfRegister
|
regs []*DwarfRegister
|
||||||
|
|
||||||
ByteOrder binary.ByteOrder
|
ByteOrder binary.ByteOrder
|
||||||
PCRegNum uint64
|
PCRegNum uint64
|
||||||
SPRegNum uint64
|
SPRegNum uint64
|
||||||
BPRegNum uint64
|
BPRegNum uint64
|
||||||
LRRegNum uint64
|
LRRegNum uint64
|
||||||
|
ChangeFunc RegisterChangeFunc
|
||||||
|
|
||||||
FloatLoadError error // error produced when loading floating point registers
|
FloatLoadError error // error produced when loading floating point registers
|
||||||
loadMoreCallback func()
|
loadMoreCallback func()
|
||||||
@ -29,6 +30,8 @@ type DwarfRegister struct {
|
|||||||
Bytes []byte
|
Bytes []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RegisterChangeFunc func(regNum uint64, reg *DwarfRegister) error
|
||||||
|
|
||||||
// NewDwarfRegisters returns a new DwarfRegisters object.
|
// NewDwarfRegisters returns a new DwarfRegisters object.
|
||||||
func NewDwarfRegisters(staticBase uint64, regs []*DwarfRegister, byteOrder binary.ByteOrder, pcRegNum, spRegNum, bpRegNum, lrRegNum uint64) *DwarfRegisters {
|
func NewDwarfRegisters(staticBase uint64, regs []*DwarfRegister, byteOrder binary.ByteOrder, pcRegNum, spRegNum, bpRegNum, lrRegNum uint64) *DwarfRegisters {
|
||||||
return &DwarfRegisters{
|
return &DwarfRegisters{
|
||||||
@ -152,3 +155,12 @@ func DwarfRegisterFromBytes(bytes []byte) *DwarfRegister {
|
|||||||
}
|
}
|
||||||
return &DwarfRegister{Uint64Val: v, Bytes: bytes}
|
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/frame"
|
||||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
)
|
"github.com/go-delve/delve/pkg/dwarf/regnum"
|
||||||
|
|
||||||
const (
|
|
||||||
amd64DwarfIPRegNum uint64 = 16
|
|
||||||
amd64DwarfSPRegNum uint64 = 7
|
|
||||||
amd64DwarfBPRegNum uint64 = 6
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var amd64BreakInstruction = []byte{0xCC}
|
var amd64BreakInstruction = []byte{0xCC}
|
||||||
@ -39,6 +34,10 @@ func AMD64Arch(goos string) *Arch {
|
|||||||
DwarfRegisterToString: amd64DwarfRegisterToString,
|
DwarfRegisterToString: amd64DwarfRegisterToString,
|
||||||
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
|
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
|
||||||
asmDecode: amd64AsmDecode,
|
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).
|
// here).
|
||||||
|
|
||||||
return &frame.FrameContext{
|
return &frame.FrameContext{
|
||||||
RetAddrReg: amd64DwarfIPRegNum,
|
RetAddrReg: regnum.AMD64_Rip,
|
||||||
Regs: map[uint64]frame.DWRule{
|
Regs: map[uint64]frame.DWRule{
|
||||||
amd64DwarfIPRegNum: {
|
regnum.AMD64_Rip: {
|
||||||
Rule: frame.RuleOffset,
|
Rule: frame.RuleOffset,
|
||||||
Offset: int64(-a.PtrSize()),
|
Offset: int64(-a.PtrSize()),
|
||||||
},
|
},
|
||||||
amd64DwarfBPRegNum: {
|
regnum.AMD64_Rbp: {
|
||||||
Rule: frame.RuleOffset,
|
Rule: frame.RuleOffset,
|
||||||
Offset: int64(-2 * a.PtrSize()),
|
Offset: int64(-2 * a.PtrSize()),
|
||||||
},
|
},
|
||||||
amd64DwarfSPRegNum: {
|
regnum.AMD64_Rsp: {
|
||||||
Rule: frame.RuleValOffset,
|
Rule: frame.RuleValOffset,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CFA: frame.DWRule{
|
CFA: frame.DWRule{
|
||||||
Rule: frame.RuleCFA,
|
Rule: frame.RuleCFA,
|
||||||
Reg: amd64DwarfBPRegNum,
|
Reg: regnum.AMD64_Rbp,
|
||||||
Offset: int64(2 * a.PtrSize()),
|
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
|
// so that we can use it to unwind the stack even when we encounter frames
|
||||||
// without descriptor entries.
|
// without descriptor entries.
|
||||||
// If there isn't a rule already we emit one.
|
// If there isn't a rule already we emit one.
|
||||||
if fctxt.Regs[amd64DwarfBPRegNum].Rule == frame.RuleUndefined {
|
if fctxt.Regs[regnum.AMD64_Rbp].Rule == frame.RuleUndefined {
|
||||||
fctxt.Regs[amd64DwarfBPRegNum] = frame.DWRule{
|
fctxt.Regs[regnum.AMD64_Rbp] = frame.DWRule{
|
||||||
Rule: frame.RuleFramePointer,
|
Rule: frame.RuleFramePointer,
|
||||||
Reg: amd64DwarfBPRegNum,
|
Reg: regnum.AMD64_Rbp,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,110 +243,22 @@ func amd64SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
|||||||
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
|
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
|
||||||
// figure 3.36
|
// figure 3.36
|
||||||
// https://www.uclibc.org/docs/psABI-x86_64.pdf
|
// https://www.uclibc.org/docs/psABI-x86_64.pdf
|
||||||
func amd64RegSize(regnum uint64) int {
|
func amd64RegSize(rn uint64) int {
|
||||||
// XMM registers
|
// XMM registers
|
||||||
if regnum > amd64DwarfIPRegNum && regnum <= 32 {
|
if rn > regnum.AMD64_Rip && rn <= 32 {
|
||||||
return 16
|
return 16
|
||||||
}
|
}
|
||||||
// x87 registers
|
// x87 registers
|
||||||
if regnum >= 33 && regnum <= 40 {
|
if rn >= 33 && rn <= 40 {
|
||||||
return 10
|
return 10
|
||||||
}
|
}
|
||||||
return 8
|
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 {
|
func amd64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
||||||
dregs := initDwarfRegistersFromSlice(maxAmd64DwarfRegister(), regs, amd64NameToDwarf)
|
dregs := initDwarfRegistersFromSlice(int(regnum.AMD64MaxRegNum()), regs, regnum.AMD64NameToDwarf)
|
||||||
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, amd64DwarfIPRegNum, amd64DwarfSPRegNum, amd64DwarfBPRegNum, 0)
|
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.AMD64_Rip, regnum.AMD64_Rsp, regnum.AMD64_Rbp, 0)
|
||||||
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, amd64NameToDwarf))
|
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, regnum.AMD64NameToDwarf))
|
||||||
return *dr
|
return *dr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,18 +300,19 @@ func loadMoreDwarfRegistersFromSliceFunc(dr *op.DwarfRegisters, regs Registers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func amd64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
func amd64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
||||||
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
|
dregs := make([]*op.DwarfRegister, regnum.AMD64_Rip+1)
|
||||||
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
dregs[regnum.AMD64_Rip] = op.DwarfRegisterFromUint64(pc)
|
||||||
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
dregs[regnum.AMD64_Rsp] = op.DwarfRegisterFromUint64(sp)
|
||||||
dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
|
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) {
|
func amd64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||||
name, ok := amd64DwarfToName[i]
|
name = regnum.AMD64ToName(uint64(i))
|
||||||
if !ok {
|
|
||||||
name = fmt.Sprintf("unknown%d", i)
|
if reg == nil {
|
||||||
|
return name, false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n := strings.ToLower(name); n {
|
switch n := strings.ToLower(name); n {
|
||||||
|
@ -74,6 +74,7 @@ func (xsave *AMD64Xstate) Decode() []proc.Register {
|
|||||||
const (
|
const (
|
||||||
_XSTATE_MAX_KNOWN_SIZE = 2969
|
_XSTATE_MAX_KNOWN_SIZE = 2969
|
||||||
|
|
||||||
|
_XSAVE_XMM_REGION_START = 160
|
||||||
_XSAVE_HEADER_START = 512
|
_XSAVE_HEADER_START = 512
|
||||||
_XSAVE_HEADER_LEN = 64
|
_XSAVE_HEADER_LEN = 64
|
||||||
_XSAVE_EXTENDED_REGION_START = 576
|
_XSAVE_EXTENDED_REGION_START = 576
|
||||||
@ -129,3 +130,61 @@ func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate) er
|
|||||||
|
|
||||||
return nil
|
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
|
breakInstrMovesPC bool
|
||||||
derefTLS bool
|
derefTLS bool
|
||||||
usesLR bool // architecture uses a link register, also called RA on some architectures
|
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.
|
// 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.
|
// 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
|
// addrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
||||||
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
||||||
addrAndStackRegsToDwarfRegisters func(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
|
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)
|
DwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string)
|
||||||
// inhibitStepInto returns whether StepBreakpoint can be set at pc.
|
// inhibitStepInto returns whether StepBreakpoint can be set at pc.
|
||||||
inhibitStepInto func(bi *BinaryInfo, pc uint64) bool
|
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/frame"
|
||||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
|
"github.com/go-delve/delve/pkg/dwarf/regnum"
|
||||||
"golang.org/x/arch/arm64/arm64asm"
|
"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}
|
var arm64BreakInstruction = []byte{0x0, 0x0, 0x20, 0xd4}
|
||||||
|
|
||||||
// ARM64Arch returns an initialized ARM64
|
// ARM64Arch returns an initialized ARM64
|
||||||
@ -40,6 +34,8 @@ func ARM64Arch(goos string) *Arch {
|
|||||||
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
|
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
|
||||||
asmDecode: arm64AsmDecode,
|
asmDecode: arm64AsmDecode,
|
||||||
usesLR: true,
|
usesLR: true,
|
||||||
|
PCRegNum: regnum.ARM64_PC,
|
||||||
|
SPRegNum: regnum.ARM64_SP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,24 +65,24 @@ func arm64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *Binary
|
|||||||
// here).
|
// here).
|
||||||
|
|
||||||
return &frame.FrameContext{
|
return &frame.FrameContext{
|
||||||
RetAddrReg: arm64DwarfIPRegNum,
|
RetAddrReg: regnum.ARM64_PC,
|
||||||
Regs: map[uint64]frame.DWRule{
|
Regs: map[uint64]frame.DWRule{
|
||||||
arm64DwarfIPRegNum: frame.DWRule{
|
regnum.ARM64_PC: frame.DWRule{
|
||||||
Rule: frame.RuleOffset,
|
Rule: frame.RuleOffset,
|
||||||
Offset: int64(-a.PtrSize()),
|
Offset: int64(-a.PtrSize()),
|
||||||
},
|
},
|
||||||
arm64DwarfBPRegNum: frame.DWRule{
|
regnum.ARM64_BP: frame.DWRule{
|
||||||
Rule: frame.RuleOffset,
|
Rule: frame.RuleOffset,
|
||||||
Offset: int64(-2 * a.PtrSize()),
|
Offset: int64(-2 * a.PtrSize()),
|
||||||
},
|
},
|
||||||
arm64DwarfSPRegNum: frame.DWRule{
|
regnum.ARM64_SP: frame.DWRule{
|
||||||
Rule: frame.RuleValOffset,
|
Rule: frame.RuleValOffset,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CFA: frame.DWRule{
|
CFA: frame.DWRule{
|
||||||
Rule: frame.RuleCFA,
|
Rule: frame.RuleCFA,
|
||||||
Reg: arm64DwarfBPRegNum,
|
Reg: regnum.ARM64_BP,
|
||||||
Offset: int64(2 * a.PtrSize()),
|
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
|
// so that we can use it to unwind the stack even when we encounter frames
|
||||||
// without descriptor entries.
|
// without descriptor entries.
|
||||||
// If there isn't a rule already we emit one.
|
// If there isn't a rule already we emit one.
|
||||||
if fctxt.Regs[arm64DwarfBPRegNum].Rule == frame.RuleUndefined {
|
if fctxt.Regs[regnum.ARM64_BP].Rule == frame.RuleUndefined {
|
||||||
fctxt.Regs[arm64DwarfBPRegNum] = frame.DWRule{
|
fctxt.Regs[regnum.ARM64_BP] = frame.DWRule{
|
||||||
Rule: frame.RuleFramePointer,
|
Rule: frame.RuleFramePointer,
|
||||||
Reg: arm64DwarfBPRegNum,
|
Reg: regnum.ARM64_BP,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fctxt.Regs[arm64DwarfLRRegNum].Rule == frame.RuleUndefined {
|
if fctxt.Regs[regnum.ARM64_LR].Rule == frame.RuleUndefined {
|
||||||
fctxt.Regs[arm64DwarfLRRegNum] = frame.DWRule{
|
fctxt.Regs[regnum.ARM64_LR] = frame.DWRule{
|
||||||
Rule: frame.RuleFramePointer,
|
Rule: frame.RuleFramePointer,
|
||||||
Reg: arm64DwarfLRRegNum,
|
Reg: regnum.ARM64_LR,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,8 +313,8 @@ var arm64NameToDwarf = func() map[string]int {
|
|||||||
for i := 0; i <= 30; i++ {
|
for i := 0; i <= 30; i++ {
|
||||||
r[fmt.Sprintf("x%d", i)] = i
|
r[fmt.Sprintf("x%d", i)] = i
|
||||||
}
|
}
|
||||||
r["pc"] = int(arm64DwarfIPRegNum)
|
r["pc"] = int(regnum.ARM64_PC)
|
||||||
r["lr"] = int(arm64DwarfLRRegNum)
|
r["lr"] = int(regnum.ARM64_LR)
|
||||||
r["sp"] = 31
|
r["sp"] = 31
|
||||||
for i := 0; i <= 31; i++ {
|
for i := 0; i <= 31; i++ {
|
||||||
r[fmt.Sprintf("v%d", i)] = i + 64
|
r[fmt.Sprintf("v%d", i)] = i + 64
|
||||||
@ -327,7 +323,7 @@ var arm64NameToDwarf = func() map[string]int {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
func maxArm64DwarfRegister() int {
|
func maxArm64DwarfRegister() int {
|
||||||
max := int(arm64DwarfIPRegNum)
|
max := int(regnum.ARM64_PC)
|
||||||
for i := range arm64DwarfToHardware {
|
for i := range arm64DwarfToHardware {
|
||||||
if i > max {
|
if i > max {
|
||||||
max = i
|
max = i
|
||||||
@ -339,11 +335,11 @@ func maxArm64DwarfRegister() int {
|
|||||||
func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
||||||
dregs := make([]*op.DwarfRegister, maxArm64DwarfRegister()+1)
|
dregs := make([]*op.DwarfRegister, maxArm64DwarfRegister()+1)
|
||||||
|
|
||||||
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
|
dregs[regnum.ARM64_PC] = op.DwarfRegisterFromUint64(regs.PC())
|
||||||
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(regs.SP())
|
dregs[regnum.ARM64_SP] = op.DwarfRegisterFromUint64(regs.SP())
|
||||||
dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(regs.BP())
|
dregs[regnum.ARM64_BP] = op.DwarfRegisterFromUint64(regs.BP())
|
||||||
if lr, err := regs.Get(int(arm64asm.X30)); err != nil {
|
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 {
|
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))
|
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, arm64NameToDwarf))
|
||||||
return *dr
|
return *dr
|
||||||
}
|
}
|
||||||
|
|
||||||
func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
||||||
dregs := make([]*op.DwarfRegister, arm64DwarfIPRegNum+1)
|
dregs := make([]*op.DwarfRegister, regnum.ARM64_PC+1)
|
||||||
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
dregs[regnum.ARM64_PC] = op.DwarfRegisterFromUint64(pc)
|
||||||
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
dregs[regnum.ARM64_SP] = op.DwarfRegisterFromUint64(sp)
|
||||||
dregs[arm64DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
|
dregs[regnum.ARM64_BP] = op.DwarfRegisterFromUint64(bp)
|
||||||
dregs[arm64DwarfLRRegNum] = op.DwarfRegisterFromUint64(lr)
|
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) {
|
func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||||
// see arm64DwarfToHardware table for explanation
|
name = regnum.ARM64ToName(uint64(i))
|
||||||
switch {
|
|
||||||
case i <= 30:
|
if reg == nil {
|
||||||
name = fmt.Sprintf("X%d", i)
|
return name, false, ""
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if reg.Bytes != nil && name[0] == 'V' {
|
if reg.Bytes != nil && name[0] == 'V' {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/go-delve/delve/pkg/elfwriter"
|
"github.com/go-delve/delve/pkg/elfwriter"
|
||||||
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
"github.com/go-delve/delve/pkg/proc"
|
"github.com/go-delve/delve/pkg/proc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -372,6 +373,12 @@ func (t *thread) SetDX(uint64) error {
|
|||||||
return ErrChangeRegisterCore
|
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.
|
// Breakpoints will return all breakpoints for the process.
|
||||||
func (p *process) Breakpoints() *proc.BreakpointMap {
|
func (p *process) Breakpoints() *proc.BreakpointMap {
|
||||||
return &p.breakpoints
|
return &p.breakpoints
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
package proc
|
package proc
|
||||||
|
|
||||||
|
import "github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
|
|
||||||
// PackageVars returns bi.packageVars (for tests)
|
// PackageVars returns bi.packageVars (for tests)
|
||||||
func (bi *BinaryInfo) PackageVars() []packageVar {
|
func (bi *BinaryInfo) PackageVars() []packageVar {
|
||||||
return bi.packageVars
|
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
|
return len(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mem *fakeMemory) WriteMemory(uint64, []byte) (int, error) {
|
func (mem *fakeMemory) WriteMemory(addr uint64, data []byte) (int, error) {
|
||||||
return 0, fmt.Errorf("not implemented")
|
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) {
|
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 {
|
func fakeScope(mem proc.MemoryReadWriter, regs op.DwarfRegisters, bi *proc.BinaryInfo, fn *proc.Function) *proc.EvalScope {
|
||||||
scope := &proc.EvalScope{Location: proc.Location{PC: 0x40100, Fn: fn}, Regs: regs, Mem: mem, BinInfo: bi}
|
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 {
|
for name, value := range testCases {
|
||||||
uintExprCheck(t, scope, name, uint64(value))
|
uintExprCheck(t, scope, name, uint64(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
return scope
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dwarfRegisters(bi *proc.BinaryInfo, regs *linutil.AMD64Registers) op.DwarfRegisters {
|
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.Rax = uint64(testCases["a"])
|
||||||
regs.Regs.Rdx = uint64(testCases["c"])
|
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) {
|
func TestDwarfExprComposite(t *testing.T) {
|
||||||
@ -192,7 +202,17 @@ func TestDwarfExprComposite(t *testing.T) {
|
|||||||
regs.Regs.Rcx = uint64(testCases["pair.k"])
|
regs.Regs.Rcx = uint64(testCases["pair.k"])
|
||||||
regs.Regs.Rbx = uint64(testCases["n"])
|
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)
|
thevar, err := scope.EvalExpression("s", normalLoadConfig)
|
||||||
assertNoError(err, t, fmt.Sprintf("EvalExpression(%s)", "s"))
|
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)
|
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) {
|
func TestDwarfExprLoclist(t *testing.T) {
|
||||||
|
@ -421,13 +421,13 @@ func callOP(bi *BinaryInfo, thread Thread, regs Registers, callAddr uint64) erro
|
|||||||
sp := regs.SP()
|
sp := regs.SP()
|
||||||
// push PC on the stack
|
// push PC on the stack
|
||||||
sp -= uint64(bi.Arch.PtrSize())
|
sp -= uint64(bi.Arch.PtrSize())
|
||||||
if err := thread.SetSP(sp); err != nil {
|
if err := setSP(thread, sp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := writePointer(bi, thread.ProcessMemory(), sp, regs.PC()); err != nil {
|
if err := writePointer(bi, thread.ProcessMemory(), sp, regs.PC()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return thread.SetPC(callAddr)
|
return setPC(thread, callAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// funcCallEvalFuncExpr evaluates expr.Fun and returns the function that we're trying to call.
|
// 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 {
|
if fncall.closureAddr != 0 {
|
||||||
// When calling a function pointer we must set the DX register to the
|
// When calling a function pointer we must set the DX register to the
|
||||||
// address of the function pointer itself.
|
// address of the function pointer itself.
|
||||||
thread.SetDX(fncall.closureAddr)
|
setClosureReg(thread, fncall.closureAddr)
|
||||||
}
|
}
|
||||||
cfa := regs.SP()
|
cfa := regs.SP()
|
||||||
oldpc := regs.PC()
|
oldpc := regs.PC()
|
||||||
@ -770,8 +770,8 @@ func funcCallStep(callScope *EvalScope, fncall *functionCallState, thread Thread
|
|||||||
err := funcCallEvalArgs(callScope, fncall, cfa)
|
err := funcCallEvalArgs(callScope, fncall, cfa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// rolling back the call, note: this works because we called regs.Copy() above
|
// rolling back the call, note: this works because we called regs.Copy() above
|
||||||
thread.SetSP(cfa)
|
setSP(thread, cfa)
|
||||||
thread.SetPC(oldpc)
|
setPC(thread, oldpc)
|
||||||
fncall.err = err
|
fncall.err = err
|
||||||
fncall.lateCallFailure = true
|
fncall.lateCallFailure = true
|
||||||
break
|
break
|
||||||
@ -784,10 +784,10 @@ func funcCallStep(callScope *EvalScope, fncall *functionCallState, thread Thread
|
|||||||
if err := thread.RestoreRegisters(fncall.savedRegs); err != nil {
|
if err := thread.RestoreRegisters(fncall.savedRegs); err != nil {
|
||||||
fncall.err = fmt.Errorf("could not restore registers: %v", err)
|
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)
|
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)
|
fncall.err = fmt.Errorf("could not restore SP: %v", err)
|
||||||
}
|
}
|
||||||
if err := stepInstructionOut(p, thread, debugCallFunctionName, debugCallFunctionName); err != nil {
|
if err := stepInstructionOut(p, thread, debugCallFunctionName, debugCallFunctionName); err != nil {
|
||||||
|
@ -80,6 +80,7 @@ import (
|
|||||||
"golang.org/x/arch/arm64/arm64asm"
|
"golang.org/x/arch/arm64/arm64asm"
|
||||||
"golang.org/x/arch/x86/x86asm"
|
"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/elfwriter"
|
||||||
"github.com/go-delve/delve/pkg/logflags"
|
"github.com/go-delve/delve/pkg/logflags"
|
||||||
"github.com/go-delve/delve/pkg/proc"
|
"github.com/go-delve/delve/pkg/proc"
|
||||||
@ -1744,7 +1745,7 @@ func (t *gdbThread) SetCurrentBreakpoint(adjustPC bool) error {
|
|||||||
pc := regs.PC()
|
pc := regs.PC()
|
||||||
if bp, ok := t.p.FindBreakpoint(pc); ok {
|
if bp, ok := t.p.FindBreakpoint(pc); ok {
|
||||||
if t.regs.PC() != bp.Addr {
|
if t.regs.PC() != bp.Addr {
|
||||||
if err := t.SetPC(bp.Addr); err != nil {
|
if err := t.setPC(bp.Addr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1770,13 +1771,6 @@ func (regs *gdbRegisters) setPC(value uint64) {
|
|||||||
func (regs *gdbRegisters) SP() uint64 {
|
func (regs *gdbRegisters) SP() uint64 {
|
||||||
return binary.LittleEndian.Uint64(regs.regs[regnameSP].value)
|
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 {
|
func (regs *gdbRegisters) BP() uint64 {
|
||||||
return binary.LittleEndian.Uint64(regs.regs[regnameBP].value)
|
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.
|
// 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.Registers() // Registes must be loaded first
|
||||||
t.regs.setPC(pc)
|
t.regs.setPC(pc)
|
||||||
if t.p.gcmdok {
|
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)
|
return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP will set the value of the SP register to the given value.
|
// SetReg will change the value of a list of registers
|
||||||
func (t *gdbThread) SetSP(sp uint64) error {
|
func (t *gdbThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||||
_, _ = t.Registers() // Registes must be loaded first
|
regName, _, _ := t.p.bi.Arch.DwarfRegisterToString(int(regNum), nil)
|
||||||
t.regs.setSP(sp)
|
regName = strings.ToLower(regName)
|
||||||
if t.p.gcmdok {
|
_, _ = t.Registers() // Registers must be loaded first
|
||||||
return t.p.conn.writeRegisters(t.strID, t.regs.buf)
|
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]
|
if !ok {
|
||||||
return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value)
|
return fmt.Errorf("could not set register %s: not found", regName)
|
||||||
}
|
|
||||||
|
|
||||||
// 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")
|
|
||||||
}
|
}
|
||||||
|
reg.FillBytes()
|
||||||
_, _ = t.Registers() // Registes must be loaded first
|
if len(reg.Bytes) != len(gdbreg.value) {
|
||||||
t.regs.setDX(dx)
|
return fmt.Errorf("could not set register %s: wrong size, expected %d got %d", regName, len(gdbreg.value), len(reg.Bytes))
|
||||||
if t.p.gcmdok {
|
|
||||||
return t.p.conn.writeRegisters(t.strID, t.regs.buf)
|
|
||||||
}
|
}
|
||||||
reg := t.regs.regs[regnameDX]
|
copy(gdbreg.value, reg.Bytes)
|
||||||
return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value)
|
return t.p.conn.writeRegister(t.strID, gdbreg.regnum, gdbreg.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (regs *gdbRegisters) Slice(floatingPoint bool) ([]proc.Register, error) {
|
func (regs *gdbRegisters) Slice(floatingPoint bool) ([]proc.Register, error) {
|
||||||
|
@ -3,15 +3,11 @@ package proc
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-delve/delve/pkg/dwarf/frame"
|
"github.com/go-delve/delve/pkg/dwarf/frame"
|
||||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
"strings"
|
"github.com/go-delve/delve/pkg/dwarf/regnum"
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
i386DwarfIPRegNum uint64 = 8
|
|
||||||
i386DwarfSPRegNum uint64 = 4
|
|
||||||
i386DwarfBPRegNum uint64 = 5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var i386BreakInstruction = []byte{0xCC}
|
var i386BreakInstruction = []byte{0xCC}
|
||||||
@ -36,6 +32,8 @@ func I386Arch(goos string) *Arch {
|
|||||||
DwarfRegisterToString: i386DwarfRegisterToString,
|
DwarfRegisterToString: i386DwarfRegisterToString,
|
||||||
inhibitStepInto: i386InhibitStepInto,
|
inhibitStepInto: i386InhibitStepInto,
|
||||||
asmDecode: i386AsmDecode,
|
asmDecode: i386AsmDecode,
|
||||||
|
PCRegNum: regnum.I386_Eip,
|
||||||
|
SPRegNum: regnum.I386_Esp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,24 +63,24 @@ func i386FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryI
|
|||||||
// here).
|
// here).
|
||||||
|
|
||||||
return &frame.FrameContext{
|
return &frame.FrameContext{
|
||||||
RetAddrReg: i386DwarfIPRegNum,
|
RetAddrReg: regnum.I386_Eip,
|
||||||
Regs: map[uint64]frame.DWRule{
|
Regs: map[uint64]frame.DWRule{
|
||||||
i386DwarfIPRegNum: frame.DWRule{
|
regnum.I386_Eip: frame.DWRule{
|
||||||
Rule: frame.RuleOffset,
|
Rule: frame.RuleOffset,
|
||||||
Offset: int64(-i.PtrSize()),
|
Offset: int64(-i.PtrSize()),
|
||||||
},
|
},
|
||||||
i386DwarfBPRegNum: frame.DWRule{
|
regnum.I386_Ebp: frame.DWRule{
|
||||||
Rule: frame.RuleOffset,
|
Rule: frame.RuleOffset,
|
||||||
Offset: int64(-2 * i.PtrSize()),
|
Offset: int64(-2 * i.PtrSize()),
|
||||||
},
|
},
|
||||||
i386DwarfSPRegNum: frame.DWRule{
|
regnum.I386_Esp: frame.DWRule{
|
||||||
Rule: frame.RuleValOffset,
|
Rule: frame.RuleValOffset,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CFA: frame.DWRule{
|
CFA: frame.DWRule{
|
||||||
Rule: frame.RuleCFA,
|
Rule: frame.RuleCFA,
|
||||||
Reg: i386DwarfBPRegNum,
|
Reg: regnum.I386_Ebp,
|
||||||
Offset: int64(2 * i.PtrSize()),
|
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
|
// so that we can use it to unwind the stack even when we encounter frames
|
||||||
// without descriptor entries.
|
// without descriptor entries.
|
||||||
// If there isn't i rule already we emit one.
|
// If there isn't i rule already we emit one.
|
||||||
if fctxt.Regs[i386DwarfBPRegNum].Rule == frame.RuleUndefined {
|
if fctxt.Regs[regnum.I386_Ebp].Rule == frame.RuleUndefined {
|
||||||
fctxt.Regs[i386DwarfBPRegNum] = frame.DWRule{
|
fctxt.Regs[regnum.I386_Ebp] = frame.DWRule{
|
||||||
Rule: frame.RuleFramePointer,
|
Rule: frame.RuleFramePointer,
|
||||||
Reg: i386DwarfBPRegNum,
|
Reg: regnum.I386_Ebp,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,94 +184,28 @@ func i386RegSize(regnum uint64) int {
|
|||||||
return 4
|
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 {
|
func i386RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
||||||
dregs := initDwarfRegistersFromSlice(maxI386DwarfRegister(), regs, i386NameToDwarf)
|
dregs := initDwarfRegistersFromSlice(regnum.I386MaxRegNum(), regs, regnum.I386NameToDwarf)
|
||||||
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, i386DwarfIPRegNum, i386DwarfSPRegNum, i386DwarfBPRegNum, 0)
|
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.I386_Eip, regnum.I386_Esp, regnum.I386_Ebp, 0)
|
||||||
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, i386NameToDwarf))
|
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, regnum.I386NameToDwarf))
|
||||||
|
|
||||||
return *dr
|
return *dr
|
||||||
}
|
}
|
||||||
|
|
||||||
func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
||||||
dregs := make([]*op.DwarfRegister, i386DwarfIPRegNum+1)
|
dregs := make([]*op.DwarfRegister, regnum.I386_Eip+1)
|
||||||
dregs[i386DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
dregs[regnum.I386_Eip] = op.DwarfRegisterFromUint64(pc)
|
||||||
dregs[i386DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
dregs[regnum.I386_Esp] = op.DwarfRegisterFromUint64(sp)
|
||||||
dregs[i386DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
|
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) {
|
func i386DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||||
name, ok := i386DwarfToName[j]
|
name = regnum.I386ToName(j)
|
||||||
if !ok {
|
|
||||||
name = fmt.Sprintf("unknown%d", j)
|
if reg == nil {
|
||||||
|
return name, false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n := strings.ToLower(name); n {
|
switch n := strings.ToLower(name); n {
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package linutil
|
package linutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"golang.org/x/arch/x86/x86asm"
|
"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"
|
||||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||||
)
|
)
|
||||||
@ -307,3 +311,71 @@ func (r *AMD64Registers) Copy() (proc.Registers, error) {
|
|||||||
}
|
}
|
||||||
return &rr, nil
|
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.
|
// memory.
|
||||||
type compositeMemory struct {
|
type compositeMemory struct {
|
||||||
realmem MemoryReadWriter
|
realmem MemoryReadWriter
|
||||||
|
arch *Arch
|
||||||
regs op.DwarfRegisters
|
regs op.DwarfRegisters
|
||||||
pieces []op.Piece
|
pieces []op.Piece
|
||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCompositeMemory(mem MemoryReadWriter, regs op.DwarfRegisters, pieces []op.Piece) (*compositeMemory, error) {
|
func newCompositeMemory(mem MemoryReadWriter, arch *Arch, regs op.DwarfRegisters, pieces []op.Piece) (*compositeMemory, error) {
|
||||||
cmem := &compositeMemory{realmem: mem, regs: regs, pieces: pieces, data: []byte{}}
|
cmem := &compositeMemory{realmem: mem, arch: arch, regs: regs, pieces: pieces, data: []byte{}}
|
||||||
for _, piece := range pieces {
|
for i := range pieces {
|
||||||
|
piece := &pieces[i]
|
||||||
if piece.IsRegister {
|
if piece.IsRegister {
|
||||||
reg := regs.Bytes(piece.RegNum)
|
reg := regs.Bytes(piece.RegNum)
|
||||||
sz := piece.Size
|
if piece.Size == 0 && len(pieces) == 1 {
|
||||||
if sz == 0 && len(pieces) == 1 {
|
piece.Size = len(reg)
|
||||||
sz = len(reg)
|
|
||||||
}
|
}
|
||||||
if sz > len(reg) {
|
if piece.Size > len(reg) {
|
||||||
if regs.FloatLoadError != nil {
|
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 {
|
} else {
|
||||||
buf := make([]byte, piece.Size)
|
buf := make([]byte, piece.Size)
|
||||||
mem.ReadMemory(buf, uint64(piece.Addr))
|
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) {
|
func (mem *compositeMemory) WriteMemory(addr uint64, data []byte) (int, error) {
|
||||||
//TODO(aarzilli): implement
|
addr -= fakeAddress
|
||||||
return 0, errors.New("can't write composite memory")
|
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
|
// DereferenceMemory returns a MemoryReadWriter that can read and write the
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
"github.com/go-delve/delve/pkg/proc"
|
"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.
|
// SetPC sets the value of the PC register.
|
||||||
func (t *nativeThread) SetPC(pc uint64) error {
|
func (t *nativeThread) setPC(pc uint64) error {
|
||||||
panic(ErrNativeBackendDisabled)
|
panic(ErrNativeBackendDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP sets the value of the SP register.
|
// SetReg changes the value of the specified register.
|
||||||
func (t *nativeThread) SetSP(sp uint64) error {
|
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||||
panic(ErrNativeBackendDisabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDX sets the value of the DX register.
|
|
||||||
func (t *nativeThread) SetDX(dx uint64) error {
|
|
||||||
panic(ErrNativeBackendDisabled)
|
panic(ErrNativeBackendDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,7 +594,7 @@ func (dbp *nativeProcess) stop(trapthread *nativeThread) (*nativeThread, error)
|
|||||||
}
|
}
|
||||||
if !isHardcodedBreakpoint {
|
if !isHardcodedBreakpoint {
|
||||||
// phantom breakpoint hit
|
// 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
|
th.os.setbp = false
|
||||||
if trapthread.ThreadID() == th.ThreadID() {
|
if trapthread.ThreadID() == th.ThreadID() {
|
||||||
// Will switch to a different thread for trapthread because we don't
|
// 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 {
|
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"
|
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"
|
||||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetPC sets EIP to the value specified by 'pc'.
|
// setPC sets EIP to the value specified by 'pc'.
|
||||||
func (thread *nativeThread) SetPC(pc uint64) error {
|
func (thread *nativeThread) setPC(pc uint64) error {
|
||||||
ir, err := registers(thread)
|
ir, err := registers(thread)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -22,29 +24,26 @@ func (thread *nativeThread) SetPC(pc uint64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP sets ESP to the value specified by 'sp'
|
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||||
func (thread *nativeThread) SetSP(sp uint64) (err error) {
|
ir, err := registers(thread)
|
||||||
var ir proc.Registers
|
|
||||||
ir, err = registers(thread)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r := ir.(*linutil.I386Registers)
|
r := ir.(*linutil.I386Registers)
|
||||||
r.Regs.Esp = int32(sp)
|
switch regNum {
|
||||||
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
|
case regnum.I386_Eip:
|
||||||
return
|
r.Regs.Eip = int32(reg.Uint64Val)
|
||||||
}
|
case regnum.I386_Esp:
|
||||||
|
r.Regs.Esp = int32(reg.Uint64Val)
|
||||||
func (thread *nativeThread) SetDX(dx uint64) (err error) {
|
case regnum.I386_Edx:
|
||||||
var ir proc.Registers
|
r.Regs.Edx = int32(reg.Uint64Val)
|
||||||
ir, err = registers(thread)
|
default:
|
||||||
if err != nil {
|
//TODO(aarzilli): when the register calling convention is adopted by Go on
|
||||||
return err
|
// 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)) })
|
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func registers(thread *nativeThread) (proc.Registers, error) {
|
func registers(thread *nativeThread) (proc.Registers, error) {
|
||||||
|
@ -5,12 +5,13 @@ package native
|
|||||||
// #include "threads_darwin.h"
|
// #include "threads_darwin.h"
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/arch/x86/x86asm"
|
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ func (r *Regs) GAddr() (uint64, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetPC sets the RIP register to the value specified by `pc`.
|
// 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))
|
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
|
||||||
if kret != C.KERN_SUCCESS {
|
if kret != C.KERN_SUCCESS {
|
||||||
return fmt.Errorf("could not set pc")
|
return fmt.Errorf("could not set pc")
|
||||||
@ -119,13 +120,12 @@ func (thread *nativeThread) SetPC(pc uint64) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP sets the RSP register to the value specified by `pc`.
|
// SetReg changes the value of the specified register.
|
||||||
func (thread *nativeThread) SetSP(sp uint64) error {
|
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||||
return errors.New("not implemented")
|
if regNum != regnum.AMD64_Rip {
|
||||||
}
|
return fmt.Errorf("changing register %d not implemented", regNum)
|
||||||
|
}
|
||||||
func (thread *nativeThread) SetDX(dx uint64) error {
|
return thread.setPC(reg.Uint64Val)
|
||||||
return errors.New("not implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Regs) Get(n int) (uint64, error) {
|
func (r *Regs) Get(n int) (uint64, error) {
|
||||||
|
@ -5,13 +5,15 @@ import (
|
|||||||
|
|
||||||
sys "golang.org/x/sys/unix"
|
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"
|
||||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||||
"github.com/go-delve/delve/pkg/proc/fbsdutil"
|
"github.com/go-delve/delve/pkg/proc/fbsdutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetPC sets RIP to the value specified by 'pc'.
|
// 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)
|
ir, err := registers(thread)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -22,27 +24,23 @@ func (thread *nativeThread) SetPC(pc uint64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP sets RSP to the value specified by 'sp'
|
// SetReg changes the value of the specified register.
|
||||||
func (thread *nativeThread) SetSP(sp uint64) (err error) {
|
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) (err error) {
|
||||||
var ir proc.Registers
|
ir, err := registers(thread)
|
||||||
ir, err = registers(thread)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r := ir.(*fbsdutil.AMD64Registers)
|
r := ir.(*fbsdutil.AMD64Registers)
|
||||||
r.Regs.Rsp = int64(sp)
|
switch regNum {
|
||||||
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.Reg)(r.Regs)) })
|
case regnum.AMD64_Rip:
|
||||||
return
|
r.Regs.Rip = int64(reg.Uint64Val)
|
||||||
}
|
case regnum.AMD64_Rsp:
|
||||||
|
r.Regs.Rsp = int64(reg.Uint64Val)
|
||||||
func (thread *nativeThread) SetDX(dx uint64) (err error) {
|
case regnum.AMD64_Rdx:
|
||||||
var ir proc.Registers
|
r.Regs.Rdx = int64(reg.Uint64Val)
|
||||||
ir, err = registers(thread)
|
default:
|
||||||
if err != nil {
|
return fmt.Errorf("changing register %d not implemented", regNum)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
r := ir.(*fbsdutil.AMD64Registers)
|
|
||||||
r.Regs.Rdx = int64(dx)
|
|
||||||
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.Reg)(r.Regs)) })
|
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.Reg)(r.Regs)) })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,19 @@ package native
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
sys "golang.org/x/sys/unix"
|
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"
|
||||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetPC sets RIP to the value specified by 'pc'.
|
// 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)
|
ir, err := registers(thread)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -22,29 +25,31 @@ func (thread *nativeThread) SetPC(pc uint64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP sets RSP to the value specified by 'sp'
|
// SetReg changes the value of the specified register.
|
||||||
func (thread *nativeThread) SetSP(sp uint64) (err error) {
|
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||||
var ir proc.Registers
|
ir, err := registers(thread)
|
||||||
ir, err = registers(thread)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r := ir.(*linutil.AMD64Registers)
|
r := ir.(*linutil.AMD64Registers)
|
||||||
r.Regs.Rsp = sp
|
fpchanged, err := r.SetReg(regNum, reg)
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r := ir.(*linutil.AMD64Registers)
|
thread.dbp.execPtraceFunc(func() {
|
||||||
r.Regs.Rdx = dx
|
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
|
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) {
|
func registers(thread *nativeThread) (proc.Registers, error) {
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
sys "golang.org/x/sys/unix"
|
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"
|
||||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||||
)
|
)
|
||||||
@ -64,8 +66,8 @@ func ptraceGetFpRegset(tid int) (fpregset []byte, err error) {
|
|||||||
return fpregset, err
|
return fpregset, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPC sets PC to the value specified by 'pc'.
|
// setPC sets PC to the value specified by 'pc'.
|
||||||
func (thread *nativeThread) SetPC(pc uint64) error {
|
func (thread *nativeThread) setPC(pc uint64) error {
|
||||||
ir, err := registers(thread)
|
ir, err := registers(thread)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -76,21 +78,26 @@ func (thread *nativeThread) SetPC(pc uint64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP sets RSP to the value specified by 'sp'
|
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||||
func (thread *nativeThread) SetSP(sp uint64) (err error) {
|
ir, err := registers(thread)
|
||||||
var ir proc.Registers
|
|
||||||
ir, err = registers(thread)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r := ir.(*linutil.ARM64Registers)
|
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) {
|
switch regNum {
|
||||||
return fmt.Errorf("not supported")
|
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) {
|
func registers(thread *nativeThread) (proc.Registers, error) {
|
||||||
|
@ -4,12 +4,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"unsafe"
|
"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"
|
||||||
"github.com/go-delve/delve/pkg/proc/winutil"
|
"github.com/go-delve/delve/pkg/proc/winutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetPC sets the RIP register to the value specified by `pc`.
|
// 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 := winutil.NewCONTEXT()
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
context.ContextFlags = _CONTEXT_ALL
|
||||||
|
|
||||||
@ -23,8 +25,8 @@ func (thread *nativeThread) SetPC(pc uint64) error {
|
|||||||
return _SetThreadContext(thread.os.hThread, context)
|
return _SetThreadContext(thread.os.hThread, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSP sets the RSP register to the value specified by `sp`.
|
// SetReg changes the value of the specified register.
|
||||||
func (thread *nativeThread) SetSP(sp uint64) error {
|
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||||
context := winutil.NewCONTEXT()
|
context := winutil.NewCONTEXT()
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
context.ContextFlags = _CONTEXT_ALL
|
||||||
|
|
||||||
@ -33,21 +35,60 @@ func (thread *nativeThread) SetSP(sp uint64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Rsp = sp
|
var p *uint64
|
||||||
|
|
||||||
return _SetThreadContext(thread.os.hThread, context)
|
switch regNum {
|
||||||
}
|
case regnum.AMD64_Rax:
|
||||||
|
p = &context.Rax
|
||||||
func (thread *nativeThread) SetDX(dx uint64) error {
|
case regnum.AMD64_Rbx:
|
||||||
context := winutil.NewCONTEXT()
|
p = &context.Rbx
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
case regnum.AMD64_Rcx:
|
||||||
|
p = &context.Rcx
|
||||||
err := _GetThreadContext(thread.os.hThread, context)
|
case regnum.AMD64_Rdx:
|
||||||
if err != nil {
|
p = &context.Rdx
|
||||||
return err
|
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)
|
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 bp, ok := t.dbp.FindBreakpoint(pc, adjustPC); ok {
|
||||||
if adjustPC {
|
if adjustPC {
|
||||||
if err = t.SetPC(bp.Addr); err != nil {
|
if err = t.setPC(bp.Addr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package proc_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"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
|
return nil, err
|
||||||
}
|
}
|
||||||
so := thread.BinInfo().PCToImage(regs.PC())
|
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 it.stacktrace(depth)
|
||||||
}
|
}
|
||||||
return g.Stacktrace(depth, 0)
|
return g.Stacktrace(depth, 0)
|
||||||
@ -119,9 +121,11 @@ func (g *G) stackIterator(opts StacktraceOptions) (*stackIterator, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
so := bi.PCToImage(regs.PC())
|
so := bi.PCToImage(regs.PC())
|
||||||
|
dwarfRegs := bi.Arch.RegistersToDwarfRegisters(so.StaticBase, regs)
|
||||||
|
dwarfRegs.ChangeFunc = g.Thread.SetReg
|
||||||
return newStackIterator(
|
return newStackIterator(
|
||||||
bi, g.variable.mem,
|
bi, g.variable.mem,
|
||||||
bi.Arch.RegistersToDwarfRegisters(so.StaticBase, regs),
|
dwarfRegs,
|
||||||
g.stack.hi, stkbar, g.stkbarPos, g, opts), nil
|
g.stack.hi, stkbar, g.stkbarPos, g, opts), nil
|
||||||
}
|
}
|
||||||
so := g.variable.bi.PCToImage(g.PC)
|
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
|
// In linux-arm64, PtraceSingleStep seems cannot step over BRK instruction
|
||||||
// (linux-arm64 feature or kernel bug maybe).
|
// (linux-arm64 feature or kernel bug maybe).
|
||||||
if !arch.BreakInstrMovesPC() {
|
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
|
// Single-step current thread until we exit runtime.breakpoint and
|
||||||
// runtime.Breakpoint.
|
// runtime.Breakpoint.
|
||||||
@ -145,7 +145,7 @@ func (dbp *Target) Continue() error {
|
|||||||
bp := make([]byte, bpsize)
|
bp := make([]byte, bpsize)
|
||||||
_, err = dbp.Memory().ReadMemory(bp, loc.PC)
|
_, err = dbp.Memory().ReadMemory(bp, loc.PC)
|
||||||
if bytes.Equal(bp, arch.BreakpointInstruction()) {
|
if bytes.Equal(bp, arch.BreakpointInstruction()) {
|
||||||
curthread.SetPC(loc.PC + uint64(bpsize))
|
setPC(curthread, loc.PC+uint64(bpsize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return conditionErrors(threads)
|
return conditionErrors(threads)
|
||||||
|
@ -2,6 +2,8 @@ package proc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Thread represents a thread.
|
// Thread represents a thread.
|
||||||
@ -31,9 +33,10 @@ type Thread interface {
|
|||||||
// Common returns the CommonThread structure for this thread
|
// Common returns the CommonThread structure for this thread
|
||||||
Common() *CommonThread
|
Common() *CommonThread
|
||||||
|
|
||||||
SetPC(uint64) error
|
// SetReg changes the value of the specified register. A minimal
|
||||||
SetSP(uint64) error
|
// implementation of this interface can support just setting the PC
|
||||||
SetDX(uint64) error
|
// register.
|
||||||
|
SetReg(uint64, *op.DwarfRegister) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Location represents the location of a thread.
|
// 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
|
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 {
|
if pieces != nil {
|
||||||
addr = fakeAddress
|
addr = fakeAddress
|
||||||
var cmem *compositeMemory
|
var cmem *compositeMemory
|
||||||
cmem, err = newCompositeMemory(mem, regs, pieces)
|
cmem, err = newCompositeMemory(mem, bi.Arch, regs, pieces)
|
||||||
if cmem != nil {
|
if cmem != nil {
|
||||||
mem = cmem
|
mem = cmem
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user