Two bugfixes regarding stale executable files, and executables changing between restarts (#689)

* service/debugger: Restore breakpoints using file:line on restart

Restoring by address can cause the breakpoint to be inserted in the
middle of an instruction if the executable file has changed.

* terminal: Warn of stale executable when printing source
This commit is contained in:
Alessandro Arzilli
2016-12-22 17:53:34 +01:00
committed by Derek Parker
parent 8f0646e426
commit f4aaffbbf3
12 changed files with 100 additions and 34 deletions

View File

@ -11,6 +11,7 @@ import (
"runtime"
"strings"
"sync"
"time"
"github.com/derekparker/delve/proc"
"github.com/derekparker/delve/service/api"
@ -81,6 +82,12 @@ func (d *Debugger) ProcessPid() int {
return d.process.Pid
}
// LastModified returns the time that the process' executable was last
// modified.
func (d *Debugger) LastModified() time.Time {
return d.process.LastModified
}
// Detach detaches from the target process.
// If `kill` is true we will kill the process after
// detaching.
@ -100,7 +107,7 @@ func (d *Debugger) detach(kill bool) error {
// Restart will restart the target process, first killing
// and then exec'ing it again.
func (d *Debugger) Restart() error {
func (d *Debugger) Restart() ([]api.DiscardedBreakpoint, error) {
d.processMutex.Lock()
defer d.processMutex.Unlock()
@ -110,30 +117,38 @@ func (d *Debugger) Restart() error {
}
// Ensure the process is in a PTRACE_STOP.
if err := stopProcess(d.ProcessPid()); err != nil {
return err
return nil, err
}
if err := d.detach(true); err != nil {
return err
return nil, err
}
}
p, err := proc.Launch(d.config.ProcessArgs, d.config.WorkingDir)
if err != nil {
return fmt.Errorf("could not launch process: %s", err)
return nil, fmt.Errorf("could not launch process: %s", err)
}
discarded := []api.DiscardedBreakpoint{}
for _, oldBp := range d.breakpoints() {
if oldBp.ID < 0 {
continue
}
if len(oldBp.File) > 0 {
oldBp.Addr, err = d.process.FindFileLocation(oldBp.File, oldBp.Line)
if err != nil {
discarded = append(discarded, api.DiscardedBreakpoint{oldBp, err})
continue
}
}
newBp, err := p.SetBreakpoint(oldBp.Addr, proc.UserBreakpoint, nil)
if err != nil {
return err
return nil, err
}
if err := copyBreakpointInfo(newBp, oldBp); err != nil {
return err
return nil, err
}
}
d.process = p
return nil
return discarded, nil
}
// State returns the current state of the debugger.