program: trace multi-threaded programs.

LGTM=r
R=r
https://golang.org/cl/86370043
diff --git a/program/client/client.go b/program/client/client.go
index bc585b1..57ce552 100644
--- a/program/client/client.go
+++ b/program/client/client.go
@@ -162,10 +162,8 @@
 	panic("unimplemented")
 }
 
-func (p *Program) Run(start bool) (program.Status, error) {
-	req := proxyrpc.RunRequest{
-		Start: start,
-	}
+func (p *Program) Run() (program.Status, error) {
+	req := proxyrpc.RunRequest{}
 	var resp proxyrpc.RunResponse
 	err := p.client.Call("Server.Run", &req, &resp)
 	if err != nil {
diff --git a/program/program.go b/program/program.go
index bc71091..2bed9dd 100644
--- a/program/program.go
+++ b/program/program.go
@@ -34,11 +34,9 @@
 	// and execs a new instance of the target binary file
 	// (which may have changed underfoot).
 	// Breakpoints and open files are re-established.
-	// The flag specifies whether to run the program (true)
-	// or stop it before it executes any instructions (false).
 	// The call hangs until the program stops executing,
 	// at which point it returns the program status.
-	Run(start bool) (Status, error)
+	Run() (Status, error)
 
 	// Stop stops execution of the current process but
 	// does not kill it.
diff --git a/program/proxyrpc/proxyrpc.go b/program/proxyrpc/proxyrpc.go
index eeef340..e201f1f 100644
--- a/program/proxyrpc/proxyrpc.go
+++ b/program/proxyrpc/proxyrpc.go
@@ -52,7 +52,6 @@
 }
 
 type RunRequest struct {
-	Start bool
 }
 
 type RunResponse struct {
diff --git a/program/server/ptrace.go b/program/server/ptrace.go
index 0072e7f..0f25e80 100644
--- a/program/server/ptrace.go
+++ b/program/server/ptrace.go
@@ -4,9 +4,6 @@
 
 package server
 
-// TODO: syscall.PTRACE_O_TRACECLONE shenanigans to trace multi-threaded
-// programs.
-
 import (
 	"fmt"
 	"os"
@@ -50,13 +47,6 @@
 	return <-s.ec
 }
 
-func (s *Server) ptraceSetRegs(pid int, regs *syscall.PtraceRegs) (err error) {
-	s.fc <- func() error {
-		return syscall.PtraceSetRegs(pid, regs)
-	}
-	return <-s.ec
-}
-
 func (s *Server) ptracePeek(pid int, addr uintptr, out []byte) (err error) {
 	s.fc <- func() error {
 		n, err := syscall.PtracePeekText(pid, addr, out)
@@ -85,6 +75,20 @@
 	return <-s.ec
 }
 
+func (s *Server) ptraceSetOptions(pid int, options int) (err error) {
+	s.fc <- func() error {
+		return syscall.PtraceSetOptions(pid, options)
+	}
+	return <-s.ec
+}
+
+func (s *Server) ptraceSetRegs(pid int, regs *syscall.PtraceRegs) (err error) {
+	s.fc <- func() error {
+		return syscall.PtraceSetRegs(pid, regs)
+	}
+	return <-s.ec
+}
+
 func (s *Server) ptraceSingleStep(pid int) (err error) {
 	s.fc <- func() error {
 		return syscall.PtraceSingleStep(pid)
@@ -92,12 +96,11 @@
 	return <-s.ec
 }
 
-func (s *Server) wait() (err error) {
-	var status syscall.WaitStatus
+func (s *Server) wait(pid int) (wpid int, status syscall.WaitStatus, err error) {
 	s.fc <- func() error {
-		_, err1 := syscall.Wait4(-1, &status, 0, nil)
+		var err1 error
+		wpid, err1 = syscall.Wait4(pid, &status, syscall.WALL, nil)
 		return err1
 	}
-	// TODO: do something with status.
-	return <-s.ec
+	return wpid, status, <-s.ec
 }
diff --git a/program/server/server.go b/program/server/server.go
index fb6a503..c9a425c 100644
--- a/program/server/server.go
+++ b/program/server/server.go
@@ -40,6 +40,9 @@
 	ec chan error
 
 	proc        *os.Process
+	procIsUp    bool
+	stoppedPid  int
+	stoppedRegs syscall.PtraceRegs
 	breakpoints map[uint64]breakpoint
 	files       []*file // Index == file descriptor.
 }
@@ -183,6 +186,9 @@
 	if s.proc != nil {
 		s.proc.Kill()
 		s.proc = nil
+		s.procIsUp = false
+		s.stoppedPid = 0
+		s.stoppedRegs = syscall.PtraceRegs{}
 	}
 	p, err := s.startProcess(s.executable, nil, &os.ProcAttr{
 		Files: []*os.File{
@@ -191,17 +197,15 @@
 			os.Stderr,
 		},
 		Sys: &syscall.SysProcAttr{
-			Ptrace: !req.Start,
+			Pdeathsig: syscall.SIGKILL,
+			Ptrace:    true,
 		},
 	})
 	if err != nil {
 		return err
 	}
 	s.proc = p
-
-	if !req.Start {
-		// TODO: wait until /proc/{s.proc.Pid}/status says "State:	t (tracing stop)".
-	}
+	s.stoppedPid = p.Pid
 	return nil
 }
 
@@ -209,29 +213,41 @@
 	s.mu.Lock()
 	defer s.mu.Unlock()
 
-	regs := syscall.PtraceRegs{}
-	err := s.ptraceGetRegs(s.proc.Pid, &regs)
-	if err != nil {
-		return err
+	if s.proc == nil {
+		return fmt.Errorf("Resume: Run did not successfully start a process")
 	}
-	if _, ok := s.breakpoints[regs.Rip]; ok {
-		err = s.ptraceSingleStep(s.proc.Pid)
+
+	if !s.procIsUp {
+		s.procIsUp = true
+		_, err := s.waitForTrap(s.stoppedPid)
+		if err != nil {
+			return err
+		}
+		err = s.ptraceSetOptions(s.stoppedPid, syscall.PTRACE_O_TRACECLONE)
+		if err != nil {
+			return fmt.Errorf("ptraceSetOptions: %v", err)
+		}
+	} else if _, ok := s.breakpoints[s.stoppedRegs.Rip]; ok {
+		err := s.ptraceSingleStep(s.stoppedPid)
 		if err != nil {
 			return fmt.Errorf("ptraceSingleStep: %v", err)
 		}
+		_, err = s.waitForTrap(s.stoppedPid)
+		if err != nil {
+			return err
+		}
 	}
 
-	err = s.setBreakpoints()
+	err := s.setBreakpoints()
 	if err != nil {
 		return err
 	}
-
-	err = s.ptraceCont(s.proc.Pid, 0)
+	err = s.ptraceCont(s.stoppedPid, 0)
 	if err != nil {
-		return err
+		return fmt.Errorf("ptraceCont: %v", err)
 	}
 
-	err = s.wait()
+	s.stoppedPid, err = s.waitForTrap(-1)
 	if err != nil {
 		return err
 	}
@@ -241,22 +257,39 @@
 		return err
 	}
 
-	err = s.ptraceGetRegs(s.proc.Pid, &regs)
+	err = s.ptraceGetRegs(s.stoppedPid, &s.stoppedRegs)
 	if err != nil {
-		return err
+		return fmt.Errorf("ptraceGetRegs: %v", err)
 	}
 
-	regs.Rip -= uint64(s.arch.BreakpointSize)
-	err = s.ptraceSetRegs(s.proc.Pid, &regs)
+	s.stoppedRegs.Rip -= uint64(s.arch.BreakpointSize)
+
+	err = s.ptraceSetRegs(s.stoppedPid, &s.stoppedRegs)
 	if err != nil {
 		return fmt.Errorf("ptraceSetRegs: %v", err)
 	}
 
-	resp.Status.PC = regs.Rip
-	resp.Status.SP = regs.Rsp
+	resp.Status.PC = s.stoppedRegs.Rip
+	resp.Status.SP = s.stoppedRegs.Rsp
 	return nil
 }
 
+func (s *Server) waitForTrap(pid int) (wpid int, err error) {
+	for {
+		wpid, status, err := s.wait(pid)
+		if err != nil {
+			return 0, fmt.Errorf("wait: %v", err)
+		}
+		if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != syscall.PTRACE_EVENT_CLONE {
+			return wpid, nil
+		}
+		err = s.ptraceCont(wpid, 0) // TODO: non-zero when wait catches other signals?
+		if err != nil {
+			return 0, fmt.Errorf("ptraceCont: %v", err)
+		}
+	}
+}
+
 func (s *Server) Breakpoint(req *proxyrpc.BreakpointRequest, resp *proxyrpc.BreakpointResponse) (err error) {
 	s.mu.Lock()
 	defer s.mu.Unlock()
@@ -275,7 +308,7 @@
 			return fmt.Errorf("breakpoint already set at %#x (TODO)", pc)
 		}
 
-		err = s.ptracePeek(s.proc.Pid, uintptr(pc), bp.origInstr[:s.arch.BreakpointSize])
+		err = s.ptracePeek(s.stoppedPid, uintptr(pc), bp.origInstr[:s.arch.BreakpointSize])
 		if err != nil {
 			return fmt.Errorf("ptracePeek: %v", err)
 		}
@@ -288,7 +321,7 @@
 
 func (s *Server) setBreakpoints() error {
 	for pc := range s.breakpoints {
-		err := s.ptracePoke(s.proc.Pid, uintptr(pc), s.arch.BreakpointInstr[:s.arch.BreakpointSize])
+		err := s.ptracePoke(s.stoppedPid, uintptr(pc), s.arch.BreakpointInstr[:s.arch.BreakpointSize])
 		if err != nil {
 			return fmt.Errorf("setBreakpoints: %v", err)
 		}
@@ -298,7 +331,7 @@
 
 func (s *Server) liftBreakpoints() error {
 	for pc, breakpoint := range s.breakpoints {
-		err := s.ptracePoke(s.proc.Pid, uintptr(pc), breakpoint.origInstr[:s.arch.BreakpointSize])
+		err := s.ptracePoke(s.stoppedPid, uintptr(pc), breakpoint.origInstr[:s.arch.BreakpointSize])
 		if err != nil {
 			return fmt.Errorf("liftBreakpoints: %v", err)
 		}
@@ -381,7 +414,7 @@
 	// TODO: we're assuming we're at a function's entry point (LowPC).
 
 	regs := syscall.PtraceRegs{}
-	err := s.ptraceGetRegs(s.proc.Pid, &regs)
+	err := s.ptraceGetRegs(s.stoppedPid, &regs)
 	if err != nil {
 		return err
 	}
@@ -432,7 +465,7 @@
 				if location == 0 {
 					return fmt.Errorf("no location for FormalParameter")
 				}
-				err = s.ptracePeek(s.proc.Pid, location, buf[:s.arch.IntSize])
+				err = s.ptracePeek(s.stoppedPid, location, buf[:s.arch.IntSize])
 				if err != nil {
 					return err
 				}