diff -urp ltrace-0.5/proc.c ltrace-0.5-pm/proc.c --- ltrace-0.5/proc.c 2011-08-18 03:39:06.787377290 +0200 +++ ltrace-0.5-pm/proc.c 2011-08-18 03:39:01.792031636 +0200 @@ -8,6 +8,7 @@ #include <errno.h> #include <stdlib.h> #include <assert.h> +#include <unistd.h> #include "ltrace.h" #include "options.h" @@ -35,57 +36,71 @@ open_program(char *filename, pid_t pid, return proc; } -static void +static int open_one_pid(pid_t pid) { struct process *proc; char *filename; - if (trace_pid(pid) < 0) { - fprintf(stderr, "Cannot attach to pid %u: %s\n", pid, - strerror(errno)); - return; - } + if (trace_pid(pid) < 0) + return 0; filename = pid2name(pid); + if (filename == NULL) + return 0; -#if 0 - if (!filename) { - if (verbose) { - fprintf(stderr, "Cannot trace pid %u: %s\n", pid, - strerror(errno)); - } - return; - } -#endif proc = open_program(filename, pid, 1); trace_set_options(proc, pid); continue_process(pid); proc->breakpoints_enabled = 1; + + return 1; } void open_pid(pid_t pid, int verbose) { - pid_t *tasks; - size_t ntasks; - int should_free = 1; - if (process_tasks(pid, &tasks, &ntasks) < 0) { - fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n", pid, - strerror(errno)); - - // Attach at least this one. - tasks = &pid; - ntasks = 1; - should_free = 0; - } - - size_t i; - for (i = 0; i < ntasks; ++i) - open_one_pid(tasks[i]); + /* If we are already tracing this guy, we should be seeing all + * his children via normal tracing route. */ + if (pid2proc(pid) != NULL) + return; + + /* First, see if we can attach the requested PID itself. */ + if (!open_one_pid(pid)) { + fprintf(stderr, "Cannot attach to pid %u: %s\n", + pid, strerror(errno)); + return; + } + + /* Now attach to all tasks that belong to that PID. There's a + * race between process_tasks and open_one_pid. So when we + * fail in open_one_pid below, we just do another round. + * Chances are that by then that PID will have gone away, and + * that's why we have seen the failure. The processes that we + * manage to open_one_pid are stopped, so we should eventually + * reach a point where process_tasks doesn't give any new + * processes (because there's nobody left to produce + * them). */ + int have_all; + do { + pid_t *tasks; + size_t ntasks; + size_t i; + if (process_tasks(pid, &tasks, &ntasks) < 0) { + fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n", + pid, strerror(errno)); + return; + } + + have_all = 1; + for (i = 0; i < ntasks; ++i) + if (pid2proc(tasks[i]) == NULL + && !open_one_pid(tasks[i])) + have_all = 0; - if (should_free) free(tasks); + + } while (have_all == 0); } void open_forked_pid(pid_t pid, int early)