Implement remote variables

R=rsc
APPROVED=rsc
DELTA=282  (281 added, 0 deleted, 1 changed)
OCL=34407
CL=34781
diff --git a/usr/austin/ogle/rvalue.go b/usr/austin/ogle/rvalue.go
index 1449ed6..2d95a40 100644
--- a/usr/austin/ogle/rvalue.go
+++ b/usr/austin/ogle/rvalue.go
@@ -21,6 +21,14 @@
 	return string(e);
 }
 
+// A ReadOnlyError occurs when attempting to set or assign to a
+// read-only value.
+type ReadOnlyError string
+
+func (e ReadOnlyError) String() string {
+	return string(e);
+}
+
 // A maker is a function that converts a remote address into an
 // interpreter Value.
 type maker func(remote) eval.Value
@@ -351,7 +359,7 @@
 func (v remoteString) aSet(a aborter, x string) {
 	// TODO(austin) This isn't generally possible without the
 	// ability to allocate remote memory.
-	a.Abort(RemoteMismatchError("remote strings cannot be assigned to"));
+	a.Abort(ReadOnlyError("remote strings cannot be assigned to"));
 }
 
 func mkString(r remote) eval.Value {
diff --git a/usr/austin/ogle/vars.go b/usr/austin/ogle/vars.go
new file mode 100644
index 0000000..17c4baa
--- /dev/null
+++ b/usr/austin/ogle/vars.go
@@ -0,0 +1,277 @@
+// 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 (
+	"eval";
+	"log";
+	"os";
+	"ptrace";
+	"sym";
+)
+
+/*
+ * Remote frame pointers
+ */
+
+// A NotOnStack error occurs when attempting to access a variable in a
+// remote frame where that remote frame is not on the current stack.
+type NotOnStack struct {
+	Fn *sym.TextSym;
+	Goroutine *Goroutine;
+}
+
+func (e NotOnStack) String() string {
+	return "function " + e.Fn.Name + " not on " + e.Goroutine.String() + "'s stack";
+}
+
+// A remoteFramePtr is an implementation of eval.PtrValue that
+// represents a pointer to a function frame in a remote process.  When
+// accessed, this locates the function on the current goroutine's
+// stack and returns a structure containing the local variables of
+// that function.
+type remoteFramePtr struct {
+	p *Process;
+	fn *sym.TextSym;
+	rt *remoteType;
+}
+
+func (v remoteFramePtr) String() string {
+	// TODO(austin): This could be a really awesome string method
+	return "<remote frame>";
+}
+
+func (v remoteFramePtr) Assign(t *eval.Thread, o eval.Value) {
+	v.Set(t, o.(eval.PtrValue).Get(t));
+}
+
+func (v remoteFramePtr) Get(t *eval.Thread) eval.Value {
+	g := v.p.curGoroutine;
+	if g == nil || g.frame == nil {
+		t.Abort(NoCurrentGoroutine{});
+	}
+
+	for f := g.frame; f != nil; f = f.aOuter(t) {
+		if f.fn != v.fn {
+			continue;
+		}
+
+		// TODO(austin): Register for shootdown with f
+		return v.rt.mk(remote{f.fp, v.p});
+	}
+
+	t.Abort(NotOnStack{v.fn, g});
+	panic();
+}
+
+func (v remoteFramePtr) Set(t *eval.Thread, x eval.Value) {
+	// Theoretically this could be a static error.  If remote
+	// packages were packages, remote frames could just be defined
+	// as constants.
+	t.Abort(ReadOnlyError("remote frames cannot be assigned to"));
+}
+
+/*
+ * Remote packages
+ */
+
+// TODO(austin): Remote packages are implemented as structs right now,
+// which has some weird consequences.  You can attempt to assign to a
+// remote package.  It also produces terrible error messages.
+// Ideally, these would actually be packages, but somehow first-class
+// so they could be assigned to other names.
+
+// A remotePackage is an implementation of eval.StructValue that
+// represents a package in a remote process.  It's essentially a
+// regular struct, except it cannot be assigned to.
+type remotePackage struct {
+	defs []eval.Value;
+}
+
+func (v remotePackage) String() string {
+	return "<remote package>";
+}
+
+func (v remotePackage) Assign(t *eval.Thread, o eval.Value) {
+	t.Abort(ReadOnlyError("remote packages cannot be assigned to"));
+}
+
+func (v remotePackage) Get(t *eval.Thread) eval.StructValue {
+	return v;
+}
+
+func (v remotePackage) Field(t *eval.Thread, i int) eval.Value {
+	return v.defs[i];
+}
+
+/*
+ * Remote variables
+ */
+
+// populateWorld defines constants in the given world for each package
+// in this process.  These packages are structs that, in turn, contain
+// fields for each global and function in that package.
+func (p *Process) populateWorld(w *eval.World) os.Error {
+	type def struct {
+		t eval.Type;
+		v eval.Value;
+	}
+	packages := make(map[string] map[string] def);
+
+	for _, s := range p.syms.Syms {
+		sc := s.Common();
+		if sc.ReceiverName() != "" {
+			// TODO(austin)
+			continue;
+		}
+
+		// Package
+		pkgName := sc.PackageName();
+		switch pkgName {
+		case "", "type", "extratype", "string", "go":
+			// "go" is really "go.string"
+			continue;
+		}
+		pkg, ok := packages[pkgName];
+		if !ok {
+			pkg = make(map[string] def);
+			packages[pkgName] = pkg;
+		}
+
+		// Symbol name
+		name := sc.BaseName();
+		if prev, ok := pkg[name]; ok {
+			log.Stderrf("Multiple definitions of symbol %s", sc.Name);
+			continue;
+		}
+
+		// Symbol type
+		rt, err := p.typeOfSym(sc);
+		if err != nil {
+			return err;
+		}
+
+		// Definition
+		switch sc.Type {
+		case 'D', 'd', 'B', 'b':
+			// Global variable
+			if rt == nil {
+				continue;
+			}
+			pkg[name] = def{rt.Type, rt.mk(remote{ptrace.Word(sc.Value), p})};
+
+		case 'T', 't', 'L', 'l':
+			// Function
+			s := s.(*sym.TextSym);
+			// TODO(austin): Ideally, this would *also* be
+			// callable.  How does that interact with type
+			// conversion syntax?
+			rt, err := p.makeFrameType(s);
+			if err != nil {
+				return err;
+			}
+			pkg[name] = def{eval.NewPtrType(rt.Type), remoteFramePtr{p, s, rt}};
+		}
+	}
+
+	// TODO(austin): Define remote types
+
+	// Define packages
+	for pkgName, defs := range packages {
+		fields := make([]eval.StructField, len(defs));
+		vals := make([]eval.Value, len(defs));
+		i := 0;
+		for name, def := range defs {
+			fields[i].Name = name;
+			fields[i].Type = def.t;
+			vals[i] = def.v;
+			i++;
+		}
+		pkgType := eval.NewStructType(fields);
+		pkgVal := remotePackage{vals};
+
+		err := w.DefineConst(pkgName, pkgType, pkgVal);
+		if err != nil {
+			log.Stderrf("while defining package %s: %v", pkgName, err);
+		}
+	}
+
+	return nil;
+}
+
+// typeOfSym returns the type associated with a symbol.  If the symbol
+// has no type, returns nil.
+func (p *Process) typeOfSym(s *sym.CommonSym) (*remoteType, os.Error) {
+	if s.GoType == 0 {
+		return nil, nil;
+	}
+	addr := ptrace.Word(s.GoType);
+	var rt *remoteType;
+	err := try(func(a aborter) {
+		rt = parseRemoteType(a, p.runtime.Type.mk(remote{addr, p}).(remoteStruct));
+	});
+	if err != nil {
+		return nil, err;
+	}
+	return rt, nil;
+}
+
+// makeFrameType constructs a struct type for the frame of a function.
+// The offsets in this struct type are such that the struct can be
+// instantiated at this function's frame pointer.
+func (p *Process) makeFrameType(s *sym.TextSym) (*remoteType, os.Error) {
+	n := len(s.Params) + len(s.Locals);
+	fields := make([]eval.StructField, n);
+	layout := make([]remoteStructField, n);
+	i := 0;
+
+	// TODO(austin): There can be multiple locals/parameters with
+	// the same name.  We probably need liveness information to do
+	// anything about this.  Once we have that, perhaps we give
+	// such fields interface{} type?  Or perhaps we disambiguate
+	// the names with numbers.  Disambiguation is annoying for
+	// things like "i", where there's an obvious right answer.
+
+	for _, param := range s.Params {
+		rt, err := p.typeOfSym(param.Common());
+		if err != nil {
+			return nil, err;
+		}
+		if rt == nil {
+			//fmt.Printf(" (no type)\n");
+			continue;
+		}
+		// TODO(austin): Why do local variables carry their
+		// package name?
+		fields[i].Name = param.BaseName();
+		fields[i].Type = rt.Type;
+		// Parameters have positive offsets from FP
+		layout[i].offset = int(param.Value);
+		layout[i].fieldType = rt;
+		i++;
+	}
+
+	for _, local := range s.Locals {
+		rt, err := p.typeOfSym(local.Common());
+		if err != nil {
+			return nil, err;
+		}
+		if rt == nil {
+			continue;
+		}
+		fields[i].Name = local.BaseName();
+		fields[i].Type = rt.Type;
+		// Locals have negative offsets from FP - PtrSize
+		layout[i].offset = -int(local.Value) - p.PtrSize();
+		layout[i].fieldType = rt;
+		i++;
+	}
+
+	fields = fields[0:i];
+	layout = layout[0:i];
+	t := eval.NewStructType(fields);
+	mk := func(r remote) eval.Value { return remoteStruct{r, layout} };
+	return &remoteType{t, 0, 0, mk}, nil;
+}