Syscall wrappers for ptrace and supporting wait-related flags.

R=rsc
APPROVED=rsc
DELTA=311  (308 added, 3 deleted, 0 changed)
OCL=31569
CL=31606
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 65d69e4..70b34b4 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -386,6 +386,163 @@
 	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l));
 }
 
+//sys	ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
+
+// See bytes.Copy.
+func bytesCopy(dst, src []byte) int {
+	if len(src) > len(dst) {
+		src = src[0:len(dst)];
+	}
+	for i, x := range src {
+		dst[i] = x
+	}
+	return len(src)
+}
+
+func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
+	// The peek requests are machine-size oriented, so we wrap it
+	// to retrieve arbitrary-length data.
+
+	// The ptrace syscall differs from glibc's ptrace.
+	// Peeks returns the word in *data, not as the return value.
+
+	var buf [sizeofPtr]byte;
+
+	// Leading edge.  PEEKTEXT/PEEKDATA don't require aligned
+	// access (PEEKUSER warns that it might), but if we don't
+	// align our reads, we might straddle an unmapped page
+	// boundary and not get the bytes leading up to the page
+	// boundary.
+	n := 0;
+	if addr % sizeofPtr != 0 {
+		errno = ptrace(req, pid, addr - addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])));
+		if errno != 0 {
+			return 0, errno;
+		}
+		n += bytesCopy(out, buf[addr%sizeofPtr:len(buf)]);
+		out = out[n:len(out)];
+	}
+
+	// Remainder.
+	for len(out) > 0 {
+		// We use an internal buffer to gaurantee alignment.
+		// It's not documented if this is necessary, but we're paranoid.
+		errno = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])));
+		if errno != 0 {
+			return n, errno;
+		}
+		copied := bytesCopy(out, &buf);
+		n += copied;
+		out = out[copied:len(out)];
+	}
+
+	return n, 0;
+}
+
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
+	return ptracePeek(_PTRACE_PEEKTEXT, pid, addr, out);
+}
+
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
+	return ptracePeek(_PTRACE_PEEKDATA, pid, addr, out);
+}
+
+func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
+	// As for ptracePeek, we need to align our accesses to deal
+	// with the possibility of straddling an invalid page.
+
+	// Leading edge.
+	n := 0;
+	if addr % sizeofPtr != 0 {
+		var buf [sizeofPtr]byte;
+		errno = ptrace(peekReq, pid, addr - addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])));
+		if errno != 0 {
+			return 0, errno;
+		}
+		n += bytesCopy(buf[addr%sizeofPtr:len(buf)], data);
+		word := *((*uintptr)(unsafe.Pointer(&buf[0])));
+		errno = ptrace(pokeReq, pid, addr - addr%sizeofPtr, word);
+		if errno != 0 {
+			return 0, errno;
+		}
+		data = data[n:len(data)];
+	}
+
+	// Interior.
+	for len(data) > sizeofPtr {
+		word := *((*uintptr)(unsafe.Pointer(&data[0])));
+		errno = ptrace(pokeReq, pid, addr+uintptr(n), word);
+		if errno != 0 {
+			return n, errno;
+		}
+		n += sizeofPtr;
+		data = data[sizeofPtr:len(data)];
+	}
+
+	// Trailing edge.
+	if len(data) > 0 {
+		var buf [sizeofPtr]byte;
+		errno = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])));
+		if errno != 0 {
+			return n, errno;
+		}
+		bytesCopy(&buf, data);
+		word := *((*uintptr)(unsafe.Pointer(&buf[0])));
+		errno = ptrace(pokeReq, pid, addr+uintptr(n), word);
+		if errno != 0 {
+			return n, errno;
+		}
+		n += len(data);
+	}
+
+	return n, 0;
+}
+
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
+	return ptracePoke(_PTRACE_POKETEXT, _PTRACE_PEEKTEXT, pid, addr, data);
+}
+
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
+	return ptracePoke(_PTRACE_POKEDATA, _PTRACE_PEEKDATA, pid, addr, data);
+}
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
+	return ptrace(_PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)));
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
+	return ptrace(_PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)));
+}
+
+func PtraceSetOptions(pid int, options int) (errno int) {
+	return ptrace(_PTRACE_SETOPTIONS, pid, 0, uintptr(options));
+}
+
+func PtraceGetEventMsg(pid int) (msg uint, errno int) {
+	var data _C_long;
+	errno = ptrace(_PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)));
+	if errno != 0 {
+		msg = uint(data);
+	}
+	return;
+}
+
+func PtraceCont(pid int, signal int) (errno int) {
+	return ptrace(_PTRACE_CONT, pid, 0, uintptr(signal));
+}
+
+func PtraceSingleStep(pid int) (errno int) {
+	return ptrace(_PTRACE_SINGLESTEP, pid, 0, 0);
+}
+
+func PtraceAttach(pid int) (errno int) {
+	return ptrace(_PTRACE_ATTACH, pid, 0, 0);
+}
+
+func PtraceDetach(pid int) (errno int) {
+	return ptrace(_PTRACE_DETACH, pid, 0, 0);
+}
+
 // Sendto
 // Recvfrom
 // Sendmsg
@@ -634,3 +791,4 @@
 // Waitid
 // Writev
 // _Sysctl
+
diff --git a/src/pkg/syscall/types_linux.c b/src/pkg/syscall/types_linux.c
index 40b3648..234e5dd 100644
--- a/src/pkg/syscall/types_linux.c
+++ b/src/pkg/syscall/types_linux.c
@@ -13,6 +13,7 @@
 
 #include <dirent.h>
 #include <fcntl.h>
+#include <linux/user.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <signal.h>
@@ -52,6 +53,12 @@
 	$PathMax = PATH_MAX,
 };
 
+// Basic types
+
+typedef short $_C_short;
+typedef int $_C_int;
+typedef long $_C_long;
+typedef long long $_C_long_long;
 
 // Time
 
@@ -67,7 +74,6 @@
 typedef struct rusage $Rusage;
 typedef struct rlimit $Rlimit;
 
-typedef int $_C_int;
 typedef gid_t $_Gid_t;
 
 // Files
@@ -130,6 +136,11 @@
 	$WSTOPPED = WSTOPPED,
 	$WCONTINUED = WCONTINUED,
 	$WNOWAIT = WNOWAIT,
+
+        // Linux-specific
+        $WCLONE = __WCLONE,
+        $WALL = __WALL,
+        $WNOTHREAD = __WNOTHREAD,
 };
 
 // Sockets
@@ -192,6 +203,60 @@
 typedef socklen_t $_Socklen;
 typedef struct linger $Linger;
 
+// Ptrace
+
+// Ptrace requests
+enum {
+	$_PTRACE_TRACEME = PTRACE_TRACEME,
+	$_PTRACE_PEEKTEXT = PTRACE_PEEKTEXT,
+	$_PTRACE_PEEKDATA = PTRACE_PEEKDATA,
+	$_PTRACE_PEEKUSER = PTRACE_PEEKUSER,
+	$_PTRACE_POKETEXT = PTRACE_POKETEXT,
+	$_PTRACE_POKEDATA = PTRACE_POKEDATA,
+	$_PTRACE_POKEUSER = PTRACE_POKEUSER,
+	$_PTRACE_CONT = PTRACE_CONT,
+	$_PTRACE_KILL = PTRACE_KILL,
+	$_PTRACE_SINGLESTEP = PTRACE_SINGLESTEP,
+	$_PTRACE_GETREGS = PTRACE_GETREGS,
+	$_PTRACE_SETREGS = PTRACE_SETREGS,
+	$_PTRACE_GETFPREGS = PTRACE_GETFPREGS,
+	$_PTRACE_SETFPREGS = PTRACE_SETFPREGS,
+	$_PTRACE_ATTACH = PTRACE_ATTACH,
+	$_PTRACE_DETACH = PTRACE_DETACH,
+	$_PTRACE_GETFPXREGS = PTRACE_GETFPXREGS,
+	$_PTRACE_SETFPXREGS = PTRACE_SETFPXREGS,
+	$_PTRACE_SYSCALL = PTRACE_SYSCALL,
+	$_PTRACE_SETOPTIONS = PTRACE_SETOPTIONS,
+	$_PTRACE_GETEVENTMSG = PTRACE_GETEVENTMSG,
+	$_PTRACE_GETSIGINFO = PTRACE_GETSIGINFO,
+	$_PTRACE_SETSIGINFO = PTRACE_SETSIGINFO,
+};
+
+// PTRACE_SETOPTIONS options
+enum {
+	$PTRACE_O_TRACESYSGOOD = PTRACE_O_TRACESYSGOOD,
+	$PTRACE_O_TRACEFORK = PTRACE_O_TRACEFORK,
+	$PTRACE_O_TRACEVFORK = PTRACE_O_TRACEVFORK,
+	$PTRACE_O_TRACECLONE = PTRACE_O_TRACECLONE,
+	$PTRACE_O_TRACEEXEC = PTRACE_O_TRACEEXEC,
+	$PTRACE_O_TRACEVFORKDONE = PTRACE_O_TRACEVFORKDONE,
+	$PTRACE_O_TRACEEXIT = PTRACE_O_TRACEEXIT,
+	$PTRACE_O_MASK = PTRACE_O_MASK,
+};
+
+// Extended result codes
+enum {
+	$PTRACE_EVENT_FORK = PTRACE_EVENT_FORK,
+	$PTRACE_EVENT_VFORK = PTRACE_EVENT_VFORK,
+	$PTRACE_EVENT_CLONE = PTRACE_EVENT_CLONE,
+	$PTRACE_EVENT_EXEC = PTRACE_EVENT_EXEC,
+	$PTRACE_EVENT_VFORK_DONE = PTRACE_EVENT_VFORK_DONE,
+	$PTRACE_EVENT_EXIT = PTRACE_EVENT_EXIT,
+};
+
+// Register structures
+typedef struct user_regs_struct $PtraceRegs;
+
 // Misc
 
 enum {
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index 09f21df..743c528 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -42,6 +42,12 @@
 	return;
 }
 
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+	r0, r1, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0);
+	errno = int(e1);
+	return;
+}
+
 func Access(path string, mode int) (errno int) {
 	r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0);
 	errno = int(e1);
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index 5733f3e..56211b4 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -49,6 +49,9 @@
 	WSTOPPED = 0x2;
 	WCONTINUED = 0x8;
 	WNOWAIT = 0x1000000;
