2018-10-17 14:55:53 +00:00
|
|
|
package linutil
|
|
|
|
|
|
|
|
import (
|
2021-03-04 18:28:28 +00:00
|
|
|
"fmt"
|
|
|
|
|
2018-10-17 14:55:53 +00:00
|
|
|
"golang.org/x/arch/x86/x86asm"
|
|
|
|
|
2021-03-04 18:28:28 +00:00
|
|
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
|
|
|
"github.com/go-delve/delve/pkg/dwarf/regnum"
|
2019-01-04 18:39:25 +00:00
|
|
|
"github.com/go-delve/delve/pkg/proc"
|
2020-12-14 17:39:01 +00:00
|
|
|
"github.com/go-delve/delve/pkg/proc/amd64util"
|
2018-10-17 14:55:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// AMD64Registers implements the proc.Registers interface for the native/linux
|
|
|
|
// backend and core/linux backends, on AMD64.
|
|
|
|
type AMD64Registers struct {
|
|
|
|
Regs *AMD64PtraceRegs
|
|
|
|
Fpregs []proc.Register
|
2020-12-14 17:39:01 +00:00
|
|
|
Fpregset *amd64util.AMD64Xstate
|
2020-05-13 18:56:50 +00:00
|
|
|
|
|
|
|
loadFpRegs func(*AMD64Registers) error
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewAMD64Registers(regs *AMD64PtraceRegs, loadFpRegs func(*AMD64Registers) error) *AMD64Registers {
|
|
|
|
return &AMD64Registers{Regs: regs, loadFpRegs: loadFpRegs}
|
2018-10-17 14:55:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AMD64PtraceRegs is the struct used by the linux kernel to return the
|
|
|
|
// general purpose registers for AMD64 CPUs.
|
|
|
|
type AMD64PtraceRegs struct {
|
|
|
|
R15 uint64
|
|
|
|
R14 uint64
|
|
|
|
R13 uint64
|
|
|
|
R12 uint64
|
|
|
|
Rbp uint64
|
|
|
|
Rbx uint64
|
|
|
|
R11 uint64
|
|
|
|
R10 uint64
|
|
|
|
R9 uint64
|
|
|
|
R8 uint64
|
|
|
|
Rax uint64
|
|
|
|
Rcx uint64
|
|
|
|
Rdx uint64
|
|
|
|
Rsi uint64
|
|
|
|
Rdi uint64
|
|
|
|
Orig_rax uint64
|
|
|
|
Rip uint64
|
|
|
|
Cs uint64
|
|
|
|
Eflags uint64
|
|
|
|
Rsp uint64
|
|
|
|
Ss uint64
|
|
|
|
Fs_base uint64
|
|
|
|
Gs_base uint64
|
|
|
|
Ds uint64
|
|
|
|
Es uint64
|
|
|
|
Fs uint64
|
|
|
|
Gs uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slice returns the registers as a list of (name, value) pairs.
|
2020-05-13 18:56:50 +00:00
|
|
|
func (r *AMD64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
|
2018-10-17 14:55:53 +00:00
|
|
|
var regs = []struct {
|
|
|
|
k string
|
|
|
|
v uint64
|
|
|
|
}{
|
|
|
|
{"Rip", r.Regs.Rip},
|
|
|
|
{"Rsp", r.Regs.Rsp},
|
|
|
|
{"Rax", r.Regs.Rax},
|
|
|
|
{"Rbx", r.Regs.Rbx},
|
|
|
|
{"Rcx", r.Regs.Rcx},
|
|
|
|
{"Rdx", r.Regs.Rdx},
|
|
|
|
{"Rdi", r.Regs.Rdi},
|
|
|
|
{"Rsi", r.Regs.Rsi},
|
|
|
|
{"Rbp", r.Regs.Rbp},
|
|
|
|
{"R8", r.Regs.R8},
|
|
|
|
{"R9", r.Regs.R9},
|
|
|
|
{"R10", r.Regs.R10},
|
|
|
|
{"R11", r.Regs.R11},
|
|
|
|
{"R12", r.Regs.R12},
|
|
|
|
{"R13", r.Regs.R13},
|
|
|
|
{"R14", r.Regs.R14},
|
|
|
|
{"R15", r.Regs.R15},
|
|
|
|
{"Orig_rax", r.Regs.Orig_rax},
|
|
|
|
{"Cs", r.Regs.Cs},
|
2020-02-12 21:31:48 +00:00
|
|
|
{"Rflags", r.Regs.Eflags},
|
2018-10-17 14:55:53 +00:00
|
|
|
{"Ss", r.Regs.Ss},
|
|
|
|
{"Fs_base", r.Regs.Fs_base},
|
|
|
|
{"Gs_base", r.Regs.Gs_base},
|
|
|
|
{"Ds", r.Regs.Ds},
|
|
|
|
{"Es", r.Regs.Es},
|
|
|
|
{"Fs", r.Regs.Fs},
|
|
|
|
{"Gs", r.Regs.Gs},
|
|
|
|
}
|
|
|
|
out := make([]proc.Register, 0, len(regs)+len(r.Fpregs))
|
|
|
|
for _, reg := range regs {
|
2020-02-12 21:31:48 +00:00
|
|
|
out = proc.AppendUint64Register(out, reg.k, reg.v)
|
2018-10-17 14:55:53 +00:00
|
|
|
}
|
2020-05-13 18:56:50 +00:00
|
|
|
var floatLoadError error
|
2019-02-26 16:53:45 +00:00
|
|
|
if floatingPoint {
|
2020-05-13 18:56:50 +00:00
|
|
|
if r.loadFpRegs != nil {
|
|
|
|
floatLoadError = r.loadFpRegs(r)
|
|
|
|
r.loadFpRegs = nil
|
|
|
|
}
|
2019-02-26 16:53:45 +00:00
|
|
|
out = append(out, r.Fpregs...)
|
|
|
|
}
|
2020-05-13 18:56:50 +00:00
|
|
|
return out, floatLoadError
|
2018-10-17 14:55:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PC returns the value of RIP register.
|
|
|
|
func (r *AMD64Registers) PC() uint64 {
|
|
|
|
return r.Regs.Rip
|
|
|
|
}
|
|
|
|
|
|
|
|
// SP returns the value of RSP register.
|
|
|
|
func (r *AMD64Registers) SP() uint64 {
|
|
|
|
return r.Regs.Rsp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *AMD64Registers) BP() uint64 {
|
|
|
|
return r.Regs.Rbp
|
|
|
|
}
|
|
|
|
|
|
|
|
// TLS returns the address of the thread local storage memory segment.
|
|
|
|
func (r *AMD64Registers) TLS() uint64 {
|
|
|
|
return r.Regs.Fs_base
|
|
|
|
}
|
|
|
|
|
|
|
|
// GAddr returns the address of the G variable if it is known, 0 and false
|
|
|
|
// otherwise.
|
|
|
|
func (r *AMD64Registers) GAddr() (uint64, bool) {
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns the value of the n-th register (in x86asm order).
|
|
|
|
func (r *AMD64Registers) Get(n int) (uint64, error) {
|
|
|
|
reg := x86asm.Reg(n)
|
|
|
|
const (
|
2019-06-16 00:56:51 +00:00
|
|
|
mask8 = 0x000000ff
|
|
|
|
mask16 = 0x0000ffff
|
|
|
|
mask32 = 0xffffffff
|
2018-10-17 14:55:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
switch reg {
|
|
|
|
// 8-bit
|
|
|
|
case x86asm.AL:
|
|
|
|
return r.Regs.Rax & mask8, nil
|
|
|
|
case x86asm.CL:
|
|
|
|
return r.Regs.Rcx & mask8, nil
|
|
|
|
case x86asm.DL:
|
|
|
|
return r.Regs.Rdx & mask8, nil
|
|
|
|
case x86asm.BL:
|
|
|
|
return r.Regs.Rbx & mask8, nil
|
|
|
|
case x86asm.AH:
|
|
|
|
return (r.Regs.Rax >> 8) & mask8, nil
|
|
|
|
case x86asm.CH:
|
|
|
|
return (r.Regs.Rcx >> 8) & mask8, nil
|
|
|
|
case x86asm.DH:
|
|
|
|
return (r.Regs.Rdx >> 8) & mask8, nil
|
|
|
|
case x86asm.BH:
|
|
|
|
return (r.Regs.Rbx >> 8) & mask8, nil
|
|
|
|
case x86asm.SPB:
|
|
|
|
return r.Regs.Rsp & mask8, nil
|
|
|
|
case x86asm.BPB:
|
|
|
|
return r.Regs.Rbp & mask8, nil
|
|
|
|
case x86asm.SIB:
|
|
|
|
return r.Regs.Rsi & mask8, nil
|
|
|
|
case x86asm.DIB:
|
|
|
|
return r.Regs.Rdi & mask8, nil
|
|
|
|
case x86asm.R8B:
|
|
|
|
return r.Regs.R8 & mask8, nil
|
|
|
|
case x86asm.R9B:
|
|
|
|
return r.Regs.R9 & mask8, nil
|
|
|
|
case x86asm.R10B:
|
|
|
|
return r.Regs.R10 & mask8, nil
|
|
|
|
case x86asm.R11B:
|
|
|
|
return r.Regs.R11 & mask8, nil
|
|
|
|
case x86asm.R12B:
|
|
|
|
return r.Regs.R12 & mask8, nil
|
|
|
|
case x86asm.R13B:
|
|
|
|
return r.Regs.R13 & mask8, nil
|
|
|
|
case x86asm.R14B:
|
|
|
|
return r.Regs.R14 & mask8, nil
|
|
|
|
case x86asm.R15B:
|
|
|
|
return r.Regs.R15 & mask8, nil
|
|
|
|
|
|
|
|
// 16-bit
|
|
|
|
case x86asm.AX:
|
|
|
|
return r.Regs.Rax & mask16, nil
|
|
|
|
case x86asm.CX:
|
|
|
|
return r.Regs.Rcx & mask16, nil
|
|
|
|
case x86asm.DX:
|
|
|
|
return r.Regs.Rdx & mask16, nil
|
|
|
|
case x86asm.BX:
|
|
|
|
return r.Regs.Rbx & mask16, nil
|
|
|
|
case x86asm.SP:
|
|
|
|
return r.Regs.Rsp & mask16, nil
|
|
|
|
case x86asm.BP:
|
|
|
|
return r.Regs.Rbp & mask16, nil
|
|
|
|
case x86asm.SI:
|
|
|
|
return r.Regs.Rsi & mask16, nil
|
|
|
|
case x86asm.DI:
|
|
|
|
return r.Regs.Rdi & mask16, nil
|
|
|
|
case x86asm.R8W:
|
|
|
|
return r.Regs.R8 & mask16, nil
|
|
|
|
case x86asm.R9W:
|
|
|
|
return r.Regs.R9 & mask16, nil
|
|
|
|
case x86asm.R10W:
|
|
|
|
return r.Regs.R10 & mask16, nil
|
|
|
|
case x86asm.R11W:
|
|
|
|
return r.Regs.R11 & mask16, nil
|
|
|
|
case x86asm.R12W:
|
|
|
|
return r.Regs.R12 & mask16, nil
|
|
|
|
case x86asm.R13W:
|
|
|
|
return r.Regs.R13 & mask16, nil
|
|
|
|
case x86asm.R14W:
|
|
|
|
return r.Regs.R14 & mask16, nil
|
|
|
|
case x86asm.R15W:
|
|
|
|
return r.Regs.R15 & mask16, nil
|
|
|
|
|
|
|
|
// 32-bit
|
|
|
|
case x86asm.EAX:
|
|
|
|
return r.Regs.Rax & mask32, nil
|
|
|
|
case x86asm.ECX:
|
|
|
|
return r.Regs.Rcx & mask32, nil
|
|
|
|
case x86asm.EDX:
|
|
|
|
return r.Regs.Rdx & mask32, nil
|
|
|
|
case x86asm.EBX:
|
|
|
|
return r.Regs.Rbx & mask32, nil
|
|
|
|
case x86asm.ESP:
|
|
|
|
return r.Regs.Rsp & mask32, nil
|
|
|
|
case x86asm.EBP:
|
|
|
|
return r.Regs.Rbp & mask32, nil
|
|
|
|
case x86asm.ESI:
|
|
|
|
return r.Regs.Rsi & mask32, nil
|
|
|
|
case x86asm.EDI:
|
|
|
|
return r.Regs.Rdi & mask32, nil
|
|
|
|
case x86asm.R8L:
|
|
|
|
return r.Regs.R8 & mask32, nil
|
|
|
|
case x86asm.R9L:
|
|
|
|
return r.Regs.R9 & mask32, nil
|
|
|
|
case x86asm.R10L:
|
|
|
|
return r.Regs.R10 & mask32, nil
|
|
|
|
case x86asm.R11L:
|
|
|
|
return r.Regs.R11 & mask32, nil
|
|
|
|
case x86asm.R12L:
|
|
|
|
return r.Regs.R12 & mask32, nil
|
|
|
|
case x86asm.R13L:
|
|
|
|
return r.Regs.R13 & mask32, nil
|
|
|
|
case x86asm.R14L:
|
|
|
|
return r.Regs.R14 & mask32, nil
|
|
|
|
case x86asm.R15L:
|
|
|
|
return r.Regs.R15 & mask32, nil
|
|
|
|
|
|
|
|
// 64-bit
|
|
|
|
case x86asm.RAX:
|
|
|
|
return r.Regs.Rax, nil
|
|
|
|
case x86asm.RCX:
|
|
|
|
return r.Regs.Rcx, nil
|
|
|
|
case x86asm.RDX:
|
|
|
|
return r.Regs.Rdx, nil
|
|
|
|
case x86asm.RBX:
|
|
|
|
return r.Regs.Rbx, nil
|
|
|
|
case x86asm.RSP:
|
|
|
|
return r.Regs.Rsp, nil
|
|
|
|
case x86asm.RBP:
|
|
|
|
return r.Regs.Rbp, nil
|
|
|
|
case x86asm.RSI:
|
|
|
|
return r.Regs.Rsi, nil
|
|
|
|
case x86asm.RDI:
|
|
|
|
return r.Regs.Rdi, nil
|
|
|
|
case x86asm.R8:
|
|
|
|
return r.Regs.R8, nil
|
|
|
|
case x86asm.R9:
|
|
|
|
return r.Regs.R9, nil
|
|
|
|
case x86asm.R10:
|
|
|
|
return r.Regs.R10, nil
|
|
|
|
case x86asm.R11:
|
|
|
|
return r.Regs.R11, nil
|
|
|
|
case x86asm.R12:
|
|
|
|
return r.Regs.R12, nil
|
|
|
|
case x86asm.R13:
|
|
|
|
return r.Regs.R13, nil
|
|
|
|
case x86asm.R14:
|
|
|
|
return r.Regs.R14, nil
|
|
|
|
case x86asm.R15:
|
|
|
|
return r.Regs.R15, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0, proc.ErrUnknownRegister
|
|
|
|
}
|
|
|
|
|
2020-08-24 17:19:50 +00:00
|
|
|
// Copy returns a copy of these registers that is guaranteed not to change.
|
2020-05-13 18:56:50 +00:00
|
|
|
func (r *AMD64Registers) Copy() (proc.Registers, error) {
|
|
|
|
if r.loadFpRegs != nil {
|
|
|
|
err := r.loadFpRegs(r)
|
|
|
|
r.loadFpRegs = nil
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2018-10-17 14:55:53 +00:00
|
|
|
var rr AMD64Registers
|
|
|
|
rr.Regs = &AMD64PtraceRegs{}
|
2020-12-14 17:39:01 +00:00
|
|
|
rr.Fpregset = &amd64util.AMD64Xstate{}
|
2018-10-17 14:55:53 +00:00
|
|
|
*(rr.Regs) = *(r.Regs)
|
|
|
|
if r.Fpregset != nil {
|
|
|
|
*(rr.Fpregset) = *(r.Fpregset)
|
|
|
|
}
|
|
|
|
if r.Fpregs != nil {
|
|
|
|
rr.Fpregs = make([]proc.Register, len(r.Fpregs))
|
|
|
|
copy(rr.Fpregs, r.Fpregs)
|
|
|
|
}
|
2020-05-13 18:56:50 +00:00
|
|
|
return &rr, nil
|
2018-10-17 14:55:53 +00:00
|
|
|
}
|
2021-03-04 18:28:28 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|