]> Cypherpunks repositories - gostls13.git/commitdiff
Switch ogle over to the in-tree debug/proc package. Fix
authorAustin Clements <aclements@csail.mit.edu>
Thu, 24 Sep 2009 16:07:47 +0000 (09:07 -0700)
committerAustin Clements <aclements@csail.mit.edu>
Thu, 24 Sep 2009 16:07:47 +0000 (09:07 -0700)
debug/proc to install to the right place.  Delete the old
ptrace package.  The diff looks huge, but it's mostly
s/ptrace/proc/.

R=rsc
APPROVED=rsc
DELTA=1940  (10 added, 1835 deleted, 95 changed)
OCL=34966
CL=34968

16 files changed:
src/pkg/debug/proc/Makefile
usr/austin/ogle/arch.go
usr/austin/ogle/cmd.go
usr/austin/ogle/event.go
usr/austin/ogle/frame.go
usr/austin/ogle/goroutine.go
usr/austin/ogle/process.go
usr/austin/ogle/rruntime.go
usr/austin/ogle/rtype.go
usr/austin/ogle/rvalue.go
usr/austin/ogle/vars.go
usr/austin/ptrace/Makefile [deleted file]
usr/austin/ptrace/process.go [deleted file]
usr/austin/ptrace/ptrace-nptl.txt [deleted file]
usr/austin/ptrace/ptrace_linux.go [deleted file]
usr/austin/ptrace/regs_linux_amd64.go [deleted file]

index d7eb34855e125b27a9457d5fe1793811f184c68c..1c6dc9089fec406cb7045ae4184e467cc79099aa 100644 (file)
@@ -4,7 +4,7 @@
 
 include $(GOROOT)/src/Make.$(GOARCH)
 
-TARG=ptrace
+TARG=debug/proc
 GOFILES=\
        proc.go\
        proc_$(GOOS).go\