+	WCLONE = 0x80000000;
+	WALL = 0x40000000;
+	WNOTHREAD = 0x20000000;
 	AF_UNIX = 0x1;
 	AF_INET = 0x2;
 	AF_INET6 = 0xa;
@@ -74,6 +77,43 @@
 	SizeofSockaddrInet6 = 0x1c;
 	SizeofSockaddrAny = 0x1c;
 	SizeofSockaddrUnix = 0x6e;
+	_PTRACE_TRACEME = 0;
+	_PTRACE_PEEKTEXT = 0x1;
+	_PTRACE_PEEKDATA = 0x2;
+	_PTRACE_PEEKUSER = 0x3;
+	_PTRACE_POKETEXT = 0x4;
+	_PTRACE_POKEDATA = 0x5;
+	_PTRACE_POKEUSER = 0x6;
+	_PTRACE_CONT = 0x7;
+	_PTRACE_KILL = 0x8;
+	_PTRACE_SINGLESTEP = 0x9;
+	_PTRACE_GETREGS = 0xc;
+	_PTRACE_SETREGS = 0xd;
+	_PTRACE_GETFPREGS = 0xe;
+	_PTRACE_SETFPREGS = 0xf;
+	_PTRACE_ATTACH = 0x10;
+	_PTRACE_DETACH = 0x11;
+	_PTRACE_GETFPXREGS = 0x12;
+	_PTRACE_SETFPXREGS = 0x13;
+	_PTRACE_SYSCALL = 0x18;
+	_PTRACE_SETOPTIONS = 0x4200;
+	_PTRACE_GETEVENTMSG = 0x4201;
+	_PTRACE_GETSIGINFO = 0x4202;
+	_PTRACE_SETSIGINFO = 0x4203;
+	PTRACE_O_TRACESYSGOOD = 0x1;
+	PTRACE_O_TRACEFORK = 0x2;
+	PTRACE_O_TRACEVFORK = 0x4;
+	PTRACE_O_TRACECLONE = 0x8;
+	PTRACE_O_TRACEEXEC = 0x10;
+	PTRACE_O_TRACEVFORKDONE = 0x20;
+	PTRACE_O_TRACEEXIT = 0x40;
+	PTRACE_O_MASK = 0x7f;
+	PTRACE_EVENT_FORK = 0x1;
+	PTRACE_EVENT_VFORK = 0x2;
+	PTRACE_EVENT_CLONE = 0x3;
+	PTRACE_EVENT_EXEC = 0x4;
+	PTRACE_EVENT_VFORK_DONE = 0x5;
+	PTRACE_EVENT_EXIT = 0x6;
 	EPOLLIN = 0x1;
 	EPOLLRDHUP = 0x2000;
 	EPOLLOUT = 0x4;
@@ -85,6 +125,14 @@
 
 // Types
 
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int64
+
+type _C_long_long int64
+
 type Timespec struct {
 	Sec int64;
 	Nsec int64;
@@ -170,8 +218,6 @@
 	Max uint64;
 }
 
-type _C_int int32
-
 type _Gid_t uint32
 
 type Stat_t struct {
@@ -252,6 +298,36 @@
 	Linger int32;
 }
 
+type PtraceRegs struct {
+	R15 uint64;
+	R14 uint64;
+	R13 uint64;
+	R12 uint64;
+	Rbp uint64;
+	Rbx uint64;
+	R11 uint64;
+	R10 uint64;
+	R9 uint64;
+	R8 uint64;
+	Rax uint64;
+	Rcx uint64;
+	Rdx uint64;
+	Rsi uint64;
+	Rdi uint64;
+	Orig_rax uint64;
+	Rip uint64;
+	Cs uint64;
+	Eflags uint64;
+	Rsp uint64;
+	Ss uint64;
+	Fs_base uint64;
+	Gs_base uint64;
+	Ds uint64;
+	Es uint64;
+	Fs uint64;
+	Gs uint64;
+}
+
 type FdSet struct {
 	Bits [16]int64;
 }