From 8d4d0871cf9dde237c374ed55b059dea636861d5 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Wed, 17 Feb 2016 21:23:17 +1100 Subject: [PATCH] proc: replace cgo with syscalls on windows Unrelated to conversion, I have also changed (*Thread).readMemory to return only first count bytes of memory just as advised by ReadProcessMemory. Fixes #409 Fixes #412 Fixes #416 --- proc/proc_windows.go | 92 +++++++++++------------- proc/registers_windows_amd64.go | 36 ++++------ proc/syscall_windows.go | 54 ++++++++++++++ proc/syscall_windows_amd64.go | 95 +++++++++++++++++++++++++ proc/threads_windows.go | 97 ++++++++++--------------- proc/zsyscall_windows.go | 122 +++++++++++++++++++++++++++++++- 6 files changed, 366 insertions(+), 130 deletions(-) create mode 100644 proc/syscall_windows_amd64.go mode change 100755 => 100644 proc/zsyscall_windows.go diff --git a/proc/proc_windows.go b/proc/proc_windows.go index a9ec29e1..ff985821 100644 --- a/proc/proc_windows.go +++ b/proc/proc_windows.go @@ -1,7 +1,5 @@ package proc -// #include "windows.h" -import "C" import ( "debug/gosym" "debug/pe" @@ -30,7 +28,7 @@ const ( // OSProcessDetails holds Windows specific information. type OSProcessDetails struct { - hProcess sys.Handle + hProcess syscall.Handle breakThread int } @@ -121,17 +119,13 @@ func (dbp *Process) Kill() error { // TODO: Should not have to ignore failures here, // but some tests appear to Kill twice causing // this to fail on second attempt. - _ = C.TerminateProcess(C.HANDLE(dbp.os.hProcess), 1) + _ = syscall.TerminateProcess(dbp.os.hProcess, 1) dbp.exited = true return nil } func (dbp *Process) requestManualStop() error { - res := C.DebugBreakProcess(C.HANDLE(dbp.os.hProcess)) - if res == C.FALSE { - return fmt.Errorf("failed to break process %d", dbp.Pid) - } - return nil + return _DebugBreakProcess(dbp.os.hProcess) } func (dbp *Process) updateThreadList() error { @@ -140,7 +134,7 @@ func (dbp *Process) updateThreadList() error { return nil } -func (dbp *Process) addThread(hThread sys.Handle, threadID int, attach bool) (*Thread, error) { +func (dbp *Process) addThread(hThread syscall.Handle, threadID int, attach bool) (*Thread, error) { if thread, ok := dbp.Threads[threadID]; ok { return thread, nil } @@ -341,76 +335,76 @@ func dwarfFromPE(f *pe.File) (*dwarf.Data, error) { } func (dbp *Process) waitForDebugEvent() (threadID, exitCode int, err error) { - var debugEvent C.DEBUG_EVENT + var debugEvent _DEBUG_EVENT shouldExit := false for { // Wait for a debug event... - res := C.WaitForDebugEvent(&debugEvent, C.INFINITE) - if res == C.FALSE { - return 0, 0, fmt.Errorf("could not WaitForDebugEvent") + err := _WaitForDebugEvent(&debugEvent, syscall.INFINITE) + if err != nil { + return 0, 0, err } // ... 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") + unionPtr := unsafe.Pointer(&debugEvent.U[0]) + switch debugEvent.DebugEventCode { + case _CREATE_PROCESS_DEBUG_EVENT: + debugInfo := (*_CREATE_PROCESS_DEBUG_INFO)(unionPtr) + hFile := debugInfo.File + if hFile != 0 && hFile != syscall.InvalidHandle { + err = syscall.CloseHandle(hFile) + if err != nil { + return 0, 0, err } } - dbp.os.hProcess = sys.Handle(debugInfo.hProcess) - _, err = dbp.addThread(sys.Handle(debugInfo.hThread), int(debugEvent.dwThreadId), false) + dbp.os.hProcess = debugInfo.Process + _, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), 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) + case _CREATE_THREAD_DEBUG_EVENT: + debugInfo := (*_CREATE_THREAD_DEBUG_INFO)(unionPtr) + _, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false) if err != nil { return 0, 0, err } break - case C.EXIT_THREAD_DEBUG_EVENT: - delete(dbp.Threads, int(debugEvent.dwThreadId)) + case _EXIT_THREAD_DEBUG_EVENT: + delete(dbp.Threads, int(debugEvent.ThreadId)) break - case C.OUTPUT_DEBUG_STRING_EVENT: + case _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") + case _LOAD_DLL_DEBUG_EVENT: + debugInfo := (*_LOAD_DLL_DEBUG_INFO)(unionPtr) + hFile := debugInfo.File + if hFile != 0 && hFile != syscall.InvalidHandle { + err = syscall.CloseHandle(hFile) + if err != nil { + return 0, 0, err } } break - case C.UNLOAD_DLL_DEBUG_EVENT: + case _UNLOAD_DLL_DEBUG_EVENT: break - case C.RIP_EVENT: + case _RIP_EVENT: break - case C.EXCEPTION_DEBUG_EVENT: - tid := int(debugEvent.dwThreadId) + case _EXCEPTION_DEBUG_EVENT: + tid := int(debugEvent.ThreadId) dbp.os.breakThread = tid return tid, 0, nil - case C.EXIT_PROCESS_DEBUG_EVENT: - debugInfo := (*C.EXIT_PROCESS_DEBUG_INFO)(unionPtr) - exitCode = int(debugInfo.dwExitCode) + case _EXIT_PROCESS_DEBUG_EVENT: + debugInfo := (*_EXIT_PROCESS_DEBUG_INFO)(unionPtr) + exitCode = int(debugInfo.ExitCode) shouldExit = true default: - return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.dwDebugEventCode) + return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.DebugEventCode) } // .. 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") + err = _ContinueDebugEvent(debugEvent.ProcessId, debugEvent.ThreadId, _DBG_CONTINUE) + if err != nil { + return 0, 0, err } if shouldExit { diff --git a/proc/registers_windows_amd64.go b/proc/registers_windows_amd64.go index 282b795b..f5aa9b6a 100644 --- a/proc/registers_windows_amd64.go +++ b/proc/registers_windows_amd64.go @@ -1,12 +1,9 @@ package proc -// #include -import "C" import ( "bytes" "fmt" "rsc.io/x86/x86asm" - "syscall" "unsafe" ) @@ -97,22 +94,17 @@ func (r *Regs) TLS() uint64 { // SetPC sets the RIP register to the value specified by `pc`. func (r *Regs) SetPC(thread *Thread, pc uint64) error { - var context C.CONTEXT - context.ContextFlags = C.CONTEXT_ALL + context := newCONTEXT() + context.ContextFlags = _CONTEXT_ALL - res := C.GetThreadContext(C.HANDLE(thread.os.hThread), &context) - if res == C.FALSE { - return fmt.Errorf("could not GetThreadContext") + err := _GetThreadContext(thread.os.hThread, context) + if err != nil { + return err } - context.Rip = C.DWORD64(pc) + context.Rip = pc - res = C.SetThreadContext(C.HANDLE(thread.os.hThread), &context) - if res == C.FALSE { - return fmt.Errorf("could not SetThreadContext") - } - - return nil + return _SetThreadContext(thread.os.hThread, context) } func (r *Regs) Get(n int) (uint64, error) { @@ -273,18 +265,18 @@ func (r *Regs) Get(n int) (uint64, error) { } func registers(thread *Thread) (Registers, error) { - var context C.CONTEXT + context := newCONTEXT() - context.ContextFlags = C.CONTEXT_ALL - res := C.GetThreadContext(C.HANDLE(thread.os.hThread), &context) - if res == C.FALSE { - return nil, fmt.Errorf("failed to read ThreadContext") + context.ContextFlags = _CONTEXT_ALL + err := _GetThreadContext(thread.os.hThread, context) + if err != nil { + return nil, err } var threadInfo _THREAD_BASIC_INFORMATION - status := _NtQueryInformationThread(syscall.Handle(thread.os.hThread), _ThreadBasicInformation, uintptr(unsafe.Pointer(&threadInfo)), uint32(unsafe.Sizeof(threadInfo)), nil) + status := _NtQueryInformationThread(thread.os.hThread, _ThreadBasicInformation, uintptr(unsafe.Pointer(&threadInfo)), uint32(unsafe.Sizeof(threadInfo)), nil) if !_NT_SUCCESS(status) { - return nil, fmt.Errorf("failed to get thread_basic_information") + return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status) } regs := &Regs{ diff --git a/proc/syscall_windows.go b/proc/syscall_windows.go index f0123f8c..039d2c0b 100644 --- a/proc/syscall_windows.go +++ b/proc/syscall_windows.go @@ -22,8 +22,53 @@ type _THREAD_BASIC_INFORMATION struct { BasePriority int32 } +type _CREATE_PROCESS_DEBUG_INFO struct { + File syscall.Handle + Process syscall.Handle + Thread syscall.Handle + BaseOfImage uintptr + DebugInfoFileOffset uint32 + DebugInfoSize uint32 + ThreadLocalBase uintptr + StartAddress uintptr + ImageName uintptr + Unicode uint16 +} + +type _CREATE_THREAD_DEBUG_INFO struct { + Thread syscall.Handle + ThreadLocalBase uintptr + StartAddress uintptr +} + +type _EXIT_PROCESS_DEBUG_INFO struct { + ExitCode uint32 +} + +type _LOAD_DLL_DEBUG_INFO struct { + File syscall.Handle + BaseOfDll uintptr + DebugInfoFileOffset uint32 + DebugInfoSize uint32 + ImageName uintptr + Unicode uint16 +} + const ( _ThreadBasicInformation = 0 + + _DBG_CONTINUE = 0x00010002 + _DBG_EXCEPTION_NOT_HANDLED = 0x80010001 + + _EXCEPTION_DEBUG_EVENT = 1 + _CREATE_THREAD_DEBUG_EVENT = 2 + _CREATE_PROCESS_DEBUG_EVENT = 3 + _EXIT_THREAD_DEBUG_EVENT = 4 + _EXIT_PROCESS_DEBUG_EVENT = 5 + _LOAD_DLL_DEBUG_EVENT = 6 + _UNLOAD_DLL_DEBUG_EVENT = 7 + _OUTPUT_DEBUG_STRING_EVENT = 8 + _RIP_EVENT = 9 ) func _NT_SUCCESS(x _NTSTATUS) bool { @@ -31,3 +76,12 @@ func _NT_SUCCESS(x _NTSTATUS) bool { } //sys _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) = ntdll.NtQueryInformationThread +//sys _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.GetThreadContext +//sys _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.SetThreadContext +//sys _SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.SuspendThread +//sys _ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.ResumeThread +//sys _ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) = kernel32.ContinueDebugEvent +//sys _WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) = kernel32.WriteProcessMemory +//sys _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) = kernel32.ReadProcessMemory +//sys _DebugBreakProcess(process syscall.Handle) (err error) = kernel32.DebugBreakProcess +//sys _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) = kernel32.WaitForDebugEvent diff --git a/proc/syscall_windows_amd64.go b/proc/syscall_windows_amd64.go new file mode 100644 index 00000000..80d4fdba --- /dev/null +++ b/proc/syscall_windows_amd64.go @@ -0,0 +1,95 @@ +package proc + +import "unsafe" + +const ( + _CONTEXT_AMD64 = 0x100000 + _CONTEXT_CONTROL = (_CONTEXT_AMD64 | 0x1) + _CONTEXT_INTEGER = (_CONTEXT_AMD64 | 0x2) + _CONTEXT_SEGMENTS = (_CONTEXT_AMD64 | 0x4) + _CONTEXT_FLOATING_POINT = (_CONTEXT_AMD64 | 0x8) + _CONTEXT_DEBUG_REGISTERS = (_CONTEXT_AMD64 | 0x10) + _CONTEXT_FULL = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_FLOATING_POINT) + _CONTEXT_ALL = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_SEGMENTS | _CONTEXT_FLOATING_POINT | _CONTEXT_DEBUG_REGISTERS) + _CONTEXT_EXCEPTION_ACTIVE = 0x8000000 + _CONTEXT_SERVICE_ACTIVE = 0x10000000 + _CONTEXT_EXCEPTION_REQUEST = 0x40000000 + _CONTEXT_EXCEPTION_REPORTING = 0x80000000 +) + +type _M128A struct { + Low uint64 + High int64 +} + +type _CONTEXT struct { + P1Home uint64 + P2Home uint64 + P3Home uint64 + P4Home uint64 + P5Home uint64 + P6Home uint64 + + ContextFlags uint32 + MxCsr uint32 + + SegCs uint16 + SegDs uint16 + SegEs uint16 + SegFs uint16 + SegGs uint16 + SegSs uint16 + EFlags uint32 + + Dr0 uint64 + Dr1 uint64 + Dr2 uint64 + Dr3 uint64 + Dr6 uint64 + Dr7 uint64 + + Rax uint64 + Rcx uint64 + Rdx uint64 + Rbx uint64 + Rsp uint64 + Rbp uint64 + Rsi uint64 + Rdi uint64 + R8 uint64 + R9 uint64 + R10 uint64 + R11 uint64 + R12 uint64 + R13 uint64 + R14 uint64 + R15 uint64 + + Rip uint64 + + FltSave [512]byte + + VectorRegister [26]_M128A + VectorControl uint64 + + DebugControl uint64 + LastBranchToRip uint64 + LastBranchFromRip uint64 + LastExceptionToRip uint64 + LastExceptionFromRip uint64 +} + +// newCONTEXT allocates Windows CONTEXT structure aligned to 16 bytes. +func newCONTEXT() *_CONTEXT { + var c *_CONTEXT + buf := make([]byte, unsafe.Sizeof(*c)+15) + return (*_CONTEXT)(unsafe.Pointer((uintptr(unsafe.Pointer(&buf[15]))) &^ 15)) +} + +type _DEBUG_EVENT struct { + DebugEventCode uint32 + ProcessId uint32 + ThreadId uint32 + _ uint32 // to align Union properly + U [160]byte +} diff --git a/proc/threads_windows.go b/proc/threads_windows.go index c82fc7be..94ced6cd 100644 --- a/proc/threads_windows.go +++ b/proc/threads_windows.go @@ -1,10 +1,8 @@ package proc -// #include -import "C" import ( "fmt" - "unsafe" + "syscall" sys "golang.org/x/sys/windows" ) @@ -15,7 +13,7 @@ type WaitStatus sys.WaitStatus // OSSpecificDetails holds information specific to the Windows // operating system / kernel. type OSSpecificDetails struct { - hThread sys.Handle + hThread syscall.Handle } func (t *Thread) halt() (err error) { @@ -29,20 +27,20 @@ func (t *Thread) halt() (err error) { } func (t *Thread) singleStep() error { - var context C.CONTEXT - context.ContextFlags = C.CONTEXT_ALL + context := newCONTEXT() + context.ContextFlags = _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") + err := _GetThreadContext(t.os.hThread, context) + if err != nil { + return err } context.EFlags |= 0x100 - res = C.SetThreadContext(C.HANDLE(t.os.hThread), &context) - if res == C.FALSE { - return fmt.Errorf("could not SetThreadContext") + err = _SetThreadContext(t.os.hThread, context) + if err != nil { + return err } // Suspend all threads except this one @@ -50,20 +48,21 @@ func (t *Thread) singleStep() error { 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) + _, err := _SuspendThread(thread.os.hThread) + if err != nil { + return fmt.Errorf("could not suspend thread: %d: %v", thread.ID, err) } } // Continue and wait for the step to complete + err = nil t.dbp.execPtraceFunc(func() { - res = C.ContinueDebugEvent(C.DWORD(t.dbp.Pid), C.DWORD(t.ID), C.DBG_CONTINUE) + err = _ContinueDebugEvent(uint32(t.dbp.Pid), uint32(t.ID), _DBG_CONTINUE) }) - if res == C.FALSE { - return fmt.Errorf("could not ContinueDebugEvent.") + if err != nil { + return err } - _, err := t.dbp.trapWait(0) + _, err = t.dbp.trapWait(0) if err != nil { return err } @@ -73,40 +72,32 @@ func (t *Thread) singleStep() error { 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) + _, err := _ResumeThread(thread.os.hThread) + if err != nil { + return fmt.Errorf("could not resume thread: %d: %v", thread.ID, err) } } // Unset the processor TRAP flag - res = C.GetThreadContext(C.HANDLE(t.os.hThread), &context) - if res == C.FALSE { - return fmt.Errorf("could not GetThreadContext") + err = _GetThreadContext(t.os.hThread, context) + if err != nil { + return err } - context.EFlags &= ^C.DWORD(0x100) + context.EFlags &= ^uint32(0x100) - res = C.SetThreadContext(C.HANDLE(t.os.hThread), &context) - if res == C.FALSE { - return fmt.Errorf("could not SetThreadContext") - } - - return nil + return _SetThreadContext(t.os.hThread, context) } func (t *Thread) resume() error { t.running = true - var res C.WINBOOL + var err error 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) + err = _ContinueDebugEvent(uint32(t.dbp.Pid), uint32(t.ID), _DBG_CONTINUE) }) - if res == C.FALSE { - return fmt.Errorf("could not ContinueDebugEvent.") - } - return nil + return err } func (t *Thread) blocked() bool { @@ -135,15 +126,10 @@ func (t *Thread) stopped() bool { } func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) { - var ( - vmData = C.LPCVOID(unsafe.Pointer(&data[0])) - vmAddr = C.LPVOID(addr) - length = C.SIZE_T(len(data)) - count C.SIZE_T - ) - ret := C.WriteProcessMemory(C.HANDLE(t.dbp.os.hProcess), vmAddr, vmData, length, &count) - if ret == C.FALSE { - return int(count), fmt.Errorf("could not write memory") + var count uintptr + err := _WriteProcessMemory(t.dbp.os.hProcess, addr, &data[0], uintptr(len(data)), &count) + if err != nil { + return 0, err } return int(count), nil } @@ -152,16 +138,11 @@ func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { if size == 0 { return nil, nil } - var ( - buf = make([]byte, size) - vmData = C.LPVOID(unsafe.Pointer(&buf[0])) - vmAddr = C.LPCVOID(addr) - length = C.SIZE_T(size) - count C.SIZE_T - ) - ret := C.ReadProcessMemory(C.HANDLE(t.dbp.os.hProcess), vmAddr, vmData, length, &count) - if ret == C.FALSE { - return nil, fmt.Errorf("could not read memory") + var count uintptr + buf := make([]byte, size) + err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(size), &count) + if err != nil { + return nil, err } - return buf, nil + return buf[:count], nil } diff --git a/proc/zsyscall_windows.go b/proc/zsyscall_windows.go old mode 100755 new mode 100644 index 35d044b3..fe8ba258 --- a/proc/zsyscall_windows.go +++ b/proc/zsyscall_windows.go @@ -8,9 +8,19 @@ import "syscall" var _ unsafe.Pointer var ( - modntdll = syscall.NewLazyDLL("ntdll.dll") + modntdll = syscall.NewLazyDLL("ntdll.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") procNtQueryInformationThread = modntdll.NewProc("NtQueryInformationThread") + procGetThreadContext = modkernel32.NewProc("GetThreadContext") + procSetThreadContext = modkernel32.NewProc("SetThreadContext") + procSuspendThread = modkernel32.NewProc("SuspendThread") + procResumeThread = modkernel32.NewProc("ResumeThread") + procContinueDebugEvent = modkernel32.NewProc("ContinueDebugEvent") + procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory") + procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory") + procDebugBreakProcess = modkernel32.NewProc("DebugBreakProcess") + procWaitForDebugEvent = modkernel32.NewProc("WaitForDebugEvent") ) func _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) { @@ -18,3 +28,113 @@ func _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, inf status = _NTSTATUS(r0) return } + +func _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) { + r1, _, e1 := syscall.Syscall(procGetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) { + r1, _, e1 := syscall.Syscall(procSetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) { + r0, _, e1 := syscall.Syscall(procSuspendThread.Addr(), 1, uintptr(threadid), 0, 0) + prevsuspcount = uint32(r0) + if prevsuspcount == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) { + r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(threadid), 0, 0) + prevsuspcount = uint32(r0) + if prevsuspcount == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) { + r1, _, e1 := syscall.Syscall(procContinueDebugEvent.Addr(), 3, uintptr(processid), uintptr(threadid), uintptr(continuestatus)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(byteswritten)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(bytesread)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _DebugBreakProcess(process syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall(procDebugBreakProcess.Addr(), 1, uintptr(process), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) { + r1, _, e1 := syscall.Syscall(procWaitForDebugEvent.Addr(), 2, uintptr(unsafe.Pointer(debugevent)), uintptr(milliseconds), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +}