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