// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ptrace provides a platform-independent interface for
// tracing and controlling running processes. It supports
// multi-threaded processes and provides typical low-level debugging
// controls such as breakpoints, single stepping, and manipulating
// memory and registers.
package proc
// TODO(rsc): Have to import everything that proc_linux.go
// and proc_darwin.go do, because deps.bash only looks at
// this file.
import (
_ "container/vector";
_ "fmt";
_ "io";
"os";
_ "runtime";
"strconv";
_ "strings";
_ "sync";
_ "syscall";
)
type Word uint64
// A Cause explains why a thread is stopped.
type Cause interface {
String() string;
}
// Regs is a set of named machine registers, including a program
// counter, link register, and stack pointer.
//
// TODO(austin) There's quite a proliferation of methods here. We
// could make a Reg interface with Get and Set and make this just PC,
// Link, SP, Names, and Reg. We could also put Index in Reg and that
// makes it easy to get the index of things like the PC (currently
// there's just no way to know that). This would also let us include
// other per-register information like how to print it.
type Regs interface {
// PC returns the value of the program counter.
PC() Word;
// SetPC sets the program counter to val.
SetPC(val Word) os.Error;
// Link returns the link register, if any.
Link() Word;
// SetLink sets the link register to val.
SetLink(val Word) os.Error;
// SP returns the value of the stack pointer.
SP() Word;
// SetSP sets the stack pointer register to val.
SetSP(val Word) os.Error;
// Names returns the names of all of the registers.
Names() []string;
// Get returns the value of a register, where i corresponds to
// the index of the register's name in the array returned by
// Names.
Get(i int) Word;
// Set sets the value of a register.
Set(i int, val Word) os.Error;
}
// Thread is a thread in the process being traced.
type Thread interface {
// Step steps this thread by a single instruction. The thread
// must be stopped. If the thread is currently stopped on a
// breakpoint, this will step over the breakpoint.
//
// XXX What if it's stopped because of a signal?
Step() os.Error;
// Stopped returns the reason that this thread is stopped. It
// is an error is the thread not stopped.
Stopped() (Cause, os.Error);
// Regs retrieves the current register values from this
// thread. The thread must be stopped.
Regs() (Regs, os.Error);
// Peek reads len(out) bytes from the address addr in this
// thread into out. The thread must be stopped. It returns
// the number of bytes successfully read. If an error occurs,
// such as attempting to read unmapped memory, this count
// could be short and an error will be returned. If this does
// encounter unmapped memory, it will read up to the byte
// preceding the unmapped area.
Peek(addr Word, out []byte) (int, os.Error);
// Poke writes b to the address addr in this thread. The
// thread must be stopped. It returns the number of bytes
// successfully written. If an error occurs, such as
// attempting to write to unmapped memory, this count could be
// short and an error will be returned. If this does
// encounter unmapped memory, it will write up to the byte
// preceding the unmapped area.
Poke(addr Word, b []byte) (int, os.Error);
}
// Process is a process being traced. It consists of a set of
// threads. A process can be running, stopped, or terminated. The
// process's state extends to all of its threads.
type Process interface {
// Threads returns an array of all threads in this process.
Threads() []Thread;
// AddBreakpoint creates a new breakpoint at program counter
// pc. Breakpoints can only be created when the process is
// stopped. It is an error if a breakpoint already exists at
// pc.
AddBreakpoint(pc Word) os.Error;
// RemoveBreakpoint removes the breakpoint at the program
// counter pc. It is an error if no breakpoint exists at pc.
RemoveBreakpoint(pc Word) os.Error;
// Stop stops all running threads in this process before
// returning.
Stop() os.Error;
// Continue resumes execution of all threads in this process.
// Any thread that is stopped on a breakpoint will be stepped
// over that breakpoint. Any thread that is stopped because
// of a signal (other than SIGSTOP or SIGTRAP) will receive
// the pending signal.
Continue() os.Error;
// WaitStop waits until all threads in process p are stopped
// as a result of some thread hitting a breakpoint, receiving
// a signal, creating a new thread, or exiting.
WaitStop() os.Error;
// Detach detaches from this process. All stopped threads
// will be resumed.
Detach() os.Error;
}
// Stopped is a stop cause used for threads that are stopped either by
// user request (e.g., from the Stop method or after single stepping),
// or that are stopped because some other thread caused the program to
// stop.
type Stopped struct{}
func (c Stopped) String() string { return "stopped" }
// Breakpoint is a stop cause resulting from a thread reaching a set
// breakpoint.
type Breakpoint Word
// PC returns the program counter that the program is stopped at.
func (c Breakpoint) PC() Word { return Word(c) }
func (c Breakpoint) String() string {
return "breakpoint at 0x" + strconv.Uitob64(uint64(c.PC()), 16)
}
// Signal is a stop cause resulting from a thread receiving a signal.
// When the process is continued, the signal will be delivered.
type Signal string
// Signal returns the signal being delivered to the thread.
func (c Signal) Name() string { return string(c) }
func (c Signal) String() string { return c.Name() }
// ThreadCreate is a stop cause returned from an existing thread when
// it creates a new thread. The new thread exists in a primordial
// form at this point and will begin executing in earnest when the
// process is continued.
type ThreadCreate struct {
thread Thread;
}
func (c *ThreadCreate) NewThread() Thread { return c.thread }
func (c *ThreadCreate) String() string { return "thread create" }
// ThreadExit is a stop cause resulting from a thread exiting. When
// this cause first arises, the thread will still be in the list of
// process threads and its registers and memory will still be
// accessible.
type ThreadExit struct {
exitStatus int;
signal string;
}
// Exited returns true if the thread exited normally.
func (c *ThreadExit) Exited() bool { return c.exitStatus != -1 }
// ExitStatus returns the exit status of the thread if it exited
// normally or -1 otherwise.
func (c *ThreadExit) ExitStatus() int { return c.exitStatus }
// Signaled returns true if the thread was terminated by a signal.
func (c *ThreadExit) Signaled() bool { return c.exitStatus == -1 }
// StopSignal returns the signal that terminated the thread, or "" if
// it was not terminated by a signal.
func (c *ThreadExit) StopSignal() string { return c.signal }
func (c *ThreadExit) String() string {
res := "thread exited ";
switch {
case c.Exited():
res += "with status " + strconv.Itoa(c.ExitStatus())
case c.Signaled():
res += "from signal " + c.StopSignal()
default:
res += "from unknown cause"
}
return res;
}
|