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