2019-07-13 01:28:04 +00:00
|
|
|
package native
|
|
|
|
|
|
|
|
// #cgo LDFLAGS: -lutil
|
|
|
|
//#include <sys/types.h>
|
|
|
|
//#include <sys/ptrace.h>
|
|
|
|
//
|
|
|
|
// #include <stdlib.h>
|
2022-05-31 23:04:36 +00:00
|
|
|
//
|
2019-07-13 01:28:04 +00:00
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
2023-02-14 17:32:13 +00:00
|
|
|
"runtime"
|
2022-12-20 17:54:16 +00:00
|
|
|
"syscall"
|
2023-02-14 17:32:13 +00:00
|
|
|
"unsafe"
|
2019-07-13 01:28:04 +00:00
|
|
|
|
|
|
|
sys "golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
2020-03-26 12:05:09 +00:00
|
|
|
// ptraceAttach executes the sys.PtraceAttach call.
|
2019-07-13 01:28:04 +00:00
|
|
|
// pid must be a PID, not a LWPID
|
2020-03-26 12:05:09 +00:00
|
|
|
func ptraceAttach(pid int) error {
|
2019-07-13 01:28:04 +00:00
|
|
|
return sys.PtraceAttach(pid)
|
|
|
|
}
|
|
|
|
|
2020-03-26 12:05:09 +00:00
|
|
|
// ptraceDetach calls ptrace(PTRACE_DETACH).
|
|
|
|
func ptraceDetach(pid int) error {
|
2019-07-13 01:28:04 +00:00
|
|
|
return sys.PtraceDetach(pid)
|
|
|
|
}
|
|
|
|
|
2020-03-26 12:05:09 +00:00
|
|
|
// ptraceCont executes ptrace PTRACE_CONT
|
2019-07-13 01:28:04 +00:00
|
|
|
// id may be a PID or an LWPID
|
2020-03-26 12:05:09 +00:00
|
|
|
func ptraceCont(id, sig int) error {
|
2019-07-13 01:28:04 +00:00
|
|
|
return sys.PtraceCont(id, sig)
|
|
|
|
}
|
|
|
|
|
2020-03-26 12:05:09 +00:00
|
|
|
// ptraceSingleStep executes ptrace PTRACE_SINGLE_STEP.
|
2019-07-13 01:28:04 +00:00
|
|
|
// id may be a PID or an LWPID
|
2020-03-26 12:05:09 +00:00
|
|
|
func ptraceSingleStep(id int) error {
|
2019-07-13 01:28:04 +00:00
|
|
|
return sys.PtraceSingleStep(id)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a list of the thread ids of a process
|
2020-03-26 12:05:09 +00:00
|
|
|
func ptraceGetLwpList(pid int) (tids []int32) {
|
2022-05-31 23:04:36 +00:00
|
|
|
numLWPS := C.ptrace(C.PT_GETNUMLWPS, C.pid_t(pid), C.caddr_t(unsafe.Pointer(uintptr(0))), C.int(0))
|
|
|
|
if numLWPS < 0 {
|
|
|
|
panic("PT_GETNUMLWPS failed")
|
|
|
|
}
|
|
|
|
tids = make([]int32, numLWPS)
|
|
|
|
n := C.ptrace(C.PT_GETLWPLIST, C.pid_t(pid), C.caddr_t(unsafe.Pointer(&tids[0])), C.int(numLWPS))
|
|
|
|
if n < 0 {
|
|
|
|
panic("PT_GETLWPLIST failed")
|
|
|
|
}
|
2019-07-13 01:28:04 +00:00
|
|
|
return tids[0:n]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get info of the thread that caused wpid's process to stop.
|
|
|
|
func ptraceGetLwpInfo(wpid int) (info sys.PtraceLwpInfoStruct, err error) {
|
2023-08-30 17:22:08 +00:00
|
|
|
err = sys.PtraceLwpInfo(wpid, &info)
|
2019-07-13 01:28:04 +00:00
|
|
|
return info, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// id may be a PID or an LWPID
|
|
|
|
func ptraceReadData(id int, addr uintptr, data []byte) (n int, err error) {
|
2023-02-14 17:32:13 +00:00
|
|
|
defer runtime.KeepAlive(&data[0]) // PIN
|
2019-07-13 01:28:04 +00:00
|
|
|
return sys.PtraceIO(sys.PIOD_READ_D, id, addr, data, len(data))
|
|
|
|
}
|
|
|
|
|
|
|
|
// id may be a PID or an LWPID
|
|
|
|
func ptraceWriteData(id int, addr uintptr, data []byte) (n int, err error) {
|
2023-02-14 17:32:13 +00:00
|
|
|
defer runtime.KeepAlive(&data[0]) // PIN
|
2019-07-13 01:28:04 +00:00
|
|
|
return sys.PtraceIO(sys.PIOD_WRITE_D, id, addr, data, len(data))
|
|
|
|
}
|
2022-12-20 17:54:16 +00:00
|
|
|
|
|
|
|
func ptraceSuspend(id int) error {
|
|
|
|
_, _, e1 := sys.Syscall6(sys.SYS_PTRACE, uintptr(C.PT_SUSPEND), uintptr(id), uintptr(1), uintptr(0), 0, 0)
|
|
|
|
if e1 != 0 {
|
|
|
|
return syscall.Errno(e1)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ptraceResume(id int) error {
|
|
|
|
_, _, e1 := sys.Syscall6(sys.SYS_PTRACE, uintptr(C.PT_RESUME), uintptr(id), uintptr(1), uintptr(0), 0, 0)
|
|
|
|
if e1 != 0 {
|
|
|
|
return syscall.Errno(e1)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ptraceSetStep(id int) error {
|
|
|
|
_, _, e1 := sys.Syscall6(sys.SYS_PTRACE, uintptr(C.PT_SETSTEP), uintptr(id), uintptr(0), uintptr(0), 0, 0)
|
|
|
|
if e1 != 0 {
|
|
|
|
return syscall.Errno(e1)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ptraceClearStep(id int) error {
|
|
|
|
_, _, e1 := sys.Syscall6(sys.SYS_PTRACE, uintptr(C.PT_CLEARSTEP), uintptr(id), uintptr(0), uintptr(0), 0, 0)
|
|
|
|
if e1 != 0 {
|
|
|
|
return syscall.Errno(e1)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|