proc: move windows register handling code to winutil package
Move windows register handling code to winutil package in preparation for using it in proc/core to read minidump files.
This commit is contained in:
parent
3048b9605a
commit
31fff84519
@ -4,136 +4,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/arch/x86/x86asm"
|
|
||||||
|
|
||||||
"github.com/derekparker/delve/pkg/proc"
|
"github.com/derekparker/delve/pkg/proc"
|
||||||
|
"github.com/derekparker/delve/pkg/proc/winutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Regs represents CPU registers on an AMD64 processor.
|
|
||||||
type Regs struct {
|
|
||||||
rax uint64
|
|
||||||
rbx uint64
|
|
||||||
rcx uint64
|
|
||||||
rdx uint64
|
|
||||||
rdi uint64
|
|
||||||
rsi uint64
|
|
||||||
rbp uint64
|
|
||||||
rsp uint64
|
|
||||||
r8 uint64
|
|
||||||
r9 uint64
|
|
||||||
r10 uint64
|
|
||||||
r11 uint64
|
|
||||||
r12 uint64
|
|
||||||
r13 uint64
|
|
||||||
r14 uint64
|
|
||||||
r15 uint64
|
|
||||||
rip uint64
|
|
||||||
eflags uint64
|
|
||||||
cs uint64
|
|
||||||
fs uint64
|
|
||||||
gs uint64
|
|
||||||
tls uint64
|
|
||||||
context *_CONTEXT
|
|
||||||
fltSave *_XMM_SAVE_AREA32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Regs) Slice() []proc.Register {
|
|
||||||
var regs = []struct {
|
|
||||||
k string
|
|
||||||
v uint64
|
|
||||||
}{
|
|
||||||
{"Rip", r.rip},
|
|
||||||
{"Rsp", r.rsp},
|
|
||||||
{"Rax", r.rax},
|
|
||||||
{"Rbx", r.rbx},
|
|
||||||
{"Rcx", r.rcx},
|
|
||||||
{"Rdx", r.rdx},
|
|
||||||
{"Rdi", r.rdi},
|
|
||||||
{"Rsi", r.rsi},
|
|
||||||
{"Rbp", r.rbp},
|
|
||||||
{"R8", r.r8},
|
|
||||||
{"R9", r.r9},
|
|
||||||
{"R10", r.r10},
|
|
||||||
{"R11", r.r11},
|
|
||||||
{"R12", r.r12},
|
|
||||||
{"R13", r.r13},
|
|
||||||
{"R14", r.r14},
|
|
||||||
{"R15", r.r15},
|
|
||||||
{"Eflags", r.eflags},
|
|
||||||
{"Cs", r.cs},
|
|
||||||
{"Fs", r.fs},
|
|
||||||
{"Gs", r.gs},
|
|
||||||
{"TLS", r.tls},
|
|
||||||
}
|
|
||||||
outlen := len(regs)
|
|
||||||
if r.fltSave != nil {
|
|
||||||
outlen += 6 + 8 + 2 + 16
|
|
||||||
}
|
|
||||||
out := make([]proc.Register, 0, outlen)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if r.fltSave != nil {
|
|
||||||
out = proc.AppendWordReg(out, "CW", r.fltSave.ControlWord)
|
|
||||||
out = proc.AppendWordReg(out, "SW", r.fltSave.StatusWord)
|
|
||||||
out = proc.AppendWordReg(out, "TW", uint16(r.fltSave.TagWord))
|
|
||||||
out = proc.AppendWordReg(out, "FOP", r.fltSave.ErrorOpcode)
|
|
||||||
out = proc.AppendQwordReg(out, "FIP", uint64(r.fltSave.ErrorSelector)<<32|uint64(r.fltSave.ErrorOffset))
|
|
||||||
out = proc.AppendQwordReg(out, "FDP", uint64(r.fltSave.DataSelector)<<32|uint64(r.fltSave.DataOffset))
|
|
||||||
|
|
||||||
for i := range r.fltSave.FloatRegisters {
|
|
||||||
out = proc.AppendX87Reg(out, i, uint16(r.fltSave.FloatRegisters[i].High), r.fltSave.FloatRegisters[i].Low)
|
|
||||||
}
|
|
||||||
|
|
||||||
out = proc.AppendMxcsrReg(out, "MXCSR", uint64(r.fltSave.MxCsr))
|
|
||||||
out = proc.AppendDwordReg(out, "MXCSR_MASK", r.fltSave.MxCsr_Mask)
|
|
||||||
|
|
||||||
for i := 0; i < len(r.fltSave.XmmRegisters); i += 16 {
|
|
||||||
out = proc.AppendSSEReg(out, fmt.Sprintf("XMM%d", i/16), r.fltSave.XmmRegisters[i:i+16])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// PC returns the current program counter
|
|
||||||
// i.e. the RIP CPU register.
|
|
||||||
func (r *Regs) PC() uint64 {
|
|
||||||
return r.rip
|
|
||||||
}
|
|
||||||
|
|
||||||
// SP returns the stack pointer location,
|
|
||||||
// i.e. the RSP register.
|
|
||||||
func (r *Regs) SP() uint64 {
|
|
||||||
return r.rsp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Regs) BP() uint64 {
|
|
||||||
return r.rbp
|
|
||||||
}
|
|
||||||
|
|
||||||
// CX returns the value of the RCX register.
|
|
||||||
func (r *Regs) CX() uint64 {
|
|
||||||
return r.rcx
|
|
||||||
}
|
|
||||||
|
|
||||||
// TLS returns the value of the register
|
|
||||||
// that contains the location of the thread
|
|
||||||
// local storage segment.
|
|
||||||
func (r *Regs) TLS() uint64 {
|
|
||||||
return r.tls
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Regs) GAddr() (uint64, bool) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPC sets the RIP register to the value specified by `pc`.
|
// SetPC sets the RIP register to the value specified by `pc`.
|
||||||
func (thread *Thread) SetPC(pc uint64) error {
|
func (thread *Thread) SetPC(pc uint64) error {
|
||||||
context := newCONTEXT()
|
context := winutil.NewCONTEXT()
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
context.ContextFlags = _CONTEXT_ALL
|
||||||
|
|
||||||
err := _GetThreadContext(thread.os.hThread, context)
|
err := _GetThreadContext(thread.os.hThread, context)
|
||||||
@ -148,7 +25,7 @@ func (thread *Thread) SetPC(pc uint64) error {
|
|||||||
|
|
||||||
// SetSP sets the RSP register to the value specified by `sp`.
|
// SetSP sets the RSP register to the value specified by `sp`.
|
||||||
func (thread *Thread) SetSP(sp uint64) error {
|
func (thread *Thread) SetSP(sp uint64) error {
|
||||||
context := newCONTEXT()
|
context := winutil.NewCONTEXT()
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
context.ContextFlags = _CONTEXT_ALL
|
||||||
|
|
||||||
err := _GetThreadContext(thread.os.hThread, context)
|
err := _GetThreadContext(thread.os.hThread, context)
|
||||||
@ -162,7 +39,7 @@ func (thread *Thread) SetSP(sp uint64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (thread *Thread) SetDX(dx uint64) error {
|
func (thread *Thread) SetDX(dx uint64) error {
|
||||||
context := newCONTEXT()
|
context := winutil.NewCONTEXT()
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
context.ContextFlags = _CONTEXT_ALL
|
||||||
|
|
||||||
err := _GetThreadContext(thread.os.hThread, context)
|
err := _GetThreadContext(thread.os.hThread, context)
|
||||||
@ -175,165 +52,8 @@ func (thread *Thread) SetDX(dx uint64) error {
|
|||||||
return _SetThreadContext(thread.os.hThread, context)
|
return _SetThreadContext(thread.os.hThread, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
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.rax & mask8, nil
|
|
||||||
case x86asm.CL:
|
|
||||||
return r.rcx & mask8, nil
|
|
||||||
case x86asm.DL:
|
|
||||||
return r.rdx & mask8, nil
|
|
||||||
case x86asm.BL:
|
|
||||||
return r.rbx & mask8, nil
|
|
||||||
case x86asm.AH:
|
|
||||||
return (r.rax >> 8) & mask8, nil
|
|
||||||
case x86asm.CH:
|
|
||||||
return (r.rcx >> 8) & mask8, nil
|
|
||||||
case x86asm.DH:
|
|
||||||
return (r.rdx >> 8) & mask8, nil
|
|
||||||
case x86asm.BH:
|
|
||||||
return (r.rbx >> 8) & mask8, nil
|
|
||||||
case x86asm.SPB:
|
|
||||||
return r.rsp & mask8, nil
|
|
||||||
case x86asm.BPB:
|
|
||||||
return r.rbp & mask8, nil
|
|
||||||
case x86asm.SIB:
|
|
||||||
return r.rsi & mask8, nil
|
|
||||||
case x86asm.DIB:
|
|
||||||
return r.rdi & mask8, nil
|
|
||||||
case x86asm.R8B:
|
|
||||||
return r.r8 & mask8, nil
|
|
||||||
case x86asm.R9B:
|
|
||||||
return r.r9 & mask8, nil
|
|
||||||
case x86asm.R10B:
|
|
||||||
return r.r10 & mask8, nil
|
|
||||||
case x86asm.R11B:
|
|
||||||
return r.r11 & mask8, nil
|
|
||||||
case x86asm.R12B:
|
|
||||||
return r.r12 & mask8, nil
|
|
||||||
case x86asm.R13B:
|
|
||||||
return r.r13 & mask8, nil
|
|
||||||
case x86asm.R14B:
|
|
||||||
return r.r14 & mask8, nil
|
|
||||||
case x86asm.R15B:
|
|
||||||
return r.r15 & mask8, nil
|
|
||||||
|
|
||||||
// 16-bit
|
|
||||||
case x86asm.AX:
|
|
||||||
return r.rax & mask16, nil
|
|
||||||
case x86asm.CX:
|
|
||||||
return r.rcx & mask16, nil
|
|
||||||
case x86asm.DX:
|
|
||||||
return r.rdx & mask16, nil
|
|
||||||
case x86asm.BX:
|
|
||||||
return r.rbx & mask16, nil
|
|
||||||
case x86asm.SP:
|
|
||||||
return r.rsp & mask16, nil
|
|
||||||
case x86asm.BP:
|
|
||||||
return r.rbp & mask16, nil
|
|
||||||
case x86asm.SI:
|
|
||||||
return r.rsi & mask16, nil
|
|
||||||
case x86asm.DI:
|
|
||||||
return r.rdi & mask16, nil
|
|
||||||
case x86asm.R8W:
|
|
||||||
return r.r8 & mask16, nil
|
|
||||||
case x86asm.R9W:
|
|
||||||
return r.r9 & mask16, nil
|
|
||||||
case x86asm.R10W:
|
|
||||||
return r.r10 & mask16, nil
|
|
||||||
case x86asm.R11W:
|
|
||||||
return r.r11 & mask16, nil
|
|
||||||
case x86asm.R12W:
|
|
||||||
return r.r12 & mask16, nil
|
|
||||||
case x86asm.R13W:
|
|
||||||
return r.r13 & mask16, nil
|
|
||||||
case x86asm.R14W:
|
|
||||||
return r.r14 & mask16, nil
|
|
||||||
case x86asm.R15W:
|
|
||||||
return r.r15 & mask16, nil
|
|
||||||
|
|
||||||
// 32-bit
|
|
||||||
case x86asm.EAX:
|
|
||||||
return r.rax & mask32, nil
|
|
||||||
case x86asm.ECX:
|
|
||||||
return r.rcx & mask32, nil
|
|
||||||
case x86asm.EDX:
|
|
||||||
return r.rdx & mask32, nil
|
|
||||||
case x86asm.EBX:
|
|
||||||
return r.rbx & mask32, nil
|
|
||||||
case x86asm.ESP:
|
|
||||||
return r.rsp & mask32, nil
|
|
||||||
case x86asm.EBP:
|
|
||||||
return r.rbp & mask32, nil
|
|
||||||
case x86asm.ESI:
|
|
||||||
return r.rsi & mask32, nil
|
|
||||||
case x86asm.EDI:
|
|
||||||
return r.rdi & mask32, nil
|
|
||||||
case x86asm.R8L:
|
|
||||||
return r.r8 & mask32, nil
|
|
||||||
case x86asm.R9L:
|
|
||||||
return r.r9 & mask32, nil
|
|
||||||
case x86asm.R10L:
|
|
||||||
return r.r10 & mask32, nil
|
|
||||||
case x86asm.R11L:
|
|
||||||
return r.r11 & mask32, nil
|
|
||||||
case x86asm.R12L:
|
|
||||||
return r.r12 & mask32, nil
|
|
||||||
case x86asm.R13L:
|
|
||||||
return r.r13 & mask32, nil
|
|
||||||
case x86asm.R14L:
|
|
||||||
return r.r14 & mask32, nil
|
|
||||||
case x86asm.R15L:
|
|
||||||
return r.r15 & mask32, nil
|
|
||||||
|
|
||||||
// 64-bit
|
|
||||||
case x86asm.RAX:
|
|
||||||
return r.rax, nil
|
|
||||||
case x86asm.RCX:
|
|
||||||
return r.rcx, nil
|
|
||||||
case x86asm.RDX:
|
|
||||||
return r.rdx, nil
|
|
||||||
case x86asm.RBX:
|
|
||||||
return r.rbx, nil
|
|
||||||
case x86asm.RSP:
|
|
||||||
return r.rsp, nil
|
|
||||||
case x86asm.RBP:
|
|
||||||
return r.rbp, nil
|
|
||||||
case x86asm.RSI:
|
|
||||||
return r.rsi, nil
|
|
||||||
case x86asm.RDI:
|
|
||||||
return r.rdi, nil
|
|
||||||
case x86asm.R8:
|
|
||||||
return r.r8, nil
|
|
||||||
case x86asm.R9:
|
|
||||||
return r.r9, nil
|
|
||||||
case x86asm.R10:
|
|
||||||
return r.r10, nil
|
|
||||||
case x86asm.R11:
|
|
||||||
return r.r11, nil
|
|
||||||
case x86asm.R12:
|
|
||||||
return r.r12, nil
|
|
||||||
case x86asm.R13:
|
|
||||||
return r.r13, nil
|
|
||||||
case x86asm.R14:
|
|
||||||
return r.r14, nil
|
|
||||||
case x86asm.R15:
|
|
||||||
return r.r15, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, proc.ErrUnknownRegister
|
|
||||||
}
|
|
||||||
|
|
||||||
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
||||||
context := newCONTEXT()
|
context := winutil.NewCONTEXT()
|
||||||
|
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
context.ContextFlags = _CONTEXT_ALL
|
||||||
err := _GetThreadContext(thread.os.hThread, context)
|
err := _GetThreadContext(thread.os.hThread, context)
|
||||||
@ -347,44 +67,5 @@ func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
|
|||||||
return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status)
|
return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status)
|
||||||
}
|
}
|
||||||
|
|
||||||
regs := &Regs{
|
return winutil.NewAMD64Registers(context, uint64(threadInfo.TebBaseAddress), floatingPoint), nil
|
||||||
rax: uint64(context.Rax),
|
|
||||||
rbx: uint64(context.Rbx),
|
|
||||||
rcx: uint64(context.Rcx),
|
|
||||||
rdx: uint64(context.Rdx),
|
|
||||||
rdi: uint64(context.Rdi),
|
|
||||||
rsi: uint64(context.Rsi),
|
|
||||||
rbp: uint64(context.Rbp),
|
|
||||||
rsp: uint64(context.Rsp),
|
|
||||||
r8: uint64(context.R8),
|
|
||||||
r9: uint64(context.R9),
|
|
||||||
r10: uint64(context.R10),
|
|
||||||
r11: uint64(context.R11),
|
|
||||||
r12: uint64(context.R12),
|
|
||||||
r13: uint64(context.R13),
|
|
||||||
r14: uint64(context.R14),
|
|
||||||
r15: uint64(context.R15),
|
|
||||||
rip: uint64(context.Rip),
|
|
||||||
eflags: uint64(context.EFlags),
|
|
||||||
cs: uint64(context.SegCs),
|
|
||||||
fs: uint64(context.SegFs),
|
|
||||||
gs: uint64(context.SegGs),
|
|
||||||
tls: uint64(threadInfo.TebBaseAddress),
|
|
||||||
}
|
|
||||||
|
|
||||||
if floatingPoint {
|
|
||||||
regs.fltSave = &context.FltSave
|
|
||||||
}
|
|
||||||
regs.context = context
|
|
||||||
|
|
||||||
return regs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Regs) Copy() proc.Registers {
|
|
||||||
var rr Regs
|
|
||||||
rr = *r
|
|
||||||
rr.context = newCONTEXT()
|
|
||||||
*(rr.context) = *(r.context)
|
|
||||||
rr.fltSave = &rr.context.FltSave
|
|
||||||
return &rr
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@ package native
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/derekparker/delve/pkg/proc/winutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _NTSTATUS int32
|
type _NTSTATUS int32
|
||||||
@ -97,6 +99,11 @@ func _NT_SUCCESS(x _NTSTATUS) bool {
|
|||||||
return x >= 0
|
return x >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// zsyscall_windows.go, an autogenerated file, wants to refer to the context
|
||||||
|
// structure as _CONTEXT, but we need to have it in pkg/proc/winutil.CONTEXT
|
||||||
|
// because it's also used on non-windows operating systems.
|
||||||
|
type _CONTEXT = winutil.CONTEXT
|
||||||
|
|
||||||
//sys _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) = ntdll.NtQueryInformationThread
|
//sys _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) = ntdll.NtQueryInformationThread
|
||||||
//sys _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.GetThreadContext
|
//sys _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.GetThreadContext
|
||||||
//sys _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.SetThreadContext
|
//sys _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.SetThreadContext
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
package native
|
package native
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_CONTEXT_AMD64 = 0x100000
|
_CONTEXT_AMD64 = 0x100000
|
||||||
_CONTEXT_CONTROL = (_CONTEXT_AMD64 | 0x1)
|
_CONTEXT_CONTROL = (_CONTEXT_AMD64 | 0x1)
|
||||||
@ -17,94 +15,6 @@ const (
|
|||||||
_CONTEXT_EXCEPTION_REPORTING = 0x80000000
|
_CONTEXT_EXCEPTION_REPORTING = 0x80000000
|
||||||
)
|
)
|
||||||
|
|
||||||
type _M128A struct {
|
|
||||||
Low uint64
|
|
||||||
High int64
|
|
||||||
}
|
|
||||||
|
|
||||||
type _XMM_SAVE_AREA32 struct {
|
|
||||||
ControlWord uint16
|
|
||||||
StatusWord uint16
|
|
||||||
TagWord byte
|
|
||||||
Reserved1 byte
|
|
||||||
ErrorOpcode uint16
|
|
||||||
ErrorOffset uint32
|
|
||||||
ErrorSelector uint16
|
|
||||||
Reserved2 uint16
|
|
||||||
DataOffset uint32
|
|
||||||
DataSelector uint16
|
|
||||||
Reserved3 uint16
|
|
||||||
MxCsr uint32
|
|
||||||
MxCsr_Mask uint32
|
|
||||||
FloatRegisters [8]_M128A
|
|
||||||
XmmRegisters [256]byte
|
|
||||||
Reserved4 [96]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type _CONTEXT struct {
|
|
||||||
P1Home uint64
|
|
||||||
P2Home uint64
|
|
||||||
P3Home uint64
|
|
||||||
P4Home uint64
|
|
||||||
P5Home uint64
|
|
||||||
P6Home uint64
|
|
||||||
|
|
||||||
ContextFlags uint32
|
|
||||||
MxCsr uint32
|
|
||||||
|
|
||||||
SegCs uint16
|
|
||||||
SegDs uint16
|
|
||||||
SegEs uint16
|
|
||||||
SegFs uint16
|
|
||||||
SegGs uint16
|
|
||||||
SegSs uint16
|
|
||||||
EFlags uint32
|
|
||||||
|
|
||||||
Dr0 uint64
|
|
||||||
Dr1 uint64
|
|
||||||
Dr2 uint64
|
|
||||||
Dr3 uint64
|
|
||||||
Dr6 uint64
|
|
||||||
Dr7 uint64
|
|
||||||
|
|
||||||
Rax uint64
|
|
||||||
Rcx uint64
|
|
||||||
Rdx uint64
|
|
||||||
Rbx uint64
|
|
||||||
Rsp uint64
|
|
||||||
Rbp uint64
|
|
||||||
Rsi uint64
|
|
||||||
Rdi uint64
|
|
||||||
R8 uint64
|
|
||||||
R9 uint64
|
|
||||||
R10 uint64
|
|
||||||
R11 uint64
|
|
||||||
R12 uint64
|
|
||||||
R13 uint64
|
|
||||||
R14 uint64
|
|
||||||
R15 uint64
|
|
||||||
|
|
||||||
Rip uint64
|
|
||||||
|
|
||||||
FltSave _XMM_SAVE_AREA32
|
|
||||||
|
|
||||||
VectorRegister [26]_M128A
|
|
||||||
VectorControl uint64
|
|
||||||
|
|
||||||
DebugControl uint64
|
|
||||||
LastBranchToRip uint64
|
|
||||||
LastBranchFromRip uint64
|
|
||||||
LastExceptionToRip uint64
|
|
||||||
LastExceptionFromRip uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// newCONTEXT allocates Windows CONTEXT structure aligned to 16 bytes.
|
|
||||||
func newCONTEXT() *_CONTEXT {
|
|
||||||
var c *_CONTEXT
|
|
||||||
buf := make([]byte, unsafe.Sizeof(*c)+15)
|
|
||||||
return (*_CONTEXT)(unsafe.Pointer((uintptr(unsafe.Pointer(&buf[15]))) &^ 15))
|
|
||||||
}
|
|
||||||
|
|
||||||
type _DEBUG_EVENT struct {
|
type _DEBUG_EVENT struct {
|
||||||
DebugEventCode uint32
|
DebugEventCode uint32
|
||||||
ProcessId uint32
|
ProcessId uint32
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
sys "golang.org/x/sys/windows"
|
sys "golang.org/x/sys/windows"
|
||||||
|
|
||||||
"github.com/derekparker/delve/pkg/proc"
|
"github.com/derekparker/delve/pkg/proc"
|
||||||
|
"github.com/derekparker/delve/pkg/proc/winutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WaitStatus is a synonym for the platform-specific WaitStatus
|
// WaitStatus is a synonym for the platform-specific WaitStatus
|
||||||
@ -19,7 +20,7 @@ type OSSpecificDetails struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Thread) singleStep() error {
|
func (t *Thread) singleStep() error {
|
||||||
context := newCONTEXT()
|
context := winutil.NewCONTEXT()
|
||||||
context.ContextFlags = _CONTEXT_ALL
|
context.ContextFlags = _CONTEXT_ALL
|
||||||
|
|
||||||
// Set the processor TRAP flag
|
// Set the processor TRAP flag
|
||||||
@ -154,5 +155,5 @@ func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
|
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
|
||||||
return _SetThreadContext(t.os.hThread, savedRegs.(*Regs).context)
|
return _SetThreadContext(t.os.hThread, savedRegs.(*winutil.AMD64Registers).Context)
|
||||||
}
|
}
|
||||||
|
|||||||
430
pkg/proc/winutil/regs.go
Normal file
430
pkg/proc/winutil/regs.go
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
package winutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/arch/x86/x86asm"
|
||||||
|
|
||||||
|
"github.com/derekparker/delve/pkg/proc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AMD64Registers represents CPU registers on an AMD64 processor.
|
||||||
|
type AMD64Registers struct {
|
||||||
|
rax uint64
|
||||||
|
rbx uint64
|
||||||
|
rcx uint64
|
||||||
|
rdx uint64
|
||||||
|
rdi uint64
|
||||||
|
rsi uint64
|
||||||
|
rbp uint64
|
||||||
|
rsp uint64
|
||||||
|
r8 uint64
|
||||||
|
r9 uint64
|
||||||
|
r10 uint64
|
||||||
|
r11 uint64
|
||||||
|
r12 uint64
|
||||||
|
r13 uint64
|
||||||
|
r14 uint64
|
||||||
|
r15 uint64
|
||||||
|
rip uint64
|
||||||
|
eflags uint64
|
||||||
|
cs uint64
|
||||||
|
fs uint64
|
||||||
|
gs uint64
|
||||||
|
tls uint64
|
||||||
|
Context *CONTEXT
|
||||||
|
fltSave *XMM_SAVE_AREA32
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAMD64Registers creates a new AMD64Registers struct from a CONTEXT
|
||||||
|
// struct and the TEB base address of the thread.
|
||||||
|
func NewAMD64Registers(context *CONTEXT, TebBaseAddress uint64, floatingPoint bool) *AMD64Registers {
|
||||||
|
regs := &AMD64Registers{
|
||||||
|
rax: uint64(context.Rax),
|
||||||
|
rbx: uint64(context.Rbx),
|
||||||
|
rcx: uint64(context.Rcx),
|
||||||
|
rdx: uint64(context.Rdx),
|
||||||
|
rdi: uint64(context.Rdi),
|
||||||
|
rsi: uint64(context.Rsi),
|
||||||
|
rbp: uint64(context.Rbp),
|
||||||
|
rsp: uint64(context.Rsp),
|
||||||
|
r8: uint64(context.R8),
|
||||||
|
r9: uint64(context.R9),
|
||||||
|
r10: uint64(context.R10),
|
||||||
|
r11: uint64(context.R11),
|
||||||
|
r12: uint64(context.R12),
|
||||||
|
r13: uint64(context.R13),
|
||||||
|
r14: uint64(context.R14),
|
||||||
|
r15: uint64(context.R15),
|
||||||
|
rip: uint64(context.Rip),
|
||||||
|
eflags: uint64(context.EFlags),
|
||||||
|
cs: uint64(context.SegCs),
|
||||||
|
fs: uint64(context.SegFs),
|
||||||
|
gs: uint64(context.SegGs),
|
||||||
|
tls: TebBaseAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
if floatingPoint {
|
||||||
|
regs.fltSave = &context.FltSave
|
||||||
|
}
|
||||||
|
regs.Context = context
|
||||||
|
|
||||||
|
return regs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice returns the registers as a list of (name, value) pairs.
|
||||||
|
func (r *AMD64Registers) Slice() []proc.Register {
|
||||||
|
var regs = []struct {
|
||||||
|
k string
|
||||||
|
v uint64
|
||||||
|
}{
|
||||||
|
{"Rip", r.rip},
|
||||||
|
{"Rsp", r.rsp},
|
||||||
|
{"Rax", r.rax},
|
||||||
|
{"Rbx", r.rbx},
|
||||||
|
{"Rcx", r.rcx},
|
||||||
|
{"Rdx", r.rdx},
|
||||||
|
{"Rdi", r.rdi},
|
||||||
|
{"Rsi", r.rsi},
|
||||||
|
{"Rbp", r.rbp},
|
||||||
|
{"R8", r.r8},
|
||||||
|
{"R9", r.r9},
|
||||||
|
{"R10", r.r10},
|
||||||
|
{"R11", r.r11},
|
||||||
|
{"R12", r.r12},
|
||||||
|
{"R13", r.r13},
|
||||||
|
{"R14", r.r14},
|
||||||
|
{"R15", r.r15},
|
||||||
|
{"Eflags", r.eflags},
|
||||||
|
{"Cs", r.cs},
|
||||||
|
{"Fs", r.fs},
|
||||||
|
{"Gs", r.gs},
|
||||||
|
{"TLS", r.tls},
|
||||||
|
}
|
||||||
|
outlen := len(regs)
|
||||||
|
if r.fltSave != nil {
|
||||||
|
outlen += 6 + 8 + 2 + 16
|
||||||
|
}
|
||||||
|
out := make([]proc.Register, 0, outlen)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.fltSave != nil {
|
||||||
|
out = proc.AppendWordReg(out, "CW", r.fltSave.ControlWord)
|
||||||
|
out = proc.AppendWordReg(out, "SW", r.fltSave.StatusWord)
|
||||||
|
out = proc.AppendWordReg(out, "TW", uint16(r.fltSave.TagWord))
|
||||||
|
out = proc.AppendWordReg(out, "FOP", r.fltSave.ErrorOpcode)
|
||||||
|
out = proc.AppendQwordReg(out, "FIP", uint64(r.fltSave.ErrorSelector)<<32|uint64(r.fltSave.ErrorOffset))
|
||||||
|
out = proc.AppendQwordReg(out, "FDP", uint64(r.fltSave.DataSelector)<<32|uint64(r.fltSave.DataOffset))
|
||||||
|
|
||||||
|
for i := range r.fltSave.FloatRegisters {
|
||||||
|
out = proc.AppendX87Reg(out, i, uint16(r.fltSave.FloatRegisters[i].High), r.fltSave.FloatRegisters[i].Low)
|
||||||
|
}
|
||||||
|
|
||||||
|
out = proc.AppendMxcsrReg(out, "MXCSR", uint64(r.fltSave.MxCsr))
|
||||||
|
out = proc.AppendDwordReg(out, "MXCSR_MASK", r.fltSave.MxCsr_Mask)
|
||||||
|
|
||||||
|
for i := 0; i < len(r.fltSave.XmmRegisters); i += 16 {
|
||||||
|
out = proc.AppendSSEReg(out, fmt.Sprintf("XMM%d", i/16), r.fltSave.XmmRegisters[i:i+16])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// PC returns the current program counter
|
||||||
|
// i.e. the RIP CPU register.
|
||||||
|
func (r *AMD64Registers) PC() uint64 {
|
||||||
|
return r.rip
|
||||||
|
}
|
||||||
|
|
||||||
|
// SP returns the stack pointer location,
|
||||||
|
// i.e. the RSP register.
|
||||||
|
func (r *AMD64Registers) SP() uint64 {
|
||||||
|
return r.rsp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AMD64Registers) BP() uint64 {
|
||||||
|
return r.rbp
|
||||||
|
}
|
||||||
|
|
||||||
|
// CX returns the value of the RCX register.
|
||||||
|
func (r *AMD64Registers) CX() uint64 {
|
||||||
|
return r.rcx
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLS returns the value of the register
|
||||||
|
// that contains the location of the thread
|
||||||
|
// local storage segment.
|
||||||
|
func (r *AMD64Registers) TLS() uint64 {
|
||||||
|
return r.tls
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (
|
||||||
|
mask8 = 0x000f
|
||||||
|
mask16 = 0x00ff
|
||||||
|
mask32 = 0xffff
|
||||||
|
)
|
||||||
|
|
||||||
|
switch reg {
|
||||||
|
// 8-bit
|
||||||
|
case x86asm.AL:
|
||||||
|
return r.rax & mask8, nil
|
||||||
|
case x86asm.CL:
|
||||||
|
return r.rcx & mask8, nil
|
||||||
|
case x86asm.DL:
|
||||||
|
return r.rdx & mask8, nil
|
||||||
|
case x86asm.BL:
|
||||||
|
return r.rbx & mask8, nil
|
||||||
|
case x86asm.AH:
|
||||||
|
return (r.rax >> 8) & mask8, nil
|
||||||
|
case x86asm.CH:
|
||||||
|
return (r.rcx >> 8) & mask8, nil
|
||||||
|
case x86asm.DH:
|
||||||
|
return (r.rdx >> 8) & mask8, nil
|
||||||
|
case x86asm.BH:
|
||||||
|
return (r.rbx >> 8) & mask8, nil
|
||||||
|
case x86asm.SPB:
|
||||||
|
return r.rsp & mask8, nil
|
||||||
|
case x86asm.BPB:
|
||||||
|
return r.rbp & mask8, nil
|
||||||
|
case x86asm.SIB:
|
||||||
|
return r.rsi & mask8, nil
|
||||||
|
case x86asm.DIB:
|
||||||
|
return r.rdi & mask8, nil
|
||||||
|
case x86asm.R8B:
|
||||||
|
return r.r8 & mask8, nil
|
||||||
|
case x86asm.R9B:
|
||||||
|
return r.r9 & mask8, nil
|
||||||
|
case x86asm.R10B:
|
||||||
|
return r.r10 & mask8, nil
|
||||||
|
case x86asm.R11B:
|
||||||
|
return r.r11 & mask8, nil
|
||||||
|
case x86asm.R12B:
|
||||||
|
return r.r12 & mask8, nil
|
||||||
|
case x86asm.R13B:
|
||||||
|
return r.r13 & mask8, nil
|
||||||
|
case x86asm.R14B:
|
||||||
|
return r.r14 & mask8, nil
|
||||||
|
case x86asm.R15B:
|
||||||
|
return r.r15 & mask8, nil
|
||||||
|
|
||||||
|
// 16-bit
|
||||||
|
case x86asm.AX:
|
||||||
|
return r.rax & mask16, nil
|
||||||
|
case x86asm.CX:
|
||||||
|
return r.rcx & mask16, nil
|
||||||
|
case x86asm.DX:
|
||||||
|
return r.rdx & mask16, nil
|
||||||
|
case x86asm.BX:
|
||||||
|
return r.rbx & mask16, nil
|
||||||
|
case x86asm.SP:
|
||||||
|
return r.rsp & mask16, nil
|
||||||
|
case x86asm.BP:
|
||||||
|
return r.rbp & mask16, nil
|
||||||
|
case x86asm.SI:
|
||||||
|
return r.rsi & mask16, nil
|
||||||
|
case x86asm.DI:
|
||||||
|
return r.rdi & mask16, nil
|
||||||
|
case x86asm.R8W:
|
||||||
|
return r.r8 & mask16, nil
|
||||||
|
case x86asm.R9W:
|
||||||
|
return r.r9 & mask16, nil
|
||||||
|
case x86asm.R10W:
|
||||||
|
return r.r10 & mask16, nil
|
||||||
|
case x86asm.R11W:
|
||||||
|
return r.r11 & mask16, nil
|
||||||
|
case x86asm.R12W:
|
||||||
|
return r.r12 & mask16, nil
|
||||||
|
case x86asm.R13W:
|
||||||
|
return r.r13 & mask16, nil
|
||||||
|
case x86asm.R14W:
|
||||||
|
return r.r14 & mask16, nil
|
||||||
|
case x86asm.R15W:
|
||||||
|
return r.r15 & mask16, nil
|
||||||
|
|
||||||
|
// 32-bit
|
||||||
|
case x86asm.EAX:
|
||||||
|
return r.rax & mask32, nil
|
||||||
|
case x86asm.ECX:
|
||||||
|
return r.rcx & mask32, nil
|
||||||
|
case x86asm.EDX:
|
||||||
|
return r.rdx & mask32, nil
|
||||||
|
case x86asm.EBX:
|
||||||
|
return r.rbx & mask32, nil
|
||||||
|
case x86asm.ESP:
|
||||||
|
return r.rsp & mask32, nil
|
||||||
|
case x86asm.EBP:
|
||||||
|
return r.rbp & mask32, nil
|
||||||
|
case x86asm.ESI:
|
||||||
|
return r.rsi & mask32, nil
|
||||||
|
case x86asm.EDI:
|
||||||
|
return r.rdi & mask32, nil
|
||||||
|
case x86asm.R8L:
|
||||||
|
return r.r8 & mask32, nil
|
||||||
|
case x86asm.R9L:
|
||||||
|
return r.r9 & mask32, nil
|
||||||
|
case x86asm.R10L:
|
||||||
|
return r.r10 & mask32, nil
|
||||||
|
case x86asm.R11L:
|
||||||
|
return r.r11 & mask32, nil
|
||||||
|
case x86asm.R12L:
|
||||||
|
return r.r12 & mask32, nil
|
||||||
|
case x86asm.R13L:
|
||||||
|
return r.r13 & mask32, nil
|
||||||
|
case x86asm.R14L:
|
||||||
|
return r.r14 & mask32, nil
|
||||||
|
case x86asm.R15L:
|
||||||
|
return r.r15 & mask32, nil
|
||||||
|
|
||||||
|
// 64-bit
|
||||||
|
case x86asm.RAX:
|
||||||
|
return r.rax, nil
|
||||||
|
case x86asm.RCX:
|
||||||
|
return r.rcx, nil
|
||||||
|
case x86asm.RDX:
|
||||||
|
return r.rdx, nil
|
||||||
|
case x86asm.RBX:
|
||||||
|
return r.rbx, nil
|
||||||
|
case x86asm.RSP:
|
||||||
|
return r.rsp, nil
|
||||||
|
case x86asm.RBP:
|
||||||
|
return r.rbp, nil
|
||||||
|
case x86asm.RSI:
|
||||||
|
return r.rsi, nil
|
||||||
|
case x86asm.RDI:
|
||||||
|
return r.rdi, nil
|
||||||
|
case x86asm.R8:
|
||||||
|
return r.r8, nil
|
||||||
|
case x86asm.R9:
|
||||||
|
return r.r9, nil
|
||||||
|
case x86asm.R10:
|
||||||
|
return r.r10, nil
|
||||||
|
case x86asm.R11:
|
||||||
|
return r.r11, nil
|
||||||
|
case x86asm.R12:
|
||||||
|
return r.r12, nil
|
||||||
|
case x86asm.R13:
|
||||||
|
return r.r13, nil
|
||||||
|
case x86asm.R14:
|
||||||
|
return r.r14, nil
|
||||||
|
case x86asm.R15:
|
||||||
|
return r.r15, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, proc.ErrUnknownRegister
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns a copy of these registers that is guarenteed not to change.
|
||||||
|
func (r *AMD64Registers) Copy() proc.Registers {
|
||||||
|
var rr AMD64Registers
|
||||||
|
rr = *r
|
||||||
|
rr.Context = NewCONTEXT()
|
||||||
|
*(rr.Context) = *(r.Context)
|
||||||
|
rr.fltSave = &rr.Context.FltSave
|
||||||
|
return &rr
|
||||||
|
}
|
||||||
|
|
||||||
|
// M128A tracks the _M128A windows struct.
|
||||||
|
type M128A struct {
|
||||||
|
Low uint64
|
||||||
|
High int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// XMM_SAVE_AREA32 tracks the _XMM_SAVE_AREA32 windows struct.
|
||||||
|
type XMM_SAVE_AREA32 struct {
|
||||||
|
ControlWord uint16
|
||||||
|
StatusWord uint16
|
||||||
|
TagWord byte
|
||||||
|
Reserved1 byte
|
||||||
|
ErrorOpcode uint16
|
||||||
|
ErrorOffset uint32
|
||||||
|
ErrorSelector uint16
|
||||||
|
Reserved2 uint16
|
||||||
|
DataOffset uint32
|
||||||
|
DataSelector uint16
|
||||||
|
Reserved3 uint16
|
||||||
|
MxCsr uint32
|
||||||
|
MxCsr_Mask uint32
|
||||||
|
FloatRegisters [8]M128A
|
||||||
|
XmmRegisters [256]byte
|
||||||
|
Reserved4 [96]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONTEXT tracks the _CONTEXT of windows.
|
||||||
|
type CONTEXT struct {
|
||||||
|
P1Home uint64
|
||||||
|
P2Home uint64
|
||||||
|
P3Home uint64
|
||||||
|
P4Home uint64
|
||||||
|
P5Home uint64
|
||||||
|
P6Home uint64
|
||||||
|
|
||||||
|
ContextFlags uint32
|
||||||
|
MxCsr uint32
|
||||||
|
|
||||||
|
SegCs uint16
|
||||||
|
SegDs uint16
|
||||||
|
SegEs uint16
|
||||||
|
SegFs uint16
|
||||||
|
SegGs uint16
|
||||||
|
SegSs uint16
|
||||||
|
EFlags uint32
|
||||||
|
|
||||||
|
Dr0 uint64
|
||||||
|
Dr1 uint64
|
||||||
|
Dr2 uint64
|
||||||
|
Dr3 uint64
|
||||||
|
Dr6 uint64
|
||||||
|
Dr7 uint64
|
||||||
|
|
||||||
|
Rax uint64
|
||||||
|
Rcx uint64
|
||||||
|
Rdx uint64
|
||||||
|
Rbx uint64
|
||||||
|
Rsp uint64
|
||||||
|
Rbp uint64
|
||||||
|
Rsi uint64
|
||||||
|
Rdi uint64
|
||||||
|
R8 uint64
|
||||||
|
R9 uint64
|
||||||
|
R10 uint64
|
||||||
|
R11 uint64
|
||||||
|
R12 uint64
|
||||||
|
R13 uint64
|
||||||
|
R14 uint64
|
||||||
|
R15 uint64
|
||||||
|
|
||||||
|
Rip uint64
|
||||||
|
|
||||||
|
FltSave XMM_SAVE_AREA32
|
||||||
|
|
||||||
|
VectorRegister [26]M128A
|
||||||
|
VectorControl uint64
|
||||||
|
|
||||||
|
DebugControl uint64
|
||||||
|
LastBranchToRip uint64
|
||||||
|
LastBranchFromRip uint64
|
||||||
|
LastExceptionToRip uint64
|
||||||
|
LastExceptionFromRip uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCONTEXT allocates Windows CONTEXT structure aligned to 16 bytes.
|
||||||
|
func NewCONTEXT() *CONTEXT {
|
||||||
|
var c *CONTEXT
|
||||||
|
buf := make([]byte, unsafe.Sizeof(*c)+15)
|
||||||
|
return (*CONTEXT)(unsafe.Pointer((uintptr(unsafe.Pointer(&buf[15]))) &^ 15))
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user