mirror of https://github.com/beego/bee.git
343 lines
7.5 KiB
Go
343 lines
7.5 KiB
Go
package native
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"golang.org/x/arch/x86/x86asm"
|
|
sys "golang.org/x/sys/unix"
|
|
|
|
"github.com/derekparker/delve/pkg/proc"
|
|
)
|
|
|
|
// Regs is a wrapper for sys.PtraceRegs.
|
|
type Regs struct {
|
|
regs *sys.PtraceRegs
|
|
fpregs []proc.Register
|
|
fpregset *proc.LinuxX86Xstate
|
|
}
|
|
|
|
func (r *Regs) Slice() []proc.Register {
|
|
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},
|
|
{"Eflags", r.regs.Eflags},
|
|
{"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 {
|
|
if reg.k == "Eflags" {
|
|
out = proc.AppendEflagReg(out, reg.k, reg.v)
|
|
} else {
|
|
out = proc.AppendQwordReg(out, reg.k, reg.v)
|
|
}
|
|
}
|
|
out = append(out, r.fpregs...)
|
|
return out
|
|
}
|
|
|
|
// PC returns the value of RIP register.
|
|
func (r *Regs) PC() uint64 {
|
|
return r.regs.PC()
|
|
}
|
|
|
|
// SP returns the value of RSP register.
|
|
func (r *Regs) SP() uint64 {
|
|
return r.regs.Rsp
|
|
}
|
|
|
|
func (r *Regs) BP() uint64 {
|
|
return r.regs.Rbp
|
|
}
|
|
|
|
// CX returns the value of RCX register.
|
|
func (r *Regs) CX() uint64 {
|
|
return r.regs.Rcx
|
|
}
|
|
|
|
// TLS returns the address of the thread
|
|
// local storage memory segment.
|
|
func (r *Regs) TLS() uint64 {
|
|
return r.regs.Fs_base
|
|
}
|
|
|
|
func (r *Regs) GAddr() (uint64, bool) {
|
|
return 0, false
|
|
}
|
|
|
|
// SetPC sets RIP to the value specified by 'pc'.
|
|
func (thread *Thread) SetPC(pc uint64) error {
|
|
ir, err := registers(thread, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r := ir.(*Regs)
|
|
r.regs.SetPC(pc)
|
|
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, r.regs) })
|
|
return err
|
|
}
|
|
|
|
// SetSP sets RSP to the value specified by 'sp'
|
|
func (thread *Thread) SetSP(sp uint64) (err error) {
|
|
var ir proc.Registers
|
|
ir, err = registers(thread, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r := ir.(*Regs)
|
|
r.regs.Rsp = sp
|
|
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, r.regs) })
|
|
return
|
|
}
|
|
|
|
func (thread *Thread) SetDX(dx uint64) (err error) {
|
|
var ir proc.Registers
|
|
ir, err = registers(thread, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r := ir.(*Regs)
|
|
r.regs.Rdx = dx
|
|
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, r.regs) })
|
|
return
|
|
}
|
|
|
|
func (r *Regs) Get(n int) (uint64, error) {
|
|
reg := x86asm.Reg(n)
|
|
const (
|
|
mask8 = 0x000f
|
|
mask16 = 0x00ff
|
|
mask32 = 0xffff
|
|
)
|
|
|
|
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
|
|
}
|
|
|
|
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
|
var (
|
|
regs sys.PtraceRegs
|
|
err error
|
|
)
|
|
thread.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(thread.ID, ®s) })
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r := &Regs{®s, nil, nil}
|
|
if floatingPoint {
|
|
var fpregset proc.LinuxX86Xstate
|
|
r.fpregs, fpregset, err = thread.fpRegisters()
|
|
r.fpregset = &fpregset
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
const (
|
|
_X86_XSTATE_MAX_SIZE = 2688
|
|
_NT_X86_XSTATE = 0x202
|
|
|
|
_XSAVE_HEADER_START = 512
|
|
_XSAVE_HEADER_LEN = 64
|
|
_XSAVE_EXTENDED_REGION_START = 576
|
|
_XSAVE_SSE_REGION_LEN = 416
|
|
)
|
|
|
|
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs proc.LinuxX86Xstate, err error) {
|
|
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) })
|
|
regs = fpregs.Decode()
|
|
if err != nil {
|
|
err = fmt.Errorf("could not get floating point registers: %v", err.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
// Copy returns a copy of these registers that is
|
|
// guarenteed not to change.
|
|
func (r *Regs) Copy() proc.Registers {
|
|
var rr Regs
|
|
rr.regs = &sys.PtraceRegs{}
|
|
rr.fpregset = &proc.LinuxX86Xstate{}
|
|
*(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)
|
|
}
|
|
return &rr
|
|
}
|