* process.c [LINUX] (internal_fork): Move the code to attach a new child process into a new function internal_fork_child. This is called at the end of fork/vfork/clone, when the syscall is returning. This should not change any behaviour. It is a preparation for a later change which uses PTRACE_EVENT_{FORK,VFORK,CLONE} and needs the new function to be separate. * process.c [LINUX] (internal_fork_child): New function. * defs.h [LINUX] (internal_fork_child): Declare. * defs.h (struct tcb): Rearrange so the LINUX ifdef can omit ->baddr.
Signed-off-by: Jamie Lokier <ja...@shareable.org> --- defs.h | 9 ++- process.c | 174 ++++++++++++++++++++++++++++++++---------------------------- 2 files changed, 99 insertions(+), 84 deletions(-) diff --git a/defs.h b/defs.h index 62b3719..7ce1fa6 100644 --- a/defs.h +++ b/defs.h @@ -331,10 +331,10 @@ struct tcb { int nclone_threads; /* # of nchildren with CLONE_THREAD */ int nclone_detached; /* # of nchildren with CLONE_DETACHED */ int nclone_waiting; /* clone threads in wait4 (TCB_SUSPENDED) */ -#endif - /* (1st arg of wait4()) */ +#else long baddr; /* `Breakpoint' address */ - long inst[2]; /* Instructions on above */ +#endif + long inst[2]; /* Instructions on breakpoint */ int pfd; /* proc file descriptor */ #ifdef SVR4 #ifdef HAVE_MP_PROCFS @@ -535,6 +535,9 @@ extern const char *sprint_open_modes(mode_t); extern int is_restart_error(struct tcb *); extern int change_syscall(struct tcb *, int); +#ifdef LINUX +extern int internal_fork_child(struct tcb *, int); +#endif extern int internal_fork(struct tcb *); extern int internal_exec(struct tcb *); extern int internal_wait(struct tcb *, int); diff --git a/process.c b/process.c index 6ae08a9..645f2c4 100644 --- a/process.c +++ b/process.c @@ -788,6 +788,97 @@ change_syscall(struct tcb *tcp, int new) } #ifdef LINUX +/* + * Called when we learn about a child process and know which parent + * it's from. (Dubiously, pid here is int because alloctcb() uses it, + * but syscall return values are unsigned long and could overflow.) + */ +int +internal_fork_child(struct tcb *tcp, int pid) +{ + struct tcb *tcpchild; + int clone_flags; + + tcpchild = pid2tcb(pid); + if (tcpchild != NULL) { + /* The child already reported its startup trap before + the parent reported its syscall return or PTRACE_EVENT. */ + if ((tcpchild->flags + & (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED)) + != (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED)) + fprintf(stderr, "\ +[preattached child %d of %d in weird state!]\n", + pid, tcp->pid); + } else { + fork_tcb(tcp); + tcpchild = alloctcb(pid); + } + + tcpchild->flags |= TCB_ATTACHED; + + if ((tcp->flags & TCB_CLONE_THREAD) && tcp->parent != NULL) { + /* + * The parent in this clone is itself a thread belonging to + * another process. There is no meaning to the parentage + * relationship of the new child with the thread, only with + * the process. We associate the new thread with our + * parent. Since this is done for every new thread, there + * will never be a TCB_CLONE_THREAD process that has + * children. + */ + tcpchild->parent = tcp->parent; + } else { + tcpchild->parent = tcp; + } + ++(tcpchild->parent)->nchildren; + + /* Set by setbpt. */ + clone_flags = tcp->u_arg[ARG_FLAGS]; + + if (clone_flags & CLONE_THREAD) { + tcpchild->flags |= TCB_CLONE_THREAD; + ++(tcpchild->parent)->nclone_threads; + } + if (clone_flags & CLONE_DETACHED) { + tcpchild->flags |= TCB_CLONE_DETACHED; + ++(tcpchild->parent)->nclone_detached; + } + + /* Child has BPT too, must be removed on first child stop. */ + if (tcp->flags & TCB_BPTSET) { + tcpchild->flags |= TCB_BPTSET; + memcpy(tcpchild->inst, tcp->inst, sizeof tcpchild->inst); + if (clearbpt(tcp)) + return -1; + } + + if (tcpchild->flags & TCB_SUSPENDED) { + /* + * The child was born suspended, due to our having used + * CLONE_PTRACE and the child event happened before getting + * the pid from the parent. + */ + if (tcpchild->flags & TCB_BPTSET) + if (clearbpt(tcpchild)) + return -1; + + tcpchild->flags &= ~(TCB_SUSPENDED|TCB_STARTUP); + if (ptrace_restart(PTRACE_SYSCALL, tcpchild, 0) < 0) + return -1; + + if (!qflag) + fprintf(stderr, "\ +Process %u resumed (parent %d ready)\n", + pid, tcp->pid); + } else { + if (!qflag) + fprintf(stderr, "\ +Process %d attached\n", pid); + } + + return 0; +} + int internal_fork(struct tcb *tcp) { @@ -798,10 +889,7 @@ internal_fork(struct tcb *tcp) if (setbpt(tcp) < 0) return 0; } else { - struct tcb *tcpchild; - int pid; - int bpt; - int call_flags; + int pid, bpt; if (!(tcp->flags & TCB_FOLLOWFORK)) return 0; @@ -816,83 +904,7 @@ internal_fork(struct tcb *tcp) pid = tcp->u_rval; - tcpchild = pid2tcb(pid); - if (tcpchild != NULL) { - /* The child already reported its startup trap - before the parent reported its syscall return. */ - if ((tcpchild->flags - & (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED)) - != (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED)) - fprintf(stderr, "\ -[preattached child %d of %d in weird state!]\n", - pid, tcp->pid); - } else { - fork_tcb(tcp); - tcpchild = alloctcb(pid); - } - - if (bpt) - clearbpt(tcp); - - tcpchild->flags |= TCB_ATTACHED; - /* Child has BPT too, must be removed on first occasion. */ - if (bpt) { - tcpchild->flags |= TCB_BPTSET; - tcpchild->baddr = tcp->baddr; - memcpy(tcpchild->inst, tcp->inst, - sizeof tcpchild->inst); - } - tcpchild->parent = tcp; - tcp->nchildren++; - if (tcpchild->flags & TCB_SUSPENDED) { - /* The child was born suspended, due to our having - forced CLONE_PTRACE. */ - if (bpt) - clearbpt(tcpchild); - - tcpchild->flags &= ~(TCB_SUSPENDED|TCB_STARTUP); - if (ptrace_restart(PTRACE_SYSCALL, tcpchild, 0) < 0) - return -1; - - if (!qflag) - fprintf(stderr, "\ -Process %u resumed (parent %d ready)\n", - pid, tcp->pid); - } - else { - if (!qflag) - fprintf(stderr, "Process %d attached\n", pid); - } - - /* - * Save the flags used in this call, - * in case we point TCP to our parent below. - */ - call_flags = tcp->u_arg[ARG_FLAGS]; - if ((tcp->flags & TCB_CLONE_THREAD) && - tcp->parent != NULL) { - /* - * The parent in this clone is itself a thread belonging - * to another process. There is now meaning to the - * parentage relationship of the new child with the - * thread, only with the process. We associate the new - * thread with our parent. Since this is done for every - * new thread, there will never be a TCB_CLONE_THREAD - * process that has children. - */ - --tcp->nchildren; - tcp = tcp->parent; - tcpchild->parent = tcp; - ++tcp->nchildren; - } - if (call_flags & CLONE_THREAD) { - tcpchild->flags |= TCB_CLONE_THREAD; - ++tcp->nclone_threads; - } - if (call_flags & CLONE_DETACHED) { - tcpchild->flags |= TCB_CLONE_DETACHED; - ++tcp->nclone_detached; - } + return internal_fork_child(tcp, pid); } return 0; } -- 1.7.0.4 _______________________________________________ uClinux-dev mailing list uClinux-dev@uclinux.org http://mailman.uclinux.org/mailman/listinfo/uclinux-dev This message was resent by uclinux-dev@uclinux.org To unsubscribe see: http://mailman.uclinux.org/mailman/options/uclinux-dev