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
|
// 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
|
// 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) {
|
func Disassemble(dbp Process, g *G, startPC, endPC uint64) ([]AsmInstruction, error) {
|
||||||
|
if dbp.Exited() {
|
||||||
|
return nil, &ProcessExitedError{Pid: dbp.Pid()}
|
||||||
|
}
|
||||||
if g == nil {
|
if g == nil {
|
||||||
ct := dbp.CurrentThread()
|
ct := dbp.CurrentThread()
|
||||||
regs, _ := ct.Registers(false)
|
regs, _ := ct.Registers(false)
|
||||||
|
|||||||
@ -173,7 +173,7 @@ func (dbp *Process) LoadInformation(path string) error {
|
|||||||
// sends SIGSTOP to all threads.
|
// sends SIGSTOP to all threads.
|
||||||
func (dbp *Process) RequestManualStop() error {
|
func (dbp *Process) RequestManualStop() error {
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return &proc.ProcessExitedError{}
|
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
dbp.haltMu.Lock()
|
dbp.haltMu.Lock()
|
||||||
defer dbp.haltMu.Unlock()
|
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.
|
// ClearBreakpoint clears the breakpoint at addr.
|
||||||
func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return nil, &proc.ProcessExitedError{}
|
return nil, &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
bp, ok := dbp.FindBreakpoint(addr)
|
bp, ok := dbp.FindBreakpoint(addr)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -259,7 +259,7 @@ func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
|||||||
|
|
||||||
func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return nil, &proc.ProcessExitedError{}
|
return nil, &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dbp.resume(); err != nil {
|
if err := dbp.resume(); err != nil {
|
||||||
@ -307,7 +307,7 @@ func (dbp *Process) StepInstruction() (err error) {
|
|||||||
}
|
}
|
||||||
dbp.allGCache = nil
|
dbp.allGCache = nil
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return &proc.ProcessExitedError{}
|
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
thread.clearBreakpointState()
|
thread.clearBreakpointState()
|
||||||
err = thread.StepInstruction()
|
err = thread.StepInstruction()
|
||||||
@ -327,7 +327,7 @@ func (dbp *Process) StepInstruction() (err error) {
|
|||||||
// SwitchThread changes from current thread to the thread specified by `tid`.
|
// SwitchThread changes from current thread to the thread specified by `tid`.
|
||||||
func (dbp *Process) SwitchThread(tid int) error {
|
func (dbp *Process) SwitchThread(tid int) error {
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return &proc.ProcessExitedError{}
|
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
if th, ok := dbp.threads[tid]; ok {
|
if th, ok := dbp.threads[tid]; ok {
|
||||||
dbp.currentThread = th
|
dbp.currentThread = th
|
||||||
@ -341,7 +341,7 @@ func (dbp *Process) SwitchThread(tid int) error {
|
|||||||
// running the specified goroutine.
|
// running the specified goroutine.
|
||||||
func (dbp *Process) SwitchGoroutine(gid int) error {
|
func (dbp *Process) SwitchGoroutine(gid int) error {
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return &proc.ProcessExitedError{}
|
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
g, err := proc.FindGoroutine(dbp, gid)
|
g, err := proc.FindGoroutine(dbp, gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -361,7 +361,7 @@ func (dbp *Process) SwitchGoroutine(gid int) error {
|
|||||||
// Halt stops all threads.
|
// Halt stops all threads.
|
||||||
func (dbp *Process) Halt() (err error) {
|
func (dbp *Process) Halt() (err error) {
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return &proc.ProcessExitedError{}
|
return &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
for _, th := range dbp.threads {
|
for _, th := range dbp.threads {
|
||||||
if err := th.Halt(); err != nil {
|
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.
|
// Next continues execution until the next source line.
|
||||||
func Next(dbp Process) (err error) {
|
func Next(dbp Process) (err error) {
|
||||||
if dbp.Exited() {
|
if dbp.Exited() {
|
||||||
return &ProcessExitedError{}
|
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
for _, bp := range dbp.Breakpoints() {
|
for _, bp := range dbp.Breakpoints() {
|
||||||
if bp.Internal() {
|
if bp.Internal() {
|
||||||
@ -91,6 +91,9 @@ func Next(dbp Process) (err error) {
|
|||||||
// process. It will continue until it hits a breakpoint
|
// process. It will continue until it hits a breakpoint
|
||||||
// or is otherwise stopped.
|
// or is otherwise stopped.
|
||||||
func Continue(dbp Process) error {
|
func Continue(dbp Process) error {
|
||||||
|
if dbp.Exited() {
|
||||||
|
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||||
|
}
|
||||||
dbp.ManualStopRequested()
|
dbp.ManualStopRequested()
|
||||||
for {
|
for {
|
||||||
if dbp.ManualStopRequested() {
|
if dbp.ManualStopRequested() {
|
||||||
@ -213,7 +216,7 @@ func pickCurrentThread(dbp Process, trapthread Thread, threads []Thread) error {
|
|||||||
// Will step into functions.
|
// Will step into functions.
|
||||||
func Step(dbp Process) (err error) {
|
func Step(dbp Process) (err error) {
|
||||||
if dbp.Exited() {
|
if dbp.Exited() {
|
||||||
return &ProcessExitedError{}
|
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
for _, bp := range dbp.Breakpoints() {
|
for _, bp := range dbp.Breakpoints() {
|
||||||
if bp.Internal() {
|
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
|
// StepOut will continue until the current goroutine exits the
|
||||||
// function currently being executed or a deferred function is executed
|
// function currently being executed or a deferred function is executed
|
||||||
func StepOut(dbp Process) error {
|
func StepOut(dbp Process) error {
|
||||||
|
if dbp.Exited() {
|
||||||
|
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||||
|
}
|
||||||
selg := dbp.SelectedGoroutine()
|
selg := dbp.SelectedGoroutine()
|
||||||
curthread := dbp.CurrentThread()
|
curthread := dbp.CurrentThread()
|
||||||
|
|
||||||
@ -349,7 +355,7 @@ type AllGCache interface {
|
|||||||
// Delve cares about from the internal runtime G structure.
|
// Delve cares about from the internal runtime G structure.
|
||||||
func GoroutinesInfo(dbp Process) ([]*G, error) {
|
func GoroutinesInfo(dbp Process) ([]*G, error) {
|
||||||
if dbp.Exited() {
|
if dbp.Exited() {
|
||||||
return nil, &ProcessExitedError{}
|
return nil, &ProcessExitedError{Pid: dbp.Pid()}
|
||||||
}
|
}
|
||||||
if dbp, ok := dbp.(AllGCache); ok {
|
if dbp, ok := dbp.(AllGCache); ok {
|
||||||
if allGCache := dbp.AllGCache(); *allGCache != nil {
|
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
|
// ConvertEvalScope returns a new EvalScope in the context of the
|
||||||
// specified goroutine ID and stack frame.
|
// specified goroutine ID and stack frame.
|
||||||
func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) {
|
func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) {
|
||||||
|
if dbp.Exited() {
|
||||||
|
return nil, &ProcessExitedError{Pid: dbp.Pid()}
|
||||||
|
}
|
||||||
ct := dbp.CurrentThread()
|
ct := dbp.CurrentThread()
|
||||||
g, err := FindGoroutine(dbp, gid)
|
g, err := FindGoroutine(dbp, gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -42,7 +42,7 @@ type Stackframe struct {
|
|||||||
Err error
|
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.
|
// Note the locations in the array are return addresses not call addresses.
|
||||||
func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) {
|
func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) {
|
||||||
regs, err := thread.Registers(false)
|
regs, err := thread.Registers(false)
|
||||||
|
|||||||
@ -457,8 +457,9 @@ func (d *Debugger) Threads() ([]*api.Thread, error) {
|
|||||||
defer d.processMutex.Unlock()
|
defer d.processMutex.Unlock()
|
||||||
|
|
||||||
if d.target.Exited() {
|
if d.target.Exited() {
|
||||||
return nil, &proc.ProcessExitedError{}
|
return nil, proc.ProcessExitedError{Pid: d.ProcessPid()}
|
||||||
}
|
}
|
||||||
|
|
||||||
threads := []*api.Thread{}
|
threads := []*api.Thread{}
|
||||||
for _, th := range d.target.ThreadList() {
|
for _, th := range d.target.ThreadList() {
|
||||||
threads = append(threads, api.ConvertThread(th))
|
threads = append(threads, api.ConvertThread(th))
|
||||||
@ -472,7 +473,7 @@ func (d *Debugger) FindThread(id int) (*api.Thread, error) {
|
|||||||
defer d.processMutex.Unlock()
|
defer d.processMutex.Unlock()
|
||||||
|
|
||||||
if d.target.Exited() {
|
if d.target.Exited() {
|
||||||
return nil, &proc.ProcessExitedError{}
|
return nil, proc.ProcessExitedError{Pid: d.ProcessPid()}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, th := range d.target.ThreadList() {
|
for _, th := range d.target.ThreadList() {
|
||||||
@ -838,6 +839,10 @@ func (d *Debugger) Stacktrace(goroutineID, depth int, cfg *proc.LoadConfig) ([]a
|
|||||||
d.processMutex.Lock()
|
d.processMutex.Lock()
|
||||||
defer d.processMutex.Unlock()
|
defer d.processMutex.Unlock()
|
||||||
|
|
||||||
|
if d.target.Exited() {
|
||||||
|
return nil, proc.ProcessExitedError{Pid: d.ProcessPid()}
|
||||||
|
}
|
||||||
|
|
||||||
var rawlocs []proc.Stackframe
|
var rawlocs []proc.Stackframe
|
||||||
|
|
||||||
g, err := proc.FindGoroutine(d.target, goroutineID)
|
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()
|
d.processMutex.Lock()
|
||||||
defer d.processMutex.Unlock()
|
defer d.processMutex.Unlock()
|
||||||
|
|
||||||
|
if d.target.Exited() {
|
||||||
|
return nil, &proc.ProcessExitedError{Pid: d.target.Pid()}
|
||||||
|
}
|
||||||
|
|
||||||
loc, err := parseLocationSpec(locStr)
|
loc, err := parseLocationSpec(locStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -910,12 +919,16 @@ func (d *Debugger) FindLocation(scope api.EvalScope, locStr string) ([]api.Locat
|
|||||||
return locs, err
|
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
|
// 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) {
|
func (d *Debugger) Disassemble(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
|
||||||
d.processMutex.Lock()
|
d.processMutex.Lock()
|
||||||
defer d.processMutex.Unlock()
|
defer d.processMutex.Unlock()
|
||||||
|
|
||||||
|
if d.target.Exited() {
|
||||||
|
return nil, &proc.ProcessExitedError{Pid: d.target.Pid()}
|
||||||
|
}
|
||||||
|
|
||||||
if endPC == 0 {
|
if endPC == 0 {
|
||||||
_, _, fn := d.target.BinInfo().PCToLine(startPC)
|
_, _, fn := d.target.BinInfo().PCToLine(startPC)
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user