func munmap(b []byte) (err error) { m := memoryMap(b) dh := m.header() addr := dh.Data length := uintptr(dh.Len) flush(addr, length) err = windows.UnmapViewOfFile(addr) if err != nil { return err } handleLock.Lock() defer handleLock.Unlock() handle, ok := handleMap[addr] if !ok { // should be impossible; we would've errored above return errors.New("unknown base address") } delete(handleMap, addr) e := windows.CloseHandle(windows.Handle(handle)) return os.NewSyscallError("CloseHandle", e) }
func (s *service) run() { s.goWaits.Wait() s.h = windows.Handle(ssHandle) argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc] args := make([]string, len(argv)) for i, a := range argv { args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:]) } cmdsToHandler := make(chan ChangeRequest) changesFromHandler := make(chan Status) exitFromHandler := make(chan exitCode) go func() { ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler) exitFromHandler <- exitCode{ss, errno} }() status := Status{State: Stopped} ec := exitCode{isSvcSpecific: true, errno: 0} var outch chan ChangeRequest inch := s.c var cmd Cmd loop: for { select { case r := <-inch: if r.errno != 0 { ec.errno = r.errno break loop } inch = nil outch = cmdsToHandler cmd = r.cmd case outch <- ChangeRequest{cmd, status}: inch = s.c outch = nil case c := <-changesFromHandler: err := s.updateStatus(&c, &ec) if err != nil { // best suitable error number ec.errno = sysErrSetServiceStatusFailed if err2, ok := err.(syscall.Errno); ok { ec.errno = uint32(err2) } break loop } status = c case ec = <-exitFromHandler: break loop } } s.updateStatus(&Status{State: Stopped}, &ec) s.cWaits.Set() }
func rdat(fd int, p []byte, off int64) (n int, err error) { // hi := int32(off >> 32) // lo := int32(off) // _, err = windows.SetFilePointer(windows.Handle(fd), lo, &hi, windows.FILE_BEGIN) // if err != nil { // return 0, err // } ol := windows.Overlapped{Offset: uint32(off), OffsetHigh: uint32(off >> 32), HEvent: windows.Handle(0)} var done uint32 err = windows.ReadFile(windows.Handle(fd), p, &done, &ol) if err != nil { return 0, err } return int(done), nil }
func mmap(fd int, length int) (data []byte, err error) { h, errno := windows.CreateFileMapping(windows.Handle(fd), nil, uint32(windows.PAGE_READONLY), 0, uint32(length), nil) if h == 0 { return nil, os.NewSyscallError("CreateFileMapping", errno) } addr, errno := windows.MapViewOfFile(h, uint32(windows.FILE_MAP_READ), 0, 0, uintptr(length)) if addr == 0 { return nil, os.NewSyscallError("MapViewOfFile", errno) } handleLock.Lock() handleMap[addr] = h handleLock.Unlock() m := memoryMap{} dh := m.header() dh.Data = addr dh.Len = length dh.Cap = dh.Len return m, nil }
// Launch creates and begins debugging a new process. func Launch(cmd []string) (*Process, error) { argv0Go, err := filepath.Abs(cmd[0]) if err != nil { return nil, err } // Make sure the binary exists. if filepath.Base(cmd[0]) == cmd[0] { if _, err := exec.LookPath(cmd[0]); err != nil { return nil, err } } if _, err := os.Stat(argv0Go); err != nil { return nil, err } // Duplicate the stdin/stdout/stderr handles files := []uintptr{uintptr(syscall.Stdin), uintptr(syscall.Stdout), uintptr(syscall.Stderr)} p, _ := syscall.GetCurrentProcess() fd := make([]syscall.Handle, len(files)) for i := range files { err := syscall.DuplicateHandle(p, syscall.Handle(files[i]), p, &fd[i], 0, true, syscall.DUPLICATE_SAME_ACCESS) if err != nil { return nil, err } defer syscall.CloseHandle(syscall.Handle(fd[i])) } argv0, err := syscall.UTF16PtrFromString(argv0Go) if err != nil { return nil, err } // create suitable command line for CreateProcess // see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L326 // adapted from standard library makeCmdLine // see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L86 var cmdLineGo string if len(cmd) >= 1 { for _, v := range cmd { if cmdLineGo != "" { cmdLineGo += " " } cmdLineGo += syscall.EscapeArg(v) } } var cmdLine *uint16 if cmdLineGo != "" { if cmdLine, err = syscall.UTF16PtrFromString(cmdLineGo); err != nil { return nil, err } } // Initialize the startup info and create process si := new(sys.StartupInfo) si.Cb = uint32(unsafe.Sizeof(*si)) si.Flags = syscall.STARTF_USESTDHANDLES si.StdInput = sys.Handle(fd[0]) si.StdOutput = sys.Handle(fd[1]) si.StdErr = sys.Handle(fd[2]) pi := new(sys.ProcessInformation) err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, DEBUGONLYTHISPROCESS, nil, nil, si, pi) if err != nil { return nil, err } sys.CloseHandle(sys.Handle(pi.Process)) sys.CloseHandle(sys.Handle(pi.Thread)) dbp := New(int(pi.ProcessId)) switch runtime.GOARCH { case "amd64": dbp.arch = AMD64Arch() } // Note - it should not actually be possible for the // call to waitForDebugEvent to fail, since Windows // will always fire a CreateProcess event immediately // after launching under DEBUGONLYTHISPROCESS. var tid, exitCode int dbp.execPtraceFunc(func() { tid, exitCode, err = dbp.waitForDebugEvent() }) if err != nil { return nil, err } if tid == 0 { dbp.postExit() return nil, ProcessExitedError{Pid: dbp.Pid, Status: exitCode} } return initializeDebugProcess(dbp, argv0Go, false) }
func (dbp *Process) waitForDebugEvent() (threadID, exitCode int, err error) { var debugEvent C.DEBUG_EVENT for { // Wait for a debug event... res := C.WaitForDebugEvent(&debugEvent, C.INFINITE) if res == C.FALSE { return 0, 0, fmt.Errorf("could not WaitForDebugEvent") } // ... handle each event kind ... unionPtr := unsafe.Pointer(&debugEvent.u[0]) switch debugEvent.dwDebugEventCode { case C.CREATE_PROCESS_DEBUG_EVENT: debugInfo := (*C.CREATE_PROCESS_DEBUG_INFO)(unionPtr) hFile := debugInfo.hFile if hFile != C.HANDLE(uintptr(0)) /* NULL */ && hFile != C.HANDLE(uintptr(0xFFFFFFFFFFFFFFFF)) /* INVALID_HANDLE_VALUE */ { res = C.CloseHandle(hFile) if res == C.FALSE { return 0, 0, fmt.Errorf("could not close create process file handle") } } dbp.os.hProcess = sys.Handle(debugInfo.hProcess) _, err = dbp.addThread(sys.Handle(debugInfo.hThread), int(debugEvent.dwThreadId), false) if err != nil { return 0, 0, err } break case C.CREATE_THREAD_DEBUG_EVENT: debugInfo := (*C.CREATE_THREAD_DEBUG_INFO)(unionPtr) _, err = dbp.addThread(sys.Handle(debugInfo.hThread), int(debugEvent.dwThreadId), false) if err != nil { return 0, 0, err } break case C.EXIT_THREAD_DEBUG_EVENT: delete(dbp.Threads, int(debugEvent.dwThreadId)) break case C.OUTPUT_DEBUG_STRING_EVENT: //TODO: Handle debug output strings break case C.LOAD_DLL_DEBUG_EVENT: debugInfo := (*C.LOAD_DLL_DEBUG_INFO)(unionPtr) hFile := debugInfo.hFile if hFile != C.HANDLE(uintptr(0)) /* NULL */ && hFile != C.HANDLE(uintptr(0xFFFFFFFFFFFFFFFF)) /* INVALID_HANDLE_VALUE */ { res = C.CloseHandle(hFile) if res == C.FALSE { return 0, 0, fmt.Errorf("could not close DLL load file handle") } } break case C.UNLOAD_DLL_DEBUG_EVENT: break case C.RIP_EVENT: break case C.EXCEPTION_DEBUG_EVENT: tid := int(debugEvent.dwThreadId) dbp.os.breakThread = tid return tid, 0, nil case C.EXIT_PROCESS_DEBUG_EVENT: debugInfo := (*C.EXIT_PROCESS_DEBUG_INFO)(unionPtr) return 0, int(debugInfo.dwExitCode), nil default: return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.dwDebugEventCode) } // .. and then continue unless we received an event that indicated we should break into debugger. res = C.ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, C.DBG_CONTINUE) if res == C.WINBOOL(0) { return 0, 0, fmt.Errorf("could not ContinueDebugEvent") } } }
// Frees the loaded dynamic-link library (DLL) module and, if necessary, // decrements its reference count. When the reference count reaches zero, the // module is unloaded from the address space of the calling process and the // handle is no longer valid. func freeLibrary(handle Handle) error { // Wrap the method so that we can stub it out and use our own Handle type. return windows.FreeLibrary(windows.Handle(handle)) }
func rlck(fd, from, ln int) (err error) { // f, err = os.OpenFile(fn, os.O_RDONLY, os.FileMode(0600)) // if err != nil { // return nil, err // } // type Overlapped struct { // Internal uintptr // InternalHigh uintptr // Offset uint32 // OffsetHigh uint32 // HEvent Handle // } // fdh, err := windows.Open(fn, os.O_RDONLY, 0) // if err != nil { // return 0, err // } // fd = int(fdh) // ol := windows.Overlapped{HEvent: windows.Handle(0)} // var ol windows.Overlapped // ln := int64(to - from) // hi := int32(ln >> 32) // lo := int32(ln) ol := windows.Overlapped{Offset: uint32(from), OffsetHigh: uint32(from >> 32), HEvent: windows.Handle(0)} r1, _, err := procLockFileEx.Call(uintptr(fd), uintptr(LOCKFILE_FAIL_IMMEDIATELY), uintptr(0), uintptr(int32(ln)), uintptr(int32(ln>>32)), uintptr(unsafe.Pointer(&ol))) // fmt.Printf("rlck %v %v %v %v = %v %v\n", fd, uintptr(int32(ln)), uintptr(int32(ln >> 32)), ol, r1, err) if r1 != 1 { return err } //r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol))) return nil // wait := true // st := time.Now() // for wait { // f, err := os.Open(fn) // if err == nil { // return f, err // } else if !os.IsNotExist(err) { // return nil, err // } // time.Sleep(10 * time.Millisecond) // if time.Since(st) > timeout { // wait = false // } // } // return nil, errTimeout }
func cl(fd int) (err error) { return windows.CloseHandle(windows.Handle(fd)) }
func unlck(fd, from, ln int) (err error) { // fmt.Println(fd, from, to) // ln := int64(to - from) // hi := int32(ln >> 32) // lo := int32(ln) ol := windows.Overlapped{Offset: uint32(from), OffsetHigh: uint32(from >> 32), HEvent: windows.Handle(0)} // ol := windows.Overlapped{Offset: uint32(from), HEvent: windows.Handle(0)} // ol := windows.Overlapped{HEvent: windows.Handle(0)} r1, _, err := procUnlockFileEx.Call(uintptr(fd), uintptr(0), uintptr(int32(ln)), uintptr(int32(ln>>32)), uintptr(unsafe.Pointer(&ol))) // fmt.Printf("unlck %v %v %v %v = %v %v\n", fd, uintptr(int32(ln)), uintptr(int32(ln >> 32)), ol, r1, err) if r1 != 1 { return err } return nil //windows.CloseHandle(windows.Handle(fd)) }
// Launch creates and begins debugging a new process. func Launch(cmd []string) (*Process, error) { argv0Go, err := filepath.Abs(cmd[0]) if err != nil { return nil, err } // Make sure the binary exists and is an executable file if filepath.Base(cmd[0]) == cmd[0] { if _, err := exec.LookPath(cmd[0]); err != nil { return nil, err } } peFile, err := openExecutablePath(argv0Go) if err != nil { return nil, NotExecutableErr } peFile.Close() // Duplicate the stdin/stdout/stderr handles files := []uintptr{uintptr(syscall.Stdin), uintptr(syscall.Stdout), uintptr(syscall.Stderr)} p, _ := syscall.GetCurrentProcess() fd := make([]syscall.Handle, len(files)) for i := range files { err := syscall.DuplicateHandle(p, syscall.Handle(files[i]), p, &fd[i], 0, true, syscall.DUPLICATE_SAME_ACCESS) if err != nil { return nil, err } defer syscall.CloseHandle(syscall.Handle(fd[i])) } argv0, err := syscall.UTF16PtrFromString(argv0Go) if err != nil { return nil, err } // create suitable command line for CreateProcess // see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L326 // adapted from standard library makeCmdLine // see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L86 var cmdLineGo string if len(cmd) >= 1 { for _, v := range cmd { if cmdLineGo != "" { cmdLineGo += " " } cmdLineGo += syscall.EscapeArg(v) } } var cmdLine *uint16 if cmdLineGo != "" { if cmdLine, err = syscall.UTF16PtrFromString(cmdLineGo); err != nil { return nil, err } } // Initialize the startup info and create process si := new(sys.StartupInfo) si.Cb = uint32(unsafe.Sizeof(*si)) si.Flags = syscall.STARTF_USESTDHANDLES si.StdInput = sys.Handle(fd[0]) si.StdOutput = sys.Handle(fd[1]) si.StdErr = sys.Handle(fd[2]) pi := new(sys.ProcessInformation) err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, _DEBUG_ONLY_THIS_PROCESS, nil, nil, si, pi) if err != nil { return nil, err } sys.CloseHandle(sys.Handle(pi.Process)) sys.CloseHandle(sys.Handle(pi.Thread)) return newDebugProcess(int(pi.ProcessId), argv0Go) }