func (t *Thread) resume() error { t.running = true var res C.WINBOOL t.dbp.execPtraceFunc(func() { //TODO: Note that we are ignoring the thread we were asked to continue and are continuing the //thread that we last broke on. res = C.ContinueDebugEvent(C.DWORD(t.dbp.Pid), C.DWORD(t.ID), C.DBG_CONTINUE) }) if res == C.FALSE { return fmt.Errorf("could not ContinueDebugEvent.") } return nil }
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") } } }
func (t *Thread) singleStep() error { var context C.CONTEXT context.ContextFlags = C.CONTEXT_ALL // Set the processor TRAP flag res := C.GetThreadContext(C.HANDLE(t.os.hThread), &context) if res == C.FALSE { return fmt.Errorf("could not GetThreadContext") } context.EFlags |= 0x100 res = C.SetThreadContext(C.HANDLE(t.os.hThread), &context) if res == C.FALSE { return fmt.Errorf("could not SetThreadContext") } // Suspend all threads except this one for _, thread := range t.dbp.Threads { if thread.ID == t.ID { continue } res := C.SuspendThread(C.HANDLE(thread.os.hThread)) if res == C.DWORD(0xFFFFFFFF) { return fmt.Errorf("could not suspend thread: %d", thread.ID) } } // Continue and wait for the step to complete t.dbp.execPtraceFunc(func() { res = C.ContinueDebugEvent(C.DWORD(t.dbp.Pid), C.DWORD(t.ID), C.DBG_CONTINUE) }) if res == C.FALSE { return fmt.Errorf("could not ContinueDebugEvent.") } _, err := t.dbp.trapWait(0) if err != nil { return err } // Resume all threads except this one for _, thread := range t.dbp.Threads { if thread.ID == t.ID { continue } res := C.ResumeThread(C.HANDLE(thread.os.hThread)) if res == C.DWORD(0xFFFFFFFF) { return fmt.Errorf("ould not resume thread: %d", thread.ID) } } // Unset the processor TRAP flag res = C.GetThreadContext(C.HANDLE(t.os.hThread), &context) if res == C.FALSE { return fmt.Errorf("could not GetThreadContext") } context.EFlags &= ^C.DWORD(0x100) res = C.SetThreadContext(C.HANDLE(t.os.hThread), &context) if res == C.FALSE { return fmt.Errorf("could not SetThreadContext") } return nil }