pkg/proc: return proper error when debugger has exited
Instead of panicing for sending on a closed channel, detect that the process has exited and return a proper error message. This patch also cleans up some spots where the Pid is omitted from the error. Fixes #920
This commit is contained in:
parent
d7a92b58ce
commit
cc63d209c1
@ -21,6 +21,9 @@ const (
|
||||
// If currentGoroutine is set and thread is stopped at a CALL instruction Disassemble will evaluate the argument of the CALL instruction using the thread's registers
|
||||
// Be aware that the Bytes field of each returned instruction is a slice of a larger array of size endPC - startPC
|
||||
func Disassemble(dbp Process, g *G, startPC, endPC uint64) ([]AsmInstruction, error) {
|
||||
if dbp.Exited() {
|
||||
return nil, &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
if g == nil {
|
||||
ct := dbp.CurrentThread()
|
||||
regs, _ := ct.Registers(false)
|
||||
|
@ -173,7 +173,7 @@ func (dbp *Process) LoadInformation(path string) error {
|
||||
// sends SIGSTOP to all threads.
|
||||
func (dbp *Process) RequestManualStop() error {
|
||||
if dbp.exited {
|
||||
return &proc.ProcessExitedError{}
|
||||
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
dbp.haltMu.Lock()
|
||||
defer dbp.haltMu.Unlock()
|
||||
@ -241,7 +241,7 @@ func (dbp *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond as
|
||||
// ClearBreakpoint clears the breakpoint at addr.
|
||||
func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||
if dbp.exited {
|
||||
return nil, &proc.ProcessExitedError{}
|
||||
return nil, &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
bp, ok := dbp.FindBreakpoint(addr)
|
||||
if !ok {
|
||||
@ -259,7 +259,7 @@ func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||
|
||||
func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
||||
if dbp.exited {
|
||||
return nil, &proc.ProcessExitedError{}
|
||||
return nil, &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
|
||||
if err := dbp.resume(); err != nil {
|
||||
@ -307,7 +307,7 @@ func (dbp *Process) StepInstruction() (err error) {
|
||||
}
|
||||
dbp.allGCache = nil
|
||||
if dbp.exited {
|
||||
return &proc.ProcessExitedError{}
|
||||
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
thread.clearBreakpointState()
|
||||
err = thread.StepInstruction()
|
||||
@ -327,7 +327,7 @@ func (dbp *Process) StepInstruction() (err error) {
|
||||
// SwitchThread changes from current thread to the thread specified by `tid`.
|
||||
func (dbp *Process) SwitchThread(tid int) error {
|
||||
if dbp.exited {
|
||||
return &proc.ProcessExitedError{}
|
||||
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
if th, ok := dbp.threads[tid]; ok {
|
||||
dbp.currentThread = th
|
||||
@ -341,7 +341,7 @@ func (dbp *Process) SwitchThread(tid int) error {
|
||||
// running the specified goroutine.
|
||||
func (dbp *Process) SwitchGoroutine(gid int) error {
|
||||
if dbp.exited {
|
||||
return &proc.ProcessExitedError{}
|
||||
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
g, err := proc.FindGoroutine(dbp, gid)
|
||||
if err != nil {
|
||||
@ -361,7 +361,7 @@ func (dbp *Process) SwitchGoroutine(gid int) error {
|
||||
// Halt stops all threads.
|
||||
func (dbp *Process) Halt() (err error) {
|
||||
if dbp.exited {
|
||||
return &proc.ProcessExitedError{}
|
||||
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
for _, th := range dbp.threads {
|
||||
if err := th.Halt(); err != nil {
|
||||
|
@ -71,7 +71,7 @@ func FindFunctionLocation(p Process, funcName string, firstLine bool, lineOffset
|
||||
// Next continues execution until the next source line.
|
||||
func Next(dbp Process) (err error) {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{}
|
||||
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
for _, bp := range dbp.Breakpoints() {
|
||||
if bp.Internal() {
|
||||
@ -91,6 +91,9 @@ func Next(dbp Process) (err error) {
|
||||
// process. It will continue until it hits a breakpoint
|
||||
// or is otherwise stopped.
|
||||
func Continue(dbp Process) error {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
dbp.ManualStopRequested()
|
||||
for {
|
||||
if dbp.ManualStopRequested() {
|
||||
@ -213,7 +216,7 @@ func pickCurrentThread(dbp Process, trapthread Thread, threads []Thread) error {
|
||||
// Will step into functions.
|
||||
func Step(dbp Process) (err error) {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{}
|
||||
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
for _, bp := range dbp.Breakpoints() {
|
||||
if bp.Internal() {
|
||||
@ -277,6 +280,9 @@ func andFrameoffCondition(cond ast.Expr, frameoff int64) ast.Expr {
|
||||
// StepOut will continue until the current goroutine exits the
|
||||
// function currently being executed or a deferred function is executed
|
||||
func StepOut(dbp Process) error {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
selg := dbp.SelectedGoroutine()
|
||||
curthread := dbp.CurrentThread()
|
||||
|
||||
@ -349,7 +355,7 @@ type AllGCache interface {
|
||||
// Delve cares about from the internal runtime G structure.
|
||||
func GoroutinesInfo(dbp Process) ([]*G, error) {
|
||||
if dbp.Exited() {
|
||||
return nil, &ProcessExitedError{}
|
||||
return nil, &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
if dbp, ok := dbp.(AllGCache); ok {
|
||||
if allGCache := dbp.AllGCache(); *allGCache != nil {
|
||||
@ -453,6 +459,9 @@ func FindGoroutine(dbp Process, gid int) (*G, error) {
|
||||
// ConvertEvalScope returns a new EvalScope in the context of the
|
||||
// specified goroutine ID and stack frame.
|
||||
func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) {
|
||||
if dbp.Exited() {
|
||||
return nil, &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
ct := dbp.CurrentThread()
|
||||
g, err := FindGoroutine(dbp, gid)
|
||||
if err != nil {
|
||||
|
@ -42,7 +42,7 @@ type Stackframe struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// Stacktrace returns the stack trace for thread.
|
||||
// ThreadStacktrace returns the stack trace for thread.
|
||||
// Note the locations in the array are return addresses not call addresses.
|
||||
func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) {
|
||||
regs, err := thread.Registers(false)
|
||||
|
@ -457,8 +457,9 @@ func (d *Debugger) Threads() ([]*api.Thread, error) {
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
if d.target.Exited() {
|
||||
return nil, &proc.ProcessExitedError{}
|
||||
return nil, proc.ProcessExitedError{Pid: d.ProcessPid()}
|
||||
}
|
||||
|
||||
threads := []*api.Thread{}
|
||||
for _, th := range d.target.ThreadList() {
|
||||
threads = append(threads, api.ConvertThread(th))
|
||||
@ -472,7 +473,7 @@ func (d *Debugger) FindThread(id int) (*api.Thread, error) {
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
if d.target.Exited() {
|
||||
return nil, &proc.ProcessExitedError{}
|
||||
return nil, proc.ProcessExitedError{Pid: d.ProcessPid()}
|
||||
}
|
||||
|
||||
for _, th := range d.target.ThreadList() {
|
||||
@ -838,6 +839,10 @@ func (d *Debugger) Stacktrace(goroutineID, depth int, cfg *proc.LoadConfig) ([]a
|
||||
d.processMutex.Lock()
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
if d.target.Exited() {
|
||||
return nil, proc.ProcessExitedError{Pid: d.ProcessPid()}
|
||||
}
|
||||
|
||||
var rawlocs []proc.Stackframe
|
||||
|
||||
g, err := proc.FindGoroutine(d.target, goroutineID)
|
||||
@ -893,6 +898,10 @@ func (d *Debugger) FindLocation(scope api.EvalScope, locStr string) ([]api.Locat
|
||||
d.processMutex.Lock()
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
if d.target.Exited() {
|
||||
return nil, &proc.ProcessExitedError{Pid: d.target.Pid()}
|
||||
}
|
||||
|
||||
loc, err := parseLocationSpec(locStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -910,12 +919,16 @@ func (d *Debugger) FindLocation(scope api.EvalScope, locStr string) ([]api.Locat
|
||||
return locs, err
|
||||
}
|
||||
|
||||
// Disassembles code between startPC and endPC
|
||||
// Disassemble code between startPC and endPC
|
||||
// if endPC == 0 it will find the function containing startPC and disassemble the whole function
|
||||
func (d *Debugger) Disassemble(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
|
||||
d.processMutex.Lock()
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
if d.target.Exited() {
|
||||
return nil, &proc.ProcessExitedError{Pid: d.target.Pid()}
|
||||
}
|
||||
|
||||
if endPC == 0 {
|
||||
_, _, fn := d.target.BinInfo().PCToLine(startPC)
|
||||
if fn == nil {
|
||||
|
Loading…
Reference in New Issue
Block a user