提交 8b04d877 编写于 作者: I Ivar Gaitan 提交者: Derek Parker

Handle process natural death a bit better

上级 f39e134d
...@@ -87,9 +87,14 @@ func Run(run bool, pid int, args []string) { ...@@ -87,9 +87,14 @@ func Run(run bool, pid int, args []string) {
} }
cmd := cmds.Find(cmdstr) cmd := cmds.Find(cmdstr)
err = cmd(dbp, args...) if err := cmd(dbp, args...); err != nil {
if err != nil { switch err.(type) {
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err) case proctl.ProcessExitedError:
pe := err.(proctl.ProcessExitedError)
fmt.Fprintf(os.Stderr, "Process exited with status %d\n", pe.Status)
default:
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
}
} }
} }
} }
......
...@@ -45,6 +45,17 @@ func (mse ManualStopError) Error() string { ...@@ -45,6 +45,17 @@ func (mse ManualStopError) Error() string {
return "Manual stop requested" return "Manual stop requested"
} }
// ProcessExitedError indicates that the process has exited and contains both
// process id and exit status.
type ProcessExitedError struct {
Pid int
Status int
}
func (pe ProcessExitedError) Error() string {
return fmt.Sprintf("process %d has exited with status %d", pe.Pid, pe.Status)
}
// Attach to an existing process with the given PID. // 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)
...@@ -238,7 +249,7 @@ func (dbp *DebuggedProcess) Continue() error { ...@@ -238,7 +249,7 @@ func (dbp *DebuggedProcess) Continue() error {
} }
fn := func() error { fn := func() error {
wpid, _, err := trapWait(dbp, -1) wpid, err := trapWait(dbp, -1)
if err != nil { if err != nil {
return err return err
} }
...@@ -380,11 +391,3 @@ func (dbp *DebuggedProcess) run(fn func() error) error { ...@@ -380,11 +391,3 @@ func (dbp *DebuggedProcess) run(fn func() error) error {
} }
return nil return nil
} }
type ProcessExitedError struct {
pid int
}
func (pe ProcessExitedError) Error() string {
return fmt.Sprintf("process %d has exited", pe.pid)
}
...@@ -172,14 +172,14 @@ func (dbp *DebuggedProcess) findExecutable() (*macho.File, error) { ...@@ -172,14 +172,14 @@ func (dbp *DebuggedProcess) findExecutable() (*macho.File, error) {
return macho.Open(C.GoString(pathptr)) return macho.Open(C.GoString(pathptr))
} }
func trapWait(dbp *DebuggedProcess, pid int) (int, *sys.WaitStatus, error) { func trapWait(dbp *DebuggedProcess, pid int) (int, error) {
port := C.mach_port_wait(dbp.os.exceptionPort) port := C.mach_port_wait(dbp.os.exceptionPort)
if port == 0 { if port == 0 {
return -1, nil, ProcessExitedError{} return -1, ProcessExitedError{Pid: dbp.Pid}
} }
dbp.updateThreadList() dbp.updateThreadList()
return int(port), nil, nil return int(port), nil
} }
func wait(pid, options int) (int, *sys.WaitStatus, error) { func wait(pid, options int) (int, *sys.WaitStatus, error) {
......
...@@ -223,11 +223,11 @@ func stopped(pid int) bool { ...@@ -223,11 +223,11 @@ func stopped(pid int) bool {
return false return false
} }
func trapWait(dbp *DebuggedProcess, pid int) (int, *sys.WaitStatus, error) { func trapWait(dbp *DebuggedProcess, pid int) (int, error) {
for { for {
wpid, status, err := wait(pid, 0) wpid, status, err := wait(pid, 0)
if err != nil { if err != nil {
return -1, nil, fmt.Errorf("wait err %s %d", err, pid) return -1, fmt.Errorf("wait err %s %d", err, pid)
} }
if wpid == 0 { if wpid == 0 {
continue continue
...@@ -235,38 +235,39 @@ func trapWait(dbp *DebuggedProcess, pid int) (int, *sys.WaitStatus, error) { ...@@ -235,38 +235,39 @@ func trapWait(dbp *DebuggedProcess, pid int) (int, *sys.WaitStatus, error) {
if th, ok := dbp.Threads[wpid]; ok { if th, ok := dbp.Threads[wpid]; ok {
th.Status = status th.Status = status
} }
if status.Exited() && wpid == dbp.Pid { if status.Exited() && wpid == dbp.Pid {
return -1, status, ProcessExitedError{wpid} return -1, ProcessExitedError{Pid: wpid, Status: status.ExitStatus()}
} }
if status.StopSignal() == sys.SIGTRAP && status.TrapCause() == sys.PTRACE_EVENT_CLONE { if status.StopSignal() == sys.SIGTRAP && status.TrapCause() == sys.PTRACE_EVENT_CLONE {
// A traced thread has cloned a new thread, grab the pid and // A traced thread has cloned a new thread, grab the pid and
// add it to our list of traced threads. // add it to our list of traced threads.
cloned, err := sys.PtraceGetEventMsg(wpid) cloned, err := sys.PtraceGetEventMsg(wpid)
if err != nil { if err != nil {
return -1, nil, fmt.Errorf("could not get event message: %s", err) return -1, fmt.Errorf("could not get event message: %s", err)
} }
th, err := dbp.addThread(int(cloned), false) th, err := dbp.addThread(int(cloned), false)
if err != nil { if err != nil {
return -1, nil, err return -1, err
} }
err = th.Continue() err = th.Continue()
if err != nil { if err != nil {
return -1, nil, fmt.Errorf("could not continue new thread %d %s", cloned, err) return -1, fmt.Errorf("could not continue new thread %d %s", cloned, err)
} }
err = dbp.Threads[int(wpid)].Continue() err = dbp.Threads[int(wpid)].Continue()
if err != nil { if err != nil {
return -1, nil, fmt.Errorf("could not continue new thread %d %s", cloned, err) return -1, fmt.Errorf("could not continue new thread %d %s", cloned, err)
} }
continue continue
} }
if status.StopSignal() == sys.SIGTRAP { if status.StopSignal() == sys.SIGTRAP {
return wpid, status, nil return wpid, nil
} }
if status.StopSignal() == sys.SIGSTOP && dbp.halt { if status.StopSignal() == sys.SIGSTOP && dbp.halt {
return -1, nil, ManualStopError{} return -1, ManualStopError{}
} }
} }
} }
......
...@@ -71,6 +71,22 @@ func currentLineNumber(p *DebuggedProcess, t *testing.T) (string, int) { ...@@ -71,6 +71,22 @@ func currentLineNumber(p *DebuggedProcess, t *testing.T) (string, int) {
return f, l return f, l
} }
func TestExit(t *testing.T) {
withTestProcess("../_fixtures/continuetestprog", t, func(p *DebuggedProcess) {
err := p.Continue()
pe, ok := err.(ProcessExitedError)
if !ok {
t.Fatalf("Continue() returned unexpected error type")
}
if pe.Status != 0 {
t.Errorf("Unexpected error status: %d", pe.Status)
}
if pe.Pid != p.Pid {
t.Errorf("Unexpected process id: %d", pe.Pid)
}
})
}
func TestStep(t *testing.T) { func TestStep(t *testing.T) {
withTestProcess("../_fixtures/testprog", t, func(p *DebuggedProcess) { withTestProcess("../_fixtures/testprog", t, func(p *DebuggedProcess) {
helloworldfunc := p.GoSymTable.LookupFunc("main.helloworld") helloworldfunc := p.GoSymTable.LookupFunc("main.helloworld")
......
...@@ -35,7 +35,7 @@ type Registers interface { ...@@ -35,7 +35,7 @@ type Registers interface {
func (thread *ThreadContext) Registers() (Registers, error) { func (thread *ThreadContext) Registers() (Registers, error) {
regs, err := registers(thread) regs, err := registers(thread)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not get registers %s", err) return nil, fmt.Errorf("could not get registers: %s", err)
} }
return regs, nil return regs, nil
} }
...@@ -70,13 +70,13 @@ func (thread *ThreadContext) PrintInfo() error { ...@@ -70,13 +70,13 @@ func (thread *ThreadContext) PrintInfo() error {
// we step over any breakpoints. It will restore the instruction, // we step over any breakpoints. It will restore the instruction,
// step, and then restore the breakpoint and continue. // 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
// if so, single step over it before continuing.
regs, err := thread.Registers() regs, err := thread.Registers()
if err != nil { if err != nil {
return fmt.Errorf("could not get registers %s", err) return err
} }
// Check whether we are stopped at a breakpoint, and
// if so, single step over it before continuing.
if _, ok := thread.Process.BreakPoints[regs.PC()-1]; ok { if _, ok := thread.Process.BreakPoints[regs.PC()-1]; ok {
err := thread.Step() err := thread.Step()
if err != nil { if err != nil {
...@@ -195,7 +195,7 @@ func (thread *ThreadContext) continueToReturnAddress(pc uint64, fde *frame.Frame ...@@ -195,7 +195,7 @@ func (thread *ThreadContext) continueToReturnAddress(pc uint64, fde *frame.Frame
return err return err
} }
// Wait on -1, just in case scheduler switches threads for this G. // Wait on -1, just in case scheduler switches threads for this G.
wpid, _, err := trapWait(thread.Process, -1) wpid, err := trapWait(thread.Process, -1)
if err != nil { if err != nil {
return err return err
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册