index 5c23c4ea6f582b58cffa9d6e378be8e669773f74..30a2bcf58bde730d30faf151e432873d993e6d95 100644 (file)
@@ -5,17 +5,17 @@
 package ogle
 
 import (
+       "debug/proc";
        "math";
-       "ptrace";
 )
 
 type Arch interface {
        // ToWord converts an array of up to 8 bytes in memory order
        // to a word.
-       ToWord(data []byte) ptrace.Word;
+       ToWord(data []byte) proc.Word;
        // FromWord converts a word to an array of up to 8 bytes in
        // memory order.
-       FromWord(v ptrace.Word, out []byte);
+       FromWord(v proc.Word, out []byte);
        // ToFloat32 converts a word to a float.  The order of this
        // word will be the order returned by ToWord on the memory
        // representation of a float, and thus may require reversing.
@@ -40,7 +40,7 @@ type Arch interface {
        Align(offset, width int) int;
 
        // G returns the current G pointer.
-       G(regs ptrace.Regs) ptrace.Word;
+       G(regs proc.Regs) proc.Word;
 
        // ClosureSize returns the number of bytes expected by
        // ParseClosure.
@@ -53,15 +53,15 @@ type Arch interface {
 
 type ArchLSB struct {}
 
-func (ArchLSB) ToWord(data []byte) ptrace.Word {
-       var v ptrace.Word;
+func (ArchLSB) ToWord(data []byte) proc.Word {
+       var v proc.Word;
        for i, b := range data {
-               v |= ptrace.Word(b) << (uint(i)*8);
+               v |= proc.Word(b) << (uint(i)*8);
        }
        return v;
 }
 
-func (ArchLSB) FromWord(v ptrace.Word, out []byte) {
+func (ArchLSB) FromWord(v proc.Word, out []byte) {
        for i := range out {
                out[i] = byte(v);
                v >>= 8;
@@ -110,7 +110,7 @@ func (a *amd64) FloatSize() int {
        return 4;
 }
 
-func (a *amd64) G(regs ptrace.Regs) ptrace.Word {
+func (a *amd64) G(regs proc.Regs) proc.Word {
        // See src/pkg/runtime/mkasmh
        if a.gReg == -1 {
                ns := regs.Names();
index 88a675711fb4bc3860fba0e0e3bdeec2ce1d3513..150b5a5a3e333634fe7d19f2da05e9feae52d750 100644 (file)
@@ -6,12 +6,12 @@ package ogle
 
 import (
        "bufio";
+       "debug/proc";
        "eval";
        "fmt";
        "go/scanner";
        "go/token";
        "os";
-       "ptrace";
        "strconv";
        "strings";
        "sym";
@@ -139,7 +139,7 @@ func cmdLoad(args []byte) os.Error {
 
        // Parse argument and start or attach to process
        var fname string;
-       var proc ptrace.Process;
+       var tproc proc.Process;
        if len(path) >= 4 && path[0:4] == "pid:" {
                pid, err := strconv.Atoi(path[4:len(path)]);
                if err != nil {
@@ -149,7 +149,7 @@ func cmdLoad(args []byte) os.Error {
                if err != nil {
                        return err;
                }
-               proc, err = ptrace.Attach(pid);
+               tproc, err = proc.Attach(pid);
                if err != nil {
                        return err;
                }
@@ -161,30 +161,30 @@ func cmdLoad(args []byte) os.Error {
                } else {
                        fname = parts[0];
                }
-               proc, err = ptrace.ForkExec(fname, parts, os.Environ(), "", []*os.File{os.Stdin, os.Stdout, os.Stderr});
+               tproc, err = proc.ForkExec(fname, parts, os.Environ(), "", []*os.File{os.Stdin, os.Stdout, os.Stderr});
                if err != nil {
                        return err;
                }
                println("Started", path);
-               // TODO(austin) If we fail after this point, kill proc
+               // TODO(austin) If we fail after this point, kill tproc
                // before detaching.
        }
 
        // Get symbols
        f, err := os.Open(fname, os.O_RDONLY, 0);
        if err != nil {
-               proc.Detach();
+               tproc.Detach();
                return err;
        }
        defer f.Close();
        elf, err := sym.NewElf(f);
        if err != nil {
-               proc.Detach();
+               tproc.Detach();
                return err;
        }
-       curProc, err = NewProcessElf(proc, elf);
+       curProc, err = NewProcessElf(tproc, elf);
        if err != nil {
-               proc.Detach();
+               tproc.Detach();
                return err;
        }
 
@@ -194,7 +194,7 @@ func cmdLoad(args []byte) os.Error {
 
        err = curProc.populateWorld(world);
        if err != nil {
-               proc.Detach();
+               tproc.Detach();
                return err;
        }
 
@@ -374,5 +374,5 @@ func fnBpSet(t *eval.Thread, args []eval.Value, res []eval.Value) {
        if !ok {
                t.Abort(UsageError("symbol " + name + " is not a function"));
        }
-       curProc.OnBreakpoint(ptrace.Word(fn.Entry())).AddHandler(EventStop);
+       curProc.OnBreakpoint(proc.Word(fn.Entry())).AddHandler(EventStop);
 }
index 86892e691f81d349db19d1151537f5fdc9412876..9dc7a8445fc63095b38862f10711fa92577e2e9a 100644 (file)
@@ -5,9 +5,9 @@
 package ogle
 
 import (
+       "debug/proc";
        "fmt";
        "os";
-       "ptrace";
 )
 
 /*
@@ -183,7 +183,7 @@ func EventStop(ev Event) (EventAction, os.Error) {
 type breakpointHook struct {
        commonHook;
        p *Process;
-       pc ptrace.Word;
+       pc proc.Word;
 }
 
 // A Breakpoint event occurs when a process reaches a particular
@@ -191,8 +191,8 @@ type breakpointHook struct {
 // will be the goroutine that reached the program counter.
 type Breakpoint struct {
        commonEvent;
-       osThread ptrace.Thread;
-       pc ptrace.Word;
+       osThread proc.Thread;
+       pc proc.Word;
 }
 
 func (h *breakpointHook) AddHandler(eh EventHandler) {
@@ -229,7 +229,7 @@ func (h *breakpointHook) String() string {
        return fmt.Sprintf("breakpoint at %#x", h.pc);
 }
 
-func (b *Breakpoint) PC() ptrace.Word {
+func (b *Breakpoint) PC() proc.Word {
        return b.pc;
 }
 
index d36f9aa1c84c4d541bca19b12f0c9ea833e239d2..8e9dc3e1063d1e8293740e2bce6938d06bf3c3ab 100644 (file)
@@ -5,9 +5,9 @@
 package ogle
 
 import (
+       "debug/proc";
        "fmt";
        "os";
-       "ptrace";
        "sym";
 )
 
@@ -16,7 +16,7 @@ type Frame struct {
        // pc is the PC of the next instruction that will execute in
        // this frame.  For lower frames, this is the instruction
        // following the CALL instruction.
-       pc, sp, fp ptrace.Word;
+       pc, sp, fp proc.Word;
        // The runtime.Stktop of the active stack segment
        stk remoteStruct;
        // The function this stack frame is in
@@ -39,7 +39,7 @@ func newFrame(g remoteStruct) (*Frame, os.Error) {
 
 func aNewFrame(a aborter, g remoteStruct) *Frame {
        p := g.r.p;
-       var pc, sp ptrace.Word;
+       var pc, sp proc.Word;
 
        // Is this G alive?
        switch g.field(p.f.G.Status).(remoteInt).aGet(a) {
@@ -79,8 +79,8 @@ func aNewFrame(a aborter, g remoteStruct) *Frame {
                // G is not mapped to an OS thread.  Use the
                // scheduler's stored PC and SP.
                sched := g.field(p.f.G.Sched).(remoteStruct);
-               pc = ptrace.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
-               sp = ptrace.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
+               pc = proc.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
+               sp = proc.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
        }
 
        // Get Stktop
@@ -92,7 +92,7 @@ func aNewFrame(a aborter, g remoteStruct) *Frame {
 // prepareFrame creates a Frame from the PC and SP within that frame,
 // as well as the active stack segment.  This function takes care of
 // traversing stack breaks and unwinding closures.
-func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
+func prepareFrame(a aborter, pc, sp proc.Word, stk remoteStruct, inner *Frame) *Frame {
        // Based on src/pkg/runtime/amd64/traceback.c:traceback
        p := stk.r.p;
        top := inner == nil;
@@ -104,11 +104,11 @@ func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame)
 
        for i := 0; i < 100; i++ {
                // Traverse segmented stack breaks
-               if p.sys.lessstack != nil && pc == ptrace.Word(p.sys.lessstack.Value) {
+               if p.sys.lessstack != nil && pc == proc.Word(p.sys.lessstack.Value) {
                        // Get stk->gobuf.pc
-                       pc = ptrace.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
+                       pc = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
                        // Get stk->gobuf.sp
-                       sp = ptrace.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
+                       sp = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
                        // Get stk->stackbase
                        stk = stk.field(p.f.Stktop.Stackbase).(remotePtr).aGet(a).(remoteStruct);
                        continue;
@@ -116,7 +116,7 @@ func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame)
 
                // Get the PC of the call instruction
                callpc := pc;
-               if !top && (p.sys.goexit == nil || pc != ptrace.Word(p.sys.goexit.Value)) {
+               if !top && (p.sys.goexit == nil || pc != proc.Word(p.sys.goexit.Value)) {
                        callpc--;
                }
 
@@ -133,8 +133,8 @@ func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame)
                }
                spdelta, ok := p.ParseClosure(buf);
                if ok {
-                       sp += ptrace.Word(spdelta);
-                       pc = p.peekUintptr(a, sp - ptrace.Word(p.PtrSize()));
+                       sp += proc.Word(spdelta);
+                       pc = p.peekUintptr(a, sp - proc.Word(p.PtrSize()));
                }
        }
        if fn == nil {
@@ -142,11 +142,11 @@ func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame)
        }
 
        // Compute frame pointer
-       var fp ptrace.Word;
+       var fp proc.Word;
        if fn.FrameSize < p.PtrSize() {
-               fp = sp + ptrace.Word(p.PtrSize());
+               fp = sp + proc.Word(p.PtrSize());
        } else {
-               fp = sp + ptrace.Word(fn.FrameSize);
+               fp = sp + proc.Word(fn.FrameSize);
        }
        // TODO(austin) To really figure out if we're in the prologue,
        // we need to disassemble the function and look for the call
@@ -154,10 +154,10 @@ func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame)
        //
        // TODO(austin) What if we're in the call to morestack in the
        // prologue?  Then top == false.
-       if top && pc == ptrace.Word(fn.Entry()) {
+       if top && pc == proc.Word(fn.Entry()) {
                // We're in the function prologue, before SP
                // has been adjusted for the frame.
-               fp -= ptrace.Word(fn.FrameSize - p.PtrSize());
+               fp -= proc.Word(fn.FrameSize - p.PtrSize());
        }
 
        return &Frame{pc, sp, fp, stk, fn, path, line, inner, nil};
@@ -185,10 +185,10 @@ func (f *Frame) aOuter(a aborter) *Frame {
                // around calls to go and defer.  Russ says this
                // should get fixed in the compiler, but we account
                // for it for now.
-               sp += ptrace.Word(2 * p.PtrSize());
+               sp += proc.Word(2 * p.PtrSize());
        }
 
-       pc := p.peekUintptr(a, f.fp - ptrace.Word(p.PtrSize()));
+       pc := p.peekUintptr(a, f.fp - proc.Word(p.PtrSize()));
        if pc < 0x1000 {
                return nil;
        }
@@ -207,8 +207,8 @@ func (f *Frame) Inner() *Frame {
 
 func (f *Frame) String() string {
        res := f.fn.Name;
-       if f.pc > ptrace.Word(f.fn.Value) {
-               res += fmt.Sprintf("+%#x", f.pc - ptrace.Word(f.fn.Entry()));
+       if f.pc > proc.Word(f.fn.Value) {
+               res += fmt.Sprintf("+%#x", f.pc - proc.Word(f.fn.Entry()));
        }
        return res + fmt.Sprintf(" %s:%d", f.path, f.line);
 }
index 2dc3d7ec7b91f6f3be5780f55fff10c748e52734..de80c604ecd2b4073f4011f2ae079e5634561a6f 100644 (file)
@@ -5,10 +5,10 @@
 package ogle
 
 import (
+       "debug/proc";
        "eval";
        "fmt";
        "os";
-       "ptrace";
 )
 
 // A Goroutine represents a goroutine in a remote process.
@@ -68,7 +68,7 @@ func readylockedBP(ev Event) (EventAction, os.Error) {
                return EAStop, err;
        }
        sp := regs.SP();
-       addr := sp + ptrace.Word(p.PtrSize());
+       addr := sp + proc.Word(p.PtrSize());
        arg := remotePtr{remote{addr, p}, p.runtime.G};
        var gp eval.Value;
        err = try(func(a aborter) { gp = arg.aGet(a) });
index e51fb15281fe909aa65169557ddae07afa472abf..ffd4eb6723929c6bea466af7d8a30bf18164d322 100644 (file)
@@ -5,11 +5,11 @@
 package ogle
 
 import (
+       "debug/proc";
        "eval";
        "fmt";
        "log";
        "os";
-       "ptrace";
        "reflect";
        "sym";
 )
@@ -42,8 +42,8 @@ func (e ProcessNotStopped) String() string {
 // An UnknownGoroutine error is an internal error representing an
 // unrecognized G structure pointer.
 type UnknownGoroutine struct {
-       OSThread ptrace.Thread;
-       Goroutine ptrace.Word;
+       OSThread proc.Thread;
+       Goroutine proc.Word;
 }
 
 func (e UnknownGoroutine) String() string {
@@ -62,16 +62,16 @@ func (e NoCurrentGoroutine) String() string {
 // A Process represents a remote attached process.
 type Process struct {
        Arch;
-       proc ptrace.Process;
+       proc proc.Process;
 
        // The symbol table of this process
        syms *sym.GoSymTable;
 
        // A possibly-stopped OS thread, or nil
-       threadCache ptrace.Thread;
+       threadCache proc.Thread;
 
        // Types parsed from the remote process
-       types map[ptrace.Word] *remoteType;
+       types map[proc.Word] *remoteType;
 
        // Types and values from the remote runtime package
        runtime runtimeValues;
@@ -92,7 +92,7 @@ type Process struct {
        event Event;
 
        // Event hooks
-       breakpointHooks map[ptrace.Word] *breakpointHook;
+       breakpointHooks map[proc.Word] *breakpointHook;
        goroutineCreateHook *goroutineCreateHook;
        goroutineExitHook *goroutineExitHook;
 
@@ -100,25 +100,25 @@ type Process struct {
        curGoroutine *Goroutine;
 
        // Goroutines by the address of their G structure
-       goroutines map[ptrace.Word] *Goroutine;
+       goroutines map[proc.Word] *Goroutine;
 }
 
 /*
  * Process creation
  */
 
-// NewProcess constructs a new remote process around a ptrace'd
+// NewProcess constructs a new remote process around a traced
 // process, an architecture, and a symbol table.
-func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process, os.Error) {
+func NewProcess(tproc proc.Process, arch Arch, syms *sym.GoSymTable) (*Process, os.Error) {
        p := &Process{
                Arch: arch,
-               proc: proc,
+               proc: tproc,
                syms: syms,
-               types: make(map[ptrace.Word] *remoteType),
-               breakpointHooks: make(map[ptrace.Word] *breakpointHook),
+               types: make(map[proc.Word] *remoteType),
+               breakpointHooks: make(map[proc.Word] *breakpointHook),
                goroutineCreateHook: new(goroutineCreateHook),
                goroutineExitHook: new(goroutineExitHook),
-               goroutines: make(map[ptrace.Word] *Goroutine),
+               goroutines: make(map[proc.Word] *Goroutine),
        };
 
        // Fill in remote runtime
@@ -151,8 +151,8 @@ func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process,
        }
 
        // Create internal breakpoints to catch new and exited goroutines
-       p.OnBreakpoint(ptrace.Word(p.sys.newprocreadylocked.Entry())).(*breakpointHook).addHandler(readylockedBP, true);
-       p.OnBreakpoint(ptrace.Word(p.sys.goexit.Entry())).(*breakpointHook).addHandler(goexitBP, true);
+       p.OnBreakpoint(proc.Word(p.sys.newprocreadylocked.Entry())).(*breakpointHook).addHandler(readylockedBP, true);
+       p.OnBreakpoint(proc.Word(p.sys.goexit.Entry())).(*breakpointHook).addHandler(goexitBP, true);
 
        // Select current frames
        for _, g := range p.goroutines {
@@ -164,9 +164,9 @@ func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process,
        return p, nil;
 }
 
-// NewProcessElf constructs a new remote process around a ptrace'd
+// NewProcessElf constructs a new remote process around a traced
 // process and the process' ELF object.
-func NewProcessElf(proc ptrace.Process, elf *sym.Elf) (*Process, os.Error) {
+func NewProcessElf(tproc proc.Process, elf *sym.Elf) (*Process, os.Error) {
        syms, err := sym.ElfGoSyms(elf);
        if err != nil {
                return nil, err;
@@ -181,7 +181,7 @@ func NewProcessElf(proc ptrace.Process, elf *sym.Elf) (*Process, os.Error) {
        default:
                return nil, UnknownArchitecture(elf.Machine);
        }
-       return NewProcess(proc, arch, syms);
+       return NewProcess(tproc, arch, syms);
 }
 
 // bootstrap constructs the runtime structure of a remote process.
@@ -238,10 +238,10 @@ func (p *Process) bootstrap() {
        p.sys.deferproc = globalFn("sys·deferproc");
        p.sys.newprocreadylocked = globalFn("newprocreadylocked");
        if allg := p.syms.SymFromName("allg"); allg != nil {
-               p.sys.allg = remotePtr{remote{ptrace.Word(allg.Common().Value), p}, p.runtime.G};
+               p.sys.allg = remotePtr{remote{proc.Word(allg.Common().Value), p}, p.runtime.G};
        }
        if g0 := p.syms.SymFromName("g0"); g0 != nil {
-               p.sys.g0 = p.runtime.G.mk(remote{ptrace.Word(g0.Common().Value), p}).(remoteStruct);
+               p.sys.g0 = p.runtime.G.mk(remote{proc.Word(g0.Common().Value), p}).(remoteStruct);
        }
 }
 
@@ -261,7 +261,7 @@ func (p *Process) selectSomeGoroutine() {
  * Process memory
  */
 
-func (p *Process) someStoppedOSThread() ptrace.Thread {
+func (p *Process) someStoppedOSThread() proc.Thread {
        if p.threadCache != nil {
                if _, err := p.threadCache.Stopped(); err == nil {
                        return p.threadCache;
@@ -277,7 +277,7 @@ func (p *Process) someStoppedOSThread() ptrace.Thread {
        return nil;
 }
 
-func (p *Process) Peek(addr ptrace.Word, out []byte) (int, os.Error) {
+func (p *Process) Peek(addr proc.Word, out []byte) (int, os.Error) {
        thr := p.someStoppedOSThread();
        if thr == nil {
                return 0, ProcessNotStopped{};
@@ -285,7 +285,7 @@ func (p *Process) Peek(addr ptrace.Word, out []byte) (int, os.Error) {
        return thr.Peek(addr, out);
 }
 
-func (p *Process) Poke(addr ptrace.Word, b []byte) (int, os.Error) {
+func (p *Process) Poke(addr proc.Word, b []byte) (int, os.Error) {
        thr := p.someStoppedOSThread();
        if thr == nil {
                return 0, ProcessNotStopped{};
@@ -293,8 +293,8 @@ func (p *Process) Poke(addr ptrace.Word, b []byte) (int, os.Error) {
        return thr.Poke(addr, b);
 }
 
-func (p *Process) peekUintptr(a aborter, addr ptrace.Word) ptrace.Word {
-       return ptrace.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a));
+func (p *Process) peekUintptr(a aborter, addr proc.Word) proc.Word {
+       return proc.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a));
 }
 
 /*
@@ -303,7 +303,7 @@ func (p *Process) peekUintptr(a aborter, addr ptrace.Word) ptrace.Word {
 
 // OnBreakpoint returns the hook that is run when the program reaches
 // the given program counter.
-func (p *Process) OnBreakpoint(pc ptrace.Word) EventHook {
+func (p *Process) OnBreakpoint(pc proc.Word) EventHook {
        if bp, ok := p.breakpointHooks[pc]; ok {
                return bp;
        }
@@ -322,7 +322,7 @@ func (p *Process) OnGoroutineExit() EventHook {
 }
 
 // osThreadToGoroutine looks up the goroutine running on an OS thread.
-func (p *Process) osThreadToGoroutine(t ptrace.Thread) (*Goroutine, os.Error) {
+func (p *Process) osThreadToGoroutine(t proc.Thread) (*Goroutine, os.Error) {
        regs, err := t.Regs();
        if err != nil {
                return nil, err;
@@ -343,9 +343,9 @@ func (p *Process) causesToEvents() ([]Event, os.Error) {
        for _, t := range p.proc.Threads() {
                if c, err := t.Stopped(); err == nil {
                        switch c := c.(type) {
-                       case ptrace.Breakpoint:
+                       case proc.Breakpoint:
                                nev++;
-                       case ptrace.Signal:
+                       case proc.Signal:
                                // TODO(austin)
                                //nev++;
                        }
@@ -358,14 +358,14 @@ func (p *Process) causesToEvents() ([]Event, os.Error) {
        for _, t := range p.proc.Threads() {
                if c, err := t.Stopped(); err == nil {
                        switch c := c.(type) {
-                       case ptrace.Breakpoint:
+                       case proc.Breakpoint:
                                gt, err := p.osThreadToGoroutine(t);
                                if err != nil {
                                        return nil, err;
                                }
-                               events[i] = &Breakpoint{commonEvent{p, gt}, t, ptrace.Word(c)};
+                               events[i] = &Breakpoint{commonEvent{p, gt}, t, proc.Word(c)};
                                i++;
-                       case ptrace.Signal:
+                       case proc.Signal:
                                // TODO(austin)
                        }
                }
index 758f1c7084f879c903ff03de8ac6b2f1a50ad58c..03d1c798031bbbc059f6fc4d3db88d03c0118560 100644 (file)
@@ -5,8 +5,8 @@
 package ogle
 
 import (
+       "debug/proc";
        "eval";
-       "ptrace";
        "reflect";
 )
 
@@ -227,7 +227,7 @@ type runtimeValues struct {
        PFloat32Type, PFloat64Type, PFloatType,
        PArrayType, PStringType, PStructType, PPtrType, PFuncType,
        PInterfaceType, PSliceType, PMapType, PChanType,
-       PDotDotDotType, PUnsafePointerType ptrace.Word;
+       PDotDotDotType, PUnsafePointerType proc.Word;
        // G status values
        runtimeGStatus;
 }
index a71a70a4af02e2ff0a50fa22cfffa83a0799bd76..ee7b7fe7597650065afde370f90bb467392c99ab 100644 (file)
@@ -5,10 +5,10 @@
 package ogle
 
 import (
+       "debug/proc";
        "eval";
        "fmt";
        "log";
-       "ptrace";
 )
 
 const debugParseRemoteType = false
@@ -156,7 +156,7 @@ func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
        }
 
        // Get Type header
-       itype := ptrace.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a));
+       itype := proc.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a));
        typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct);
 
        // Is this a named type?
index b22f531acbb6b60b85c88ad77cf9ffebea16846b..47a54a9343855153d7e73d1ad8c0ca927154e181 100644 (file)
@@ -5,9 +5,9 @@
 package ogle
 
 import (
+       "debug/proc";
        "eval";
        "fmt";
-       "ptrace";
 )
 
 // A RemoteMismatchError occurs when an operation that requires two
@@ -38,7 +38,7 @@ type remoteValue interface {
 
 // remote represents an address in a remote process.
 type remote struct {
-       base ptrace.Word;
+       base proc.Word;
        p *Process;
 }
 
@@ -71,14 +71,14 @@ func (v remote) Get(a aborter, size int) uint64 {
 func (v remote) Set(a aborter, size int, x uint64) {
        var arr [8]byte;
        buf := arr[0:size];
-       v.p.FromWord(ptrace.Word(x), buf);
+       v.p.FromWord(proc.Word(x), buf);
        _, err := v.p.Poke(v.base, buf);
        if err != nil {
                a.Abort(err);
        }
 }
 
-func (v remote) plus(x ptrace.Word) remote {
+func (v remote) plus(x proc.Word) remote {
        return remote{v.base + x, v.p};
 }
 
@@ -340,9 +340,9 @@ func (v remoteString) Get(t *eval.Thread) string {
 
 func (v remoteString) aGet(a aborter) string {
        rs := v.r.p.runtime.String.mk(v.r).(remoteStruct);
-       str := ptrace.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a));
+       str := proc.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a));
        len := rs.field(v.r.p.f.String.Len).(remoteInt).aGet(a);
-       
+
        bytes := make([]uint8, len);
        _, err := v.r.p.Peek(str, bytes);
        if err != nil {
@@ -404,11 +404,11 @@ func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value {
 }
 
 func (v remoteArray) elem(i int64) eval.Value {
-       return v.elemType.mk(v.r.plus(ptrace.Word(int64(v.elemType.size) * i)));
+       return v.elemType.mk(v.r.plus(proc.Word(int64(v.elemType.size) * i)));
 }
 
 func (v remoteArray) Sub(i int64, len int64) eval.ArrayValue {
-       return remoteArray{v.r.plus(ptrace.Word(int64(v.elemType.size) * i)), len, v.elemType};
+       return remoteArray{v.r.plus(proc.Word(int64(v.elemType.size) * i)), len, v.elemType};
 }
 
 /*
@@ -455,7 +455,7 @@ func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value {
 
 func (v remoteStruct) field(i int) eval.Value {
        f := &v.layout[i];
-       return f.fieldType.mk(v.r.plus(ptrace.Word(f.offset)));
+       return f.fieldType.mk(v.r.plus(proc.Word(f.offset)));
 }
 
 func (v remoteStruct) addr() remote {
@@ -494,7 +494,7 @@ func (v remotePtr) Get(t *eval.Thread) eval.Value {
 }
 
 func (v remotePtr) aGet(a aborter) eval.Value {
-       addr := ptrace.Word(v.r.Get(a, v.r.p.PtrSize()));
+       addr := proc.Word(v.r.Get(a, v.r.p.PtrSize()));
        if addr == 0 {
                return nil;
        }
@@ -550,7 +550,7 @@ func (v remoteSlice) Get(t *eval.Thread) eval.Slice {
 
 func (v remoteSlice) aGet(a aborter) eval.Slice {
        rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct);
-       base := ptrace.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a));
+       base := proc.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a));
        nel := rs.field(v.r.p.f.Slice.Len).(remoteInt).aGet(a);
        cap := rs.field(v.r.p.f.Slice.Cap).(remoteInt).aGet(a);
        if base == 0 {
index eb96b60ce88ff53a85e3876076999560b93b2070..6c1bd5f6f9f96a2e5efe306a4ee8fb31630bcef3 100644 (file)
@@ -5,10 +5,10 @@
 package ogle
 
 import (
+       "debug/proc";
        "eval";
        "log";
        "os";
-       "ptrace";
        "sym";
 )
 
@@ -160,7 +160,7 @@ func (p *Process) populateWorld(w *eval.World) os.Error {
                        if rt == nil {
                                continue;
                        }
-                       pkg[name] = def{rt.Type, rt.mk(remote{ptrace.Word(sc.Value), p})};
+                       pkg[name] = def{rt.Type, rt.mk(remote{proc.Word(sc.Value), p})};
 
                case 'T', 't', 'L', 'l':
                        // Function
@@ -207,7 +207,7 @@ func (p *Process) typeOfSym(s *sym.CommonSym) (*remoteType, os.Error) {
        if s.GoType == 0 {
                return nil, nil;
        }
-       addr := ptrace.Word(s.GoType);
+       addr := proc.Word(s.GoType);
        var rt *remoteType;
        err := try(func(a aborter) {
                rt = parseRemoteType(a, p.runtime.Type.mk(remote{addr, p}).(remoteStruct));
diff --git a/usr/austin/ptrace/Makefile b/usr/austin/ptrace/Makefile
deleted file mode 100644 (file)
index 2158abc..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2009 The Go Authors.  All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include $(GOROOT)/src/Make.$(GOARCH)
-
-TARG=ptrace
-GOFILES=\
-       process.go\
-       ptrace_linux.go\
-       regs_$(GOOS)_$(GOARCH).go\
-
-include $(GOROOT)/src/Make.pkg
diff --git a/usr/austin/ptrace/process.go b/usr/austin/ptrace/process.go
deleted file mode 100644 (file)
index d88bcf7..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package ptrace provides a platform-independent interface for
-// tracing and controlling running processes.  It supports
-// multi-threaded processes and provides typical low-level debugging
-// controls such as breakpoints, single stepping, and manipulating
-// memory and registers.
-package ptrace
-
-import (
-       "os";
-       "strconv";
-)
-
-type Word uint64
-
-// A Cause explains why a thread is stopped.
-type Cause interface {
-       String() string;
-}
-
-// Regs is a set of named machine registers, including a program
-// counter, link register, and stack pointer.
-//
-// TODO(austin) There's quite a proliferation of methods here.  We
-// could make a Reg interface with Get and Set and make this just PC,
-// Link, SP, Names, and Reg.  We could also put Index in Reg and that
-// makes it easy to get the index of things like the PC (currently
-// there's just no way to know that).  This would also let us include
-// other per-register information like how to print it.
-type Regs interface {
-       // PC returns the value of the program counter.
-       PC() Word;
-
-       // SetPC sets the program counter to val.
-       SetPC(val Word) os.Error;
-
-       // Link returns the link register, if any.
-       Link() Word;
-
-       // SetLink sets the link register to val.
-       SetLink(val Word) os.Error;
-
-       // SP returns the value of the stack pointer.
-       SP() Word;
-
-       // SetSP sets the stack pointer register to val.
-       SetSP(val Word) os.Error;
-
-       // Names returns the names of all of the registers.
-       Names() []string;
-
-       // Get returns the value of a register, where i corresponds to
-       // the index of the register's name in the array returned by
-       // Names.
-       Get(i int) Word;
-
-       // Set sets the value of a register.
-       Set(i int, val Word) os.Error;
-}
-
-// Thread is a thread in the process being traced.
-type Thread interface {
-       // Step steps this thread by a single instruction.  The thread
-       // must be stopped.  If the thread is currently stopped on a
-       // breakpoint, this will step over the breakpoint.
-       //
-       // XXX What if it's stopped because of a signal?
-       Step() os.Error;
-
-       // Stopped returns the reason that this thread is stopped.  It
-       // is an error is the thread not stopped.
-       Stopped() (Cause, os.Error);
-
-       // Regs retrieves the current register values from this
-       // thread.  The thread must be stopped.
-       Regs() (Regs, os.Error);
-
-       // Peek reads len(out) bytes from the address addr in this
-       // thread into out.  The thread must be stopped.  It returns
-       // the number of bytes successfully read.  If an error occurs,
-       // such as attempting to read unmapped memory, this count
-       // could be short and an error will be returned.  If this does
-       // encounter unmapped memory, it will read up to the byte
-       // preceding the unmapped area.
-       Peek(addr Word, out []byte) (int, os.Error);
-
-       // Poke writes b to the address addr in this thread.  The
-       // thread must be stopped.  It returns the number of bytes
-       // successfully written.  If an error occurs, such as
-       // attempting to write to unmapped memory, this count could be
-       // short and an error will be returned.  If this does
-       // encounter unmapped memory, it will write up to the byte
-       // preceding the unmapped area.
-       Poke(addr Word, b []byte) (int, os.Error);
-}
-
-// Process is a process being traced.  It consists of a set of
-// threads.  A process can be running, stopped, or terminated.  The
-// process's state extends to all of its threads.
-type Process interface {
-       // Threads returns an array of all threads in this process.
-       Threads() []Thread;
-
-       // AddBreakpoint creates a new breakpoint at program counter
-       // pc.  Breakpoints can only be created when the process is
-       // stopped.  It is an error if a breakpoint already exists at
-       // pc.
-       AddBreakpoint(pc Word) os.Error;
-
-       // RemoveBreakpoint removes the breakpoint at the program
-       // counter pc.  It is an error if no breakpoint exists at pc.
-       RemoveBreakpoint(pc Word) os.Error;
-
-       // Stop stops all running threads in this process before
-       // returning.
-       Stop() os.Error;
-
-       // Continue resumes execution of all threads in this process.
-       // Any thread that is stopped on a breakpoint will be stepped
-       // over that breakpoint.  Any thread that is stopped because
-       // of a signal (other than SIGSTOP or SIGTRAP) will receive
-       // the pending signal.
-       Continue() os.Error;
-
-       // WaitStop waits until all threads in process p are stopped
-       // as a result of some thread hitting a breakpoint, receiving
-       // a signal, creating a new thread, or exiting.
-       WaitStop() os.Error;
-
-       // Detach detaches from this process.  All stopped threads
-       // will be resumed.
-       Detach() os.Error;
-}
-
-// Stopped is a stop cause used for threads that are stopped either by
-// user request (e.g., from the Stop method or after single stepping),
-// or that are stopped because some other thread caused the program to
-// stop.
-type Stopped struct {}
-
-func (c Stopped) String() string {
-       return "stopped";
-}
-
-// Breakpoint is a stop cause resulting from a thread reaching a set
-// breakpoint.
-type Breakpoint        Word
-
-// PC returns the program counter that the program is stopped at.
-func (c Breakpoint) PC() Word {
-       return Word(c);
-}
-
-func (c Breakpoint) String() string {
-       return "breakpoint at 0x" + strconv.Uitob64(uint64(c.PC()), 16);
-}
-
-// Signal is a stop cause resulting from a thread receiving a signal.
-// When the process is continued, the signal will be delivered.
-type Signal string
-
-// Signal returns the signal being delivered to the thread.
-func (c Signal) Name() string {
-       return string(c);
-}
-
-func (c Signal) String() string {
-       return c.Name();
-}
-
-// ThreadCreate is a stop cause returned from an existing thread when
-// it creates a new thread.  The new thread exists in a primordial
-// form at this point and will begin executing in earnest when the
-// process is continued.
-type ThreadCreate struct {
-       thread Thread;
-}
-
-func (c *ThreadCreate) NewThread() Thread {
-       return c.thread;
-}
-
-func (c *ThreadCreate) String() string {
-       return "thread create";
-}
-
-// ThreadExit is a stop cause resulting from a thread exiting.  When
-// this cause first arises, the thread will still be in the list of
-// process threads and its registers and memory will still be
-// accessible.
-type ThreadExit struct {
-       exitStatus int;
-       signal string;
-}
-
-// Exited returns true if the thread exited normally.
-func (c *ThreadExit) Exited() bool {
-       return c.exitStatus != -1;
-}
-
-// ExitStatus returns the exit status of the thread if it exited
-// normally or -1 otherwise.
-func (c *ThreadExit) ExitStatus() int {
-       return c.exitStatus;
-}
-
-// Signaled returns true if the thread was terminated by a signal.
-func (c *ThreadExit) Signaled() bool {
-       return c.exitStatus == -1;
-}
-
-// StopSignal returns the signal that terminated the thread, or "" if
-// it was not terminated by a signal.
-func (c *ThreadExit) StopSignal() string {
-       return c.signal;
-}
-
-func (c *ThreadExit) String() string {
-       res := "thread exited ";
-       switch {
-       case c.Exited():
-               res += "with status " + strconv.Itoa(c.ExitStatus());
-       case c.Signaled():
-               res += "from signal " + c.StopSignal();
-       default:
-               res += "from unknown cause";
-       }
-       return res;
-}
diff --git a/usr/austin/ptrace/ptrace-nptl.txt b/usr/austin/ptrace/ptrace-nptl.txt
deleted file mode 100644 (file)
index 62cbf77..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-ptrace and NTPL, the missing manpage
-
-== Signals ==
-
-A signal sent to a ptrace'd process or thread causes only the thread
-that receives it to stop and report to the attached process.
-
-Use tgkill to target a signal (for example, SIGSTOP) at a particular
-thread.  If you use kill, the signal could be delivered to another
-thread in the same process.
-
-Note that SIGSTOP differs from its usual behavior when a process is
-being traced.  Usually, a SIGSTOP sent to any thread in a thread group
-will stop all threads in the thread group.  When a thread is traced,
-however, a SIGSTOP affects only the receiving thread (and any other
-threads in the thread group that are not traced).
-
-SIGKILL behaves like it does for non-traced processes.  It affects all
-threads in the process and terminates them without the WSTOPSIG event
-generated by other signals.  However, if PTRACE_O_TRACEEXIT is set,
-the attached process will still receive PTRACE_EVENT_EXIT events
-before receiving WIFSIGNALED events.
-
-See "Following thread death" for a caveat regarding signal delivery to
-zombie threads.
-
-== Waiting on threads ==
-
-Cloned threads in ptrace'd processes are treated similarly to cloned
-threads in your own process.  Thus, you must use the __WALL option in
-order to receive notifications from threads created by the child
-process.  Similarly, the __WCLONE option will wait only on
-notifications from threads created by the child process and *not* on
-notifications from the initial child thread.
-
-Even when waiting on a specific thread's PID using waitpid or similar,
-__WALL or __WCLONE is necessary or waitpid will return ECHILD.
-
-== Attaching to existing threads ==
-
-libthread_db (which gdb uses), attaches to existing threads by pulling
-the pthread data structures out of the traced process.  The much
-easier way is to traverse the /proc/PID/task directory, though it's
-unclear how the semantics of these two approaches differ.
-
-Unfortunately, if the main thread has exited (but the overall process
-has not), it sticks around as a zombie process.  This zombie will
-appear in the /proc/PID/task directory, but trying to attach to it
-will yield EPERM.  In this case, the third field of the
-/proc/PID/task/PID/stat file will be "Z".  Attempting to open the stat
-file is also a convenient way to detect races between listing the task
-directory and the thread exiting.  Coincidentally, gdb will simply
-fail to attach to a process whose main thread is a zombie.
-
-Because new threads may be created while the debugger is in the
-process of attaching to existing threads, the debugger must repeatedly
-re-list the task directory until it has attached to (and thus stopped)
-every thread listed.
-
-In order to follow new threads created by existing threads,
-PTRACE_O_TRACECLONE must be set on each thread attached to.
-
-== Following new threads ==
-
-With the child process stopped, use PTRACE_SETOPTIONS to set the
-PTRACE_O_TRACECLONE option.  This option is per-thread, and thus must
-be set on each existing thread individually.  When an existing thread
-with PTRACE_O_TRACECLONE set spawns a new thread, the existing thread
-will stop with (SIGTRAP | PTRACE_EVENT_CLONE << 8) and the PID of the
-new thread can be retrieved with PTRACE_GETEVENTMSG on the creating
-thread.  At this time, the new thread will exist, but will initially
-be stopped with a SIGSTOP.  The new thread will automatically be
-traced and will inherit the PTRACE_O_TRACECLONE option from its
-parent.  The attached process should wait on the new thread to receive
-the SIGSTOP notification.
-
-When using waitpid(-1, ...), don't rely on the parent thread reporting
-a SIGTRAP before receiving the SIGSTOP from the new child thread.
-
-Without PTRACE_O_TRACECLONE, newly cloned threads will not be
-ptrace'd.  As a result, signals received by new threads will be
-handled in the usual way, which may affect the parent and in turn
-appear to the attached process, but attributed to the parent (possibly
-in unexpected ways).
-
-== Following thread death ==
-
-If any thread with the PTRACE_O_TRACEEXIT option set exits (either by
-returning or pthread_exit'ing), the tracing process will receive an
-immediate PTRACE_EVENT_EXIT.  At this point, the thread will still
-exist.  The exit status, encoded as for wait, can be queried using
-PTRACE_GETEVENTMSG on the exiting thread's PID.  The thread should be
-continued so it can actually exit, after which its wait behavior is
-the same as for a thread without the PTRACE_O_TRACEEXIT option.
-
-If a non-main thread exits (either by returning or pthread_exit'ing),
-its corresponding process will also exit, producing a WIFEXITED event
-(after the process is continued from a possible PTRACE_EVENT_EXIT
-event).  It is *not* necessary for another thread to ptrace_join for
-this to happen.
-
-If the main thread exits by returning, then all threads will exit,
-first generating a PTRACE_EVENT_EXIT event for each thread if
-appropriate, then producing a WIFEXITED event for each thread.
-
-If the main thread exits using pthread_exit, then it enters a
-non-waitable zombie state.  It will still produce an immediate
-PTRACE_O_TRACEEXIT event, but the WIFEXITED event will be delayed
-until the entire process exits.  This state exists so that shells
-don't think the process is done until all of the threads have exited.
-Unfortunately, signals cannot be delivered to non-waitable zombies.
-Most notably, SIGSTOP cannot be delivered; as a result, when you
-broadcast SIGSTOP to all of the threads, you must not wait for
-non-waitable zombies to stop.  Furthermore, any ptrace command on a
-non-waitable zombie, including PTRACE_DETACH, will return ESRCH.
-
-== Multi-threaded debuggers ==
-
-If the debugger itself is multi-threaded, ptrace calls must come from
-the same thread that originally attached to the remote thread.  The
-kernel simply compares the PID of the caller of ptrace against the
-tracer PID of the process passed to ptrace.  Because each debugger
-thread has a different PID, calling ptrace from a different thread
-might as well be calling it from a different process and the kernel
-will return ESRCH.
-
-wait, on the other hand, does not have this restriction.  Any debugger
-thread can wait on any thread in the attached process.
diff --git a/usr/austin/ptrace/ptrace_linux.go b/usr/austin/ptrace/ptrace_linux.go
deleted file mode 100644 (file)
index 83faa66..0000000
+++ /dev/null
@@ -1,1319 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ptrace
-
-import (
-       "container/vector";
-       "fmt";
-       "io";
-       "os";
-       "runtime";
-       "strconv";
-       "strings";
-       "sync";
-       "syscall";
-)
-
-// This is an implementation of the process tracing interface using
-// Linux's ptrace(2) interface.  The implementation is multi-threaded.
-// Each attached process has an associated monitor thread, and each
-// running attached thread has an associated "wait" thread.  The wait
-// thread calls wait4 on the thread's TID and reports any wait events
-// or errors via "debug events".  The monitor thread consumes these
-// wait events and updates the internally maintained state of each
-// thread.  All ptrace calls must run in the monitor thread, so the
-// monitor executes closures received on the debugReq channel.
-//
-// As ptrace's documentation is somewhat light, this is heavily based
-// on information gleaned from the implementation of ptrace found at
-//   http://lxr.linux.no/linux+v2.6.30/kernel/ptrace.c
-//   http://lxr.linux.no/linux+v2.6.30/arch/x86/kernel/ptrace.c#L854
-// as well as experimentation and examination of gdb's behavior.
-
-const (
-       trace = false;
-       traceIP = false;
-       traceMem = false;
-)
-
-/*
- * Thread state
- */
-
-// Each thread can be in one of the following set of states.
-// Each state satisfies
-//  isRunning() || isStopped() || isZombie() || isTerminal().
-//
-// Running threads can be sent signals and must be waited on, but they
-// cannot be inspected using ptrace.
-//
-// Stopped threads can be inspected and continued, but cannot be
-// meaningfully waited on.  They can be sent signals, but the signals
-// will be queued until they are running again.
-//
-// Zombie threads cannot be inspected, continued, or sent signals (and
-// therefore they cannot be stopped), but they must be waited on.
-//
-// Terminal threads no longer exist in the OS and thus you can't do
-// anything with them.
-type threadState string;
-
-const (
-       running             threadState = "Running";
-       singleStepping      threadState = "SingleStepping";     // Transient
-       stopping            threadState = "Stopping";   // Transient
-       stopped             threadState = "Stopped";
-       stoppedBreakpoint   threadState = "StoppedBreakpoint";
-       stoppedSignal       threadState = "StoppedSignal";
-       stoppedThreadCreate threadState = "StoppedThreadCreate";
-       stoppedExiting      threadState = "StoppedExiting";
-       exiting             threadState = "Exiting";    // Transient (except main thread)
-       exited              threadState = "Exited";
-       detached            threadState = "Detached";
-)
-
-func (ts threadState) isRunning() bool {
-       return ts == running || ts == singleStepping || ts == stopping;
-}
-
-func (ts threadState) isStopped() bool {
-       return ts == stopped || ts == stoppedBreakpoint || ts == stoppedSignal || ts == stoppedThreadCreate || ts == stoppedExiting;
-}
-
-func (ts threadState) isZombie() bool {
-       return ts == exiting;
-}
-
-func (ts threadState) isTerminal() bool {
-       return ts == exited || ts == detached;
-}
-
-func (ts threadState) String() string {
-       return string(ts);
-}
-
-/*
- * Basic types
- */
-
-// A breakpoint stores information about a single breakpoint,
-// including its program counter, the overwritten text if the
-// breakpoint is installed.
-type breakpoint struct {
-       pc uintptr;
-       olddata []byte;
-}
-
-func (bp *breakpoint) String() string {
-       if bp == nil {
-               return "<nil>";
-       }
-       return fmt.Sprintf("%#x", bp.pc);
-}
-
-// bpinst386 is the breakpoint instruction used on 386 and amd64.
-var bpinst386 = []byte{0xcc};
-
-// A debugEvent represents a reason a thread stopped or a wait error.
-type debugEvent struct {
-       *os.Waitmsg;
-       t *thread;
-       err os.Error;
-}
-
-// A debugReq is a request to execute a closure in the monitor thread.
-type debugReq struct {
-       f func () os.Error;
-       res chan os.Error;
-}
-
-// A transitionHandler specifies a function to be called when a thread
-// changes state and a function to be called when an error occurs in
-// the monitor.  Both run in the monitor thread.  Before the monitor
-// invokes a handler, it removes the handler from the handler queue.
-// The handler should re-add itself if needed.
-type transitionHandler struct {
-       handle func (*thread, threadState, threadState);
-       onErr func (os.Error);
-}
-
-// A process is a Linux process, which consists of a set of threads.
-// Each running process has one monitor thread, which processes
-// messages from the debugEvents, debugReqs, and stopReq channels and
-// calls transition handlers.
-type process struct {
-       pid int;
-       threads map[int] *thread;
-       breakpoints map[uintptr] *breakpoint;
-       debugEvents chan *debugEvent;
-       debugReqs chan *debugReq;
-       stopReq chan os.Error;
-       transitionHandlers *vector.Vector;
-}
-
-// A thread represents a Linux thread in another process that is being
-// debugged.  Each running thread has an associated goroutine that
-// waits for thread updates and sends them to the process monitor.
-type thread struct {
-       tid int;
-       proc *process;
-       // Whether to ignore the next SIGSTOP received by wait.
-       ignoreNextSigstop bool;
-
-       // Thread state.  Only modified via setState.
-       state threadState;
-       // If state == StoppedBreakpoint
-       breakpoint *breakpoint;
-       // If state == StoppedSignal or state == Exited
-       signal int;
-       // If state == StoppedThreadCreate
-       newThread *thread;
-       // If state == Exited
-       exitStatus int;
-}
-
-/*
- * Errors
- */
-
-type badState struct {
-       thread *thread;
-       message string;
-       state threadState;
-}
-
-func (e *badState) String() string {
-       return fmt.Sprintf("Thread %d %s from state %v", e.thread.tid, e.message, e.state);
-}
-
-type breakpointExistsError Word
-
-func (e breakpointExistsError) String() string {
-       return fmt.Sprintf("breakpoint already exists at PC %#x", e);
-}
-
-type noBreakpointError Word
-
-func (e noBreakpointError) String() string {
-       return fmt.Sprintf("no breakpoint at PC %#x", e);
-}
-
-type newThreadError struct {
-       *os.Waitmsg;
-       wantPid int;
-       wantSig int;
-}
-
-func (e *newThreadError) String() string {
-       return fmt.Sprintf("newThread wait wanted pid %v and signal %v, got %v and %v", e.Pid, e.StopSignal(), e.wantPid, e.wantSig);
-}
-
-/*
- * Ptrace wrappers
- */
-
-func (t *thread) ptracePeekText(addr uintptr, out []byte) (int, os.Error) {
-       c, err := syscall.PtracePeekText(t.tid, addr, out);
-       if traceMem {
-               fmt.Printf("peek(%#x) => %v, %v\n", addr, out, err);
-       }
-       return c, os.NewSyscallError("ptrace(PEEKTEXT)", err);
-}
-
-func (t *thread) ptracePokeText(addr uintptr, out []byte) (int, os.Error) {
-       c, err := syscall.PtracePokeText(t.tid, addr, out);
-       if traceMem {
-               fmt.Printf("poke(%#x, %v) => %v\n", addr, out, err);
-       }
-       return c, os.NewSyscallError("ptrace(POKETEXT)", err);
-}
-
-func (t *thread) ptraceGetRegs(regs *syscall.PtraceRegs) os.Error {
-       err := syscall.PtraceGetRegs(t.tid, regs);
-       return os.NewSyscallError("ptrace(GETREGS)", err);
-}
-
-func (t *thread) ptraceSetRegs(regs *syscall.PtraceRegs) os.Error {
-       err := syscall.PtraceSetRegs(t.tid, regs);
-       return os.NewSyscallError("ptrace(SETREGS)", err);
-}
-
-func (t *thread) ptraceSetOptions(options int) os.Error {
-       err := syscall.PtraceSetOptions(t.tid, options);
-       return os.NewSyscallError("ptrace(SETOPTIONS)", err);
-}
-
-func (t *thread) ptraceGetEventMsg() (uint, os.Error) {
-       msg, err := syscall.PtraceGetEventMsg(t.tid);
-       return msg, os.NewSyscallError("ptrace(GETEVENTMSG)", err);
-}
-
-func (t *thread) ptraceCont() os.Error {
-       err := syscall.PtraceCont(t.tid, 0);
-       return os.NewSyscallError("ptrace(CONT)", err);
-}
-
-func (t *thread) ptraceContWithSignal(sig int) os.Error {
-       err := syscall.PtraceCont(t.tid, sig);
-       return os.NewSyscallError("ptrace(CONT)", err);
-}
-
-func (t *thread) ptraceStep() os.Error {
-       err := syscall.PtraceSingleStep(t.tid);
-       return os.NewSyscallError("ptrace(SINGLESTEP)", err);
-}
-
-func (t *thread) ptraceDetach() os.Error {
-       err := syscall.PtraceDetach(t.tid);
-       return os.NewSyscallError("ptrace(DETACH)", err);
-}
-
-/*
- * Logging utilties
- */
-
-var logLock sync.Mutex
-
-func (t *thread) logTrace(format string, args ...) {
-       if !trace {
-               return;
-       }
-       logLock.Lock();
-       defer logLock.Unlock();
-       fmt.Fprintf(os.Stderr, "Thread %d", t.tid);
-       if traceIP {
-               var regs syscall.PtraceRegs;
-               err := t.ptraceGetRegs(&regs);
-               if err == nil {
-                       fmt.Fprintf(os.Stderr, "@%x", regs.Rip);
-               }
-       }
-       fmt.Fprint(os.Stderr, ": ");
-       fmt.Fprintf(os.Stderr, format, args);
-       fmt.Fprint(os.Stderr, "\n");
-}
-
-func (t *thread) warn(format string, args ...) {
-       logLock.Lock();
-       defer logLock.Unlock();
-       fmt.Fprintf(os.Stderr, "Thread %d: WARNING ", t.tid);
-       fmt.Fprintf(os.Stderr, format, args);
-       fmt.Fprint(os.Stderr, "\n");
-}
-
-func (p *process) logTrace(format string, args ...) {
-       if !trace {
-               return;
-       }
-       logLock.Lock();
-       defer logLock.Unlock();
-       fmt.Fprintf(os.Stderr, "Process %d: ", p.pid);
-       fmt.Fprintf(os.Stderr, format, args);
-       fmt.Fprint(os.Stderr, "\n");
-}
-
-/*
- * State utilities
- */
-
-// someStoppedThread returns a stopped thread from the process.
-// Returns nil if no threads are stopped.
-//
-// Must be called from the monitor thread.
-func (p *process) someStoppedThread() *thread {
-       for _, t := range p.threads {
-               if t.state.isStopped() {
-                       return t;
-               }
-       }
-       return nil;
-}
-
-// someRunningThread returns a running thread from the process.
-// Returns nil if no threads are running.
-//
-// Must be called from the monitor thread.
-func (p *process) someRunningThread() *thread {
-       for _, t := range p.threads {
-               if t.state.isRunning() {
-                       return t;
-               }
-       }
-       return nil;
-}
-
-/*
- * Breakpoint utilities
- */
-
-// installBreakpoints adds breakpoints to the attached process.
-//
-// Must be called from the monitor thread.
-func (p *process) installBreakpoints() os.Error {
-       n := 0;
-       main := p.someStoppedThread();
-       for _, b := range p.breakpoints {
-               if b.olddata != nil {
-                       continue;
-               }
-
-               b.olddata = make([]byte, len(bpinst386));
-               _, err := main.ptracePeekText(uintptr(b.pc), b.olddata);
-               if err != nil {
-                       b.olddata = nil;
-                       return err;
-               }
-
-               _, err = main.ptracePokeText(uintptr(b.pc), bpinst386);
-               if err != nil {
-                       b.olddata = nil;
-                       return err;
-               }
-               n++;
-       }
-       if n > 0 {
-               p.logTrace("installed %d/%d breakpoints", n, len(p.breakpoints));
-       }
-
-       return nil;
-}
-
-// uninstallBreakpoints removes the installed breakpoints from p.
-//
-// Must be called from the monitor thread.
-func (p *process) uninstallBreakpoints() os.Error {
-       if len(p.threads) == 0 {
-               return nil;
-       }
-       n := 0;
-       main := p.someStoppedThread();
-       for _, b := range p.breakpoints {
-               if b.olddata == nil {
-                       continue;
-               }
-
-               _, err := main.ptracePokeText(uintptr(b.pc), b.olddata);
-               if err != nil {
-                       return err;
-               }
-               b.olddata = nil;
-               n++;
-       }
-       if n > 0 {
-               p.logTrace("uninstalled %d/%d breakpoints", n, len(p.breakpoints));
-       }
-
-       return nil;
-}
-
-/*
- * Debug event handling
- */
-
-// wait waits for a wait event from this thread and sends it on the
-// debug events channel for this thread's process.  This should be
-// started in its own goroutine when the attached thread enters a
-// running state.  The goroutine will exit as soon as it sends a debug
-// event.
-func (t *thread) wait() {
-       for {
-               var ev debugEvent;
-               ev.t = t;
-               t.logTrace("beginning wait");
-               ev.Waitmsg, ev.err = os.Wait(t.tid, syscall.WALL);
-               if ev.err == nil && ev.Pid != t.tid {
-                       panic("Wait returned pid ", ev.Pid, " wanted ", t.tid);
-               }
-               if ev.StopSignal() == syscall.SIGSTOP && t.ignoreNextSigstop {
-                       // Spurious SIGSTOP.  See Thread.Stop().
-                       t.ignoreNextSigstop = false;
-                       err := t.ptraceCont();
-                       if err == nil {
-                               continue;
-                       }
-                       // If we failed to continue, just let
-                       // the stop go through so we can
-                       // update the thread's state.
-               }
-               t.proc.debugEvents <- &ev;
-               break;
-       }
-}
-
-// setState sets this thread's state, starts a wait thread if
-// necessary, and invokes state transition handlers.
-//
-// Must be called from the monitor thread.
-func (t *thread) setState(new threadState) {
-       old := t.state;
-       t.state = new;
-       t.logTrace("state %v -> %v", old, new);
-
-       if !old.isRunning() && (new.isRunning() || new.isZombie()) {
-               // Start waiting on this thread
-               go t.wait();
-       }
-
-       // Invoke state change handlers
-       handlers := t.proc.transitionHandlers;
-       if handlers.Len() == 0 {
-               return;
-       }
-
-       t.proc.transitionHandlers = vector.New(0);
-       for _, h := range handlers.Data() {
-               h := h.(*transitionHandler);
-               h.handle(t, old, new);
-       }
-}
-
-// sendSigstop sends a SIGSTOP to this thread.
-func (t *thread) sendSigstop() os.Error {
-       t.logTrace("sending SIGSTOP");
-       err := syscall.Tgkill(t.proc.pid, t.tid, syscall.SIGSTOP);
-       return os.NewSyscallError("tgkill", err);
-}
-
-// stopAsync sends SIGSTOP to all threads in state 'running'.
-//
-// Must be called from the monitor thread.
-func (p *process) stopAsync() os.Error {
-       for _, t := range p.threads {
-               if t.state == running {
-                       err := t.sendSigstop();
-                       if err != nil {
-                               return err;
-                       }
-                       t.setState(stopping);
-               }
-       }
-       return nil;
-}
-
-// doTrap handles SIGTRAP debug events with a cause of 0.  These can
-// be caused either by an installed breakpoint, a breakpoint in the
-// program text, or by single stepping.
-//
-// TODO(austin) I think we also get this on an execve syscall.
-func (ev *debugEvent) doTrap() (threadState, os.Error) {
-       t := ev.t;
-
-       if t.state == singleStepping {
-               return stopped, nil;
-       }
-
-       // Hit a breakpoint.  Linux leaves the program counter after
-       // the breakpoint.  If this is an installed breakpoint, we
-       // need to back the PC up to the breakpoint PC.
-       var regs syscall.PtraceRegs;
-       err := t.ptraceGetRegs(&regs);
-       if err != nil {
-               return stopped, err;
-       }
-
-       b, ok := t.proc.breakpoints[uintptr(regs.Rip)-uintptr(len(bpinst386))];
-       if !ok {
-               // We must have hit a breakpoint that was actually in
-               // the program.  Leave the IP where it is so we don't
-               // re-execute the breakpoint instruction.  Expose the
-               // fact that we stopped with a SIGTRAP.
-               return stoppedSignal, nil;
-       }
-
-       t.breakpoint = b;
-       t.logTrace("at breakpoint %v, backing up PC from %#x", b, regs.Rip);
-
-       regs.Rip = uint64(b.pc);
-       err = t.ptraceSetRegs(&regs);
-       if err != nil {
-               return stopped, err;
-       }
-       return stoppedBreakpoint, nil;
-}
-
-// doPtraceClone handles SIGTRAP debug events with a PTRACE_EVENT_CLONE
-// cause.  It initializes the new thread, adds it to the process, and
-// returns the appropriate thread state for the existing thread.
-func (ev *debugEvent) doPtraceClone() (threadState, os.Error) {
-       t := ev.t;
-
-       // Get the TID of the new thread
-       tid, err := t.ptraceGetEventMsg();
-       if err != nil {
-               return stopped, err;
-       }
-
-       nt, err := t.proc.newThread(int(tid), syscall.SIGSTOP, true);
-       if err != nil {
-               return stopped, err;
-       }
-
-       // Remember the thread
-       t.newThread = nt;
-
-       return stoppedThreadCreate, nil;
-}
-
-// doPtraceExit handles SIGTRAP debug events with a PTRACE_EVENT_EXIT
-// cause.  It sets up the thread's state, but does not remove it from
-// the process.  A later WIFEXITED debug event will remove it from the
-// process.
-func (ev *debugEvent) doPtraceExit() (threadState, os.Error) {
-       t := ev.t;
-
-       // Get exit status
-       exitStatus, err := t.ptraceGetEventMsg();
-       if err != nil {
-               return stopped, err;
-       }
-       ws := syscall.WaitStatus(exitStatus);
-       t.logTrace("exited with %v", ws);
-       switch {
-       case ws.Exited():
-               t.exitStatus = ws.ExitStatus();
-       case ws.Signaled():
-               t.signal = ws.Signal();
-       }
-
-       // We still need to continue this thread and wait on this
-       // thread's WIFEXITED event.  We'll delete it then.
-       return stoppedExiting, nil;
-}
-
-// process handles a debug event.  It modifies any thread or process
-// state as necessary, uninstalls breakpoints if necessary, and stops
-// any running threads.
-func (ev *debugEvent) process() os.Error {
-       if ev.err != nil {
-               return ev.err;
-       }
-
-       t := ev.t;
-       t.exitStatus = -1;
-       t.signal = -1;
-
-       // Decode wait status.
-       var state threadState;
-       switch {
-       case ev.Stopped():
-               state = stoppedSignal;
-               t.signal = ev.StopSignal();
-               t.logTrace("stopped with %v", ev);
-               if ev.StopSignal() == syscall.SIGTRAP {
-                       // What caused the debug trap?
-                       var err os.Error;
-                       switch cause := ev.TrapCause(); cause {
-                       case 0:
-                               // Breakpoint or single stepping
-                               state, err = ev.doTrap();
-
-                       case syscall.PTRACE_EVENT_CLONE:
-                               state, err = ev.doPtraceClone();
-
-                       case syscall.PTRACE_EVENT_EXIT:
-                               state, err = ev.doPtraceExit();
-
-                       default:
-                               t.warn("Unknown trap cause %d", cause);
-                       }
-
-                       if err != nil {
-                               t.setState(stopped);
-                               t.warn("failed to handle trap %v: %v", ev, err);
-                       }
-               }
-
-       case ev.Exited():
-               state = exited;
-               t.proc.threads[t.tid] = nil, false;
-               t.logTrace("exited %v", ev);
-               // We should have gotten the exit status in
-               // PTRACE_EVENT_EXIT, but just in case.
-               t.exitStatus = ev.ExitStatus();
-
-       case ev.Signaled():
-               state = exited;
-               t.proc.threads[t.tid] = nil, false;
-               t.logTrace("signaled %v", ev);
-               // Again, this should be redundant.
-               t.signal = ev.Signal();
-
-       default:
-               panic(fmt.Sprintf("Unexpected wait status %v", ev.Waitmsg));
-       }
-
-       // If we sent a SIGSTOP to the thread (indicated by state
-       // Stopping), we might have raced with a different type of
-       // stop.  If we didn't get the stop we expected, then the
-       // SIGSTOP we sent is now queued up, so we should ignore the
-       // next one we get.
-       if t.state == stopping && ev.StopSignal() != syscall.SIGSTOP {
-               t.ignoreNextSigstop = true;
-       }
-
-       // TODO(austin) If we're in state stopping and get a SIGSTOP,
-       // set state stopped instead of stoppedSignal.
-
-       t.setState(state);
-
-       if t.proc.someRunningThread() == nil {
-               // Nothing is running, uninstall breakpoints
-               return t.proc.uninstallBreakpoints();
-       }
-       // Stop any other running threads
-       return t.proc.stopAsync();
-}
-
-// onStop adds a handler for state transitions from running to
-// non-running states.  The handler will be called from the monitor
-// thread.
-//
-// Must be called from the monitor thread.
-func (t *thread) onStop(handle func (), onErr func (os.Error)) {
-       // TODO(austin) This is rather inefficient for things like
-       // stepping all threads during a continue.  Maybe move
-       // transitionHandlers to the thread, or have both per-thread
-       // and per-process transition handlers.
-       h := &transitionHandler{nil, onErr};
-       h.handle = func (st *thread, old, new threadState) {
-               if t == st && old.isRunning() && !new.isRunning() {
-                       handle();
-               } else {
-                       t.proc.transitionHandlers.Push(h);
-               }
-       };
-       t.proc.transitionHandlers.Push(h);
-}
-
-/*
- * Event monitor
- */
-
-// monitor handles debug events and debug requests for p, exiting when
-// there are no threads left in p.
-//
-// TODO(austin) When an unrecoverable error occurs, abort the monitor
-// and record this error so all future calls to do will return it
-// immediately.
-func (p *process) monitor() {
-       var err os.Error;
-
-       // Linux requires that all ptrace calls come from the thread
-       // that originally attached.  Prevent the Go scheduler from
-       // migrating us to other OS threads.
-       runtime.LockOSThread();
-       defer runtime.UnlockOSThread();
-
-       hadThreads := false;
-       for {
-               select {
-               case event := <-p.debugEvents:
-                       err = event.process();
-                       if err != nil {
-                               break;
-                       }
-
-               case req := <-p.debugReqs:
-                       req.res <- req.f();
-
-               case err = <-p.stopReq:
-                       break;
-               }
-
-               if len(p.threads) == 0 {
-                       if hadThreads {
-                               p.logTrace("no more threads; monitor exiting");
-                               // TODO(austin) Use a real error do
-                               // future operations will fail
-                               err = nil;
-                               break;
-                       }
-               } else {
-                       hadThreads = true;
-               }
-       }
-
-       // Abort waiting handlers
-       for _, h := range p.transitionHandlers.Data() {
-               h := h.(*transitionHandler);
-               h.onErr(err);
-       }
-
-       // TODO(austin) How do I stop the wait threads?
-       if err != nil {
-               panic(err.String());
-       }
-}
-
-// do executes f in the monitor thread (and, thus, atomically with
-// respect to thread state changes).  f must not block.
-//
-// Must NOT be called from the monitor thread.
-func (p *process) do(f func () os.Error) os.Error {
-       // TODO(austin) If monitor is stopped, return error.
-       req := &debugReq{f, make(chan os.Error)};
-       p.debugReqs <- req;
-       return <-req.res;
-}
-
-// stopMonitor stops the monitor with the given error.  If the monitor
-// is already stopped, does nothing.
-func (p *process) stopMonitor(err os.Error) {
-       _ = p.stopReq <- err;
-       // TODO(austin) Wait until monitor has exited?
-}
-
-/*
- * Public thread interface
- */
-
-func (t *thread) Regs() (Regs, os.Error) {
-       var regs syscall.PtraceRegs;
-
-       err := t.proc.do(func () os.Error {
-               if !t.state.isStopped() {
-                       return &badState{t, "cannot get registers", t.state};
-               }
-               return t.ptraceGetRegs(&regs);
-       });
-       if err != nil {
-               return nil, err;
-       }
-
-       setter := func (r *syscall.PtraceRegs) os.Error {
-               return t.proc.do(func () os.Error {
-                       if !t.state.isStopped() {
-                               return &badState{t, "cannot get registers", t.state};
-                       }
-                       return t.ptraceSetRegs(r);
-               });
-       };
-       return newRegs(&regs, setter), nil;
-}
-
-func (t *thread) Peek(addr Word, out []byte) (int, os.Error) {
-       var c int;
-
-       err := t.proc.do(func () os.Error {
-               if !t.state.isStopped() {
-                       return &badState{t, "cannot peek text", t.state};
-               }
-
-               var err os.Error;
-               c, err = t.ptracePeekText(uintptr(addr), out);
-               return err;
-       });
-
-       return c, err;
-}
-
-func (t *thread) Poke(addr Word, out []byte) (int, os.Error) {
-       var c int;
-
-       err := t.proc.do(func () os.Error {
-               if !t.state.isStopped() {
-                       return &badState{t, "cannot poke text", t.state};
-               }
-
-               var err os.Error;
-               c, err = t.ptracePokeText(uintptr(addr), out);
-               return err;
-       });
-
-       return c, err;
-}
-
-// stepAsync starts this thread single stepping.  When the single step
-// is complete, it will send nil on the given channel.  If an error
-// occurs while setting up the single step, it returns that error.  If
-// an error occurs while waiting for the single step to complete, it
-// sends that error on the channel.
-func (t *thread) stepAsync(ready chan os.Error) os.Error {
-       if err := t.ptraceStep(); err != nil {
-               return err;
-       }
-       t.setState(singleStepping);
-       t.onStop(func () {
-                       ready <- nil;
-               },
-               func (err os.Error) {
-                       ready <- err;
-               });
-       return nil;
-}
-
-func (t *thread) Step() os.Error {
-       t.logTrace("Step {");
-       defer t.logTrace("}");
-
-       ready := make(chan os.Error);
-
-       err := t.proc.do(func () os.Error {
-               if !t.state.isStopped() {
-                       return &badState{t, "cannot single step", t.state};
-               }
-               return t.stepAsync(ready);
-       });
-       if err != nil {
-               return err;
-       }
-
-       err = <-ready;
-       return err;
-}
-
-// TODO(austin) We should probably get this via C's strsignal.
-var sigNames = [...]string {
-       "SIGEXIT", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL",
-       "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL",
-       "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM",
-       "SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP",
-       "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU",
-       "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGPOLL",
-       "SIGPWR", "SIGSYS"
-}
-
-// sigName returns the symbolic name for the given signal number.  If
-// the signal number is invalid, returns "<invalid>".
-func sigName(signal int) string {
-       if signal < 0 || signal >= len(sigNames) {
-               return "<invalid>";
-       }
-       return sigNames[signal];
-}
-
-func (t *thread) Stopped() (Cause, os.Error) {
-       var c Cause;
-       err := t.proc.do(func() os.Error {
-               switch t.state {
-               case stopped:
-                       c = Stopped{};
-
-               case stoppedBreakpoint:
-                       c = Breakpoint(t.breakpoint.pc);
-
-               case stoppedSignal:
-                       c = Signal(sigName(t.signal));
-
-               case stoppedThreadCreate:
-                       c = &ThreadCreate{t.newThread};
-
-               case stoppedExiting, exiting, exited:
-                       if t.signal == -1 {
-                               c = &ThreadExit{t.exitStatus, ""};
-                       } else {
-                               c = &ThreadExit{t.exitStatus, sigName(t.signal)};
-                       }
-
-               default:
-                       return &badState{t, "cannot get stop cause", t.state};
-               }
-               return nil;
-       });
-       if err != nil {
-               return nil, err;
-       }
-
-       return c, nil;
-}
-
-func (p *process) Threads() []Thread {
-       var res []Thread;
-
-       p.do(func () os.Error {
-               res = make([]Thread, len(p.threads));
-               i := 0;
-               for _, t := range p.threads {
-                       // Exclude zombie threads.
-                       st := t.state;
-                       if st == exiting || st == exited || st == detached {
-                               continue;
-                       }
-
-                       res[i] = t;
-                       i++;
-               }
-               res = res[0:i];
-               return nil;
-       });
-       return res;
-}
-
-func (p *process) AddBreakpoint(pc Word) os.Error {
-       return p.do(func () os.Error {
-               if t := p.someRunningThread(); t != nil {
-                       return &badState{t, "cannot add breakpoint", t.state};
-               }
-               if _, ok := p.breakpoints[uintptr(pc)]; ok {
-                       return breakpointExistsError(pc);
-               }
-               p.breakpoints[uintptr(pc)] = &breakpoint{pc: uintptr(pc)};
-               return nil;
-       });
-}
-
-func (p *process) RemoveBreakpoint(pc Word) os.Error {
-       return p.do(func () os.Error {
-               if t := p.someRunningThread(); t != nil {
-                       return &badState{t, "cannot remove breakpoint", t.state};
-               }
-               if _, ok := p.breakpoints[uintptr(pc)]; !ok {
-                       return noBreakpointError(pc);
-               }
-               p.breakpoints[uintptr(pc)] = nil, false;
-               return nil;
-       });
-}
-
-func (p *process) Continue() os.Error {
-       // Single step any threads that are stopped at breakpoints so
-       // we can reinstall breakpoints.
-       var ready chan os.Error;
-       count := 0;
-
-       err := p.do(func () os.Error {
-               // We make the ready channel big enough to hold all
-               // ready message so we don't jam up the monitor if we
-               // stop listening (e.g., if there's an error).
-               ready = make(chan os.Error, len(p.threads));
-
-               for _, t := range p.threads {
-                       if !t.state.isStopped() {
-                               continue;
-                       }
-
-                       // We use the breakpoint map directly here
-                       // instead of checking the stop cause because
-                       // it could have been stopped at a breakpoint
-                       // for some other reason, or the breakpoint
-                       // could have been added since it was stopped.
-                       var regs syscall.PtraceRegs;
-                       err := t.ptraceGetRegs(&regs);
-                       if err != nil {
-                               return err;
-                       }
-                       if b, ok := p.breakpoints[uintptr(regs.Rip)]; ok {
-                               t.logTrace("stepping over breakpoint %v", b);
-                               if err := t.stepAsync(ready); err != nil {
-                                       return err;
-                               }
-                               count++;
-                       }
-               }
-               return nil;
-       });
-       if err != nil {
-               p.stopMonitor(err);
-               return err;
-       }
-
-       // Wait for single stepping threads
-       for count > 0 {
-               err = <-ready;
-               if err != nil {
-                       p.stopMonitor(err);
-                       return err;
-               }
-               count--;
-       }
-
-       // Continue all threads
-       err = p.do(func () os.Error {
-               if err := p.installBreakpoints(); err != nil {
-                       return err;
-               }
-
-               for _, t := range p.threads {
-                       var err os.Error;
-                       switch {
-                       case !t.state.isStopped():
-                               continue;
-
-                       case t.state == stoppedSignal && t.signal != syscall.SIGSTOP && t.signal != syscall.SIGTRAP:
-                               t.logTrace("continuing with signal %d", t.signal);
-                               err = t.ptraceContWithSignal(t.signal);
-
-                       default:
-                               t.logTrace("continuing");
-                               err = t.ptraceCont();
-                       }
-                       if err != nil {
-                               return err;
-                       }
-                       if t.state == stoppedExiting {
-                               t.setState(exiting);
-                       } else {
-                               t.setState(running);
-                       }
-               }
-               return nil;
-       });
-       if err != nil {
-               // TODO(austin) Do we need to stop the monitor with
-               // this error atomically with the do-routine above?
-               p.stopMonitor(err);
-               return err;
-       }
-
-       return nil;
-}
-
-func (p *process) WaitStop() os.Error {
-       // We need a non-blocking ready channel for the case where all
-       // threads are already stopped.
-       ready := make(chan os.Error, 1);
-
-       err := p.do(func () os.Error {
-               // Are all of the threads already stopped?
-               if p.someRunningThread() == nil {
-                       ready <- nil;
-                       return nil;
-               }
-
-               // Monitor state transitions
-               h := &transitionHandler{};
-               h.handle = func (st *thread, old, new threadState) {
-                       if !new.isRunning() {
-                               if p.someRunningThread() == nil {
-                                       ready <- nil;
-                                       return;
-                               }
-                       }
-                       p.transitionHandlers.Push(h);
-               };
-               h.onErr = func (err os.Error) {
-                       ready <- err;
-               };
-               p.transitionHandlers.Push(h);
-               return nil;
-       });
-       if err != nil {
-               return err;
-       }
-
-       return <-ready;
-}
-
-func (p *process) Stop() os.Error {
-       err := p.do(func () os.Error {
-               return p.stopAsync();
-       });
-       if err != nil {
-               return err;
-       }
-
-       return p.WaitStop();
-}
-
-func (p *process) Detach() os.Error {
-       if err := p.Stop(); err != nil {
-               return err;
-       }
-
-       err := p.do(func () os.Error {
-               if err := p.uninstallBreakpoints(); err != nil {
-                       return err;
-               }
-
-               for pid, t := range p.threads {
-                       if t.state.isStopped() {
-                               // We can't detach from zombies.
-                               if err := t.ptraceDetach(); err != nil {
-                                       return err;
-                               }
-                       }
-                       t.setState(detached);
-                       p.threads[pid] = nil, false;
-               }
-               return nil;
-       });
-       // TODO(austin) Wait for monitor thread to exit?
-       return err;
-}
-
-// newThread creates a new thread object and waits for its initial
-// signal.  If cloned is true, this thread was cloned from a thread we
-// are already attached to.
-//
-// Must be run from the monitor thread.
-func (p *process) newThread(tid int, signal int, cloned bool) (*thread, os.Error) {
-       t := &thread{tid: tid, proc: p, state: stopped};
-
-       // Get the signal from the thread
-       // TODO(austin) Thread might already be stopped if we're attaching.
-       w, err := os.Wait(tid, syscall.WALL);
-       if err != nil {
-               return nil, err;
-       }
-       if w.Pid != tid || w.StopSignal() != signal {
-               return nil, &newThreadError{w, tid, signal};
-       }
-
-       if !cloned {
-               err = t.ptraceSetOptions(syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEEXIT);
-               if err != nil {
-                       return nil, err;
-               }
-       }
-
-       p.threads[tid] = t;
-
-       return t, nil;
-}
-
-// attachThread attaches a running thread to the process.
-//
-// Must NOT be run from the monitor thread.
-func (p *process) attachThread(tid int) (*thread, os.Error) {
-       p.logTrace("attaching to thread %d", tid);
-       var thr *thread;
-       err := p.do(func () os.Error {
-               errno := syscall.PtraceAttach(tid);
-               if errno != 0 {
-                       return os.NewSyscallError("ptrace(ATTACH)", errno);
-               }
-
-               var err os.Error;
-               thr, err = p.newThread(tid, syscall.SIGSTOP, false);
-               return err;
-       });
-       return thr, err;
-}
-
-// attachAllThreads attaches to all threads in a process.
-func (p *process) attachAllThreads() os.Error {
-       taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task";
-       taskDir, err := os.Open(taskPath, os.O_RDONLY, 0);
-       if err != nil {
-               return err;
-       }
-       defer taskDir.Close();
-
-       // We stop threads as we attach to them; however, because new
-       // threads can appear while we're looping over all of them, we
-       // have to repeatly scan until we know we're attached to all
-       // of them.
-       for again := true; again; {
-               again = false;
-
-               tids, err := taskDir.Readdirnames(-1);
-               if err != nil {
-                       return err;
-               }
-
-               for _, tidStr := range tids {
-                       tid, err := strconv.Atoi(tidStr);
-                       if err != nil {
-                               return err;
-                       }
-                       if _, ok := p.threads[tid]; ok {
-                               continue;
-                       }
-
-                       _, err = p.attachThread(tid);
-                       if err != nil {
-                               // There could have been a race, or
-                               // this process could be a zobmie.
-                               statFile, err2 := io.ReadFile(taskPath + "/" + tidStr + "/stat");
-                               if err2 != nil {
-                                       switch err2 := err2.(type) {
-                                       case *os.PathError:
-                                               if err2.Error == os.ENOENT {
-                                                       // Raced with thread exit
-                                                       p.logTrace("raced with thread %d exit", tid);
-                                                       continue;
-                                               }
-                                       }
-                                       // Return the original error
-                                       return err;
-                               }
-
-                               statParts := strings.Split(string(statFile), " ", 4);
-                               if len(statParts) > 2 && statParts[2] == "Z" {
-                                       // tid is a zombie
-                                       p.logTrace("thread %d is a zombie", tid);
-                                       continue;
-                               }
-
-                               // Return the original error
-                               return err;
-                       }
-                       again = true;
-               }
-       }
-
-       return nil;
-}
-
-// newProcess creates a new process object and starts its monitor thread.
-func newProcess(pid int) *process {
-       p := &process{
-               pid: pid,
-               threads: make(map[int] *thread),
-               breakpoints: make(map[uintptr] *breakpoint),
-               debugEvents: make(chan *debugEvent),
-               debugReqs: make(chan *debugReq),
-               stopReq: make(chan os.Error),
-               transitionHandlers: vector.New(0)
-       };
-
-       go p.monitor();
-
-       return p;
-}
-
-// Attach attaches to process pid and stops all of its threads.
-func Attach(pid int) (Process, os.Error) {
-       p := newProcess(pid);
-
-       // Attach to all threads
-       err := p.attachAllThreads();
-       if err != nil {
-               p.Detach();
-               // TODO(austin) Detach stopped the monitor already
-               //p.stopMonitor(err);
-               return nil, err;
-       }
-
-       return p, nil;
-}
-
-// ForkExec forks the current process and execs argv0, stopping the
-// new process after the exec syscall.  See os.ForkExec for additional
-// details.
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File)
-       (Process, os.Error)
-{
-       p := newProcess(-1);
-
-       // Create array of integer (system) fds.
-       intfd := make([]int, len(fd));
-       for i, f := range fd {
-               if f == nil {
-                       intfd[i] = -1;
-               } else {
-                       intfd[i] = f.Fd();
-               }
-       }
-
-       // Fork from the monitor thread so we get the right tracer pid.
-       err := p.do(func () os.Error {
-               pid, errno := syscall.PtraceForkExec(argv0, argv, envv, dir, intfd);
-               if errno != 0 {
-                       return &os.PathError{"fork/exec", argv0, os.Errno(errno)};
-               }
-               p.pid = pid;
-
-               // The process will raise SIGTRAP when it reaches execve.
-               _, err := p.newThread(pid, syscall.SIGTRAP, false);
-               return err;
-       });
-       if err != nil {
-               p.stopMonitor(err);
-               return nil, err;
-       }
-
-       return p, nil;
-}
diff --git a/usr/austin/ptrace/regs_linux_amd64.go b/usr/austin/ptrace/regs_linux_amd64.go
deleted file mode 100644 (file)
index 3b2a058..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ptrace
-
-import (
-       "os";
-       "strconv";
-       "syscall";
-)
-
-type amd64Regs struct {
-       syscall.PtraceRegs;
-       setter func (*syscall.PtraceRegs) os.Error;
-}
-
-var names = [...]string {
-       "rax",
-       "rbx",
-       "rcx",
-       "rdx",
-       "rsi",
-       "rdi",
-       "rbp",
-       "rsp",
-       "r8",
-       "r9",
-       "r10",
-       "r11",
-       "r12",
-       "r13",
-       "r14",
-       "r15",
-       "rip",
-       "eflags",
-       "cs",
-       "ss",
-       "ds",
-       "es",
-       "fs",
-       "gs",
-
-       // PtraceRegs contains these registers, but I don't think
-       // they're actually meaningful.
-       //"orig_rax",
-       //"fs_base",
-       //"gs_base",
-}
-
-func (r *amd64Regs) PC() Word {
-       return Word(r.Rip);
-}
-
-func (r *amd64Regs) SetPC(val Word) os.Error {
-       r.Rip = uint64(val);
-       return r.setter(&r.PtraceRegs);
-}
-
-func (r *amd64Regs) Link() Word {
-       // TODO(austin)
-       panic("No link register");
-}
-
-func (r *amd64Regs) SetLink(val Word) os.Error {
-       panic("No link register");
-}
-
-func (r *amd64Regs) SP() Word {
-       return Word(r.Rsp);
-}
-
-func (r *amd64Regs) SetSP(val Word) os.Error {
-       r.Rsp = uint64(val);
-       return r.setter(&r.PtraceRegs);
-}
-
-func (r *amd64Regs) Names() []string {
-       return &names;
-}
-
-func (r *amd64Regs) Get(i int) Word {
-       switch i {
-       case 0: return Word(r.Rax);
-       case 1: return Word(r.Rbx);
-       case 2: return Word(r.Rcx);
-       case 3: return Word(r.Rdx);
-       case 4: return Word(r.Rsi);
-       case 5: return Word(r.Rdi);
-       case 6: return Word(r.Rbp);
-       case 7: return Word(r.Rsp);
-       case 8: return Word(r.R8);
-       case 9: return Word(r.R9);
-       case 10: return Word(r.R10);
-       case 11: return Word(r.R11);
-       case 12: return Word(r.R12);
-       case 13: return Word(r.R13);
-       case 14: return Word(r.R14);
-       case 15: return Word(r.R15);
-       case 16: return Word(r.Rip);
-       case 17: return Word(r.Eflags);
-       case 18: return Word(r.Cs);
-       case 19: return Word(r.Ss);
-       case 20: return Word(r.Ds);
-       case 21: return Word(r.Es);
-       case 22: return Word(r.Fs);
-       case 23: return Word(r.Gs);
-       }
-       panic("invalid register index ", strconv.Itoa(i));
-}
-
-func (r *amd64Regs) Set(i int, val Word) os.Error {
-       switch i {
-       case 0: r.Rax = uint64(val);
-       case 1: r.Rbx = uint64(val);
-       case 2: r.Rcx = uint64(val);
-       case 3: r.Rdx = uint64(val);
-       case 4: r.Rsi = uint64(val);
-       case 5: r.Rdi = uint64(val);
-       case 6: r.Rbp = uint64(val);
-       case 7: r.Rsp = uint64(val);
-       case 8: r.R8 = uint64(val);
-       case 9: r.R9 = uint64(val);
-       case 10: r.R10 = uint64(val);
-       case 11: r.R11 = uint64(val);
-       case 12: r.R12 = uint64(val);
-       case 13: r.R13 = uint64(val);
-       case 14: r.R14 = uint64(val);
-       case 15: r.R15 = uint64(val);
-       case 16: r.Rip = uint64(val);
-       case 17: r.Eflags = uint64(val);
-       case 18: r.Cs = uint64(val);
-       case 19: r.Ss = uint64(val);
-       case 20: r.Ds = uint64(val);
-       case 21: r.Es = uint64(val);
-       case 22: r.Fs = uint64(val);
-       case 23: r.Gs = uint64(val);
-       default:
-               panic("invalid register index ", strconv.Itoa(i));
-       }
-       return r.setter(&r.PtraceRegs);
-}
-
-func newRegs(regs *syscall.PtraceRegs, setter func (*syscall.PtraceRegs) os.Error) Regs {
-       res := amd64Regs{};
-       res.PtraceRegs = *regs;
-       res.setter = setter;
-       return &res;
-}