提交 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) {
}
cmd := cmds.Find(cmdstr)
err = cmd(dbp, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
if err := cmd(dbp, args...); err != nil {
switch err.(type) {
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 {
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.
func Attach(pid int) (*DebuggedProcess, error) {
dbp, err := newDebugProcess(pid, true)
......@@ -238,7 +249,7 @@ func (dbp *DebuggedProcess) Continue() error {
}
fn := func() error {
wpid, _, err := trapWait(dbp, -1)
wpid, err := trapWait(dbp, -1)
if err != nil {
return err
}
......@@ -380,11 +391,3 @@ func (dbp *DebuggedProcess) run(fn func() error) error {
}
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) {
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)
if port == 0 {
return -1, nil, ProcessExitedError{}
return -1, ProcessExitedError{Pid: dbp.Pid}
}
dbp.updateThreadList()
return int(port), nil, nil
return int(port), nil
}
func wait(pid, options int) (int, *sys.WaitStatus, error) {
......
......@@ -223,11 +223,11 @@ func stopped(pid int) bool {
return false
}
func trapWait(dbp *DebuggedProcess, pid int) (int, *sys.WaitStatus, error) {
func trapWait(dbp *DebuggedProcess, pid int) (int, error) {
for {
wpid, status, err := wait(pid, 0)
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 {
continue
......@@ -235,38 +235,39 @@ func trapWait(dbp *DebuggedProcess, pid int) (int, *sys.WaitStatus, error) {
if th, ok := dbp.Threads[wpid]; ok {
th.Status = status
}
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 {
// A traced thread has cloned a new thread, grab the pid and
// add it to our list of traced threads.
cloned, err := sys.PtraceGetEventMsg(wpid)
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)
if err != nil {
return -1, nil, err
return -1, err
}
err = th.Continue()
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()
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
}
if status.StopSignal() == sys.SIGTRAP {
return wpid, status, nil
return wpid, nil
}
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) {
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) {
withTestProcess("../_fixtures/testprog", t, func(p *DebuggedProcess) {
helloworldfunc := p.GoSymTable.LookupFunc("main.helloworld")
......
......@@ -35,7 +35,7 @@ type Registers interface {
func (thread *ThreadContext) Registers() (Registers, error) {
regs, err := registers(thread)
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
}
......@@ -70,13 +70,13 @@ func (thread *ThreadContext) PrintInfo() error {
// we step over any breakpoints. It will restore the instruction,
// step, and then restore the breakpoint and continue.
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()
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 {
err := thread.Step()
if err != nil {
......@@ -195,7 +195,7 @@ func (thread *ThreadContext) continueToReturnAddress(pc uint64, fde *frame.Frame
return err
}
// 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 {
return err
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册