X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Ffork.c;fp=kernel%2Ffork.c;h=f8f50bbf21dc47dca25a40d5edb4954c0a808961;hb=e0ff8aa1acd079b70e796571917ae0449b7c465b;hp=adfa44841a64d7e125b76ce2515c364716b2e9c2;hpb=bef9ea3086d47cf98cfd0ea389953a0af0b60114;p=linux-2.6.git diff --git a/kernel/fork.c b/kernel/fork.c index adfa44841..f8f50bbf2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -923,7 +923,8 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE); new_flags |= PF_FORKNOEXEC; - new_flags |= PF_STARTING; + if (!(clone_flags & CLONE_PTRACE)) + p->ptrace = 0; p->flags = new_flags; } @@ -1056,9 +1057,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, INIT_LIST_HEAD(&p->sibling); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); -#ifdef CONFIG_PTRACE - INIT_LIST_HEAD(&p->ptracees); -#endif clear_tsk_thread_flag(p, TIF_SIGPENDING); init_sigpending(&p->pending); @@ -1192,6 +1190,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, */ p->group_leader = p; INIT_LIST_HEAD(&p->thread_group); + INIT_LIST_HEAD(&p->ptrace_children); + INIT_LIST_HEAD(&p->ptrace_list); /* Perform scheduler related setup. Assign this task to a CPU. */ sched_fork(p, clone_flags); @@ -1215,9 +1215,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, /* CLONE_PARENT re-uses the old parent */ if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) - p->parent = current->parent; + p->real_parent = current->real_parent; else - p->parent = current; + p->real_parent = current; + p->parent = p->real_parent; spin_lock(¤t->sighand->siglock); @@ -1264,7 +1265,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, if (likely(p->pid)) { add_parent(p); - tracehook_init_task(p); + if (unlikely(p->ptrace & PT_PTRACED)) + __ptrace_link(p, current->parent); if (thread_group_leader(p)) { p->signal->tty = current->signal->tty; @@ -1363,6 +1365,22 @@ struct task_struct * __devinit fork_idle(int cpu) return task; } +static inline int fork_traceflag (unsigned clone_flags) +{ + if (clone_flags & CLONE_UNTRACED) + return 0; + else if (clone_flags & CLONE_VFORK) { + if (current->ptrace & PT_TRACE_VFORK) + return PTRACE_EVENT_VFORK; + } else if ((clone_flags & CSIGNAL) != SIGCHLD) { + if (current->ptrace & PT_TRACE_CLONE) + return PTRACE_EVENT_CLONE; + } else if (current->ptrace & PT_TRACE_FORK) + return PTRACE_EVENT_FORK; + + return 0; +} + /* * Ok, this is the main fork-routine. * @@ -1377,12 +1395,18 @@ long do_fork(unsigned long clone_flags, int __user *child_tidptr) { struct task_struct *p; + int trace = 0; struct pid *pid = alloc_pid(); long nr; if (!pid) return -EAGAIN; nr = pid->nr; + if (unlikely(current->ptrace)) { + trace = fork_traceflag (clone_flags); + if (trace) + clone_flags |= CLONE_PTRACE; + } p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr); /* @@ -1397,26 +1421,30 @@ long do_fork(unsigned long clone_flags, init_completion(&vfork); } - tracehook_report_clone(clone_flags, p); - - p->flags &= ~PF_STARTING; - - if (clone_flags & CLONE_STOPPED) { + if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) { /* * We'll start up with an immediate SIGSTOP. */ sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); - p->state = TASK_STOPPED; } - else + + if (!(clone_flags & CLONE_STOPPED)) wake_up_new_task(p, clone_flags); + else + p->state = TASK_STOPPED; - tracehook_report_clone_complete(clone_flags, nr, p); + if (unlikely (trace)) { + current->ptrace_message = nr; + ptrace_notify ((trace << 8) | SIGTRAP); + } if (clone_flags & CLONE_VFORK) { wait_for_completion(&vfork); - tracehook_report_vfork_done(p, nr); + if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) { + current->ptrace_message = nr; + ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); + } } } else { free_pid(pid);