2017-04-21 06:55:53 +00:00
|
|
|
package native
|
2016-01-15 05:26:54 +00:00
|
|
|
|
|
|
|
import (
|
2017-04-21 06:55:53 +00:00
|
|
|
"errors"
|
2016-02-17 10:23:17 +00:00
|
|
|
"syscall"
|
2016-01-15 05:26:54 +00:00
|
|
|
|
|
|
|
sys "golang.org/x/sys/windows"
|
2017-04-21 06:55:53 +00:00
|
|
|
|
2019-01-04 18:39:25 +00:00
|
|
|
"github.com/go-delve/delve/pkg/proc"
|
|
|
|
"github.com/go-delve/delve/pkg/proc/winutil"
|
2016-01-15 05:26:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// WaitStatus is a synonym for the platform-specific WaitStatus
|
|
|
|
type WaitStatus sys.WaitStatus
|
|
|
|
|
|
|
|
// OSSpecificDetails holds information specific to the Windows
|
|
|
|
// operating system / kernel.
|
|
|
|
type OSSpecificDetails struct {
|
2016-02-17 10:23:17 +00:00
|
|
|
hThread syscall.Handle
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Thread) singleStep() error {
|
2018-10-18 08:15:36 +00:00
|
|
|
context := winutil.NewCONTEXT()
|
2016-02-17 10:23:17 +00:00
|
|
|
context.ContextFlags = _CONTEXT_ALL
|
2016-01-15 05:26:54 +00:00
|
|
|
|
|
|
|
// Set the processor TRAP flag
|
2016-02-17 10:23:17 +00:00
|
|
|
err := _GetThreadContext(t.os.hThread, context)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
context.EFlags |= 0x100
|
|
|
|
|
2016-02-17 10:23:17 +00:00
|
|
|
err = _SetThreadContext(t.os.hThread, context)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
|
2020-02-11 01:31:54 +00:00
|
|
|
suspendcnt := 0
|
|
|
|
|
|
|
|
// If a thread simultaneously hits a breakpoint and is suspended by the Go
|
|
|
|
// runtime it will have a suspend count greater than 1 and to actually take
|
|
|
|
// a single step we have to resume it multiple times here.
|
|
|
|
// We keep a counter of how many times it was suspended so that after
|
|
|
|
// single-stepping we can re-suspend it the corrent number of times.
|
|
|
|
for {
|
|
|
|
n, err := _ResumeThread(t.os.hThread)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
suspendcnt++
|
|
|
|
if n == 1 {
|
|
|
|
break
|
|
|
|
}
|
2016-10-22 04:51:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
var tid, exitCode int
|
|
|
|
t.dbp.execPtraceFunc(func() {
|
|
|
|
tid, exitCode, err = t.dbp.waitForDebugEvent(waitBlocking | waitSuspendNewThreads)
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if tid == 0 {
|
|
|
|
t.dbp.postExit()
|
2018-08-31 18:08:18 +00:00
|
|
|
return proc.ErrProcessExited{Pid: t.dbp.pid, Status: exitCode}
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
2016-10-22 04:51:34 +00:00
|
|
|
|
|
|
|
if t.dbp.os.breakThread == t.ID {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
t.dbp.execPtraceFunc(func() {
|
2017-02-08 00:23:47 +00:00
|
|
|
err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.dbp.os.breakThread), _DBG_CONTINUE)
|
2016-10-22 04:51:34 +00:00
|
|
|
})
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
|
2020-02-11 01:31:54 +00:00
|
|
|
for i := 0; i < suspendcnt; i++ {
|
|
|
|
_, err = _SuspendThread(t.os.hThread)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
2016-10-22 04:51:34 +00:00
|
|
|
|
|
|
|
t.dbp.execPtraceFunc(func() {
|
2017-02-08 00:23:47 +00:00
|
|
|
err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.ID), _DBG_CONTINUE)
|
2016-10-22 04:51:34 +00:00
|
|
|
})
|
2016-01-15 05:26:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unset the processor TRAP flag
|
2016-02-17 10:23:17 +00:00
|
|
|
err = _GetThreadContext(t.os.hThread, context)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
|
2016-02-17 10:23:17 +00:00
|
|
|
context.EFlags &= ^uint32(0x100)
|
2016-01-15 05:26:54 +00:00
|
|
|
|
2016-02-17 10:23:17 +00:00
|
|
|
return _SetThreadContext(t.os.hThread, context)
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Thread) resume() error {
|
2016-02-17 10:23:17 +00:00
|
|
|
var err error
|
2016-01-15 05:26:54 +00:00
|
|
|
t.dbp.execPtraceFunc(func() {
|
|
|
|
//TODO: Note that we are ignoring the thread we were asked to continue and are continuing the
|
|
|
|
//thread that we last broke on.
|
2017-02-08 00:23:47 +00:00
|
|
|
err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.ID), _DBG_CONTINUE)
|
2016-01-15 05:26:54 +00:00
|
|
|
})
|
2016-02-17 10:23:17 +00:00
|
|
|
return err
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
func (t *Thread) Blocked() bool {
|
2016-01-15 05:26:54 +00:00
|
|
|
// TODO: Probably incorrect - what are the runtime functions that
|
|
|
|
// indicate blocking on Windows?
|
2017-02-22 08:35:21 +00:00
|
|
|
regs, err := t.Registers(false)
|
2016-01-15 05:26:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2017-02-22 08:35:21 +00:00
|
|
|
pc := regs.PC()
|
2017-04-21 06:55:53 +00:00
|
|
|
fn := t.BinInfo().PCToFunc(pc)
|
2016-01-15 05:26:54 +00:00
|
|
|
if fn == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
switch fn.Name {
|
|
|
|
case "runtime.kevent", "runtime.usleep":
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-13 16:10:44 +00:00
|
|
|
// Stopped returns whether the thread is stopped at the operating system
|
|
|
|
// level. On windows this always returns true.
|
|
|
|
func (t *Thread) Stopped() bool {
|
2016-01-15 05:26:54 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
|
2017-05-01 16:57:37 +00:00
|
|
|
if t.dbp.exited {
|
2018-08-31 18:08:18 +00:00
|
|
|
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
|
2017-05-01 16:57:37 +00:00
|
|
|
}
|
2018-08-29 18:30:37 +00:00
|
|
|
if len(data) == 0 {
|
|
|
|
return 0, nil
|
|
|
|
}
|
2016-02-17 10:23:17 +00:00
|
|
|
var count uintptr
|
|
|
|
err := _WriteProcessMemory(t.dbp.os.hProcess, addr, &data[0], uintptr(len(data)), &count)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
|
|
|
return int(count), nil
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
var ErrShortRead = errors.New("short read")
|
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
|
2017-05-01 16:57:37 +00:00
|
|
|
if t.dbp.exited {
|
2018-08-31 18:08:18 +00:00
|
|
|
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
|
2017-05-01 16:57:37 +00:00
|
|
|
}
|
2017-04-18 14:24:45 +00:00
|
|
|
if len(buf) == 0 {
|
|
|
|
return 0, nil
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
2016-02-17 10:23:17 +00:00
|
|
|
var count uintptr
|
2017-04-18 14:24:45 +00:00
|
|
|
err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(len(buf)), &count)
|
|
|
|
if err == nil && count != uintptr(len(buf)) {
|
|
|
|
err = ErrShortRead
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
2017-04-18 14:24:45 +00:00
|
|
|
return int(count), err
|
2016-01-15 05:26:54 +00:00
|
|
|
}
|
2018-05-04 17:31:45 +00:00
|
|
|
|
2018-08-03 15:17:01 +00:00
|
|
|
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
|
2018-10-18 08:15:36 +00:00
|
|
|
return _SetThreadContext(t.os.hThread, savedRegs.(*winutil.AMD64Registers).Context)
|
2018-05-04 17:31:45 +00:00
|
|
|
}
|