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