
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
115 lines
2.9 KiB
Go
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
|
|
}
|