// waitStatusToStateUpdate converts syscall.WaitStatus to a StateUpdate. func waitStatusToStateUpdate(ws syscall.WaitStatus) *stateUpdate { switch { case ws.Exited(): es := ws.ExitStatus() if es == 0 { return newExitedStateUpdate(ok) } return newExitedStateUpdate(newFailure(fmt.Sprint(es))) case ws.Signaled(): msg := fmt.Sprintf("signaled %v", ws.Signal()) if ws.CoreDump() { msg += " (core dumped)" } return newUnexitedStateUpdate(msg) case ws.Stopped(): msg := fmt.Sprintf("stopped %v", ws.StopSignal()) trap := ws.TrapCause() if trap != -1 { msg += fmt.Sprintf(" (trapped %v)", trap) } return newUnexitedStateUpdate(msg) case ws.Continued(): return newUnexitedStateUpdate("continued") default: return newUnexitedStateUpdate(fmt.Sprint("unknown status", ws)) } }
func printStatus(ws syscall.WaitStatus) string { switch { case ws.Exited(): es := ws.ExitStatus() if es == 0 { return "" } return fmt.Sprintf("exited %v", es) case ws.Signaled(): msg := fmt.Sprintf("signaled %v", ws.Signal()) if ws.CoreDump() { msg += " (core dumped)" } return msg case ws.Stopped(): msg := fmt.Sprintf("stopped %v", ws.StopSignal()) trap := ws.TrapCause() if trap != -1 { msg += fmt.Sprintf(" (trapped %v)", trap) } return msg case ws.Continued(): return "continued" default: return fmt.Sprintf("unknown status %v", ws) } }
// waitStatusToError converts syscall.WaitStatus to an Error. func waitStatusToError(ws syscall.WaitStatus) error { switch { case ws.Exited(): es := ws.ExitStatus() if es == 0 { return nil } return errors.New(fmt.Sprint(es)) case ws.Signaled(): msg := fmt.Sprintf("signaled %v", ws.Signal()) if ws.CoreDump() { msg += " (core dumped)" } return errors.New(msg) case ws.Stopped(): msg := fmt.Sprintf("stopped %v", ws.StopSignal()) trap := ws.TrapCause() if trap != -1 { msg += fmt.Sprintf(" (trapped %v)", trap) } return errors.New(msg) /* case ws.Continued(): return newUnexitedStateUpdate("continued") */ default: return fmt.Errorf("unknown WaitStatus", ws) } }
func (t *PTracer) handleStopped(pid int, status syscall.WaitStatus) { signal := syscall.Signal(0) target, err := t.thread(pid) if err != nil { log.Printf("thread failed: %v", err) return } if !target.attached { target.attached = true err = syscall.PtraceSetOptions(pid, ptraceOptions) if err != nil { log.Printf("SetOptions failed, pid=%d, err=%v", pid, err) return } } else if status.Stopped() && status.StopSignal() == syscall.SIGTRAP|ptraceTracesysgoodBit { // pid entered Syscall-enter-stop or syscall-exit-stop target.syscallStopped() } else if status.Stopped() && status.StopSignal() == syscall.SIGTRAP { // pid entered PTRACE_EVENT stop switch status.TrapCause() { case syscall.PTRACE_EVENT_CLONE: err := target.handleClone(pid) if err != nil { log.Printf("clone failed: %v", err) return } default: log.Printf("Unknown PTRACE_EVENT %d for pid %d", status.TrapCause(), pid) } } else if status.Exited() || status.Signaled() { // "tracer can safely assume pid will exit" t.threadExited(target) return } else if status.Stopped() { // tracee received a non-trace related signal signal = status.StopSignal() if signal == syscall.SIGSTOP && target.process.detaching { t.detachThread(target) return } } else { // unknown stop - shouldn't happen! log.Printf("Pid %d random stop with status %x", pid, status) } // Restart stopped caller in syscall trap mode. // log.Printf("Restarting pid %d with signal %d", pid, int(signal)) err = syscall.PtraceSyscall(pid, int(signal)) if err != nil { log.Printf("PtraceSyscall failed, pid=%d, err=%v", pid, err) } }