Skip to content

Commit

Permalink
proc/native: refactor windows framework (go-delve#3079)
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal authored Jul 27, 2022
1 parent ec1d1ef commit 6ad3169
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 185 deletions.
4 changes: 2 additions & 2 deletions pkg/proc/core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ mainSearch:
}

func TestMinidump(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("minidumps can only be produced on windows")
if runtime.GOOS != "windows" || runtime.GOARCH != "amd64" {
t.Skip("minidumps can only be produced on windows/amd64")
}
var buildFlags test.BuildFlags
if buildMode == "pie" {
Expand Down
4 changes: 2 additions & 2 deletions pkg/proc/core/minidump/minidump.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ type Thread struct {
PriorityClass uint32
Priority uint32
TEB uint64
Context winutil.CONTEXT
Context winutil.AMD64CONTEXT
}

// Module represents an entry in the ModuleList stream.
Expand Down Expand Up @@ -545,7 +545,7 @@ func readThreadList(mdmp *Minidump, buf *minidumpBuf) {

readMemoryDescriptor(mdmp, buf) // thread stack
_, rawThreadContext := readLocationDescriptor(buf) // thread context
thread.Context = *((*winutil.CONTEXT)(unsafe.Pointer(&rawThreadContext[0])))
thread.Context = *((*winutil.AMD64CONTEXT)(unsafe.Pointer(&rawThreadContext[0])))
if buf.err != nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/proc/native/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc
DisableAsyncPreempt: runtime.GOOS == "windows" || runtime.GOOS == "freebsd" || (runtime.GOOS == "linux" && runtime.GOARCH == "arm64"),

StopReason: stopReason,
CanDump: runtime.GOOS == "linux" || runtime.GOOS == "windows",
CanDump: runtime.GOOS == "linux" || (runtime.GOOS == "windows" && runtime.GOARCH == "amd64"),
ContinueOnce: continueOnce,
})
if err != nil {
Expand Down
5 changes: 2 additions & 3 deletions pkg/proc/native/proc_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
"github.com/go-delve/delve/pkg/proc/winutil"
)

// osProcessDetails holds Windows specific information.
Expand Down Expand Up @@ -456,7 +455,7 @@ func (dbp *nativeProcess) stop(cctx *proc.ContinueOnceContext, trapthread *nativ
return nil, err
}

context := winutil.NewCONTEXT()
context := newContext()

for _, thread := range dbp.threads {
thread.os.delayErr = nil
Expand All @@ -466,7 +465,7 @@ func (dbp *nativeProcess) stop(cctx *proc.ContinueOnceContext, trapthread *nativ
_, thread.os.delayErr = _SuspendThread(thread.os.hThread)
if thread.os.delayErr == nil {
// This call will block until the thread has stopped.
_ = _GetThreadContext(thread.os.hThread, context)
_ = thread.getContext(context)
}
}
}
Expand Down
59 changes: 59 additions & 0 deletions pkg/proc/native/registers_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package native

import (
"fmt"
"unsafe"

"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/proc"
)

// SetPC sets the RIP register to the value specified by `pc`.
func (thread *nativeThread) setPC(pc uint64) error {
context := newContext()
context.SetFlags(_CONTEXT_ALL)

err := thread.getContext(context)
if err != nil {
return err
}

context.SetPC(pc)

return thread.setContext(context)
}

// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
context := newContext()
context.SetFlags(_CONTEXT_ALL)
err := thread.getContext(context)
if err != nil {
return err
}

err = context.SetReg(regNum, reg)
if err != nil {
return err
}

return thread.setContext(context)
}

func registers(thread *nativeThread) (proc.Registers, error) {
context := newContext()

context.SetFlags(_CONTEXT_ALL)
err := thread.getContext(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 newRegisters(context, uint64(threadInfo.TebBaseAddress)), nil
}
114 changes: 0 additions & 114 deletions pkg/proc/native/registers_windows_amd64.go

This file was deleted.

13 changes: 7 additions & 6 deletions pkg/proc/native/syscall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ package native

import (
"syscall"

"github.com/go-delve/delve/pkg/proc/winutil"
)

type _NTSTATUS int32
Expand Down Expand Up @@ -124,10 +122,13 @@ func _NT_SUCCESS(x _NTSTATUS) bool {
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
type _DEBUG_EVENT struct {
DebugEventCode uint32
ProcessId uint32
ThreadId uint32
_ uint32 // to align Union properly
U [160]byte
}

//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
Expand Down
13 changes: 6 additions & 7 deletions pkg/proc/native/syscall_windows_amd64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package native

import "github.com/go-delve/delve/pkg/proc/winutil"

const (
_CONTEXT_AMD64 = 0x100000
_CONTEXT_CONTROL = (_CONTEXT_AMD64 | 0x1)
Expand All @@ -15,10 +17,7 @@ const (
_CONTEXT_EXCEPTION_REPORTING = 0x80000000
)

type _DEBUG_EVENT struct {
DebugEventCode uint32
ProcessId uint32
ThreadId uint32
_ uint32 // to align Union properly
U [160]byte
}
// 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.AMD64CONTEXT
49 changes: 8 additions & 41 deletions pkg/proc/native/threads_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
sys "golang.org/x/sys/windows"

"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/amd64util"
"github.com/go-delve/delve/pkg/proc/winutil"
)

const enableHardwareBreakpoints = false // see https://github.com/go-delve/delve/issues/2768
Expand All @@ -26,18 +24,18 @@ type osSpecificDetails struct {
}

func (t *nativeThread) singleStep() error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
context := newContext()
context.SetFlags(_CONTEXT_ALL)

// Set the processor TRAP flag
err := _GetThreadContext(t.os.hThread, context)
err := t.getContext(context)
if err != nil {
return err
}

context.EFlags |= 0x100
context.SetTrap(true)

err = _SetThreadContext(t.os.hThread, context)
err = t.setContext(context)
if err != nil {
return err
}
Expand Down Expand Up @@ -99,14 +97,14 @@ func (t *nativeThread) singleStep() error {
}

// Unset the processor TRAP flag
err = _GetThreadContext(t.os.hThread, context)
err = t.getContext(context)
if err != nil {
return err
}

context.EFlags &= ^uint32(0x100)
context.SetTrap(false)

return _SetThreadContext(t.os.hThread, context)
return t.setContext(context)
}

func (t *nativeThread) resume() error {
Expand Down Expand Up @@ -157,37 +155,6 @@ func (t *nativeThread) ReadMemory(buf []byte, addr uint64) (int, error) {
return int(count), err
}

func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
return _SetThreadContext(t.os.hThread, savedRegs.(*winutil.AMD64Registers).Context)
}

func (t *nativeThread) withDebugRegisters(f func(*amd64util.DebugRegisters) error) error {
if !enableHardwareBreakpoints {
return errors.New("hardware breakpoints not supported")
}

context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_DEBUG_REGISTERS

err := _GetThreadContext(t.os.hThread, context)
if err != nil {
return err
}

drs := amd64util.NewDebugRegisters(&context.Dr0, &context.Dr1, &context.Dr2, &context.Dr3, &context.Dr6, &context.Dr7)

err = f(drs)
if err != nil {
return err
}

if drs.Dirty {
return _SetThreadContext(t.os.hThread, context)
}

return nil
}

// SoftExc returns true if this thread received a software exception during the last resume.
func (t *nativeThread) SoftExc() bool {
return t.os.setbp
Expand Down
Loading

0 comments on commit 6ad3169

Please sign in to comment.