2009-07-09 18:10:12 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Package ptrace provides a platform-independent interface for
|
|
|
|
// tracing and controlling running processes. It supports
|
|
|
|
// multi-threaded processes and provides typical low-level debugging
|
|
|
|
// controls such as breakpoints, single stepping, and manipulating
|
|
|
|
// memory and registers.
|
|
|
|
package ptrace
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os";
|
|
|
|
"strconv";
|
|
|
|
)
|
|
|
|
|
|
|
|
type Word uint64
|
|
|
|
|
|
|
|
// A Cause explains why a thread is stopped.
|
|
|
|
type Cause interface {
|
|
|
|
String() string;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Regs is a set of named machine registers, including a program
|
|
|
|
// counter, link register, and stack pointer.
|
2009-07-14 16:12:10 -06:00
|
|
|
//
|
|
|
|
// 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.
|
2009-07-09 18:10:12 -06:00
|
|
|
type Regs interface {
|
|
|
|
// PC returns the value of the program counter.
|
|
|
|
PC() Word;
|
|
|
|
|
2009-07-14 16:12:10 -06:00
|
|
|
// SetPC sets the program counter to val.
|
|
|
|
SetPC(val Word) os.Error;
|
|
|
|
|
2009-07-09 18:10:12 -06:00
|
|
|
// Link returns the link register, if any.
|
|
|
|
Link() Word;
|
|
|
|
|
2009-07-14 16:12:10 -06:00
|
|
|
// SetLink sets the link register to val.
|
|
|
|
SetLink(val Word) os.Error;
|
|
|
|
|
2009-07-09 18:10:12 -06:00
|
|
|
// SP returns the value of the stack pointer.
|
|
|
|
SP() Word;
|
|
|
|
|
2009-07-14 16:12:10 -06:00
|
|
|
// SetSP sets the stack pointer register to val.
|
|
|
|
SetSP(val Word) os.Error;
|
|
|
|
|
2009-07-09 18:10:12 -06:00
|
|
|
// 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.
|
2009-07-14 16:12:10 -06:00
|
|
|
Set(i int, val Word) os.Error;
|
2009-07-09 18:10:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2009-07-14 16:12:10 -06:00
|
|
|
Threads() []Thread;
|
2009-07-09 18:10:12 -06:00
|
|
|
|
|
|
|
// 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
|
2009-07-14 16:12:10 -06:00
|
|
|
// of a signal (other than SIGSTOP or SIGTRAP) will receive
|
|
|
|
// the pending signal.
|
2009-07-09 18:10:12 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-07-14 16:12:10 -06:00
|
|
|
// Stopped is a stop cause used for threads that are stopped either by
|
2009-07-09 18:10:12 -06:00
|
|
|
// 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.
|
2009-07-14 16:12:10 -06:00
|
|
|
type Stopped struct {}
|
2009-07-09 18:10:12 -06:00
|
|
|
|
2009-07-14 16:12:10 -06:00
|
|
|
func (c Stopped) String() string {
|
|
|
|
return "stopped";
|
2009-07-09 18:10:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2009-08-21 16:54:54 -06:00
|
|
|
func (c *ThreadCreate) NewThread() Thread {
|
2009-07-09 18:10:12 -06:00
|
|
|
return c.thread;
|
|
|
|
}
|
|
|
|
|
2009-08-21 16:54:54 -06:00
|
|
|
func (c *ThreadCreate) String() string {
|
2009-07-09 18:10:12 -06:00
|
|
|
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;
|
2009-07-14 16:12:10 -06:00
|
|
|
signal string;
|
2009-07-09 18:10:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exited returns true if the thread exited normally.
|
2009-08-21 16:54:54 -06:00
|
|
|
func (c *ThreadExit) Exited() bool {
|
2009-07-09 18:10:12 -06:00
|
|
|
return c.exitStatus != -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExitStatus returns the exit status of the thread if it exited
|
|
|
|
// normally or -1 otherwise.
|
2009-08-21 16:54:54 -06:00
|
|
|
func (c *ThreadExit) ExitStatus() int {
|
2009-07-09 18:10:12 -06:00
|
|
|
return c.exitStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Signaled returns true if the thread was terminated by a signal.
|
2009-08-21 16:54:54 -06:00
|
|
|
func (c *ThreadExit) Signaled() bool {
|
2009-07-14 16:12:10 -06:00
|
|
|
return c.exitStatus == -1;
|
2009-07-09 18:10:12 -06:00
|
|
|
}
|
|
|
|
|
2009-07-14 16:12:10 -06:00
|
|
|
// StopSignal returns the signal that terminated the thread, or "" if
|
2009-07-09 18:10:12 -06:00
|
|
|
// it was not terminated by a signal.
|
2009-08-21 16:54:54 -06:00
|
|
|
func (c *ThreadExit) StopSignal() string {
|
2009-07-09 18:10:12 -06:00
|
|
|
return c.signal;
|
|
|
|
}
|
|
|
|
|
2009-08-21 16:54:54 -06:00
|
|
|
func (c *ThreadExit) String() string {
|
2009-07-09 18:10:12 -06:00
|
|
|
res := "thread exited ";
|
|
|
|
switch {
|
|
|
|
case c.Exited():
|
|
|
|
res += "with status " + strconv.Itoa(c.ExitStatus());
|
|
|
|
case c.Signaled():
|
2009-07-14 16:12:10 -06:00
|
|
|
res += "from signal " + c.StopSignal();
|
2009-07-09 18:10:12 -06:00
|
|
|
default:
|
|
|
|
res += "from unknown cause";
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|