diff --git a/pkg/proc/native/ptrace_linux.go b/pkg/proc/native/ptrace_linux.go index ab4f5372..849516d8 100644 --- a/pkg/proc/native/ptrace_linux.go +++ b/pkg/proc/native/ptrace_linux.go @@ -49,3 +49,31 @@ func PtracePeekUser(tid int, off uintptr) (uintptr, error) { } return val, nil } + +// ProcessVmRead calls process_vm_readv +func ProcessVmRead(tid int, addr uintptr, data []byte) (int, error) { + len_iov := uint64(len(data)) + local_iov := sys.Iovec{Base: &data[0], Len: len_iov} + remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov} + p_local := uintptr(unsafe.Pointer(&local_iov)) + p_remote := uintptr(unsafe.Pointer(&remote_iov)) + n, _, err := syscall.Syscall6(sys.SYS_PROCESS_VM_READV, uintptr(tid), p_local, 1, p_remote, 1, 0) + if err != syscall.Errno(0) { + return 0, err + } + return int(n), nil +} + +// ProcessVmWrite calls process_vm_writev +func ProcessVmWrite(tid int, addr uintptr, data []byte) (int, error) { + len_iov := uint64(len(data)) + local_iov := sys.Iovec{Base: &data[0], Len: len_iov} + remote_iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(addr)), Len: len_iov} + p_local := uintptr(unsafe.Pointer(&local_iov)) + p_remote := uintptr(unsafe.Pointer(&remote_iov)) + n, _, err := syscall.Syscall6(sys.SYS_PROCESS_VM_WRITEV, uintptr(tid), p_local, 1, p_remote, 1, 0) + if err != syscall.Errno(0) { + return 0, err + } + return int(n), nil +} diff --git a/pkg/proc/native/threads_linux.go b/pkg/proc/native/threads_linux.go index c27971ea..5366c7d6 100644 --- a/pkg/proc/native/threads_linux.go +++ b/pkg/proc/native/threads_linux.go @@ -90,7 +90,14 @@ func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error) if len(data) == 0 { return } - t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, addr, data) }) + // ProcessVmWrite can't poke read-only memory like ptrace, so don't + // even bother for small writes -- likely breakpoints and such. + if len(data) > sys.SizeofPtr { + written, _ = ProcessVmWrite(t.ID, addr, data) + } + if written == 0 { + t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, addr, data) }) + } return } @@ -101,9 +108,9 @@ func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) { if len(data) == 0 { return } - t.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(t.ID, addr, data) }) - if err == nil { - n = len(data) + n, _ = ProcessVmRead(t.ID, addr, data) + if n == 0 { + t.dbp.execPtraceFunc(func() { n, err = sys.PtracePeekData(t.ID, addr, data) }) } return }