예제 #1
0
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
			}
		}
	}
}
예제 #2
0
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
			}
		}
	}
}