github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/proc/native/threads_windows.go (about) 1 package native 2 3 import ( 4 "errors" 5 "syscall" 6 7 sys "golang.org/x/sys/windows" 8 9 "github.com/go-delve/delve/pkg/proc" 10 ) 11 12 const enableHardwareBreakpoints = false // see https://github.com/go-delve/delve/issues/2768 13 14 // waitStatus is a synonym for the platform-specific WaitStatus 15 type waitStatus sys.WaitStatus 16 17 // osSpecificDetails holds information specific to the Windows 18 // operating system / kernel. 19 type osSpecificDetails struct { 20 hThread syscall.Handle 21 dbgUiRemoteBreakIn bool // whether thread is an auxiliary DbgUiRemoteBreakIn thread created by Windows 22 delayErr error 23 setbp bool 24 } 25 26 func (t *nativeThread) singleStep() error { 27 context := newContext() 28 context.SetFlags(_CONTEXT_ALL) 29 30 // Set the processor TRAP flag 31 err := t.getContext(context) 32 if err != nil { 33 return err 34 } 35 36 context.SetTrap(true) 37 38 err = t.setContext(context) 39 if err != nil { 40 return err 41 } 42 43 suspendcnt := 0 44 45 // If a thread simultaneously hits a breakpoint and is suspended by the Go 46 // runtime it will have a suspend count greater than 1 and to actually take 47 // a single step we have to resume it multiple times here. 48 // We keep a counter of how many times it was suspended so that after 49 // single-stepping we can re-suspend it the correct number of times. 50 for { 51 n, err := _ResumeThread(t.os.hThread) 52 if err != nil { 53 return err 54 } 55 suspendcnt++ 56 if n == 1 { 57 break 58 } 59 } 60 61 for { 62 var tid, exitCode int 63 t.dbp.execPtraceFunc(func() { 64 tid, exitCode, err = t.dbp.waitForDebugEvent(waitBlocking | waitSuspendNewThreads) 65 }) 66 if err != nil { 67 return err 68 } 69 if tid == 0 { 70 t.dbp.postExit() 71 return proc.ErrProcessExited{Pid: t.dbp.pid, Status: exitCode} 72 } 73 74 if t.dbp.os.breakThread == t.ID { 75 break 76 } 77 78 t.dbp.execPtraceFunc(func() { 79 err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.dbp.os.breakThread), _DBG_CONTINUE) 80 }) 81 } 82 83 for i := 0; i < suspendcnt; i++ { 84 if !t.os.dbgUiRemoteBreakIn { 85 _, err = _SuspendThread(t.os.hThread) 86 if err != nil { 87 return err 88 } 89 } 90 } 91 92 t.dbp.execPtraceFunc(func() { 93 err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.ID), _DBG_CONTINUE) 94 }) 95 if err != nil { 96 return err 97 } 98 99 // Unset the processor TRAP flag 100 err = t.getContext(context) 101 if err != nil { 102 return err 103 } 104 105 context.SetTrap(false) 106 107 return t.setContext(context) 108 } 109 110 func (t *nativeThread) WriteMemory(addr uint64, data []byte) (int, error) { 111 if t.dbp.exited { 112 return 0, proc.ErrProcessExited{Pid: t.dbp.pid} 113 } 114 if len(data) == 0 { 115 return 0, nil 116 } 117 var count uintptr 118 err := _WriteProcessMemory(t.dbp.os.hProcess, uintptr(addr), &data[0], uintptr(len(data)), &count) 119 if err != nil { 120 return 0, err 121 } 122 return int(count), nil 123 } 124 125 var ErrShortRead = errors.New("short read") 126 127 func (t *nativeThread) ReadMemory(buf []byte, addr uint64) (int, error) { 128 if t.dbp.exited { 129 return 0, proc.ErrProcessExited{Pid: t.dbp.pid} 130 } 131 if len(buf) == 0 { 132 return 0, nil 133 } 134 var count uintptr 135 err := _ReadProcessMemory(t.dbp.os.hProcess, uintptr(addr), &buf[0], uintptr(len(buf)), &count) 136 if err == nil && count != uintptr(len(buf)) { 137 err = ErrShortRead 138 } 139 return int(count), err 140 } 141 142 // SoftExc returns true if this thread received a software exception during the last resume. 143 func (t *nativeThread) SoftExc() bool { 144 return t.os.setbp 145 }