summaryrefslogtreecommitdiff
path: root/src/pkg/exp/ogle
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exp/ogle')
-rw-r--r--src/pkg/exp/ogle/Makefile29
-rw-r--r--src/pkg/exp/ogle/abort.go35
-rw-r--r--src/pkg/exp/ogle/arch.go125
-rw-r--r--src/pkg/exp/ogle/cmd.go373
-rw-r--r--src/pkg/exp/ogle/event.go280
-rw-r--r--src/pkg/exp/ogle/frame.go212
-rw-r--r--src/pkg/exp/ogle/goroutine.go117
-rw-r--r--src/pkg/exp/ogle/main.go9
-rw-r--r--src/pkg/exp/ogle/process.go521
-rw-r--r--src/pkg/exp/ogle/rruntime.go271
-rw-r--r--src/pkg/exp/ogle/rtype.go288
-rw-r--r--src/pkg/exp/ogle/rvalue.go515
-rw-r--r--src/pkg/exp/ogle/vars.go272
13 files changed, 0 insertions, 3047 deletions
diff --git a/src/pkg/exp/ogle/Makefile b/src/pkg/exp/ogle/Makefile
deleted file mode 100644
index ef65d36c8..000000000
--- a/src/pkg/exp/ogle/Makefile
+++ /dev/null
@@ -1,29 +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 ../../../Make.inc
-
-TARG=exp/ogle
-GOFILES=\
- abort.go\
- arch.go\
- cmd.go\
- event.go\
- frame.go\
- goroutine.go\
- rruntime.go\
- rtype.go\
- rvalue.go\
- process.go\
- vars.go\
-
-CLEANFILES+=ogle
-
-include ../../../Make.pkg
-
-main.$O: main.go package
- $(GC) -I_obj $<
-
-ogle: main.$O
- $(LD) -L_obj -o $@ $<
diff --git a/src/pkg/exp/ogle/abort.go b/src/pkg/exp/ogle/abort.go
deleted file mode 100644
index 311a7b38e..000000000
--- a/src/pkg/exp/ogle/abort.go
+++ /dev/null
@@ -1,35 +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 ogle
-
-import (
- "os"
- "runtime"
-)
-
-// An aborter aborts the thread's current computation, 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
-}
diff --git a/src/pkg/exp/ogle/arch.go b/src/pkg/exp/ogle/arch.go
deleted file mode 100644
index 52b1c9757..000000000
--- a/src/pkg/exp/ogle/arch.go
+++ /dev/null
@@ -1,125 +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 ogle
-
-import (
- "debug/proc"
- "math"
-)
-
-type Arch interface {
- // ToWord converts an array of up to 8 bytes in memory order
- // to a word.
- ToWord(data []byte) proc.Word
- // FromWord converts a word to an array of up to 8 bytes in
- // memory order.
- 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.
- ToFloat32(bits uint32) float32
- // FromFloat32 converts a float to a word. This should return
- // a word that can be passed to FromWord to get the memory
- // representation of a float on this architecture.
- FromFloat32(f float32) uint32
- // ToFloat64 is to float64 as ToFloat32 is to float32.
- ToFloat64(bits uint64) float64
- // FromFloat64 is to float64 as FromFloat32 is to float32.
- FromFloat64(f float64) uint64
-
- // IntSize returns the number of bytes in an 'int'.
- IntSize() int
- // PtrSize returns the number of bytes in a 'uintptr'.
- PtrSize() int
- // FloatSize returns the number of bytes in a 'float'.
- FloatSize() int
- // Align rounds offset up to the appropriate offset for a
- // basic type with the given width.
- Align(offset, width int) int
-
- // G returns the current G pointer.
- G(regs proc.Regs) proc.Word
-
- // ClosureSize returns the number of bytes expected by
- // ParseClosure.
- ClosureSize() int
- // ParseClosure takes ClosureSize bytes read from a return PC
- // in a remote process, determines if the code is a closure,
- // and returns the frame size of the closure if it is.
- ParseClosure(data []byte) (frame int, ok bool)
-}
-
-type ArchLSB struct{}
-
-func (ArchLSB) ToWord(data []byte) proc.Word {
- var v proc.Word
- for i, b := range data {
- v |= proc.Word(b) << (uint(i) * 8)
- }
- return v
-}
-
-func (ArchLSB) FromWord(v proc.Word, out []byte) {
- for i := range out {
- out[i] = byte(v)
- v >>= 8
- }
-}
-
-func (ArchLSB) ToFloat32(bits uint32) float32 {
- // TODO(austin) Do these definitions depend on my current
- // architecture?
- return math.Float32frombits(bits)
-}
-
-func (ArchLSB) FromFloat32(f float32) uint32 { return math.Float32bits(f) }
-
-func (ArchLSB) ToFloat64(bits uint64) float64 { return math.Float64frombits(bits) }
-
-func (ArchLSB) FromFloat64(f float64) uint64 { return math.Float64bits(f) }
-
-type ArchAlignedMultiple struct{}
-
-func (ArchAlignedMultiple) Align(offset, width int) int {
- return ((offset - 1) | (width - 1)) + 1
-}
-
-type amd64 struct {
- ArchLSB
- ArchAlignedMultiple
- gReg int
-}
-
-func (a *amd64) IntSize() int { return 4 }
-
-func (a *amd64) PtrSize() int { return 8 }
-
-func (a *amd64) FloatSize() int { return 4 }
-
-func (a *amd64) G(regs proc.Regs) proc.Word {
- // See src/pkg/runtime/mkasmh
- if a.gReg == -1 {
- ns := regs.Names()
- for i, n := range ns {
- if n == "r15" {
- a.gReg = i
- break
- }
- }
- }
-
- return regs.Get(a.gReg)
-}
-
-func (a *amd64) ClosureSize() int { return 8 }
-
-func (a *amd64) ParseClosure(data []byte) (int, bool) {
- if data[0] == 0x48 && data[1] == 0x81 && data[2] == 0xc4 && data[7] == 0xc3 {
- return int(a.ToWord(data[3:7]) + 8), true
- }
- return 0, false
-}
-
-var Amd64 = &amd64{gReg: -1}
diff --git a/src/pkg/exp/ogle/cmd.go b/src/pkg/exp/ogle/cmd.go
deleted file mode 100644
index ff0d24c69..000000000
--- a/src/pkg/exp/ogle/cmd.go
+++ /dev/null
@@ -1,373 +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 ogle is the beginning of a debugger for Go.
-package ogle
-
-import (
- "bufio"
- "debug/elf"
- "debug/proc"
- "exp/eval"
- "fmt"
- "go/scanner"
- "go/token"
- "os"
- "strconv"
- "strings"
-)
-
-var fset = token.NewFileSet()
-var world *eval.World
-var curProc *Process
-
-func Main() {
- world = eval.NewWorld()
- defineFuncs()
- r := bufio.NewReader(os.Stdin)
- for {
- print("; ")
- line, err := r.ReadSlice('\n')
- if err != nil {
- break
- }
-
- // Try line as a command
- cmd, rest := getCmd(line)
- if cmd != nil {
- err := cmd.handler(rest)
- if err != nil {
- scanner.PrintError(os.Stderr, err)
- }
- continue
- }
-
- // Try line as code
- code, err := world.Compile(fset, string(line))
- if err != nil {
- scanner.PrintError(os.Stderr, err)
- continue
- }
- v, err := code.Run()
- if err != nil {
- fmt.Fprintf(os.Stderr, err.String())
- continue
- }
- if v != nil {
- println(v.String())
- }
- }
-}
-
-// newScanner creates a new scanner that scans that given input bytes.
-func newScanner(input []byte) (*scanner.Scanner, *scanner.ErrorVector) {
- sc := new(scanner.Scanner)
- ev := new(scanner.ErrorVector)
- file := fset.AddFile("input", fset.Base(), len(input))
- sc.Init(file, input, ev, 0)
- return sc, ev
-}
-
-/*
- * Commands
- */
-
-// A UsageError occurs when a command is called with illegal arguments.
-type UsageError string
-
-func (e UsageError) String() string { return string(e) }
-
-// A cmd represents a single command with a handler.
-type cmd struct {
- cmd string
- handler func([]byte) os.Error
-}
-
-var cmds = []cmd{
- {"load", cmdLoad},
- {"bt", cmdBt},
-}
-
-// getCmd attempts to parse an input line as a registered command. If
-// successful, it returns the command and the bytes remaining after
-// the command, which should be passed to the command.
-func getCmd(line []byte) (*cmd, []byte) {
- sc, _ := newScanner(line)
- pos, tok, lit := sc.Scan()
- if sc.ErrorCount != 0 || tok != token.IDENT {
- return nil, nil
- }
-
- slit := string(lit)
- for i := range cmds {
- if cmds[i].cmd == slit {
- return &cmds[i], line[fset.Position(pos).Offset+len(lit):]
- }
- }
- return nil, nil
-}
-
-// cmdLoad starts or attaches to a process. Its form is similar to
-// import:
-//
-// load [sym] "path" [;]
-//
-// sym specifies the name to give to the process. If not given, the
-// name is derived from the path of the process. If ".", then the
-// packages from the remote process are defined into the current
-// namespace. If given, this symbol is defined as a package
-// containing the process' packages.
-//
-// path gives the path of the process to start or attach to. If it is
-// "pid:<num>", then attach to the given PID. Otherwise, treat it as
-// a file path and space-separated arguments and start a new process.
-//
-// load always sets the current process to the loaded process.
-func cmdLoad(args []byte) os.Error {
- ident, path, err := parseLoad(args)
- if err != nil {
- return err
- }
- if curProc != nil {
- return UsageError("multiple processes not implemented")
- }
- if ident != "." {
- return UsageError("process identifiers not implemented")
- }
-
- // Parse argument and start or attach to process
- var fname string
- var tproc proc.Process
- if len(path) >= 4 && path[0:4] == "pid:" {
- pid, err := strconv.Atoi(path[4:])
- if err != nil {
- return err
- }
- fname, err = os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
- if err != nil {
- return err
- }
- tproc, err = proc.Attach(pid)
- if err != nil {
- return err
- }
- println("Attached to", pid)
- } else {
- parts := strings.Split(path, " ")
- if len(parts) == 0 {
- fname = ""
- } else {
- fname = parts[0]
- }
- tproc, err = proc.StartProcess(fname, parts, &os.ProcAttr{Files: []*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 tproc
- // before detaching.
- }
-
- // Get symbols
- f, err := os.Open(fname)
- if err != nil {
- tproc.Detach()
- return err
- }
- defer f.Close()
- elf, err := elf.NewFile(f)
- if err != nil {
- tproc.Detach()
- return err
- }
- curProc, err = NewProcessElf(tproc, elf)
- if err != nil {
- tproc.Detach()
- return err
- }
-
- // Prepare new process
- curProc.OnGoroutineCreate().AddHandler(EventPrint)
- curProc.OnGoroutineExit().AddHandler(EventPrint)
-
- err = curProc.populateWorld(world)
- if err != nil {
- tproc.Detach()
- return err
- }
-
- return nil
-}
-
-func parseLoad(args []byte) (ident string, path string, err os.Error) {
- err = UsageError("Usage: load [sym] \"path\"")
- sc, ev := newScanner(args)
-
- var toks [4]token.Token
- var lits [4]string
- for i := range toks {
- _, toks[i], lits[i] = sc.Scan()
- }
- if sc.ErrorCount != 0 {
- err = ev.GetError(scanner.NoMultiples)
- return
- }
-
- i := 0
- switch toks[i] {
- case token.PERIOD, token.IDENT:
- ident = string(lits[i])
- i++
- }
-
- if toks[i] != token.STRING {
- return
- }
- path, uerr := strconv.Unquote(string(lits[i]))
- if uerr != nil {
- err = uerr
- return
- }
- i++
-
- if toks[i] == token.SEMICOLON {
- i++
- }
- if toks[i] != token.EOF {
- return
- }
-
- return ident, path, nil
-}
-
-// cmdBt prints a backtrace for the current goroutine. It takes no
-// arguments.
-func cmdBt(args []byte) os.Error {
- err := parseNoArgs(args, "Usage: bt")
- if err != nil {
- return err
- }
-
- if curProc == nil || curProc.curGoroutine == nil {
- return NoCurrentGoroutine{}
- }
-
- f := curProc.curGoroutine.frame
- if f == nil {
- fmt.Println("No frames on stack")
- return nil
- }
-
- for f.Inner() != nil {
- f = f.Inner()
- }
-
- for i := 0; i < 100; i++ {
- if f == curProc.curGoroutine.frame {
- fmt.Printf("=> ")
- } else {
- fmt.Printf(" ")
- }
- fmt.Printf("%8x %v\n", f.pc, f)
- f, err = f.Outer()
- if err != nil {
- return err
- }
- if f == nil {
- return nil
- }
- }
-
- fmt.Println("...")
- return nil
-}
-
-func parseNoArgs(args []byte, usage string) os.Error {
- sc, ev := newScanner(args)
- _, tok, _ := sc.Scan()
- if sc.ErrorCount != 0 {
- return ev.GetError(scanner.NoMultiples)
- }
- if tok != token.EOF {
- return UsageError(usage)
- }
- return nil
-}
-
-/*
- * Functions
- */
-
-// defineFuncs populates world with the built-in functions.
-func defineFuncs() {
- t, v := eval.FuncFromNativeTyped(fnOut, fnOutSig)
- world.DefineConst("Out", t, v)
- t, v = eval.FuncFromNativeTyped(fnContWait, fnContWaitSig)
- world.DefineConst("ContWait", t, v)
- t, v = eval.FuncFromNativeTyped(fnBpSet, fnBpSetSig)
- world.DefineConst("BpSet", t, v)
-}
-
-// printCurFrame prints the current stack frame, as it would appear in
-// a backtrace.
-func printCurFrame() {
- if curProc == nil || curProc.curGoroutine == nil {
- return
- }
- f := curProc.curGoroutine.frame
- if f == nil {
- return
- }
- fmt.Printf("=> %8x %v\n", f.pc, f)
-}
-
-// fnOut moves the current frame to the caller of the current frame.
-func fnOutSig() {}
-func fnOut(t *eval.Thread, args []eval.Value, res []eval.Value) {
- if curProc == nil {
- t.Abort(NoCurrentGoroutine{})
- }
- err := curProc.Out()
- if err != nil {
- t.Abort(err)
- }
- // TODO(austin) Only in the command form
- printCurFrame()
-}
-
-// fnContWait continues the current process and waits for a stopping event.
-func fnContWaitSig() {}
-func fnContWait(t *eval.Thread, args []eval.Value, res []eval.Value) {
- if curProc == nil {
- t.Abort(NoCurrentGoroutine{})
- }
- err := curProc.ContWait()
- if err != nil {
- t.Abort(err)
- }
- // TODO(austin) Only in the command form
- ev := curProc.Event()
- if ev != nil {
- fmt.Printf("%v\n", ev)
- }
- printCurFrame()
-}
-
-// fnBpSet sets a breakpoint at the entry to the named function.
-func fnBpSetSig(string) {}
-func fnBpSet(t *eval.Thread, args []eval.Value, res []eval.Value) {
- // TODO(austin) This probably shouldn't take a symbol name.
- // Perhaps it should take an interface that provides PC's.
- // Functions and instructions can implement that interface and
- // we can have something to translate file:line pairs.
- if curProc == nil {
- t.Abort(NoCurrentGoroutine{})
- }
- name := args[0].(eval.StringValue).Get(t)
- fn := curProc.syms.LookupFunc(name)
- if fn == nil {
- t.Abort(UsageError("no such function " + name))
- }
- curProc.OnBreakpoint(proc.Word(fn.Entry)).AddHandler(EventStop)
-}
diff --git a/src/pkg/exp/ogle/event.go b/src/pkg/exp/ogle/event.go
deleted file mode 100644
index d7092ded3..000000000
--- a/src/pkg/exp/ogle/event.go
+++ /dev/null
@@ -1,280 +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 ogle
-
-import (
- "debug/proc"
- "fmt"
- "os"
-)
-
-/*
- * Hooks and events
- */
-
-// An EventHandler is a function that takes an event and returns a
-// response to that event and possibly an error. If an event handler
-// returns an error, the process stops and no other handlers for that
-// event are executed.
-type EventHandler func(e Event) (EventAction, os.Error)
-
-// An EventAction is an event handler's response to an event. If all
-// of an event's handlers execute without returning errors, their
-// results are combined as follows: If any handler returned
-// EAContinue, then the process resumes (without returning from
-// WaitStop); otherwise, if any handler returned EAStop, the process
-// remains stopped; otherwise, if all handlers returned EADefault, the
-// process resumes. A handler may return EARemoveSelf bit-wise or'd
-// with any other action to indicate that the handler should be
-// removed from the hook.
-type EventAction int
-
-const (
- EARemoveSelf EventAction = 0x100
- EADefault EventAction = iota
- EAStop
- EAContinue
-)
-
-// A EventHook allows event handlers to be added and removed.
-type EventHook interface {
- AddHandler(EventHandler)
- RemoveHandler(EventHandler)
- NumHandler() int
- handle(e Event) (EventAction, os.Error)
- String() string
-}
-
-// EventHook is almost, but not quite, suitable for user-defined
-// events. If we want user-defined events, make EventHook a struct,
-// special-case adding and removing handlers in breakpoint hooks, and
-// provide a public interface for posting events to hooks.
-
-type Event interface {
- Process() *Process
- Goroutine() *Goroutine
- String() string
-}
-
-type commonHook struct {
- // Head of handler chain
- head *handler
- // Number of non-internal handlers
- len int
-}
-
-type handler struct {
- eh EventHandler
- // True if this handler must be run before user-defined
- // handlers in order to ensure correctness.
- internal bool
- // True if this handler has been removed from the chain.
- removed bool
- next *handler
-}
-
-func (h *commonHook) AddHandler(eh EventHandler) {
- h.addHandler(eh, false)
-}
-
-func (h *commonHook) addHandler(eh EventHandler, internal bool) {
- // Ensure uniqueness of handlers
- h.RemoveHandler(eh)
-
- if !internal {
- h.len++
- }
- // Add internal handlers to the beginning
- if internal || h.head == nil {
- h.head = &handler{eh, internal, false, h.head}
- return
- }
- // Add handler after internal handlers
- // TODO(austin) This should probably go on the end instead
- prev := h.head
- for prev.next != nil && prev.internal {
- prev = prev.next
- }
- prev.next = &handler{eh, internal, false, prev.next}
-}
-
-func (h *commonHook) RemoveHandler(eh EventHandler) {
- plink := &h.head
- for l := *plink; l != nil; plink, l = &l.next, l.next {
- if l.eh == eh {
- if !l.internal {
- h.len--
- }
- l.removed = true
- *plink = l.next
- break
- }
- }
-}
-
-func (h *commonHook) NumHandler() int { return h.len }
-
-func (h *commonHook) handle(e Event) (EventAction, os.Error) {
- action := EADefault
- plink := &h.head
- for l := *plink; l != nil; plink, l = &l.next, l.next {
- if l.removed {
- continue
- }
- a, err := l.eh(e)
- if a&EARemoveSelf == EARemoveSelf {
- if !l.internal {
- h.len--
- }
- l.removed = true
- *plink = l.next
- a &^= EARemoveSelf
- }
- if err != nil {
- return EAStop, err
- }
- if a > action {
- action = a
- }
- }
- return action, nil
-}
-
-type commonEvent struct {
- // The process of this event
- p *Process
- // The goroutine of this event.
- t *Goroutine
-}
-
-func (e *commonEvent) Process() *Process { return e.p }
-
-func (e *commonEvent) Goroutine() *Goroutine { return e.t }
-
-/*
- * Standard event handlers
- */
-
-// EventPrint is a standard event handler that prints events as they
-// occur. It will not cause the process to stop.
-func EventPrint(ev Event) (EventAction, os.Error) {
- // TODO(austin) Include process name here?
- fmt.Fprintf(os.Stderr, "*** %v\n", ev.String())
- return EADefault, nil
-}
-
-// EventStop is a standard event handler that causes the process to stop.
-func EventStop(ev Event) (EventAction, os.Error) {
- return EAStop, nil
-}
-
-/*
- * Breakpoints
- */
-
-type breakpointHook struct {
- commonHook
- p *Process
- pc proc.Word
-}
-
-// A Breakpoint event occurs when a process reaches a particular
-// program counter. When this event is handled, the current goroutine
-// will be the goroutine that reached the program counter.
-type Breakpoint struct {
- commonEvent
- osThread proc.Thread
- pc proc.Word
-}
-
-func (h *breakpointHook) AddHandler(eh EventHandler) {
- h.addHandler(eh, false)
-}
-
-func (h *breakpointHook) addHandler(eh EventHandler, internal bool) {
- // We register breakpoint events lazily to avoid holding
- // references to breakpoints without handlers. Be sure to use
- // the "canonical" breakpoint if there is one.
- if cur, ok := h.p.breakpointHooks[h.pc]; ok {
- h = cur
- }
- oldhead := h.head
- h.commonHook.addHandler(eh, internal)
- if oldhead == nil && h.head != nil {
- h.p.proc.AddBreakpoint(h.pc)
- h.p.breakpointHooks[h.pc] = h
- }
-}
-
-func (h *breakpointHook) RemoveHandler(eh EventHandler) {
- oldhead := h.head
- h.commonHook.RemoveHandler(eh)
- if oldhead != nil && h.head == nil {
- h.p.proc.RemoveBreakpoint(h.pc)
- h.p.breakpointHooks[h.pc] = nil, false
- }
-}
-
-func (h *breakpointHook) String() string {
- // TODO(austin) Include process name?
- // TODO(austin) Use line:pc or at least sym+%#x
- return fmt.Sprintf("breakpoint at %#x", h.pc)
-}
-
-func (b *Breakpoint) PC() proc.Word { return b.pc }
-
-func (b *Breakpoint) String() string {
- // TODO(austin) Include process name and goroutine
- // TODO(austin) Use line:pc or at least sym+%#x
- return fmt.Sprintf("breakpoint at %#x", b.pc)
-}
-
-/*
- * Goroutine create/exit
- */
-
-type goroutineCreateHook struct {
- commonHook
-}
-
-func (h *goroutineCreateHook) String() string { return "goroutine create" }
-
-// A GoroutineCreate event occurs when a process creates a new
-// goroutine. When this event is handled, the current goroutine will
-// be the newly created goroutine.
-type GoroutineCreate struct {
- commonEvent
- parent *Goroutine
-}
-
-// Parent returns the goroutine that created this goroutine. May be
-// nil if this event is the creation of the first goroutine.
-func (e *GoroutineCreate) Parent() *Goroutine { return e.parent }
-
-func (e *GoroutineCreate) String() string {
- // TODO(austin) Include process name
- if e.parent == nil {
- return fmt.Sprintf("%v created", e.t)
- }
- return fmt.Sprintf("%v created by %v", e.t, e.parent)
-}
-
-type goroutineExitHook struct {
- commonHook
-}
-
-func (h *goroutineExitHook) String() string { return "goroutine exit" }
-
-// A GoroutineExit event occurs when a Go goroutine exits.
-type GoroutineExit struct {
- commonEvent
-}
-
-func (e *GoroutineExit) String() string {
- // TODO(austin) Include process name
- //return fmt.Sprintf("%v exited", e.t);
- // For debugging purposes
- return fmt.Sprintf("goroutine %#x exited", e.t.g.addr().base)
-}
diff --git a/src/pkg/exp/ogle/frame.go b/src/pkg/exp/ogle/frame.go
deleted file mode 100644
index 1538362ba..000000000
--- a/src/pkg/exp/ogle/frame.go
+++ /dev/null
@@ -1,212 +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 ogle
-
-import (
- "debug/gosym"
- "debug/proc"
- "fmt"
- "os"
-)
-
-// A Frame represents a single frame on a remote call stack.
-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 proc.Word
- // The runtime.Stktop of the active stack segment
- stk remoteStruct
- // The function this stack frame is in
- fn *gosym.Func
- // The path and line of the CALL or current instruction. Note
- // that this differs slightly from the meaning of Frame.pc.
- path string
- line int
- // The inner and outer frames of this frame. outer is filled
- // in lazily.
- inner, outer *Frame
-}
-
-// newFrame returns the top-most Frame of the given g's thread.
-func newFrame(g remoteStruct) (*Frame, os.Error) {
- 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
- var pc, sp proc.Word
-
- // Is this G alive?
- switch g.field(p.f.G.Status).(remoteInt).aGet(a) {
- case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead:
- return nil
- }
-
- // Find the OS thread for this G
-
- // TODO(austin) Ideally, we could look at the G's state and
- // figure out if it's on an OS thread or not. However, this
- // is difficult because the state isn't updated atomically
- // with scheduling changes.
- for _, t := range p.proc.Threads() {
- regs, err := t.Regs()
- if err != nil {
- // TODO(austin) What to do?
- continue
- }
- thisg := p.G(regs)
- if thisg == g.addr().base {
- // Found this G's OS thread
- pc = regs.PC()
- sp = regs.SP()
-
- // If this thread crashed, try to recover it
- if pc == 0 {
- pc = p.peekUintptr(a, pc)
- sp += 8
- }
-
- break
- }
- }
-
- if pc == 0 && sp == 0 {
- // 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 = 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
- stk := g.field(p.f.G.Stackbase).(remotePtr).aGet(a).(remoteStruct)
-
- return prepareFrame(a, pc, sp, stk, nil)
-}
-
-// 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 proc.Word, stk remoteStruct, inner *Frame) *Frame {
- // Based on src/pkg/runtime/amd64/traceback.c:traceback
- p := stk.r.p
- top := inner == nil
-
- // Get function
- var path string
- var line int
- var fn *gosym.Func
-
- for i := 0; i < 100; i++ {
- // Traverse segmented stack breaks
- if p.sys.lessstack != nil && pc == proc.Word(p.sys.lessstack.Value) {
- // Get stk->gobuf.pc
- pc = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a))
- // Get stk->gobuf.sp
- 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
- }
-
- // Get the PC of the call instruction
- callpc := pc
- if !top && (p.sys.goexit == nil || pc != proc.Word(p.sys.goexit.Value)) {
- callpc--
- }
-
- // Look up function
- path, line, fn = p.syms.PCToLine(uint64(callpc))
- if fn != nil {
- break
- }
-
- // Closure?
- var buf = make([]byte, p.ClosureSize())
- if _, err := p.Peek(pc, buf); err != nil {
- break
- }
- spdelta, ok := p.ParseClosure(buf)
- if ok {
- sp += proc.Word(spdelta)
- pc = p.peekUintptr(a, sp-proc.Word(p.PtrSize()))
- }
- }
- if fn == nil {
- return nil
- }
-
- // Compute frame pointer
- var fp proc.Word
- if fn.FrameSize < p.PtrSize() {
- fp = sp + proc.Word(p.PtrSize())
- } else {
- 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
- // to morestack. For now, just special case the entry point.
- //
- // TODO(austin) What if we're in the call to morestack in the
- // prologue? Then top == false.
- if top && pc == proc.Word(fn.Entry) {
- // We're in the function prologue, before SP
- // has been adjusted for the frame.
- fp -= proc.Word(fn.FrameSize - p.PtrSize())
- }
-
- return &Frame{pc, sp, fp, stk, fn, path, line, inner, nil}
-}
-
-// Outer returns the Frame that called this Frame, or nil if this is
-// the outermost 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
- if f.outer != nil {
- return f.outer
- }
-
- p := f.stk.r.p
-
- sp := f.fp
- if f.fn == p.sys.newproc && f.fn == p.sys.deferproc {
- // TODO(rsc) The compiler inserts two push/pop's
- // around calls to go and defer. Russ says this
- // should get fixed in the compiler, but we account
- // for it for now.
- sp += proc.Word(2 * p.PtrSize())
- }
-
- pc := p.peekUintptr(a, f.fp-proc.Word(p.PtrSize()))
- if pc < 0x1000 {
- return nil
- }
-
- // TODO(austin) Register this frame for shoot-down.
-
- f.outer = prepareFrame(a, pc, sp, f.stk, f)
- return f.outer
-}
-
-// Inner returns the Frame called by this Frame, or nil if this is the
-// innermost frame.
-func (f *Frame) Inner() *Frame { return f.inner }
-
-func (f *Frame) String() string {
- res := f.fn.Name
- 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)
-}
diff --git a/src/pkg/exp/ogle/goroutine.go b/src/pkg/exp/ogle/goroutine.go
deleted file mode 100644
index 5104ec6d4..000000000
--- a/src/pkg/exp/ogle/goroutine.go
+++ /dev/null
@@ -1,117 +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 ogle
-
-import (
- "debug/proc"
- "exp/eval"
- "fmt"
- "os"
-)
-
-// A Goroutine represents a goroutine in a remote process.
-type Goroutine struct {
- g remoteStruct
- frame *Frame
- dead bool
-}
-
-func (t *Goroutine) String() string {
- if t.dead {
- return "<dead thread>"
- }
- // TODO(austin) Give threads friendly ID's, possibly including
- // the name of the entry function.
- return fmt.Sprintf("thread %#x", t.g.addr().base)
-}
-
-// isG0 returns true if this thread if the internal idle thread
-func (t *Goroutine) isG0() bool { return t.g.addr().base == t.g.r.p.sys.g0.addr().base }
-
-func (t *Goroutine) resetFrame() (err os.Error) {
- // TODO(austin) Reuse any live part of the current frame stack
- // so existing references to Frame's keep working.
- t.frame, err = newFrame(t.g)
- return
-}
-
-// Out selects the caller frame of the current frame.
-func (t *Goroutine) Out() os.Error {
- f, err := t.frame.Outer()
- if f != nil {
- t.frame = f
- }
- return err
-}
-
-// In selects the frame called by the current frame.
-func (t *Goroutine) In() os.Error {
- f := t.frame.Inner()
- if f != nil {
- t.frame = f
- }
- return nil
-}
-
-func readylockedBP(ev Event) (EventAction, os.Error) {
- b := ev.(*Breakpoint)
- p := b.Process()
-
- // The new g is the only argument to this function, so the
- // stack will have the return address, then the G*.
- regs, err := b.osThread.Regs()
- if err != nil {
- return EAStop, err
- }
- sp := regs.SP()
- 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) })
- if err != nil {
- return EAStop, err
- }
- if gp == nil {
- return EAStop, UnknownGoroutine{b.osThread, 0}
- }
- gs := gp.(remoteStruct)
- g := &Goroutine{gs, nil, false}
- p.goroutines[gs.addr().base] = g
-
- // Enqueue goroutine creation event
- parent := b.Goroutine()
- if parent.isG0() {
- parent = nil
- }
- p.postEvent(&GoroutineCreate{commonEvent{p, g}, parent})
-
- // If we don't have any thread selected, select this one
- if p.curGoroutine == nil {
- p.curGoroutine = g
- }
-
- return EADefault, nil
-}
-
-func goexitBP(ev Event) (EventAction, os.Error) {
- b := ev.(*Breakpoint)
- p := b.Process()
-
- g := b.Goroutine()
- g.dead = true
-
- addr := g.g.addr().base
- p.goroutines[addr] = nil, false
-
- // Enqueue thread exit event
- p.postEvent(&GoroutineExit{commonEvent{p, g}})
-
- // If we just exited our selected goroutine, selected another
- if p.curGoroutine == g {
- p.selectSomeGoroutine()
- }
-
- return EADefault, nil
-}
diff --git a/src/pkg/exp/ogle/main.go b/src/pkg/exp/ogle/main.go
deleted file mode 100644
index 1999eccca..000000000
--- a/src/pkg/exp/ogle/main.go
+++ /dev/null
@@ -1,9 +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 main
-
-import "exp/ogle"
-
-func main() { ogle.Main() }
diff --git a/src/pkg/exp/ogle/process.go b/src/pkg/exp/ogle/process.go
deleted file mode 100644
index 7c803b3a2..000000000
--- a/src/pkg/exp/ogle/process.go
+++ /dev/null
@@ -1,521 +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 ogle
-
-import (
- "debug/elf"
- "debug/gosym"
- "debug/proc"
- "exp/eval"
- "fmt"
- "log"
- "os"
- "reflect"
-)
-
-// A FormatError indicates a failure to process information in or
-// about a remote process, such as unexpected or missing information
-// in the object file or runtime structures.
-type FormatError string
-
-func (e FormatError) String() string { return string(e) }
-
-// An UnknownArchitecture occurs when trying to load an object file
-// that indicates an architecture not supported by the debugger.
-type UnknownArchitecture elf.Machine
-
-func (e UnknownArchitecture) String() string {
- return "unknown architecture: " + elf.Machine(e).String()
-}
-
-// A ProcessNotStopped error occurs when attempting to read or write
-// memory or registers of a process that is not stopped.
-type ProcessNotStopped struct{}
-
-func (e ProcessNotStopped) String() string { return "process not stopped" }
-
-// An UnknownGoroutine error is an internal error representing an
-// unrecognized G structure pointer.
-type UnknownGoroutine struct {
- OSThread proc.Thread
- Goroutine proc.Word
-}
-
-func (e UnknownGoroutine) String() string {
- return fmt.Sprintf("internal error: unknown goroutine (G %#x)", e.Goroutine)
-}
-
-// A NoCurrentGoroutine error occurs when no goroutine is currently
-// selected in a process (or when there are no goroutines in a
-// process).
-type NoCurrentGoroutine struct{}
-
-func (e NoCurrentGoroutine) String() string { return "no current goroutine" }
-
-// A Process represents a remote attached process.
-type Process struct {
- Arch
- proc proc.Process
-
- // The symbol table of this process
- syms *gosym.Table
-
- // A possibly-stopped OS thread, or nil
- threadCache proc.Thread
-
- // Types parsed from the remote process
- types map[proc.Word]*remoteType
-
- // Types and values from the remote runtime package
- runtime runtimeValues
-
- // Runtime field indexes
- f runtimeIndexes
-
- // Globals from the sys package (or from no package)
- sys struct {
- lessstack, goexit, newproc, deferproc, newprocreadylocked *gosym.Func
- allg remotePtr
- g0 remoteStruct
- }
-
- // Event queue
- posted []Event
- pending []Event
- event Event
-
- // Event hooks
- breakpointHooks map[proc.Word]*breakpointHook
- goroutineCreateHook *goroutineCreateHook
- goroutineExitHook *goroutineExitHook
-
- // Current goroutine, or nil if there are no goroutines
- curGoroutine *Goroutine
-
- // Goroutines by the address of their G structure
- goroutines map[proc.Word]*Goroutine
-}
-
-/*
- * Process creation
- */
-
-// NewProcess constructs a new remote process around a traced
-// process, an architecture, and a symbol table.
-func NewProcess(tproc proc.Process, arch Arch, syms *gosym.Table) (*Process, os.Error) {
- p := &Process{
- Arch: arch,
- proc: tproc,
- syms: syms,
- types: make(map[proc.Word]*remoteType),
- breakpointHooks: make(map[proc.Word]*breakpointHook),
- goroutineCreateHook: new(goroutineCreateHook),
- goroutineExitHook: new(goroutineExitHook),
- goroutines: make(map[proc.Word]*Goroutine),
- }
-
- // Fill in remote runtime
- p.bootstrap()
-
- switch {
- case p.sys.allg.addr().base == 0:
- return nil, FormatError("failed to find runtime symbol 'allg'")
- case p.sys.g0.addr().base == 0:
- return nil, FormatError("failed to find runtime symbol 'g0'")
- case p.sys.newprocreadylocked == nil:
- return nil, FormatError("failed to find runtime symbol 'newprocreadylocked'")
- case p.sys.goexit == nil:
- return nil, FormatError("failed to find runtime symbol 'sys.goexit'")
- }
-
- // Get current goroutines
- p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false}
- err := try(func(a aborter) {
- g := p.sys.allg.aGet(a)
- for g != nil {
- gs := g.(remoteStruct)
- fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base)
- 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
- }
-
- // Create internal breakpoints to catch new and exited goroutines
- 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 {
- g.resetFrame()
- }
-
- p.selectSomeGoroutine()
-
- return p, nil
-}
-
-func elfGoSyms(f *elf.File) (*gosym.Table, os.Error) {
- text := f.Section(".text")
- symtab := f.Section(".gosymtab")
- pclntab := f.Section(".gopclntab")
- if text == nil || symtab == nil || pclntab == nil {
- return nil, nil
- }
-
- symdat, err := symtab.Data()
- if err != nil {
- return nil, err
- }
- pclndat, err := pclntab.Data()
- if err != nil {
- return nil, err
- }
-
- pcln := gosym.NewLineTable(pclndat, text.Addr)
- tab, err := gosym.NewTable(symdat, pcln)
- if err != nil {
- return nil, err
- }
-
- return tab, nil
-}
-
-// NewProcessElf constructs a new remote process around a traced
-// process and the process' ELF object.
-func NewProcessElf(tproc proc.Process, f *elf.File) (*Process, os.Error) {
- syms, err := elfGoSyms(f)
- if err != nil {
- return nil, err
- }
- if syms == nil {
- return nil, FormatError("Failed to find symbol table")
- }
- var arch Arch
- switch f.Machine {
- case elf.EM_X86_64:
- arch = Amd64
- default:
- return nil, UnknownArchitecture(f.Machine)
- }
- return NewProcess(tproc, arch, syms)
-}
-
-// bootstrap constructs the runtime structure of a remote process.
-func (p *Process) bootstrap() {
- // Manually construct runtime types
- p.runtime.String = newManualType(eval.TypeOfNative(rt1String{}), p.Arch)
- p.runtime.Slice = newManualType(eval.TypeOfNative(rt1Slice{}), p.Arch)
- p.runtime.Eface = newManualType(eval.TypeOfNative(rt1Eface{}), p.Arch)
-
- p.runtime.Type = newManualType(eval.TypeOfNative(rt1Type{}), p.Arch)
- p.runtime.CommonType = newManualType(eval.TypeOfNative(rt1CommonType{}), p.Arch)
- p.runtime.UncommonType = newManualType(eval.TypeOfNative(rt1UncommonType{}), p.Arch)
- p.runtime.StructField = newManualType(eval.TypeOfNative(rt1StructField{}), p.Arch)
- p.runtime.StructType = newManualType(eval.TypeOfNative(rt1StructType{}), p.Arch)
- p.runtime.PtrType = newManualType(eval.TypeOfNative(rt1PtrType{}), p.Arch)
- p.runtime.ArrayType = newManualType(eval.TypeOfNative(rt1ArrayType{}), p.Arch)
- p.runtime.SliceType = newManualType(eval.TypeOfNative(rt1SliceType{}), p.Arch)
-
- p.runtime.Stktop = newManualType(eval.TypeOfNative(rt1Stktop{}), p.Arch)
- p.runtime.Gobuf = newManualType(eval.TypeOfNative(rt1Gobuf{}), p.Arch)
- p.runtime.G = newManualType(eval.TypeOfNative(rt1G{}), p.Arch)
-
- // Get addresses of type.*runtime.XType for discrimination.
- rtv := reflect.Indirect(reflect.ValueOf(&p.runtime))
- rtvt := rtv.Type()
- for i := 0; i < rtv.NumField(); i++ {
- n := rtvt.Field(i).Name
- if n[0] != 'P' || n[1] < 'A' || n[1] > 'Z' {
- continue
- }
- sym := p.syms.LookupSym("type.*runtime." + n[1:])
- if sym == nil {
- continue
- }
- rtv.Field(i).SetUint(sym.Value)
- }
-
- // Get runtime field indexes
- fillRuntimeIndexes(&p.runtime, &p.f)
-
- // Fill G status
- p.runtime.runtimeGStatus = rt1GStatus
-
- // Get globals
- p.sys.lessstack = p.syms.LookupFunc("sys.lessstack")
- p.sys.goexit = p.syms.LookupFunc("goexit")
- p.sys.newproc = p.syms.LookupFunc("sys.newproc")
- p.sys.deferproc = p.syms.LookupFunc("sys.deferproc")
- p.sys.newprocreadylocked = p.syms.LookupFunc("newprocreadylocked")
- if allg := p.syms.LookupSym("allg"); allg != nil {
- p.sys.allg = remotePtr{remote{proc.Word(allg.Value), p}, p.runtime.G}
- }
- if g0 := p.syms.LookupSym("g0"); g0 != nil {
- p.sys.g0 = p.runtime.G.mk(remote{proc.Word(g0.Value), p}).(remoteStruct)
- }
-}
-
-func (p *Process) selectSomeGoroutine() {
- // Once we have friendly goroutine ID's, there might be a more
- // reasonable behavior for this.
- p.curGoroutine = nil
- for _, g := range p.goroutines {
- if !g.isG0() && g.frame != nil {
- p.curGoroutine = g
- return
- }
- }
-}
-
-/*
- * Process memory
- */
-
-func (p *Process) someStoppedOSThread() proc.Thread {
- if p.threadCache != nil {
- if _, err := p.threadCache.Stopped(); err == nil {
- return p.threadCache
- }
- }
-
- for _, t := range p.proc.Threads() {
- if _, err := t.Stopped(); err == nil {
- p.threadCache = t
- return t
- }
- }
- return nil
-}
-
-func (p *Process) Peek(addr proc.Word, out []byte) (int, os.Error) {
- thr := p.someStoppedOSThread()
- if thr == nil {
- return 0, ProcessNotStopped{}
- }
- return thr.Peek(addr, out)
-}
-
-func (p *Process) Poke(addr proc.Word, b []byte) (int, os.Error) {
- thr := p.someStoppedOSThread()
- if thr == nil {
- return 0, ProcessNotStopped{}
- }
- return thr.Poke(addr, b)
-}
-
-func (p *Process) peekUintptr(a aborter, addr proc.Word) proc.Word {
- return proc.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a))
-}
-
-/*
- * Events
- */
-
-// OnBreakpoint returns the hook that is run when the program reaches
-// the given program counter.
-func (p *Process) OnBreakpoint(pc proc.Word) EventHook {
- if bp, ok := p.breakpointHooks[pc]; ok {
- return bp
- }
- // The breakpoint will register itself when a handler is added
- return &breakpointHook{commonHook{nil, 0}, p, pc}
-}
-
-// OnGoroutineCreate returns the hook that is run when a goroutine is created.
-func (p *Process) OnGoroutineCreate() EventHook {
- return p.goroutineCreateHook
-}
-
-// OnGoroutineExit returns the hook that is run when a goroutine exits.
-func (p *Process) OnGoroutineExit() EventHook { return p.goroutineExitHook }
-
-// osThreadToGoroutine looks up the goroutine running on an OS thread.
-func (p *Process) osThreadToGoroutine(t proc.Thread) (*Goroutine, os.Error) {
- regs, err := t.Regs()
- if err != nil {
- return nil, err
- }
- g := p.G(regs)
- gt, ok := p.goroutines[g]
- if !ok {
- return nil, UnknownGoroutine{t, g}
- }
- return gt, nil
-}
-
-// causesToEvents translates the stop causes of the underlying process
-// into an event queue.
-func (p *Process) causesToEvents() ([]Event, os.Error) {
- // Count causes we're interested in
- nev := 0
- for _, t := range p.proc.Threads() {
- if c, err := t.Stopped(); err == nil {
- switch c := c.(type) {
- case proc.Breakpoint:
- nev++
- case proc.Signal:
- // TODO(austin)
- //nev++;
- }
- }
- }
-
- // Translate causes to events
- events := make([]Event, nev)
- i := 0
- for _, t := range p.proc.Threads() {
- if c, err := t.Stopped(); err == nil {
- switch c := c.(type) {
- case proc.Breakpoint:
- gt, err := p.osThreadToGoroutine(t)
- if err != nil {
- return nil, err
- }
- events[i] = &Breakpoint{commonEvent{p, gt}, t, proc.Word(c)}
- i++
- case proc.Signal:
- // TODO(austin)
- }
- }
- }
-
- return events, nil
-}
-
-// postEvent appends an event to the posted queue. These events will
-// be processed before any currently pending events.
-func (p *Process) postEvent(ev Event) {
- p.posted = append(p.posted, ev)
-}
-
-// processEvents processes events in the event queue until no events
-// remain, a handler returns EAStop, or a handler returns an error.
-// It returns either EAStop or EAContinue and possibly an error.
-func (p *Process) processEvents() (EventAction, os.Error) {
- var ev Event
- for len(p.posted) > 0 {
- ev, p.posted = p.posted[0], p.posted[1:]
- action, err := p.processEvent(ev)
- if action == EAStop {
- return action, err
- }
- }
-
- for len(p.pending) > 0 {
- ev, p.pending = p.pending[0], p.pending[1:]
- action, err := p.processEvent(ev)
- if action == EAStop {
- return action, err
- }
- }
-
- return EAContinue, nil
-}
-
-// processEvent processes a single event, without manipulating the
-// event queues. It returns either EAStop or EAContinue and possibly
-// an error.
-func (p *Process) processEvent(ev Event) (EventAction, os.Error) {
- p.event = ev
-
- var action EventAction
- var err os.Error
- switch ev := p.event.(type) {
- case *Breakpoint:
- hook, ok := p.breakpointHooks[ev.pc]
- if !ok {
- break
- }
- p.curGoroutine = ev.Goroutine()
- action, err = hook.handle(ev)
-
- case *GoroutineCreate:
- p.curGoroutine = ev.Goroutine()
- action, err = p.goroutineCreateHook.handle(ev)
-
- case *GoroutineExit:
- action, err = p.goroutineExitHook.handle(ev)
-
- default:
- log.Panicf("Unknown event type %T in queue", p.event)
- }
-
- if err != nil {
- return EAStop, err
- } else if action == EAStop {
- return EAStop, nil
- }
- return EAContinue, nil
-}
-
-// Event returns the last event that caused the process to stop. This
-// may return nil if the process has never been stopped by an event.
-//
-// TODO(austin) Return nil if the user calls p.Stop()?
-func (p *Process) Event() Event { return p.event }
-
-/*
- * Process control
- */
-
-// TODO(austin) Cont, WaitStop, and Stop. Need to figure out how
-// event handling works with these. Originally I did it only in
-// WaitStop, but if you Cont and there are pending events, then you
-// have to not actually continue and wait until a WaitStop to process
-// them, even if the event handlers will tell you to continue. We
-// could handle them in both Cont and WaitStop to avoid this problem,
-// but it's still weird if an event happens after the Cont and before
-// the WaitStop that the handlers say to continue from. Or we could
-// handle them on a separate thread. Then obviously you get weird
-// asynchronous things, like prints while the user it typing a command,
-// but that's not necessarily a bad thing.
-
-// ContWait resumes process execution and waits for an event to occur
-// that stops the process.
-func (p *Process) ContWait() os.Error {
- for {
- a, err := p.processEvents()
- if err != nil {
- return err
- } else if a == EAStop {
- break
- }
- err = p.proc.Continue()
- if err != nil {
- return err
- }
- err = p.proc.WaitStop()
- if err != nil {
- return err
- }
- for _, g := range p.goroutines {
- g.resetFrame()
- }
- p.pending, err = p.causesToEvents()
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-// Out selects the caller frame of the current frame.
-func (p *Process) Out() os.Error {
- if p.curGoroutine == nil {
- return NoCurrentGoroutine{}
- }
- return p.curGoroutine.Out()
-}
-
-// In selects the frame called by the current frame.
-func (p *Process) In() os.Error {
- if p.curGoroutine == nil {
- return NoCurrentGoroutine{}
- }
- return p.curGoroutine.In()
-}
diff --git a/src/pkg/exp/ogle/rruntime.go b/src/pkg/exp/ogle/rruntime.go
deleted file mode 100644
index 950418b53..000000000
--- a/src/pkg/exp/ogle/rruntime.go
+++ /dev/null
@@ -1,271 +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 ogle
-
-import (
- "debug/proc"
- "exp/eval"
- "reflect"
-)
-
-// This file contains remote runtime definitions. Using reflection,
-// we convert all of these to interpreter types and layout their
-// remote representations using the architecture rules.
-//
-// We could get most of these definitions from our own runtime
-// package; however, some of them differ in convenient ways, some of
-// them are not defined or exported by the runtime, and having our own
-// definitions makes it easy to support multiple remote runtime
-// versions. This may turn out to be overkill.
-//
-// All of these structures are prefixed with rt1 to indicate the
-// runtime version and to mark them as types used only as templates
-// for remote types.
-
-/*
- * Runtime data headers
- *
- * See $GOROOT/src/pkg/runtime/runtime.h
- */
-
-type rt1String struct {
- str uintptr
- len int
-}
-
-type rt1Slice struct {
- array uintptr
- len int
- cap int
-}
-
-type rt1Eface struct {
- typ uintptr
- ptr uintptr
-}
-
-/*
- * Runtime type structures
- *
- * See $GOROOT/src/pkg/runtime/type.h and $GOROOT/src/pkg/runtime/type.go
- */
-
-type rt1UncommonType struct {
- name *string
- pkgPath *string
- //methods []method;
-}
-
-type rt1CommonType struct {
- size uintptr
- hash uint32
- alg, align, fieldAlign uint8
- string *string
- uncommonType *rt1UncommonType
-}
-
-type rt1Type struct {
- // While Type is technically an Eface, treating the
- // discriminator as an opaque pointer and taking advantage of
- // the commonType prologue on all Type's makes type parsing
- // much simpler.
- typ uintptr
- ptr *rt1CommonType
-}
-
-type rt1StructField struct {
- name *string
- pkgPath *string
- typ *rt1Type
- tag *string
- offset uintptr
-}
-
-type rt1StructType struct {
- rt1CommonType
- fields []rt1StructField
-}
-
-type rt1PtrType struct {
- rt1CommonType
- elem *rt1Type
-}
-
-type rt1SliceType struct {
- rt1CommonType
- elem *rt1Type
-}
-
-type rt1ArrayType struct {
- rt1CommonType
- elem *rt1Type
- len uintptr
-}
-
-/*
- * Runtime scheduler structures
- *
- * See $GOROOT/src/pkg/runtime/runtime.h
- */
-
-// Fields beginning with _ are only for padding
-
-type rt1Stktop struct {
- stackguard uintptr
- stackbase *rt1Stktop
- gobuf rt1Gobuf
- _args uint32
- _fp uintptr
-}
-
-type rt1Gobuf struct {
- sp uintptr
- pc uintptr
- g *rt1G
- r0 uintptr
-}
-
-type rt1G struct {
- _stackguard uintptr
- stackbase *rt1Stktop
- _defer uintptr
- sched rt1Gobuf
- _stack0 uintptr
- _entry uintptr
- alllink *rt1G
- _param uintptr
- status int16
- // Incomplete
-}
-
-var rt1GStatus = runtimeGStatus{
- Gidle: 0,
- Grunnable: 1,
- Grunning: 2,
- Gsyscall: 3,
- Gwaiting: 4,
- Gmoribund: 5,
- Gdead: 6,
-}
-
-// runtimeIndexes stores the indexes of fields in the runtime
-// structures. It is filled in using reflection, so the name of the
-// fields must match the names of the remoteType's in runtimeValues
-// exactly and the names of the index fields must be the capitalized
-// version of the names of the fields in the runtime structures above.
-type runtimeIndexes struct {
- String struct {
- Str, Len int
- }
- Slice struct {
- Array, Len, Cap int
- }
- Eface struct {
- Typ, Ptr int
- }
-
- UncommonType struct {
- Name, PkgPath int
- }
- CommonType struct {
- Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
- }
- Type struct {
- Typ, Ptr int
- }
- StructField struct {
- Name, PkgPath, Typ, Tag, Offset int
- }
- StructType struct {
- Fields int
- }
- PtrType struct {
- Elem int
- }
- SliceType struct {
- Elem int
- }
- ArrayType struct {
- Elem, Len int
- }
-
- Stktop struct {
- Stackguard, Stackbase, Gobuf int
- }
- Gobuf struct {
- Sp, Pc, G int
- }
- G struct {
- Stackbase, Sched, Status, Alllink int
- }
-}
-
-// Values of G status codes
-type runtimeGStatus struct {
- Gidle, Grunnable, Grunning, Gsyscall, Gwaiting, Gmoribund, Gdead int64
-}
-
-// runtimeValues stores the types and values that correspond to those
-// in the remote runtime package.
-type runtimeValues struct {
- // Runtime data headers
- String, Slice, Eface *remoteType
- // Runtime type structures
- Type, CommonType, UncommonType, StructField, StructType, PtrType,
- ArrayType, SliceType *remoteType
- // Runtime scheduler structures
- Stktop, Gobuf, G *remoteType
- // Addresses of *runtime.XType types. These are the
- // discriminators on the runtime.Type interface. We use local
- // reflection to fill these in from the remote symbol table,
- // so the names must match the runtime names.
- PBoolType,
- PUint8Type, PUint16Type, PUint32Type, PUint64Type, PUintType, PUintptrType,
- PInt8Type, PInt16Type, PInt32Type, PInt64Type, PIntType,
- PFloat32Type, PFloat64Type, PFloatType,
- PArrayType, PStringType, PStructType, PPtrType, PFuncType,
- PInterfaceType, PSliceType, PMapType, PChanType,
- PDotDotDotType, PUnsafePointerType proc.Word
- // G status values
- runtimeGStatus
-}
-
-// fillRuntimeIndexes fills a runtimeIndexes structure will the field
-// indexes gathered from the remoteTypes recorded in a runtimeValues
-// structure.
-func fillRuntimeIndexes(runtime *runtimeValues, out *runtimeIndexes) {
- outv := reflect.Indirect(reflect.ValueOf(out))
- outt := outv.Type()
- runtimev := reflect.Indirect(reflect.ValueOf(runtime))
-
- // out contains fields corresponding to each runtime type
- for i := 0; i < outt.NumField(); i++ {
- // Find the interpreter type for this runtime type
- name := outt.Field(i).Name
- et := runtimev.FieldByName(name).Interface().(*remoteType).Type.(*eval.StructType)
-
- // Get the field indexes of the interpreter struct type
- indexes := make(map[string]int, len(et.Elems))
- for j, f := range et.Elems {
- if f.Anonymous {
- continue
- }
- name := f.Name
- if name[0] >= 'a' && name[0] <= 'z' {
- name = string(name[0]+'A'-'a') + name[1:]
- }
- indexes[name] = j
- }
-
- // Fill this field of out
- outStructv := outv.Field(i)
- outStructt := outStructv.Type()
- for j := 0; j < outStructt.NumField(); j++ {
- f := outStructv.Field(j)
- name := outStructt.Field(j).Name
- f.SetInt(int64(indexes[name]))
- }
- }
-}
diff --git a/src/pkg/exp/ogle/rtype.go b/src/pkg/exp/ogle/rtype.go
deleted file mode 100644
index b3c35575a..000000000
--- a/src/pkg/exp/ogle/rtype.go
+++ /dev/null
@@ -1,288 +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 ogle
-
-import (
- "debug/proc"
- "exp/eval"
- "fmt"
- "log"
-)
-
-const debugParseRemoteType = false
-
-// A remoteType is the local representation of a type in a remote process.
-type remoteType struct {
- eval.Type
- // The size of values of this type in bytes.
- size int
- // The field alignment of this type. Only used for
- // manually-constructed types.
- fieldAlign int
- // The maker function to turn a remote address of a value of
- // this type into an interpreter Value.
- mk maker
-}
-
-var manualTypes = make(map[Arch]map[eval.Type]*remoteType)
-
-// newManualType constructs a remote type from an interpreter Type
-// using the size and alignment properties of the given architecture.
-// Most types are parsed directly out of the remote process, but to do
-// so we need to layout the structures that describe those types ourselves.
-func newManualType(t eval.Type, arch Arch) *remoteType {
- if nt, ok := t.(*eval.NamedType); ok {
- t = nt.Def
- }
-
- // Get the type map for this architecture
- typeMap := manualTypes[arch]
- if typeMap == nil {
- typeMap = make(map[eval.Type]*remoteType)
- manualTypes[arch] = typeMap
-
- // Construct basic types for this architecture
- basicType := func(t eval.Type, mk maker, size int, fieldAlign int) {
- t = t.(*eval.NamedType).Def
- if fieldAlign == 0 {
- fieldAlign = size
- }
- typeMap[t] = &remoteType{t, size, fieldAlign, mk}
- }
- basicType(eval.Uint8Type, mkUint8, 1, 0)
- basicType(eval.Uint32Type, mkUint32, 4, 0)
- basicType(eval.UintptrType, mkUintptr, arch.PtrSize(), 0)
- basicType(eval.Int16Type, mkInt16, 2, 0)
- basicType(eval.Int32Type, mkInt32, 4, 0)
- basicType(eval.IntType, mkInt, arch.IntSize(), 0)
- basicType(eval.StringType, mkString, arch.PtrSize()+arch.IntSize(), arch.PtrSize())
- }
-
- if rt, ok := typeMap[t]; ok {
- return rt
- }
-
- var rt *remoteType
- switch t := t.(type) {
- case *eval.PtrType:
- var elem *remoteType
- mk := func(r remote) eval.Value { return remotePtr{r, elem} }
- rt = &remoteType{t, arch.PtrSize(), arch.PtrSize(), mk}
- // Construct the element type after registering the
- // type to break cycles.
- typeMap[eval.Type(t)] = rt
- elem = newManualType(t.Elem, arch)
-
- case *eval.ArrayType:
- elem := newManualType(t.Elem, arch)
- mk := func(r remote) eval.Value { return remoteArray{r, t.Len, elem} }
- rt = &remoteType{t, elem.size * int(t.Len), elem.fieldAlign, mk}
-
- case *eval.SliceType:
- elem := newManualType(t.Elem, arch)
- mk := func(r remote) eval.Value { return remoteSlice{r, elem} }
- rt = &remoteType{t, arch.PtrSize() + 2*arch.IntSize(), arch.PtrSize(), mk}
-
- case *eval.StructType:
- layout := make([]remoteStructField, len(t.Elems))
- offset := 0
- fieldAlign := 0
- for i, f := range t.Elems {
- elem := newManualType(f.Type, arch)
- if fieldAlign == 0 {
- fieldAlign = elem.fieldAlign
- }
- offset = arch.Align(offset, elem.fieldAlign)
- layout[i].offset = offset
- layout[i].fieldType = elem
- offset += elem.size
- }
- mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
- rt = &remoteType{t, offset, fieldAlign, mk}
-
- default:
- log.Panicf("cannot manually construct type %T", t)
- }
-
- typeMap[t] = rt
- return rt
-}
-
-var prtIndent = ""
-
-// parseRemoteType parses a Type structure in a remote process to
-// construct the corresponding interpreter type and remote type.
-func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
- addr := rs.addr().base
- p := rs.addr().p
-
- // We deal with circular types by discovering cycles at
- // NamedTypes. If a type cycles back to something other than
- // a named type, we're guaranteed that there will be a named
- // type somewhere in that cycle. Thus, we continue down,
- // re-parsing types until we reach the named type in the
- // cycle. In order to still create one remoteType per remote
- // type, we insert an empty remoteType in the type map the
- // first time we encounter the type and re-use that structure
- // the second time we encounter it.
-
- rt, ok := p.types[addr]
- if ok && rt.Type != nil {
- return rt
- } else if !ok {
- rt = &remoteType{}
- p.types[addr] = rt
- }
-
- if debugParseRemoteType {
- sym := p.syms.SymByAddr(uint64(addr))
- name := "<unknown>"
- if sym != nil {
- name = sym.Name
- }
- log.Printf("%sParsing type at %#x (%s)", prtIndent, addr, name)
- prtIndent += " "
- defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }()
- }
-
- // Get Type header
- 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?
- var nt *eval.NamedType
- uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a)
- if uncommon != nil {
- name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a)
- if name != nil {
- // TODO(austin) Declare type in appropriate remote package
- nt = eval.NewNamedType(name.(remoteString).aGet(a))
- rt.Type = nt
- }
- }
-
- // Create type
- var t eval.Type
- var mk maker
- switch itype {
- case p.runtime.PBoolType:
- t = eval.BoolType
- mk = mkBool
- case p.runtime.PUint8Type:
- t = eval.Uint8Type
- mk = mkUint8
- case p.runtime.PUint16Type:
- t = eval.Uint16Type
- mk = mkUint16
- case p.runtime.PUint32Type:
- t = eval.Uint32Type
- mk = mkUint32
- case p.runtime.PUint64Type:
- t = eval.Uint64Type
- mk = mkUint64
- case p.runtime.PUintType:
- t = eval.UintType
- mk = mkUint
- case p.runtime.PUintptrType:
- t = eval.UintptrType
- mk = mkUintptr
- case p.runtime.PInt8Type:
- t = eval.Int8Type
- mk = mkInt8
- case p.runtime.PInt16Type:
- t = eval.Int16Type
- mk = mkInt16
- case p.runtime.PInt32Type:
- t = eval.Int32Type
- mk = mkInt32
- case p.runtime.PInt64Type:
- t = eval.Int64Type
- mk = mkInt64
- case p.runtime.PIntType:
- t = eval.IntType
- mk = mkInt
- case p.runtime.PFloat32Type:
- t = eval.Float32Type
- mk = mkFloat32
- case p.runtime.PFloat64Type:
- t = eval.Float64Type
- mk = mkFloat64
- case p.runtime.PStringType:
- t = eval.StringType
- mk = mkString
-
- case p.runtime.PArrayType:
- // Cast to an ArrayType
- typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct)
- len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a))
- elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct))
- t = eval.NewArrayType(len, elem.Type)
- mk = func(r remote) eval.Value { return remoteArray{r, len, elem} }
-
- case p.runtime.PStructType:
- // Cast to a StructType
- typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct)
- fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a)
-
- fields := make([]eval.StructField, fs.Len)
- layout := make([]remoteStructField, fs.Len)
- for i := range fields {
- f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct)
- elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct)
- elem := parseRemoteType(a, elemrs)
- fields[i].Type = elem.Type
- name := f.field(p.f.StructField.Name).(remotePtr).aGet(a)
- if name == nil {
- fields[i].Anonymous = true
- } else {
- fields[i].Name = name.(remoteString).aGet(a)
- }
- layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a))
- layout[i].fieldType = elem
- }
-
- t = eval.NewStructType(fields)
- mk = func(r remote) eval.Value { return remoteStruct{r, layout} }
-
- case p.runtime.PPtrType:
- // Cast to a PtrType
- typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct)
- elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct))
- t = eval.NewPtrType(elem.Type)
- mk = func(r remote) eval.Value { return remotePtr{r, elem} }
-
- case p.runtime.PSliceType:
- // Cast to a SliceType
- typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct)
- elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct))
- t = eval.NewSliceType(elem.Type)
- mk = func(r remote) eval.Value { return remoteSlice{r, elem} }
-
- case p.runtime.PMapType, p.runtime.PChanType, p.runtime.PFuncType, p.runtime.PInterfaceType, p.runtime.PUnsafePointerType, p.runtime.PDotDotDotType:
- // TODO(austin)
- t = eval.UintptrType
- mk = mkUintptr
-
- default:
- sym := p.syms.SymByAddr(uint64(itype))
- name := "<unknown symbol>"
- if sym != nil {
- name = sym.Name
- }
- err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name)
- a.Abort(FormatError(err))
- }
-
- // Fill in the remote type
- if nt != nil {
- nt.Complete(t)
- } else {
- rt.Type = t
- }
- rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a))
- rt.mk = mk
-
- return rt
-}
diff --git a/src/pkg/exp/ogle/rvalue.go b/src/pkg/exp/ogle/rvalue.go
deleted file mode 100644
index 3d630f936..000000000
--- a/src/pkg/exp/ogle/rvalue.go
+++ /dev/null
@@ -1,515 +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 ogle
-
-import (
- "debug/proc"
- "exp/eval"
- "fmt"
-)
-
-// A RemoteMismatchError occurs when an operation that requires two
-// identical remote processes is given different process. For
-// example, this occurs when trying to set a pointer in one process to
-// point to something in another process.
-type RemoteMismatchError string
-
-func (e RemoteMismatchError) String() string { 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
-
-type remoteValue interface {
- addr() remote
-}
-
-// remote represents an address in a remote process.
-type remote struct {
- base proc.Word
- p *Process
-}
-
-func (v remote) Get(a aborter, size int) uint64 {
- // TODO(austin) This variable might temporarily be in a
- // register. We could trace the assembly back from the
- // current PC, looking for the beginning of the function or a
- // call (both of which guarantee that the variable is in
- // memory), or an instruction that loads the variable into a
- // register.
- //
- // TODO(austin) If this is a local variable, it might not be
- // live at this PC. In fact, because the compiler reuses
- // slots, there might even be a different local variable at
- // this location right now. A simple solution to both
- // problems is to include the range of PC's over which a local
- // variable is live in the symbol table.
- //
- // TODO(austin) We need to prevent the remote garbage
- // collector from collecting objects out from under us.
- var arr [8]byte
- buf := arr[0:size]
- _, err := v.p.Peek(v.base, buf)
- if err != nil {
- a.Abort(err)
- }
- return uint64(v.p.ToWord(buf))
-}
-
-func (v remote) Set(a aborter, size int, x uint64) {
- var arr [8]byte
- buf := arr[0:size]
- 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 proc.Word) remote { return remote{v.base + x, v.p} }
-
-func tryRVString(f func(a aborter) string) string {
- var s string
- err := try(func(a aborter) { s = f(a) })
- if err != nil {
- return fmt.Sprintf("<error: %v>", err)
- }
- return s
-}
-
-/*
- * Bool
- */
-
-type remoteBool struct {
- r remote
-}
-
-func (v remoteBool) String() string {
- return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteBool) Assign(t *eval.Thread, o eval.Value) {
- v.Set(t, o.(eval.BoolValue).Get(t))
-}
-
-func (v remoteBool) Get(t *eval.Thread) bool { return v.aGet(t) }
-
-func (v remoteBool) aGet(a aborter) bool { return v.r.Get(a, 1) != 0 }
-
-func (v remoteBool) Set(t *eval.Thread, x bool) {
- v.aSet(t, x)
-}
-
-func (v remoteBool) aSet(a aborter, x bool) {
- if x {
- v.r.Set(a, 1, 1)
- } else {
- v.r.Set(a, 1, 0)
- }
-}
-
-func (v remoteBool) addr() remote { return v.r }
-
-func mkBool(r remote) eval.Value { return remoteBool{r} }
-
-/*
- * Uint
- */
-
-type remoteUint struct {
- r remote
- size int
-}
-
-func (v remoteUint) String() string {
- return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteUint) Assign(t *eval.Thread, o eval.Value) {
- v.Set(t, o.(eval.UintValue).Get(t))
-}
-
-func (v remoteUint) Get(t *eval.Thread) uint64 {
- return v.aGet(t)
-}
-
-func (v remoteUint) aGet(a aborter) uint64 { return v.r.Get(a, v.size) }
-
-func (v remoteUint) Set(t *eval.Thread, x uint64) {
- v.aSet(t, x)
-}
-
-func (v remoteUint) aSet(a aborter, x uint64) { v.r.Set(a, v.size, x) }
-
-func (v remoteUint) addr() remote { return v.r }
-
-func mkUint8(r remote) eval.Value { return remoteUint{r, 1} }
-
-func mkUint16(r remote) eval.Value { return remoteUint{r, 2} }
-
-func mkUint32(r remote) eval.Value { return remoteUint{r, 4} }
-
-func mkUint64(r remote) eval.Value { return remoteUint{r, 8} }
-
-func mkUint(r remote) eval.Value { return remoteUint{r, r.p.IntSize()} }
-
-func mkUintptr(r remote) eval.Value { return remoteUint{r, r.p.PtrSize()} }
-
-/*
- * Int
- */
-
-type remoteInt struct {
- r remote
- size int
-}
-
-func (v remoteInt) String() string {
- return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteInt) Assign(t *eval.Thread, o eval.Value) {
- v.Set(t, o.(eval.IntValue).Get(t))
-}
-
-func (v remoteInt) Get(t *eval.Thread) int64 { return v.aGet(t) }
-
-func (v remoteInt) aGet(a aborter) int64 { return int64(v.r.Get(a, v.size)) }
-
-func (v remoteInt) Set(t *eval.Thread, x int64) {
- v.aSet(t, x)
-}
-
-func (v remoteInt) aSet(a aborter, x int64) { v.r.Set(a, v.size, uint64(x)) }
-
-func (v remoteInt) addr() remote { return v.r }
-
-func mkInt8(r remote) eval.Value { return remoteInt{r, 1} }
-
-func mkInt16(r remote) eval.Value { return remoteInt{r, 2} }
-
-func mkInt32(r remote) eval.Value { return remoteInt{r, 4} }
-
-func mkInt64(r remote) eval.Value { return remoteInt{r, 8} }
-
-func mkInt(r remote) eval.Value { return remoteInt{r, r.p.IntSize()} }
-
-/*
- * Float
- */
-
-type remoteFloat struct {
- r remote
- size int
-}
-
-func (v remoteFloat) String() string {
- return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
-}
-
-func (v remoteFloat) Assign(t *eval.Thread, o eval.Value) {
- v.Set(t, o.(eval.FloatValue).Get(t))
-}
-
-func (v remoteFloat) Get(t *eval.Thread) float64 {
- return v.aGet(t)
-}
-
-func (v remoteFloat) aGet(a aborter) float64 {
- bits := v.r.Get(a, v.size)
- switch v.size {
- case 4:
- return float64(v.r.p.ToFloat32(uint32(bits)))
- case 8:
- return v.r.p.ToFloat64(bits)
- }
- panic("Unexpected float size")
-}
-
-func (v remoteFloat) Set(t *eval.Thread, x float64) {
- v.aSet(t, x)
-}
-
-func (v remoteFloat) aSet(a aborter, x float64) {
- var bits uint64
- switch v.size {
- case 4:
- bits = uint64(v.r.p.FromFloat32(float32(x)))
- case 8:
- bits = v.r.p.FromFloat64(x)
- default:
- panic("Unexpected float size")
- }
- v.r.Set(a, v.size, bits)
-}
-
-func (v remoteFloat) addr() remote { return v.r }
-
-func mkFloat32(r remote) eval.Value { return remoteFloat{r, 4} }
-
-func mkFloat64(r remote) eval.Value { return remoteFloat{r, 8} }
-
-func mkFloat(r remote) eval.Value { return remoteFloat{r, r.p.FloatSize()} }
-
-/*
- * String
- */
-
-type remoteString struct {
- r remote
-}
-
-func (v remoteString) String() string {
- return tryRVString(func(a aborter) string { return v.aGet(a) })
-}
-
-func (v remoteString) Assign(t *eval.Thread, o eval.Value) {
- v.Set(t, o.(eval.StringValue).Get(t))
-}
-
-func (v remoteString) Get(t *eval.Thread) string {
- return v.aGet(t)
-}
-
-func (v remoteString) aGet(a aborter) string {
- rs := v.r.p.runtime.String.mk(v.r).(remoteStruct)
- 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 {
- a.Abort(err)
- }
- return string(bytes)
-}
-
-func (v remoteString) Set(t *eval.Thread, x string) {
- v.aSet(t, x)
-}
-
-func (v remoteString) aSet(a aborter, x string) {
- // TODO(austin) This isn't generally possible without the
- // ability to allocate remote memory.
- a.Abort(ReadOnlyError("remote strings cannot be assigned to"))
-}
-
-func mkString(r remote) eval.Value { return remoteString{r} }
-
-/*
- * Array
- */
-
-type remoteArray struct {
- r remote
- len int64
- elemType *remoteType
-}
-
-func (v remoteArray) String() string {
- res := "{"
- for i := int64(0); i < v.len; i++ {
- if i > 0 {
- res += ", "
- }
- res += v.elem(i).String()
- }
- return res + "}"
-}
-
-func (v remoteArray) Assign(t *eval.Thread, o eval.Value) {
- // TODO(austin) Could do a bigger memcpy if o is a
- // remoteArray in the same Process.
- oa := o.(eval.ArrayValue)
- for i := int64(0); i < v.len; i++ {
- v.Elem(t, i).Assign(t, oa.Elem(t, i))
- }
-}
-
-func (v remoteArray) Get(t *eval.Thread) eval.ArrayValue {
- return v
-}
-
-func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value {
- return v.elem(i)
-}
-
-func (v remoteArray) elem(i int64) eval.Value {
- 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(proc.Word(int64(v.elemType.size) * i)), len, v.elemType}
-}
-
-/*
- * Struct
- */
-
-type remoteStruct struct {
- r remote
- layout []remoteStructField
-}
-
-type remoteStructField struct {
- offset int
- fieldType *remoteType
-}
-
-func (v remoteStruct) String() string {
- res := "{"
- for i := range v.layout {
- if i > 0 {
- res += ", "
- }
- res += v.field(i).String()
- }
- return res + "}"
-}
-
-func (v remoteStruct) Assign(t *eval.Thread, o eval.Value) {
- // TODO(austin) Could do a bigger memcpy.
- oa := o.(eval.StructValue)
- l := len(v.layout)
- for i := 0; i < l; i++ {
- v.Field(t, i).Assign(t, oa.Field(t, i))
- }
-}
-
-func (v remoteStruct) Get(t *eval.Thread) eval.StructValue {
- return v
-}
-
-func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value {
- return v.field(i)
-}
-
-func (v remoteStruct) field(i int) eval.Value {
- f := &v.layout[i]
- return f.fieldType.mk(v.r.plus(proc.Word(f.offset)))
-}
-
-func (v remoteStruct) addr() remote { return v.r }
-
-/*
- * Pointer
- */
-
-// TODO(austin) Comparing two remote pointers for equality in the
-// interpreter will crash it because the Value's returned from
-// remotePtr.Get() will be structs.
-
-type remotePtr struct {
- r remote
- elemType *remoteType
-}
-
-func (v remotePtr) String() string {
- return tryRVString(func(a aborter) string {
- e := v.aGet(a)
- if e == nil {
- return "<nil>"
- }
- return "&" + e.String()
- })
-}
-
-func (v remotePtr) Assign(t *eval.Thread, o eval.Value) {
- v.Set(t, o.(eval.PtrValue).Get(t))
-}
-
-func (v remotePtr) Get(t *eval.Thread) eval.Value {
- return v.aGet(t)
-}
-
-func (v remotePtr) aGet(a aborter) eval.Value {
- addr := proc.Word(v.r.Get(a, v.r.p.PtrSize()))
- if addr == 0 {
- return nil
- }
- return v.elemType.mk(remote{addr, v.r.p})
-}
-
-func (v remotePtr) Set(t *eval.Thread, x eval.Value) {
- v.aSet(t, x)
-}
-
-func (v remotePtr) aSet(a aborter, x eval.Value) {
- if x == nil {
- v.r.Set(a, v.r.p.PtrSize(), 0)
- return
- }
- xr, ok := x.(remoteValue)
- if !ok || v.r.p != xr.addr().p {
- a.Abort(RemoteMismatchError("remote pointer must point within the same process"))
- }
- v.r.Set(a, v.r.p.PtrSize(), uint64(xr.addr().base))
-}
-
-func (v remotePtr) addr() remote { return v.r }
-
-/*
- * Slice
- */
-
-type remoteSlice struct {
- r remote
- elemType *remoteType
-}
-
-func (v remoteSlice) String() string {
- return tryRVString(func(a aborter) string {
- b := v.aGet(a).Base
- if b == nil {
- return "<nil>"
- }
- return b.String()
- })
-}
-
-func (v remoteSlice) Assign(t *eval.Thread, o eval.Value) {
- v.Set(t, o.(eval.SliceValue).Get(t))
-}
-
-func (v remoteSlice) Get(t *eval.Thread) eval.Slice {
- return v.aGet(t)
-}
-
-func (v remoteSlice) aGet(a aborter) eval.Slice {
- rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
- 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 {
- return eval.Slice{nil, nel, cap}
- }
- return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap}
-}
-
-func (v remoteSlice) Set(t *eval.Thread, x eval.Slice) {
- v.aSet(t, x)
-}
-
-func (v remoteSlice) aSet(a aborter, x eval.Slice) {
- rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
- if x.Base == nil {
- rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, 0)
- } else {
- ar, ok := x.Base.(remoteArray)
- if !ok || v.r.p != ar.r.p {
- a.Abort(RemoteMismatchError("remote slice must point within the same process"))
- }
- rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, uint64(ar.r.base))
- }
- rs.field(v.r.p.f.Slice.Len).(remoteInt).aSet(a, x.Len)
- rs.field(v.r.p.f.Slice.Cap).(remoteInt).aSet(a, x.Cap)
-}
diff --git a/src/pkg/exp/ogle/vars.go b/src/pkg/exp/ogle/vars.go
deleted file mode 100644
index 8a3a14791..000000000
--- a/src/pkg/exp/ogle/vars.go
+++ /dev/null
@@ -1,272 +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 ogle
-
-import (
- "debug/gosym"
- "debug/proc"
- "exp/eval"
- "log"
- "os"
-)
-
-/*
- * 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 *gosym.Func
- 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 *gosym.Func
- 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("fail")
-}
-
-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 {
- if s.ReceiverName() != "" {
- // TODO(austin)
- continue
- }
-
- // Package
- pkgName := s.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 := s.BaseName()
- if _, ok := pkg[name]; ok {
- log.Printf("Multiple definitions of symbol %s", s.Name)
- continue
- }
-
- // Symbol type
- rt, err := p.typeOfSym(&s)
- if err != nil {
- return err
- }
-
- // Definition
- switch s.Type {
- case 'D', 'd', 'B', 'b':
- // Global variable
- if rt == nil {
- continue
- }
- pkg[name] = def{rt.Type, rt.mk(remote{proc.Word(s.Value), p})}
-
- case 'T', 't', 'L', 'l':
- // Function
- s := s.Func
- // 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.Printf("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 *gosym.Sym) (*remoteType, os.Error) {
- if s.GoType == 0 {
- return nil, nil
- }
- addr := proc.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 *gosym.Func) (*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)
- 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)
- 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
-}