Beispiel #1
0
func (dbp *Process) trapWait(pid int) (*Thread, error) {
	var (
		th  *Thread
		err error
	)
	for {
		port := C.mach_port_wait(dbp.os.portSet)

		switch port {
		case dbp.os.notificationPort:
			_, status, err := wait(dbp.Pid, dbp.Pid, 0)
			if err != nil {
				return nil, err
			}
			dbp.exited = true
			return nil, ProcessExitedError{Pid: dbp.Pid, Status: status.ExitStatus()}

		case C.MACH_RCV_INTERRUPTED:
			if !dbp.halt {
				// Call trapWait again, it seems
				// MACH_RCV_INTERRUPTED is emitted before
				// process natural death _sometimes_.
				continue
			}
			return nil, nil

		case 0:
			return nil, fmt.Errorf("error while waiting for task")
		}

		// Since we cannot be notified of new threads on OS X
		// this is as good a time as any to check for them.
		dbp.updateThreadList()
		th, err = dbp.handleBreakpointOnThread(int(port))
		if err != nil {
			if _, ok := err.(NoBreakpointError); ok {
				if dbp.halt {
					dbp.halt = false
					return dbp.Threads[int(port)], nil
				}
				th := dbp.Threads[int(port)]
				if dbp.firstStart || th.singleStepping {
					dbp.firstStart = false
					return dbp.Threads[int(port)], nil
				}
				if err := th.Continue(); err != nil {
					return nil, err
				}
				continue
			}
			return nil, err
		}
		return th, nil
	}
	return th, nil
}
Beispiel #2
0
func (t *Thread) singleStep() error {
	kret := C.single_step(t.os.threadAct)
	if kret != C.KERN_SUCCESS {
		return fmt.Errorf("could not single step")
	}
	for {
		port := C.mach_port_wait(t.dbp.os.portSet, C.int(0))
		if port == C.mach_port_t(t.ID) {
			break
		}
	}

	kret = C.clear_trap_flag(t.os.threadAct)
	if kret != C.KERN_SUCCESS {
		return fmt.Errorf("could not clear CPU trap flag")
	}
	return nil
}
Beispiel #3
0
func (dbp *Process) Kill() (err error) {
	err = sys.Kill(dbp.Pid, sys.SIGKILL)
	if err != nil {
		return errors.New("could not deliver signal: " + err.Error())
	}
	for port := range dbp.Threads {
		if C.thread_resume(C.thread_act_t(port)) != C.KERN_SUCCESS {
			return errors.New("could not resume task")
		}
	}
	for {
		port := C.mach_port_wait(dbp.os.portSet)
		if port == dbp.os.notificationPort {
			break
		}
	}
	dbp.exited = true
	return
}
Beispiel #4
0
func (dbp *Process) waitForStop() ([]int, error) {
	ports := make([]int, 0, len(dbp.Threads))
	count := 0
	for {
		port := C.mach_port_wait(dbp.os.portSet, C.int(1))
		if port != 0 {
			count = 0
			ports = append(ports, int(port))
		} else {
			n := C.num_running_threads(C.task_t(dbp.os.task))
			if n == 0 {
				return ports, nil
			} else if n < 0 {
				return nil, fmt.Errorf("error waiting for thread stop %d", n)
			} else if count > 16 {
				return nil, fmt.Errorf("could not stop process %d", n)
			}
		}
	}
}