delve/proc/threads_windows.go

142 lines
3.1 KiB
Go
Raw Normal View History

2016-01-15 05:26:54 +00:00
package proc
import (
"syscall"
2016-01-15 05:26:54 +00:00
sys "golang.org/x/sys/windows"
)
// 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 {
hThread syscall.Handle
2016-01-15 05:26:54 +00:00
}
func (t *Thread) halt() (err error) {
// Ignore the request to halt. On Windows, all threads are halted
// on return from WaitForDebugEvent.
return nil
// TODO - This may not be correct in all usages of dbp.Halt. There
// are some callers who use dbp.Halt() to stop the process when it is not
// already broken on a debug event.
}
func (t *Thread) singleStep() error {
context := newCONTEXT()
context.ContextFlags = _CONTEXT_ALL
2016-01-15 05:26:54 +00:00
// Set the processor TRAP flag
err := _GetThreadContext(t.os.hThread, context)
if err != nil {
return err
2016-01-15 05:26:54 +00:00
}
context.EFlags |= 0x100
err = _SetThreadContext(t.os.hThread, context)
if err != nil {
return err
2016-01-15 05:26:54 +00:00
}
// Suspend all threads except this one
for _, thread := range t.dbp.Threads {
if thread.ID == t.ID {
continue
}
_, _ = _SuspendThread(thread.os.hThread)
2016-01-15 05:26:54 +00:00
}
// Continue and wait for the step to complete
err = nil
2016-01-15 05:26:54 +00:00
t.dbp.execPtraceFunc(func() {
err = _ContinueDebugEvent(uint32(t.dbp.Pid), uint32(t.ID), _DBG_CONTINUE)
2016-01-15 05:26:54 +00:00
})
if err != nil {
return err
2016-01-15 05:26:54 +00:00
}
_, err = t.dbp.trapWait(0)
2016-01-15 05:26:54 +00:00
if err != nil {
return err
}
// Resume all threads except this one
for _, thread := range t.dbp.Threads {
if thread.ID == t.ID {
continue
}
_, _ = _ResumeThread(thread.os.hThread)
2016-01-15 05:26:54 +00:00
}
// Unset the processor TRAP flag
err = _GetThreadContext(t.os.hThread, context)
if err != nil {
return err
2016-01-15 05:26:54 +00:00
}
context.EFlags &= ^uint32(0x100)
2016-01-15 05:26:54 +00:00
return _SetThreadContext(t.os.hThread, context)
2016-01-15 05:26:54 +00:00
}
func (t *Thread) resume() error {
t.running = true
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.
err = _ContinueDebugEvent(uint32(t.dbp.Pid), uint32(t.ID), _DBG_CONTINUE)
2016-01-15 05:26:54 +00:00
})
return err
2016-01-15 05:26:54 +00:00
}
func (t *Thread) blocked() bool {
// TODO: Probably incorrect - what are the runtime functions that
// indicate blocking on Windows?
pc, err := t.PC()
if err != nil {
return false
}
fn := t.dbp.goSymTable.PCToFunc(pc)
if fn == nil {
return false
}
switch fn.Name {
case "runtime.kevent", "runtime.usleep":
return true
default:
return false
}
}
func (t *Thread) stopped() bool {
// TODO: We are assuming that threads are always stopped
// during command exection.
return true
}
func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) {
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
}
func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) {
if size == 0 {
return nil, nil
}
var count uintptr
buf := make([]byte, size)
err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(size), &count)
if err != nil {
return nil, err
2016-01-15 05:26:54 +00:00
}
return buf[:count], nil
2016-01-15 05:26:54 +00:00
}