func (dbp *Process) trapWait(pid int) (*Thread, error) { for { wpid, status, err := wait(pid, dbp.Pid, 0) if err != nil { return nil, fmt.Errorf("wait err %s %d", err, pid) } if wpid == 0 { continue } th, ok := dbp.Threads[wpid] if ok { th.Status = status } if status.Exited() { if wpid == dbp.Pid { dbp.exited = true return nil, ProcessExitedError{Pid: wpid, Status: status.ExitStatus()} } delete(dbp.Threads, wpid) continue } 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. var cloned uint dbp.execPtraceFunc(func() { cloned, err = sys.PtraceGetEventMsg(wpid) }) if err != nil { return nil, fmt.Errorf("could not get event message: %s", err) } th, err = dbp.addThread(int(cloned), false) if err != nil { return nil, err } // Set all hardware breakpoints on the new thread. for _, bp := range dbp.Breakpoints { if !bp.hardware { continue } if err = dbp.setHardwareBreakpoint(bp.reg, th.Id, bp.Addr); err != nil { return nil, err } } if err = th.Continue(); err != nil { return nil, fmt.Errorf("could not continue new thread %d %s", cloned, err) } if err = dbp.Threads[int(wpid)].Continue(); err != nil { return nil, fmt.Errorf("could not continue existing thread %d %s", cloned, err) } continue } if th == nil { // Sometimes we get an unknown thread, ignore it? continue } if status.StopSignal() == sys.SIGTRAP && dbp.halt { th.running = false dbp.halt = false return th, nil } if status.StopSignal() == sys.SIGTRAP { th.running = false return dbp.handleBreakpointOnThread(wpid) } if th != nil { // TODO(dp) alert user about unexpected signals here. if err := th.Continue(); err != nil { return nil, err } } } }
func (dbp *Process) trapWait(pid int) (*Thread, error) { for { wpid, status, err := dbp.wait(pid, 0) if err != nil { return nil, fmt.Errorf("wait err %s %d", err, pid) } if wpid == 0 { continue } th, ok := dbp.Threads[wpid] if ok { th.Status = (*WaitStatus)(status) } if status.Exited() { if wpid == dbp.Pid { dbp.postExit() return nil, ProcessExitedError{Pid: wpid, Status: status.ExitStatus()} } delete(dbp.Threads, wpid) continue } 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. var cloned uint dbp.execPtraceFunc(func() { cloned, err = sys.PtraceGetEventMsg(wpid) }) if err != nil { return nil, fmt.Errorf("could not get event message: %s", err) } th, err = dbp.addThread(int(cloned), false) if err != nil { if err == sys.ESRCH { // thread died while we were adding it continue } return nil, err } if err = th.Continue(); err != nil { if err == sys.ESRCH { // thread died while we were adding it delete(dbp.Threads, th.ID) continue } return nil, fmt.Errorf("could not continue new thread %d %s", cloned, err) } if err = dbp.Threads[int(wpid)].Continue(); err != nil { if err != sys.ESRCH { return nil, fmt.Errorf("could not continue existing thread %d %s", wpid, err) } } continue } if th == nil { // Sometimes we get an unknown thread, ignore it? continue } if status.StopSignal() == sys.SIGTRAP && dbp.halt { th.running = false dbp.halt = false return th, nil } if status.StopSignal() == sys.SIGTRAP { th.running = false return th, nil } if th != nil { // TODO(dp) alert user about unexpected signals here. if err := th.resumeWithSig(int(status.StopSignal())); err != nil { if err == sys.ESRCH { return nil, ProcessExitedError{Pid: dbp.Pid} } return nil, err } } } }