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  }