| // 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; |
| } |