github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/proc/native/proc_windows.go (about)

     1  package native
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  	"syscall"
     8  	"unicode/utf16"
     9  	"unsafe"
    10  
    11  	sys "golang.org/x/sys/windows"
    12  
    13  	"github.com/go-delve/delve/pkg/logflags"
    14  	"github.com/go-delve/delve/pkg/proc"
    15  	"github.com/go-delve/delve/pkg/proc/internal/ebpf"
    16  )
    17  
    18  // osProcessDetails holds Windows specific information.
    19  type osProcessDetails struct {
    20  	hProcess    syscall.Handle
    21  	breakThread int
    22  	entryPoint  uint64
    23  	running     bool
    24  }
    25  
    26  func (os *osProcessDetails) Close() {}
    27  
    28  // Launch creates and begins debugging a new process.
    29  func Launch(cmd []string, wd string, flags proc.LaunchFlags, _ []string, _ string, stdinPath string, stdoutOR proc.OutputRedirect, stderrOR proc.OutputRedirect) (*proc.TargetGroup, error) {
    30  	argv0Go := cmd[0]
    31  
    32  	env := proc.DisableAsyncPreemptEnv()
    33  
    34  	stdin, stdout, stderr, closefn, err := openRedirects(stdinPath, stdoutOR, stderrOR, true)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	creationFlags := uint32(_DEBUG_ONLY_THIS_PROCESS)
    40  	if flags&proc.LaunchForeground == 0 {
    41  		creationFlags |= syscall.CREATE_NEW_PROCESS_GROUP
    42  	}
    43  
    44  	var p *os.Process
    45  	dbp := newProcess(0)
    46  	dbp.execPtraceFunc(func() {
    47  		attr := &os.ProcAttr{
    48  			Dir:   wd,
    49  			Files: []*os.File{stdin, stdout, stderr},
    50  			Sys: &syscall.SysProcAttr{
    51  				CreationFlags: creationFlags,
    52  			},
    53  			Env: env,
    54  		}
    55  		p, err = os.StartProcess(argv0Go, cmd, attr)
    56  	})
    57  	closefn()
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	defer p.Release()
    62  
    63  	dbp.pid = p.Pid
    64  	dbp.childProcess = true
    65  
    66  	tgt, err := dbp.initialize(argv0Go, []string{})
    67  	if err != nil {
    68  		detachWithoutGroup(dbp, true)
    69  		return nil, err
    70  	}
    71  	return tgt, nil
    72  }
    73  
    74  func initialize(dbp *nativeProcess) (string, error) {
    75  	// It should not actually be possible for the
    76  	// call to waitForDebugEvent to fail, since Windows
    77  	// will always fire a CREATE_PROCESS_DEBUG_EVENT event
    78  	// immediately after launching under DEBUG_ONLY_THIS_PROCESS.
    79  	// Attaching with DebugActiveProcess has similar effect.
    80  	var err error
    81  	var tid, exitCode int
    82  	dbp.execPtraceFunc(func() {
    83  		tid, exitCode, err = dbp.waitForDebugEvent(waitBlocking)
    84  	})
    85  	if err != nil {
    86  		return "", err
    87  	}
    88  	if tid == 0 {
    89  		dbp.postExit()
    90  		return "", proc.ErrProcessExited{Pid: dbp.pid, Status: exitCode}
    91  	}
    92  
    93  	cmdline := getCmdLine(dbp.os.hProcess)
    94  
    95  	// Suspend all threads so that the call to _ContinueDebugEvent will
    96  	// not resume the target.
    97  	for _, thread := range dbp.threads {
    98  		if !thread.os.dbgUiRemoteBreakIn {
    99  			_, err := _SuspendThread(thread.os.hThread)
   100  			if err != nil {
   101  				return "", err
   102  			}
   103  		}
   104  	}
   105  
   106  	dbp.execPtraceFunc(func() {
   107  		err = _ContinueDebugEvent(uint32(dbp.pid), uint32(dbp.os.breakThread), _DBG_CONTINUE)
   108  	})
   109  	return cmdline, err
   110  }
   111  
   112  // findExePath searches for process pid, and returns its executable path
   113  func findExePath(pid int) (string, error) {
   114  	// Original code suggested different approach (see below).
   115  	// Maybe it could be useful in the future.
   116  	//
   117  	// Find executable path from PID/handle on Windows:
   118  	// https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
   119  
   120  	p, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid))
   121  	if err != nil {
   122  		return "", err
   123  	}
   124  	defer syscall.CloseHandle(p)
   125  
   126  	n := uint32(128)
   127  	for {
   128  		buf := make([]uint16, int(n))
   129  		err = _QueryFullProcessImageName(p, 0, &buf[0], &n)
   130  		switch err {
   131  		case syscall.ERROR_INSUFFICIENT_BUFFER:
   132  			// try bigger buffer
   133  			n *= 2
   134  			// but stop if it gets too big
   135  			if n > 10000 {
   136  				return "", err
   137  			}
   138  		case nil:
   139  			return syscall.UTF16ToString(buf[:n]), nil
   140  		default:
   141  			return "", err
   142  		}
   143  	}
   144  }
   145  
   146  var debugPrivilegeRequested = false
   147  
   148  // Attach to an existing process with the given PID.
   149  func Attach(pid int, waitFor *proc.WaitFor, _ []string) (*proc.TargetGroup, error) {
   150  	var aperr error
   151  	if !debugPrivilegeRequested {
   152  		debugPrivilegeRequested = true
   153  		// The following call will only work if the user is an administrator
   154  		// has the "Debug Programs" privilege in Local security settings.
   155  		// Since this privilege is not needed to debug processes owned by the
   156  		// current user, do not complain about this unless attach actually fails.
   157  		aperr = acquireDebugPrivilege()
   158  	}
   159  
   160  	if waitFor.Valid() {
   161  		var err error
   162  		pid, err = WaitFor(waitFor)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  	}
   167  
   168  	dbp := newProcess(pid)
   169  	var err error
   170  	dbp.execPtraceFunc(func() {
   171  		// TODO: Probably should have SeDebugPrivilege before starting here.
   172  		err = _DebugActiveProcess(uint32(pid))
   173  	})
   174  	if err != nil {
   175  		if aperr != nil {
   176  			return nil, fmt.Errorf("%v also %v", err, aperr)
   177  		}
   178  		return nil, err
   179  	}
   180  	exepath, err := findExePath(pid)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	tgt, err := dbp.initialize(exepath, []string{})
   185  	if err != nil {
   186  		detachWithoutGroup(dbp, true)
   187  		return nil, err
   188  	}
   189  	return tgt, nil
   190  }
   191  
   192  // acquireDebugPrivilege acquires the debug privilege which is needed to
   193  // debug other user's processes.
   194  // See:
   195  //
   196  //   - https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debug-privilege
   197  //   - https://github.com/go-delve/delve/issues/3136
   198  func acquireDebugPrivilege() error {
   199  	var token sys.Token
   200  	err := sys.OpenProcessToken(sys.CurrentProcess(), sys.TOKEN_QUERY|sys.TOKEN_ADJUST_PRIVILEGES, &token)
   201  	if err != nil {
   202  		return fmt.Errorf("could not acquire debug privilege (OpenCurrentProcessToken): %v", err)
   203  	}
   204  	defer token.Close()
   205  
   206  	privName, _ := sys.UTF16FromString("SeDebugPrivilege")
   207  	var luid sys.LUID
   208  	err = sys.LookupPrivilegeValue(nil, &privName[0], &luid)
   209  	if err != nil {
   210  		return fmt.Errorf("could not acquire debug privilege  (LookupPrivilegeValue): %v", err)
   211  	}
   212  
   213  	var tp sys.Tokenprivileges
   214  	tp.PrivilegeCount = 1
   215  	tp.Privileges[0].Luid = luid
   216  	tp.Privileges[0].Attributes = sys.SE_PRIVILEGE_ENABLED
   217  
   218  	err = sys.AdjustTokenPrivileges(token, false, &tp, 0, nil, nil)
   219  	if err != nil {
   220  		return fmt.Errorf("could not acquire debug privilege (AdjustTokenPrivileges): %v", err)
   221  	}
   222  
   223  	return nil
   224  }
   225  
   226  func waitForSearchProcess(pfx string, seen map[int]struct{}) (int, error) {
   227  	log := logflags.DebuggerLogger()
   228  	handle, err := sys.CreateToolhelp32Snapshot(sys.TH32CS_SNAPPROCESS, 0)
   229  	if err != nil {
   230  		return 0, fmt.Errorf("could not get process list: %v", err)
   231  	}
   232  	defer sys.CloseHandle(handle)
   233  
   234  	var entry sys.ProcessEntry32
   235  	entry.Size = uint32(unsafe.Sizeof(entry))
   236  	err = sys.Process32First(handle, &entry)
   237  	if err != nil {
   238  		return 0, fmt.Errorf("could not get process list: %v", err)
   239  	}
   240  
   241  	for err = sys.Process32First(handle, &entry); err == nil; err = sys.Process32Next(handle, &entry) {
   242  		if _, isseen := seen[int(entry.ProcessID)]; isseen {
   243  			continue
   244  		}
   245  		seen[int(entry.ProcessID)] = struct{}{}
   246  
   247  		hProcess, err := sys.OpenProcess(sys.PROCESS_QUERY_INFORMATION|sys.PROCESS_VM_READ, false, entry.ProcessID)
   248  		if err != nil {
   249  			continue
   250  		}
   251  		cmdline := getCmdLine(syscall.Handle(hProcess))
   252  		sys.CloseHandle(hProcess)
   253  
   254  		log.Debugf("waitfor: new process %q", cmdline)
   255  		if strings.HasPrefix(cmdline, pfx) {
   256  			return int(entry.ProcessID), nil
   257  		}
   258  	}
   259  
   260  	return 0, nil
   261  }
   262  
   263  // kill kills the process.
   264  func (procgrp *processGroup) kill(dbp *nativeProcess) error {
   265  	if dbp.exited {
   266  		return nil
   267  	}
   268  
   269  	p, err := os.FindProcess(dbp.pid)
   270  	if err != nil {
   271  		return err
   272  	}
   273  	defer p.Release()
   274  
   275  	// TODO: Should not have to ignore failures here,
   276  	// but some tests appear to Kill twice causing
   277  	// this to fail on second attempt.
   278  	_ = syscall.TerminateProcess(dbp.os.hProcess, 1)
   279  
   280  	dbp.execPtraceFunc(func() {
   281  		dbp.waitForDebugEvent(waitBlocking | waitDontHandleExceptions)
   282  	})
   283  
   284  	p.Wait()
   285  
   286  	dbp.postExit()
   287  	return nil
   288  }
   289  
   290  func (dbp *nativeProcess) requestManualStop() error {
   291  	if !dbp.os.running {
   292  		return nil
   293  	}
   294  	dbp.os.running = false
   295  	return _DebugBreakProcess(dbp.os.hProcess)
   296  }
   297  
   298  func (dbp *nativeProcess) updateThreadList() error {
   299  	// We ignore this request since threads are being
   300  	// tracked as they are created/killed in waitForDebugEvent.
   301  	return nil
   302  }
   303  
   304  func (dbp *nativeProcess) addThread(hThread syscall.Handle, threadID int, attach, suspendNewThreads bool, dbgUiRemoteBreakIn bool) (*nativeThread, error) {
   305  	if thread, ok := dbp.threads[threadID]; ok {
   306  		return thread, nil
   307  	}
   308  	thread := &nativeThread{
   309  		ID:  threadID,
   310  		dbp: dbp,
   311  		os:  new(osSpecificDetails),
   312  	}
   313  	thread.os.dbgUiRemoteBreakIn = dbgUiRemoteBreakIn
   314  	thread.os.hThread = hThread
   315  	dbp.threads[threadID] = thread
   316  	if dbp.memthread == nil {
   317  		dbp.memthread = dbp.threads[threadID]
   318  	}
   319  	if suspendNewThreads && !dbgUiRemoteBreakIn {
   320  		_, err := _SuspendThread(thread.os.hThread)
   321  		if err != nil {
   322  			return nil, err
   323  		}
   324  	}
   325  
   326  	for _, bp := range dbp.Breakpoints().M {
   327  		if bp.WatchType != 0 {
   328  			err := thread.writeHardwareBreakpoint(bp.Addr, bp.WatchType, bp.HWBreakIndex)
   329  			if err != nil {
   330  				return nil, err
   331  			}
   332  		}
   333  	}
   334  
   335  	return thread, nil
   336  }
   337  
   338  type waitForDebugEventFlags int
   339  
   340  const (
   341  	waitBlocking waitForDebugEventFlags = 1 << iota
   342  	waitSuspendNewThreads
   343  	waitDontHandleExceptions
   344  )
   345  
   346  const _MS_VC_EXCEPTION = 0x406D1388 // part of VisualC protocol to set thread names
   347  
   348  func (dbp *nativeProcess) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, exitCode int, err error) {
   349  	var debugEvent _DEBUG_EVENT
   350  	shouldExit := false
   351  	for {
   352  		continueStatus := uint32(_DBG_CONTINUE)
   353  		var milliseconds uint32 = 0
   354  		if flags&waitBlocking != 0 {
   355  			milliseconds = syscall.INFINITE
   356  		}
   357  		// Wait for a debug event...
   358  		err := _WaitForDebugEvent(&debugEvent, milliseconds)
   359  		if err != nil {
   360  			return 0, 0, err
   361  		}
   362  
   363  		// ... handle each event kind ...
   364  		unionPtr := unsafe.Pointer(&debugEvent.U[0])
   365  		switch debugEvent.DebugEventCode {
   366  		case _CREATE_PROCESS_DEBUG_EVENT:
   367  			debugInfo := (*_CREATE_PROCESS_DEBUG_INFO)(unionPtr)
   368  			hFile := debugInfo.File
   369  			if hFile != 0 && hFile != syscall.InvalidHandle {
   370  				err = syscall.CloseHandle(hFile)
   371  				if err != nil {
   372  					return 0, 0, err
   373  				}
   374  			}
   375  			dbp.os.entryPoint = uint64(debugInfo.BaseOfImage)
   376  			dbp.os.hProcess = debugInfo.Process
   377  			_, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false,
   378  				flags&waitSuspendNewThreads != 0, debugInfo.StartAddress == dbgUiRemoteBreakin.Addr())
   379  			if err != nil {
   380  				return 0, 0, err
   381  			}
   382  			break
   383  		case _CREATE_THREAD_DEBUG_EVENT:
   384  			debugInfo := (*_CREATE_THREAD_DEBUG_INFO)(unionPtr)
   385  			_, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false,
   386  				flags&waitSuspendNewThreads != 0, debugInfo.StartAddress == dbgUiRemoteBreakin.Addr())
   387  			if err != nil {
   388  				return 0, 0, err
   389  			}
   390  			break
   391  		case _EXIT_THREAD_DEBUG_EVENT:
   392  			delete(dbp.threads, int(debugEvent.ThreadId))
   393  			break
   394  		case _OUTPUT_DEBUG_STRING_EVENT:
   395  			//TODO: Handle debug output strings
   396  			break
   397  		case _LOAD_DLL_DEBUG_EVENT:
   398  			debugInfo := (*_LOAD_DLL_DEBUG_INFO)(unionPtr)
   399  			hFile := debugInfo.File
   400  			if hFile != 0 && hFile != syscall.InvalidHandle {
   401  				err = syscall.CloseHandle(hFile)
   402  				if err != nil {
   403  					return 0, 0, err
   404  				}
   405  			}
   406  			break
   407  		case _UNLOAD_DLL_DEBUG_EVENT:
   408  			break
   409  		case _RIP_EVENT:
   410  			break
   411  		case _EXCEPTION_DEBUG_EVENT:
   412  			if flags&waitDontHandleExceptions != 0 {
   413  				continueStatus = _DBG_EXCEPTION_NOT_HANDLED
   414  				break
   415  			}
   416  			exception := (*_EXCEPTION_DEBUG_INFO)(unionPtr)
   417  			tid := int(debugEvent.ThreadId)
   418  
   419  			switch code := exception.ExceptionRecord.ExceptionCode; code {
   420  			case _EXCEPTION_BREAKPOINT:
   421  
   422  				// check if the exception address really is a breakpoint instruction, if
   423  				// it isn't we already removed that breakpoint and we can't deal with
   424  				// this exception anymore.
   425  				atbp := true
   426  				if thread, found := dbp.threads[tid]; found {
   427  					data := make([]byte, dbp.bi.Arch.BreakpointSize())
   428  					if _, err := thread.ReadMemory(data, uint64(exception.ExceptionRecord.ExceptionAddress)); err == nil {
   429  						instr := dbp.bi.Arch.BreakpointInstruction()
   430  						for i := range instr {
   431  							if data[i] != instr[i] {
   432  								atbp = false
   433  								break
   434  							}
   435  						}
   436  					}
   437  					if !atbp {
   438  						thread.setPC(uint64(exception.ExceptionRecord.ExceptionAddress))
   439  					}
   440  				}
   441  
   442  				if atbp {
   443  					dbp.os.breakThread = tid
   444  					if th := dbp.threads[tid]; th != nil {
   445  						th.os.setbp = true
   446  					}
   447  					return tid, 0, nil
   448  				} else {
   449  					continueStatus = _DBG_CONTINUE
   450  				}
   451  			case _EXCEPTION_SINGLE_STEP:
   452  				dbp.os.breakThread = tid
   453  				return tid, 0, nil
   454  			case _MS_VC_EXCEPTION:
   455  				// This exception is sent to set the thread name in VisualC, we should
   456  				// mask it or it might crash the program.
   457  				continueStatus = _DBG_CONTINUE
   458  			default:
   459  				continueStatus = _DBG_EXCEPTION_NOT_HANDLED
   460  			}
   461  		case _EXIT_PROCESS_DEBUG_EVENT:
   462  			debugInfo := (*_EXIT_PROCESS_DEBUG_INFO)(unionPtr)
   463  			exitCode = int(debugInfo.ExitCode)
   464  			shouldExit = true
   465  		default:
   466  			return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.DebugEventCode)
   467  		}
   468  
   469  		// .. and then continue unless we received an event that indicated we should break into debugger.
   470  		err = _ContinueDebugEvent(debugEvent.ProcessId, debugEvent.ThreadId, continueStatus)
   471  		if err != nil {
   472  			return 0, 0, err
   473  		}
   474  
   475  		if shouldExit {
   476  			return 0, exitCode, nil
   477  		}
   478  	}
   479  }
   480  
   481  func trapWait(procgrp *processGroup, pid int) (*nativeThread, error) {
   482  	dbp := procgrp.procs[0]
   483  	var err error
   484  	var tid, exitCode int
   485  	dbp.execPtraceFunc(func() {
   486  		tid, exitCode, err = dbp.waitForDebugEvent(waitBlocking)
   487  	})
   488  	if err != nil {
   489  		return nil, err
   490  	}
   491  	if tid == 0 {
   492  		dbp.postExit()
   493  		return nil, proc.ErrProcessExited{Pid: dbp.pid, Status: exitCode}
   494  	}
   495  	th := dbp.threads[tid]
   496  	return th, nil
   497  }
   498  
   499  func (dbp *nativeProcess) exitGuard(err error) error {
   500  	return err
   501  }
   502  
   503  func (procgrp *processGroup) resume() error {
   504  	dbp := procgrp.procs[0]
   505  	for _, thread := range dbp.threads {
   506  		if thread.CurrentBreakpoint.Breakpoint != nil {
   507  			if err := thread.StepInstruction(); err != nil {
   508  				return err
   509  			}
   510  			thread.CurrentBreakpoint.Clear()
   511  		}
   512  	}
   513  
   514  	for _, thread := range dbp.threads {
   515  		_, err := _ResumeThread(thread.os.hThread)
   516  		if err != nil {
   517  			return err
   518  		}
   519  	}
   520  	dbp.os.running = true
   521  
   522  	return nil
   523  }
   524  
   525  // stop stops all running threads threads and sets breakpoints
   526  func (procgrp *processGroup) stop(cctx *proc.ContinueOnceContext, trapthread *nativeThread) (*nativeThread, error) {
   527  	dbp := procgrp.procs[0]
   528  	if dbp.exited {
   529  		return nil, proc.ErrProcessExited{Pid: dbp.pid}
   530  	}
   531  
   532  	dbp.os.running = false
   533  	for _, th := range dbp.threads {
   534  		th.os.setbp = false
   535  	}
   536  	trapthread.os.setbp = true
   537  
   538  	// While the debug event that stopped the target was being propagated
   539  	// other target threads could generate other debug events.
   540  	// After this function we need to know about all the threads
   541  	// stopped on a breakpoint. To do that we first suspend all target
   542  	// threads and then repeatedly call _ContinueDebugEvent followed by
   543  	// waitForDebugEvent in non-blocking mode.
   544  	// We need to explicitly call SuspendThread because otherwise the
   545  	// call to _ContinueDebugEvent will resume execution of some of the
   546  	// target threads.
   547  
   548  	err := trapthread.SetCurrentBreakpoint(true)
   549  	if err != nil {
   550  		return nil, err
   551  	}
   552  
   553  	context := newContext()
   554  
   555  	for _, thread := range dbp.threads {
   556  		thread.os.delayErr = nil
   557  		if !thread.os.dbgUiRemoteBreakIn {
   558  			// Wait before reporting the error, the thread could be removed when we
   559  			// call waitForDebugEvent in the next loop.
   560  			_, thread.os.delayErr = _SuspendThread(thread.os.hThread)
   561  			if thread.os.delayErr == nil {
   562  				// This call will block until the thread has stopped.
   563  				_ = thread.getContext(context)
   564  			}
   565  		}
   566  	}
   567  
   568  	for {
   569  		var err error
   570  		var tid int
   571  		dbp.execPtraceFunc(func() {
   572  			err = _ContinueDebugEvent(uint32(dbp.pid), uint32(dbp.os.breakThread), _DBG_CONTINUE)
   573  			if err == nil {
   574  				tid, _, _ = dbp.waitForDebugEvent(waitSuspendNewThreads)
   575  			}
   576  		})
   577  		if err != nil {
   578  			return nil, err
   579  		}
   580  		if tid == 0 {
   581  			break
   582  		}
   583  		err = dbp.threads[tid].SetCurrentBreakpoint(true)
   584  		if err != nil {
   585  			return nil, err
   586  		}
   587  	}
   588  
   589  	// Check if trapthread still exist, if the process is dying it could have
   590  	// been removed while we were stopping the other threads.
   591  	trapthreadFound := false
   592  	for _, thread := range dbp.threads {
   593  		if thread.ID == trapthread.ID {
   594  			trapthreadFound = true
   595  		}
   596  		if thread.os.delayErr != nil && thread.os.delayErr != syscall.Errno(0x5) {
   597  			// Do not report Access is denied error, it is caused by the thread
   598  			// having already died but we haven't been notified about it yet.
   599  			return nil, thread.os.delayErr
   600  		}
   601  	}
   602  
   603  	if !trapthreadFound {
   604  		wasDbgUiRemoteBreakIn := trapthread.os.dbgUiRemoteBreakIn
   605  		// trapthread exited during stop, pick another one
   606  		trapthread = nil
   607  		for _, thread := range dbp.threads {
   608  			if thread.CurrentBreakpoint.Breakpoint != nil && thread.os.delayErr == nil {
   609  				trapthread = thread
   610  				break
   611  			}
   612  		}
   613  		if trapthread == nil && wasDbgUiRemoteBreakIn {
   614  			// If this was triggered by a manual stop request we should stop
   615  			// regardless, pick a thread.
   616  			for _, thread := range dbp.threads {
   617  				return thread, nil
   618  			}
   619  		}
   620  	}
   621  
   622  	return trapthread, nil
   623  }
   624  
   625  func (dbp *nativeProcess) detach(kill bool) error {
   626  	if !kill {
   627  		//TODO(aarzilli): when debug.Target exist Detach should be moved to
   628  		// debug.Target and the call to RestoreAsyncPreempt should be moved there.
   629  		for _, thread := range dbp.threads {
   630  			_, err := _ResumeThread(thread.os.hThread)
   631  			if err != nil {
   632  				return err
   633  			}
   634  		}
   635  	}
   636  	return _DebugActiveProcessStop(uint32(dbp.pid))
   637  }
   638  
   639  func (dbp *nativeProcess) EntryPoint() (uint64, error) {
   640  	return dbp.os.entryPoint, nil
   641  }
   642  
   643  func (dbp *nativeProcess) SupportsBPF() bool {
   644  	return false
   645  }
   646  
   647  func (dbp *nativeProcess) SetUProbe(fnName string, goidOffset int64, args []ebpf.UProbeArgMap) error {
   648  	return nil
   649  }
   650  
   651  func (dbp *nativeProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams {
   652  	return nil
   653  }
   654  
   655  type _PROCESS_BASIC_INFORMATION struct {
   656  	ExitStatus                   sys.NTStatus
   657  	PebBaseAddress               uintptr
   658  	AffinityMask                 uintptr
   659  	BasePriority                 int32
   660  	UniqueProcessId              uintptr
   661  	InheritedFromUniqueProcessId uintptr
   662  }
   663  
   664  type _PEB struct {
   665  	reserved1              [2]byte
   666  	BeingDebugged          byte
   667  	BitField               byte
   668  	reserved3              uintptr
   669  	ImageBaseAddress       uintptr
   670  	Ldr                    uintptr
   671  	ProcessParameters      uintptr
   672  	reserved4              [3]uintptr
   673  	AtlThunkSListPtr       uintptr
   674  	reserved5              uintptr
   675  	reserved6              uint32
   676  	reserved7              uintptr
   677  	reserved8              uint32
   678  	AtlThunkSListPtr32     uint32
   679  	reserved9              [45]uintptr
   680  	reserved10             [96]byte
   681  	PostProcessInitRoutine uintptr
   682  	reserved11             [128]byte
   683  	reserved12             [1]uintptr
   684  	SessionId              uint32
   685  }
   686  
   687  type _RTL_USER_PROCESS_PARAMETERS struct {
   688  	MaximumLength, Length uint32
   689  
   690  	Flags, DebugFlags uint32
   691  
   692  	ConsoleHandle                                sys.Handle
   693  	ConsoleFlags                                 uint32
   694  	StandardInput, StandardOutput, StandardError sys.Handle
   695  
   696  	CurrentDirectory struct {
   697  		DosPath _NTUnicodeString
   698  		Handle  sys.Handle
   699  	}
   700  
   701  	DllPath       _NTUnicodeString
   702  	ImagePathName _NTUnicodeString
   703  	CommandLine   _NTUnicodeString
   704  	Environment   unsafe.Pointer
   705  
   706  	StartingX, StartingY, CountX, CountY, CountCharsX, CountCharsY, FillAttribute uint32
   707  
   708  	WindowFlags, ShowWindowFlags                     uint32
   709  	WindowTitle, DesktopInfo, ShellInfo, RuntimeData _NTUnicodeString
   710  	CurrentDirectories                               [32]struct {
   711  		Flags     uint16
   712  		Length    uint16
   713  		TimeStamp uint32
   714  		DosPath   _NTString
   715  	}
   716  
   717  	EnvironmentSize, EnvironmentVersion uintptr
   718  
   719  	PackageDependencyData uintptr
   720  	ProcessGroupId        uint32
   721  	LoaderThreads         uint32
   722  
   723  	RedirectionDllName               _NTUnicodeString
   724  	HeapPartitionName                _NTUnicodeString
   725  	DefaultThreadpoolCpuSetMasks     uintptr
   726  	DefaultThreadpoolCpuSetMaskCount uint32
   727  }
   728  
   729  type _NTString struct {
   730  	Length        uint16
   731  	MaximumLength uint16
   732  	Buffer        uintptr
   733  }
   734  
   735  type _NTUnicodeString struct {
   736  	Length        uint16
   737  	MaximumLength uint16
   738  	Buffer        uintptr
   739  }
   740  
   741  func getCmdLine(hProcess syscall.Handle) string {
   742  	logger := logflags.DebuggerLogger()
   743  	var info _PROCESS_BASIC_INFORMATION
   744  	err := sys.NtQueryInformationProcess(sys.Handle(hProcess), sys.ProcessBasicInformation, unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil)
   745  	if err != nil {
   746  		logger.Errorf("NtQueryInformationProcess: %v", err)
   747  		return ""
   748  	}
   749  	var peb _PEB
   750  	err = _ReadProcessMemory(hProcess, info.PebBaseAddress, (*byte)(unsafe.Pointer(&peb)), unsafe.Sizeof(peb), nil)
   751  	if err != nil {
   752  		logger.Errorf("Reading PEB: %v", err)
   753  		return ""
   754  	}
   755  	var upp _RTL_USER_PROCESS_PARAMETERS
   756  	err = _ReadProcessMemory(hProcess, peb.ProcessParameters, (*byte)(unsafe.Pointer(&upp)), unsafe.Sizeof(upp), nil)
   757  	if err != nil {
   758  		logger.Errorf("Reading ProcessParameters: %v", err)
   759  		return ""
   760  	}
   761  	if upp.CommandLine.Length%2 != 0 {
   762  		logger.Errorf("CommandLine length not a multiple of 2")
   763  		return ""
   764  	}
   765  	buf := make([]byte, upp.CommandLine.Length)
   766  	err = _ReadProcessMemory(hProcess, upp.CommandLine.Buffer, &buf[0], uintptr(len(buf)), nil)
   767  	if err != nil {
   768  		logger.Errorf("Reading CommandLine: %v", err)
   769  		return ""
   770  	}
   771  	utf16buf := make([]uint16, len(buf)/2)
   772  	for i := 0; i < len(buf); i += 2 {
   773  		utf16buf[i/2] = uint16(buf[i+1])<<8 + uint16(buf[i])
   774  	}
   775  	return string(utf16.Decode(utf16buf))
   776  }
   777  
   778  func killProcess(pid int) error {
   779  	p, err := os.FindProcess(pid)
   780  	if err != nil {
   781  		return err
   782  	}
   783  	defer p.Release()
   784  
   785  	return p.Kill()
   786  }