delve/pkg/proc/native/registers_windows_amd64.go
Alessandro Arzilli b53fcbe43a
proc: fix RFLAGS corruption after call injection on amd64 (#3002)
debugCallV2 for amd64 has a bug where it corrupts the flags registers
every time it is called, this commit works around that problem by
restoring flags one extra time to its original value after stepping out
of debugCallV2.

Fixes #2985
2022-05-05 08:41:40 -07:00

115 lines
2.9 KiB
Go

package native
import (
"fmt"
"unsafe"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/winutil"
)
// SetPC sets the RIP register to the value specified by `pc`.
func (thread *nativeThread) setPC(pc uint64) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return err
}
context.Rip = pc
return _SetThreadContext(thread.os.hThread, context)
}
// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return err
}
var p *uint64
switch regNum {
case regnum.AMD64_Rax:
p = &context.Rax
case regnum.AMD64_Rbx:
p = &context.Rbx
case regnum.AMD64_Rcx:
p = &context.Rcx
case regnum.AMD64_Rdx:
p = &context.Rdx
case regnum.AMD64_Rsi:
p = &context.Rsi
case regnum.AMD64_Rdi:
p = &context.Rdi
case regnum.AMD64_Rbp:
p = &context.Rbp
case regnum.AMD64_Rsp:
p = &context.Rsp
case regnum.AMD64_R8:
p = &context.R8
case regnum.AMD64_R9:
p = &context.R9
case regnum.AMD64_R10:
p = &context.R10
case regnum.AMD64_R11:
p = &context.R11
case regnum.AMD64_R12:
p = &context.R12
case regnum.AMD64_R13:
p = &context.R13
case regnum.AMD64_R14:
p = &context.R14
case regnum.AMD64_R15:
p = &context.R15
case regnum.AMD64_Rip:
p = &context.Rip
}
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_Rflags {
context.Eflags = uint32(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)
}
func registers(thread *nativeThread) (proc.Registers, error) {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return nil, err
}
var threadInfo _THREAD_BASIC_INFORMATION
status := _NtQueryInformationThread(thread.os.hThread, _ThreadBasicInformation, uintptr(unsafe.Pointer(&threadInfo)), uint32(unsafe.Sizeof(threadInfo)), nil)
if !_NT_SUCCESS(status) {
return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status)
}
return winutil.NewAMD64Registers(context, uint64(threadInfo.TebBaseAddress)), nil
}