Commit fdf5efe4 authored by Austin Clements's avatar Austin Clements

Update debugger to use Abort interface

R=rsc
APPROVED=rsc
DELTA=314  (132 added, 2 deleted, 180 changed)
OCL=34376
CL=34396
parent 05522cd5
// 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 ogle
import (
"os";
"runtime";
)
// An aborter aborts the thread's current compututation, usually
// passing the error to a waiting thread.
type aborter interface {
Abort(err os.Error);
}
type ogleAborter chan os.Error;
func (a ogleAborter) Abort(err os.Error) {
a <- err;
runtime.Goexit();
}
// try executes a computation; if the computation Aborts, try returns
// the error passed to abort.
func try(f func(a aborter)) os.Error {
a := make(ogleAborter);
go func() {
f(a);
a <- nil;
}();
err := <-a;
return err;
}
...@@ -6,6 +6,7 @@ package ogle ...@@ -6,6 +6,7 @@ package ogle
import ( import (
"fmt"; "fmt";
"os";
"ptrace"; "ptrace";
"sym"; "sym";
) )
...@@ -29,14 +30,19 @@ type Frame struct { ...@@ -29,14 +30,19 @@ type Frame struct {
inner, outer *Frame; inner, outer *Frame;
} }
// NewFrame returns the top-most Frame of the given g's thread. // newFrame returns the top-most Frame of the given g's thread.
// This function can abort. func newFrame(g remoteStruct) (*Frame, os.Error) {
func NewFrame(g remoteStruct) *Frame { var f *Frame;
err := try(func(a aborter) { f = aNewFrame(a, g) });
return f, err;
}
func aNewFrame(a aborter, g remoteStruct) *Frame {
p := g.r.p; p := g.r.p;
var pc, sp ptrace.Word; var pc, sp ptrace.Word;
// Is this G alive? // Is this G alive?
switch g.Field(p.f.G.Status).(remoteInt).Get() { switch g.field(p.f.G.Status).(remoteInt).aGet(a) {
case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead: case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead:
return nil; return nil;
} }
...@@ -61,7 +67,7 @@ func NewFrame(g remoteStruct) *Frame { ...@@ -61,7 +67,7 @@ func NewFrame(g remoteStruct) *Frame {
// If this thread crashed, try to recover it // If this thread crashed, try to recover it
if pc == 0 { if pc == 0 {
pc = p.peekUintptr(pc); pc = p.peekUintptr(a, pc);
sp += 8; sp += 8;
} }
...@@ -72,22 +78,21 @@ func NewFrame(g remoteStruct) *Frame { ...@@ -72,22 +78,21 @@ func NewFrame(g remoteStruct) *Frame {
if pc == 0 && sp == 0 { if pc == 0 && sp == 0 {
// G is not mapped to an OS thread. Use the // G is not mapped to an OS thread. Use the
// scheduler's stored PC and SP. // scheduler's stored PC and SP.
sched := g.Field(p.f.G.Sched).(remoteStruct); sched := g.field(p.f.G.Sched).(remoteStruct);
pc = ptrace.Word(sched.Field(p.f.Gobuf.Pc).(remoteUint).Get()); pc = ptrace.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
sp = ptrace.Word(sched.Field(p.f.Gobuf.Sp).(remoteUint).Get()); sp = ptrace.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
} }
// Get Stktop // Get Stktop
stk := g.Field(p.f.G.Stackbase).(remotePtr).Get().(remoteStruct); stk := g.field(p.f.G.Stackbase).(remotePtr).aGet(a).(remoteStruct);
return prepareFrame(pc, sp, stk, nil); return prepareFrame(a, pc, sp, stk, nil);
} }
// prepareFrame creates a Frame from the PC and SP within that 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 // as well as the active stack segment. This function takes care of
// traversing stack breaks and unwinding closures. This function can // traversing stack breaks and unwinding closures.
// abort. func prepareFrame(a aborter, pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
// Based on src/pkg/runtime/amd64/traceback.c:traceback // Based on src/pkg/runtime/amd64/traceback.c:traceback
p := stk.r.p; p := stk.r.p;
top := inner == nil; top := inner == nil;
...@@ -101,11 +106,11 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame { ...@@ -101,11 +106,11 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
// Traverse segmented stack breaks // Traverse segmented stack breaks
if p.sys.lessstack != nil && pc == ptrace.Word(p.sys.lessstack.Value) { if p.sys.lessstack != nil && pc == ptrace.Word(p.sys.lessstack.Value) {
// Get stk->gobuf.pc // Get stk->gobuf.pc
pc = ptrace.Word(stk.Field(p.f.Stktop.Gobuf).(remoteStruct).Field(p.f.Gobuf.Pc).(remoteUint).Get()); pc = ptrace.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a));
// Get stk->gobuf.sp // Get stk->gobuf.sp
sp = ptrace.Word(stk.Field(p.f.Stktop.Gobuf).(remoteStruct).Field(p.f.Gobuf.Sp).(remoteUint).Get()); sp = ptrace.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a));
// Get stk->stackbase // Get stk->stackbase
stk = stk.Field(p.f.Stktop.Stackbase).(remotePtr).Get().(remoteStruct); stk = stk.field(p.f.Stktop.Stackbase).(remotePtr).aGet(a).(remoteStruct);
continue; continue;
} }
...@@ -129,7 +134,7 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame { ...@@ -129,7 +134,7 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
spdelta, ok := p.ParseClosure(buf); spdelta, ok := p.ParseClosure(buf);
if ok { if ok {
sp += ptrace.Word(spdelta); sp += ptrace.Word(spdelta);
pc = p.peekUintptr(sp - ptrace.Word(p.PtrSize())); pc = p.peekUintptr(a, sp - ptrace.Word(p.PtrSize()));
} }
} }
if fn == nil { if fn == nil {
...@@ -159,8 +164,14 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame { ...@@ -159,8 +164,14 @@ func prepareFrame(pc, sp ptrace.Word, stk remoteStruct, inner *Frame) *Frame {
} }
// Outer returns the Frame that called this Frame, or nil if this is // Outer returns the Frame that called this Frame, or nil if this is
// the outermost frame. This function can abort. // the outermost frame.
func (f *Frame) Outer() *Frame { func (f *Frame) Outer() (*Frame, os.Error) {
var fr *Frame;
err := try(func(a aborter) { fr = f.aOuter(a) });
return fr, err;
}
func (f *Frame) aOuter(a aborter) *Frame {
// Is there a cached outer frame // Is there a cached outer frame
if f.outer != nil { if f.outer != nil {
return f.outer; return f.outer;
...@@ -177,14 +188,14 @@ func (f *Frame) Outer() *Frame { ...@@ -177,14 +188,14 @@ func (f *Frame) Outer() *Frame {
sp += ptrace.Word(2 * p.PtrSize()); sp += ptrace.Word(2 * p.PtrSize());
} }
pc := p.peekUintptr(f.fp - ptrace.Word(p.PtrSize())); pc := p.peekUintptr(a, f.fp - ptrace.Word(p.PtrSize()));
if pc < 0x1000 { if pc < 0x1000 {
return nil; return nil;
} }
// TODO(austin) Register this frame for shoot-down. // TODO(austin) Register this frame for shoot-down.
f.outer = prepareFrame(pc, sp, f.stk, f); f.outer = prepareFrame(a, pc, sp, f.stk, f);
return f.outer; return f.outer;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package ogle package ogle
import ( import (
"eval";
"fmt"; "fmt";
"os"; "os";
"ptrace"; "ptrace";
...@@ -31,21 +32,21 @@ func (t *Goroutine) isG0() bool { ...@@ -31,21 +32,21 @@ func (t *Goroutine) isG0() bool {
return t.g.addr().base == t.g.r.p.sys.g0.addr().base; return t.g.addr().base == t.g.r.p.sys.g0.addr().base;
} }
func (t *Goroutine) resetFrame() { func (t *Goroutine) resetFrame() (err os.Error) {
// TODO(austin) NewFrame can abort
// TODO(austin) Reuse any live part of the current frame stack // TODO(austin) Reuse any live part of the current frame stack
// so existing references to Frame's keep working. // so existing references to Frame's keep working.
t.frame = NewFrame(t.g); t.frame, err = newFrame(t.g);
return;
} }
// Out selects the caller frame of the current frame. // Out selects the caller frame of the current frame.
func (t *Goroutine) Out() os.Error { func (t *Goroutine) Out() os.Error {
// TODO(austin) Outer can abort // TODO(austin) Outer can abort
f := t.frame.Outer(); f, err := t.frame.Outer();
if f != nil { if f != nil {
t.frame = f; t.frame = f;
} }
return nil; return err;
} }
// In selects the frame called by the current frame. // In selects the frame called by the current frame.
...@@ -70,7 +71,11 @@ func readylockedBP(ev Event) (EventAction, os.Error) { ...@@ -70,7 +71,11 @@ func readylockedBP(ev Event) (EventAction, os.Error) {
sp := regs.SP(); sp := regs.SP();
addr := sp + ptrace.Word(p.PtrSize()); addr := sp + ptrace.Word(p.PtrSize());
arg := remotePtr{remote{addr, p}, p.runtime.G}; arg := remotePtr{remote{addr, p}, p.runtime.G};
gp := arg.Get(); var gp eval.Value;
err = try(func(a aborter) { gp = arg.aGet(a) });
if err != nil {
return EAStop, err;
}
if gp == nil { if gp == nil {
return EAStop, UnknownGoroutine{b.osThread, 0}; return EAStop, UnknownGoroutine{b.osThread, 0};
} }
......
...@@ -137,12 +137,17 @@ func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process, ...@@ -137,12 +137,17 @@ func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) (*Process,
// Get current goroutines // Get current goroutines
p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false}; p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false};
g := p.sys.allg.Get(); err := try(func(a aborter) {
for g != nil { g := p.sys.allg.aGet(a);
gs := g.(remoteStruct); for g != nil {
fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base); gs := g.(remoteStruct);
p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false}; fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base);
g = gs.Field(p.f.G.Alllink).(remotePtr).Get(); p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false};
g = gs.field(p.f.G.Alllink).(remotePtr).aGet(a);
}
});
if err != nil {
return nil, err;
} }
p.selectSomeGoroutine(); p.selectSomeGoroutine();
...@@ -282,8 +287,8 @@ func (p *Process) Poke(addr ptrace.Word, b []byte) (int, os.Error) { ...@@ -282,8 +287,8 @@ func (p *Process) Poke(addr ptrace.Word, b []byte) (int, os.Error) {
return thr.Poke(addr, b); return thr.Poke(addr, b);
} }
func (p *Process) peekUintptr(addr ptrace.Word) ptrace.Word { func (p *Process) peekUintptr(a aborter, addr ptrace.Word) ptrace.Word {
return ptrace.Word(mkUintptr(remote{addr, p}).(remoteUint).Get()); return ptrace.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a));
} }
/* /*
......
...@@ -122,7 +122,7 @@ var prtIndent = ""; ...@@ -122,7 +122,7 @@ var prtIndent = "";
// parseRemoteType parses a Type structure in a remote process to // parseRemoteType parses a Type structure in a remote process to
// construct the corresponding interpreter type and remote type. // construct the corresponding interpreter type and remote type.
func parseRemoteType(rs remoteStruct) *remoteType { func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
addr := rs.addr().base; addr := rs.addr().base;
p := rs.addr().p; p := rs.addr().p;
...@@ -156,17 +156,17 @@ func parseRemoteType(rs remoteStruct) *remoteType { ...@@ -156,17 +156,17 @@ func parseRemoteType(rs remoteStruct) *remoteType {
} }
// Get Type header // Get Type header
itype := ptrace.Word(rs.Field(p.f.Type.Typ).(remoteUint).Get()); itype := ptrace.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a));
typ := rs.Field(p.f.Type.Ptr).(remotePtr).Get().(remoteStruct); typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct);
// Is this a named type? // Is this a named type?
var nt *eval.NamedType; var nt *eval.NamedType;
uncommon := typ.Field(p.f.CommonType.UncommonType).(remotePtr).Get(); uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a);
if uncommon != nil { if uncommon != nil {
name := uncommon.(remoteStruct).Field(p.f.UncommonType.Name).(remotePtr).Get(); name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a);
if name != nil { if name != nil {
// TODO(austin) Declare type in appropriate remote package // TODO(austin) Declare type in appropriate remote package
nt = eval.NewNamedType(name.(remoteString).Get()); nt = eval.NewNamedType(name.(remoteString).aGet(a));
rt.Type = nt; rt.Type = nt;
} }
} }
...@@ -227,8 +227,8 @@ func parseRemoteType(rs remoteStruct) *remoteType { ...@@ -227,8 +227,8 @@ func parseRemoteType(rs remoteStruct) *remoteType {
case p.runtime.PArrayType: case p.runtime.PArrayType:
// Cast to an ArrayType // Cast to an ArrayType
typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct); typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct);
len := int64(typ.Field(p.f.ArrayType.Len).(remoteUint).Get()); len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a));
elem := parseRemoteType(typ.Field(p.f.ArrayType.Elem).(remotePtr).Get().(remoteStruct)); elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct));
t = eval.NewArrayType(len, elem.Type); t = eval.NewArrayType(len, elem.Type);
mk = func(r remote) eval.Value { mk = func(r remote) eval.Value {
return remoteArray{r, len, elem}; return remoteArray{r, len, elem};
...@@ -237,22 +237,22 @@ func parseRemoteType(rs remoteStruct) *remoteType { ...@@ -237,22 +237,22 @@ func parseRemoteType(rs remoteStruct) *remoteType {
case p.runtime.PStructType: case p.runtime.PStructType:
// Cast to a StructType // Cast to a StructType
typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct); typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct);
fs := typ.Field(p.f.StructType.Fields).(remoteSlice).Get(); fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a);
fields := make([]eval.StructField, fs.Len); fields := make([]eval.StructField, fs.Len);
layout := make([]remoteStructField, fs.Len); layout := make([]remoteStructField, fs.Len);
for i := range fields { for i := range fields {
f := fs.Base.Elem(int64(i)).(remoteStruct); f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct);
elemrs := f.Field(p.f.StructField.Typ).(remotePtr).Get().(remoteStruct); elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct);
elem := parseRemoteType(elemrs); elem := parseRemoteType(a, elemrs);
fields[i].Type = elem.Type; fields[i].Type = elem.Type;
name := f.Field(p.f.StructField.Name).(remotePtr).Get(); name := f.field(p.f.StructField.Name).(remotePtr).aGet(a);
if name == nil { if name == nil {
fields[i].Anonymous = true; fields[i].Anonymous = true;
} else { } else {
fields[i].Name = name.(remoteString).Get(); fields[i].Name = name.(remoteString).aGet(a);
} }
layout[i].offset = int(f.Field(p.f.StructField.Offset).(remoteUint).Get()); layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a));
layout[i].fieldType = elem; layout[i].fieldType = elem;
} }
...@@ -264,7 +264,7 @@ func parseRemoteType(rs remoteStruct) *remoteType { ...@@ -264,7 +264,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
case p.runtime.PPtrType: case p.runtime.PPtrType:
// Cast to a PtrType // Cast to a PtrType
typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct); typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct);
elem := parseRemoteType(typ.Field(p.f.PtrType.Elem).(remotePtr).Get().(remoteStruct)); elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct));
t = eval.NewPtrType(elem.Type); t = eval.NewPtrType(elem.Type);
mk = func(r remote) eval.Value { mk = func(r remote) eval.Value {
return remotePtr{r, elem}; return remotePtr{r, elem};
...@@ -273,7 +273,7 @@ func parseRemoteType(rs remoteStruct) *remoteType { ...@@ -273,7 +273,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
case p.runtime.PSliceType: case p.runtime.PSliceType:
// Cast to a SliceType // Cast to a SliceType
typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct); typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct);
elem := parseRemoteType(typ.Field(p.f.SliceType.Elem).(remotePtr).Get().(remoteStruct)); elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct));
t = eval.NewSliceType(elem.Type); t = eval.NewSliceType(elem.Type);
mk = func(r remote) eval.Value { mk = func(r remote) eval.Value {
return remoteSlice{r, elem}; return remoteSlice{r, elem};
...@@ -291,7 +291,7 @@ func parseRemoteType(rs remoteStruct) *remoteType { ...@@ -291,7 +291,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
name = sym.Common().Name; name = sym.Common().Name;
} }
err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name); err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name);
eval.Abort(FormatError(err)); a.Abort(FormatError(err));
} }
// Fill in the remote type // Fill in the remote type
...@@ -300,7 +300,7 @@ func parseRemoteType(rs remoteStruct) *remoteType { ...@@ -300,7 +300,7 @@ func parseRemoteType(rs remoteStruct) *remoteType {
} else { } else {
rt.Type = t; rt.Type = t;
} }
rt.size = int(typ.Field(p.f.CommonType.Size).(remoteUint).Get()); rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a));
rt.mk = mk; rt.mk = mk;
return rt; return rt;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment