Improve documentation

This commit is contained in:
Derek Parker 2015-02-02 16:09:56 -05:00
parent e001bbfff2
commit aa8ad88965
3 changed files with 42 additions and 12 deletions

@ -36,6 +36,8 @@ type BreakPoint struct {
temp bool temp bool
} }
// Returned when trying to set a breakpoint at
// an address that already has a breakpoint set for it.
type BreakPointExistsError struct { type BreakPointExistsError struct {
file string file string
line int line int
@ -46,6 +48,16 @@ func (bpe BreakPointExistsError) Error() string {
return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.file, bpe.line, bpe.addr) return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.file, bpe.line, bpe.addr)
} }
// InvalidAddressError represents the result of
// attempting to set a breakpoint at an invalid address.
type InvalidAddressError struct {
address uint64
}
func (iae InvalidAddressError) Error() string {
return fmt.Sprintf("Invalid address %#v\n", iae.address)
}
func PtracePokeUser(tid int, off, addr uintptr) error { func PtracePokeUser(tid int, off, addr uintptr) error {
_, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_POKEUSR, uintptr(tid), uintptr(off), uintptr(addr), 0, 0) _, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_POKEUSR, uintptr(tid), uintptr(off), uintptr(addr), 0, 0)
if err != syscall.Errno(0) { if err != syscall.Errno(0) {
@ -63,6 +75,7 @@ func PtracePeekUser(tid int, off uintptr) (uintptr, error) {
return val, nil return val, nil
} }
// Returns whether or not a breakpoint has been set for the given address.
func (dbp *DebuggedProcess) BreakpointExists(addr uint64) bool { func (dbp *DebuggedProcess) BreakpointExists(addr uint64) bool {
for _, bp := range dbp.HWBreakPoints { for _, bp := range dbp.HWBreakPoints {
if bp != nil && bp.Addr == addr { if bp != nil && bp.Addr == addr {

@ -37,12 +37,15 @@ type DebuggedProcess struct {
halt bool halt bool
} }
// A ManualStopError happens when the user triggers a
// manual stop via SIGERM.
type ManualStopError struct{} type ManualStopError struct{}
func (mse ManualStopError) Error() string { func (mse ManualStopError) Error() string {
return "Manual stop requested" return "Manual stop requested"
} }
// Attach to an existing process with the given PID.
func Attach(pid int) (*DebuggedProcess, error) { func Attach(pid int) (*DebuggedProcess, error) {
dbp, err := newDebugProcess(pid, true) dbp, err := newDebugProcess(pid, true)
if err != nil { if err != nil {
@ -65,6 +68,9 @@ func Attach(pid int) (*DebuggedProcess, error) {
return dbp, nil return dbp, nil
} }
// Create and begin debugging a new process. First entry in
// `cmd` is the program to run, and then rest are the arguments
// to be supplied to that process.
func Launch(cmd []string) (*DebuggedProcess, error) { func Launch(cmd []string) (*DebuggedProcess, error) {
proc := exec.Command(cmd[0]) proc := exec.Command(cmd[0])
proc.Args = cmd proc.Args = cmd
@ -120,6 +126,8 @@ func newDebugProcess(pid int, attach bool) (*DebuggedProcess, error) {
return &dbp, nil return &dbp, nil
} }
// Attach to a newly created thread, and store that thread in our list of
// known threads.
func (dbp *DebuggedProcess) AttachThread(tid int) (*ThreadContext, error) { func (dbp *DebuggedProcess) AttachThread(tid int) (*ThreadContext, error) {
if thread, ok := dbp.Threads[tid]; ok { if thread, ok := dbp.Threads[tid]; ok {
return thread, nil return thread, nil
@ -146,6 +154,8 @@ func (dbp *DebuggedProcess) AttachThread(tid int) (*ThreadContext, error) {
return dbp.addThread(tid) return dbp.addThread(tid)
} }
// Returns whether or not Delve thinks the debugged
// process is currently executing.
func (dbp *DebuggedProcess) Running() bool { func (dbp *DebuggedProcess) Running() bool {
return dbp.running return dbp.running
} }
@ -204,6 +214,8 @@ func (dbp *DebuggedProcess) FindLocation(str string) (uint64, error) {
} }
} }
// Sends out a request that the debugged process halt
// execution. Sends SIGSTOP to all threads.
func (dbp *DebuggedProcess) RequestManualStop() { func (dbp *DebuggedProcess) RequestManualStop() {
dbp.halt = true dbp.halt = true
for _, th := range dbp.Threads { for _, th := range dbp.Threads {
@ -215,7 +227,8 @@ func (dbp *DebuggedProcess) RequestManualStop() {
dbp.running = false dbp.running = false
} }
// Sets a breakpoint in the current thread. // Sets a breakpoint, adding it to our list of known breakpoints. Uses
// the "current thread" when setting the breakpoint.
func (dbp *DebuggedProcess) Break(addr uint64) (*BreakPoint, error) { func (dbp *DebuggedProcess) Break(addr uint64) (*BreakPoint, error) {
return dbp.CurrentThread.Break(addr) return dbp.CurrentThread.Break(addr)
} }
@ -357,14 +370,6 @@ func (dbp *DebuggedProcess) Registers() (Registers, error) {
return dbp.CurrentThread.Registers() return dbp.CurrentThread.Registers()
} }
type InvalidAddressError struct {
address uint64
}
func (iae InvalidAddressError) Error() string {
return fmt.Sprintf("Invalid address %#v\n", iae.address)
}
func (dbp *DebuggedProcess) CurrentPC() (uint64, error) { func (dbp *DebuggedProcess) CurrentPC() (uint64, error) {
return dbp.CurrentThread.CurrentPC() return dbp.CurrentThread.CurrentPC()
} }

@ -3,19 +3,27 @@ package proctl
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
sys "golang.org/x/sys/unix" sys "golang.org/x/sys/unix"
"github.com/derekparker/delve/dwarf/frame" "github.com/derekparker/delve/dwarf/frame"
) )
// ThreadContext represents a single thread of execution in the // ThreadContext represents a single thread in the traced process
// traced program. // Id represents the thread id, Process holds a reference to the
// DebuggedProcess struct that contains info on the process as
// a whole, and Status represents the last result of a `wait` call
// on this thread.
type ThreadContext struct { type ThreadContext struct {
Id int Id int
Process *DebuggedProcess Process *DebuggedProcess
Status *sys.WaitStatus Status *sys.WaitStatus
} }
// An interface for a generic register type. The
// interface encapsulates the generic values / actions
// we need independant of arch. The concrete register types
// will be different depending on OS/Arch.
type Registers interface { type Registers interface {
PC() uint64 PC() uint64
SP() uint64 SP() uint64
@ -32,7 +40,7 @@ func (thread *ThreadContext) Registers() (Registers, error) {
return regs, nil return regs, nil
} }
// Returns the current PC for this thread id. // Returns the current PC for this thread.
func (thread *ThreadContext) CurrentPC() (uint64, error) { func (thread *ThreadContext) CurrentPC() (uint64, error) {
regs, err := thread.Registers() regs, err := thread.Registers()
if err != nil { if err != nil {
@ -76,6 +84,10 @@ func (thread *ThreadContext) Clear(addr uint64) (*BreakPoint, error) {
return thread.Process.clearBreakpoint(thread.Id, addr) return thread.Process.clearBreakpoint(thread.Id, addr)
} }
// Continue the execution of this thread. This method takes
// software breakpoints into consideration and ensures that
// we step over any breakpoints. It will restore the instruction,
// step, and then restore the breakpoint and continue.
func (thread *ThreadContext) Continue() error { func (thread *ThreadContext) Continue() error {
// Check whether we are stopped at a breakpoint, and // Check whether we are stopped at a breakpoint, and
// if so, single step over it before continuing. // if so, single step over it before continuing.