aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common.h3
-rw-r--r--sctrace.c16
-rw-r--r--util.c15
3 files changed, 26 insertions, 8 deletions
diff --git a/common.h b/common.h
index 996b9ef..d3df014 100644
--- a/common.h
+++ b/common.h
@@ -67,8 +67,10 @@ enum type {
enum state {
Normal,
Syscall,
+ CloneChild,
ForkChild,
VforkChild,
+ CloneParent,
ForkParent,
VforkParent,
Exec
@@ -76,6 +78,7 @@ enum state {
struct process {
pid_t pid;
+ pid_t thread_group_leader;
struct process *next;
struct process *prev;
enum state state;
diff --git a/sctrace.c b/sctrace.c
index f027a77..65216a5 100644
--- a/sctrace.c
+++ b/sctrace.c
@@ -8,7 +8,7 @@ char *argv0;
static void
usage(void)
{
- fprintf(stderr, "usage: %s [-o trace-output-file] [-f] (command | -0 command argv0) [argument] ...\n", argv0);
+ fprintf(stderr, "usage: %s [-o trace-output-file] [-ft] (command | -0 command argv0) [argument] ...\n", argv0);
exit(1);
}
@@ -42,6 +42,7 @@ handle_syscall(struct process *proc)
break;
case Syscall:
+ case CloneParent:
case ForkParent:
/* Get system call result */
if (ptrace(PTRACE_GETREGS, proc->pid, NULL, &regs))
@@ -82,6 +83,7 @@ handle_syscall(struct process *proc)
proc->state = Syscall;
break;
+ case CloneChild:
case ForkChild:
case VforkChild:
tprintf(proc, "= 0\n");
@@ -104,7 +106,6 @@ main(int argc, char **argv)
struct process *proc, *proc2;
unsigned long int event;
- /* TODO add option to trace threads (-t) */
/* TODO add option to trace signals (-s) */
ARGBEGIN {
case '0':
@@ -118,6 +119,9 @@ main(int argc, char **argv)
case 'f':
trace_options |= PTRACE_O_TRACEFORK;
trace_options |= PTRACE_O_TRACEVFORK;
+ /* fall through */
+ case 't':
+ trace_options |= PTRACE_O_TRACECLONE;
multiprocess = 1;
break;
default:
@@ -226,20 +230,24 @@ have_outfp:
tprintf(proc, "\nProcess stopped by vfork until child exits or exec(2)s\n");
/* fall thought */
case PTRACE_EVENT_FORK:
+ case PTRACE_EVENT_CLONE:
if (ptrace(PTRACE_GETEVENTMSG, proc->pid, NULL, &event))
eprintf("ptrace PTRACE_GETEVENTMSG %ju NULL <buffer>:", (uintmax_t)proc->pid);
proc2 = add_process((pid_t)event, trace_options);
+ if (trace_event == PTRACE_EVENT_CLONE)
+ proc2->thread_group_leader = proc->pid;
proc->ret = event;
if (trace_event == PTRACE_EVENT_VFORK) {
proc2->continue_on_exit = proc;
proc->vfork_waiting_on = proc2;
proc->state = VforkParent;
} else {
- proc->state = ForkParent;
+ proc->state = trace_event == PTRACE_EVENT_CLONE ? CloneParent : ForkParent;
handle_syscall(proc);
}
tprintf(proc2, "\nTracing new process\n");
- proc2->state = trace_event == PTRACE_EVENT_FORK ? ForkChild : VforkChild;
+ proc2->state = trace_event == PTRACE_EVENT_FORK ? ForkChild :
+ trace_event == PTRACE_EVENT_VFORK ? VforkChild : CloneChild;
handle_syscall(proc2);
break;
diff --git a/util.c b/util.c
index 7ee9c51..521f73a 100644
--- a/util.c
+++ b/util.c
@@ -25,10 +25,17 @@ tprintf(struct process *proc, const char *fmt, ...)
fmt = &fmt[1];
}
if (multiproctrace) {
- if (last_char == '\n')
- fprintf(trace_fp, "[%ju] ", (uintmax_t)proc->pid);
- else if (proc->pid != last_pid)
- fprintf(trace_fp, "\n[%ju] ", (uintmax_t)proc->pid);
+ if (proc->thread_group_leader) {
+ if (last_char == '\n')
+ fprintf(trace_fp, "[%ju, %ju] ", (uintmax_t)proc->thread_group_leader, (uintmax_t)proc->pid);
+ else if (proc->pid != last_pid)
+ fprintf(trace_fp, "\n[%ju, %ju] ", (uintmax_t)proc->thread_group_leader, (uintmax_t)proc->pid);
+ } else {
+ if (last_char == '\n')
+ fprintf(trace_fp, "[%ju] ", (uintmax_t)proc->pid);
+ else if (proc->pid != last_pid)
+ fprintf(trace_fp, "\n[%ju] ", (uintmax_t)proc->pid);
+ }
}
va_start(ap, fmt);
vfprintf(trace_fp, fmt, ap);