diff options
Diffstat (limited to '')
-rw-r--r-- | common.h | 30 | ||||
-rw-r--r-- | config.mk | 4 | ||||
-rw-r--r-- | consts.c | 12 | ||||
-rw-r--r-- | print.c | 4 | ||||
-rw-r--r-- | process.c | 10 | ||||
-rw-r--r-- | sctrace.c | 74 |
6 files changed, 111 insertions, 23 deletions
@@ -28,6 +28,24 @@ #include "list-errnos.h" +#ifndef ERESTARTSYS +# define ERESTARTSYS 512 +# define ALSO_ERESTARTSYS +#endif +#ifndef ERESTARTNOINTR +# define ERESTARTNOINTR 513 +# define ALSO_ERESTARTNOINTR +#endif +#ifndef ERESTARTNOHAND +# define ERESTARTNOHAND 514 +# define ALSO_ERESTARTNOHAND +#endif +#ifndef ERESTART_RESTARTBLOCK +# define ERESTART_RESTARTBLOCK 516 +# define ALSO_ERESTART_RESTARTBLOCK +#endif + + enum type { Unknown, Void, @@ -48,7 +66,11 @@ enum type { enum state { Normal, - Syscall + Syscall, + ForkChild, + VforkChild, + ForkParent, + VforkParent }; struct process { @@ -62,6 +84,10 @@ struct process { unsigned long long int args[6]; unsigned long long int ret; enum type ret_type; + + /* vfork(2) data */ + struct process *continue_on_exit; + struct process *vfork_waiting_on; }; @@ -81,7 +107,7 @@ void print_systemcall_exit(struct process *proc); /* process.c */ void init_process_list(void); struct process *find_process(pid_t pid); -struct process *add_process(pid_t pid, int trace_options); +struct process *add_process(pid_t pid, unsigned long int trace_options); void remove_process(struct process *proc); /* util.c */ @@ -2,5 +2,5 @@ PREFIX = /usr MANPREFIX = $(PREFIX)/share/man CPPFLAGS = -D_XOPEN_SOURCE=700 -D_GNU_SOURCE -CFLAGS = -std=c99 -Wall -O2 -LDFLAGS = -s +CFLAGS = -std=c11 -Wall -Og -g +LDFLAGS = @@ -9,6 +9,18 @@ get_errno_name(int err) #define X(N) if (err == N) return #N; LIST_ERRNOS(X) +#ifdef ALSO_ERESTARTSYS + X(ERESTARTSYS) +#endif +#ifdef ALSO_ERESTARTNOINTR + X(ERESTARTNOINTR) +#endif +#ifdef ALSO_ERESTARTNOHAND + X(ERESTARTNOHAND) +#endif +#ifdef ALSO_ERESTART_RESTARTBLOCK + X(ERESTART_RESTARTBLOCK) +#endif #undef X sprintf(buf, "%i", err); @@ -140,12 +140,12 @@ print_systemcall(struct process *proc) break #define SIMPLE(NAME, FMT, RET_TYPE)\ case SYS_##NAME:\ - printf_systemcall(proc, #NAME, (FMT), args);\ + printf_systemcall(proc, #NAME, (FMT));\ proc->ret_type = (RET_TYPE);\ break #define FORMATTERS(NAME, FMT, RET_TYPE, ...)\ case SYS_##NAME:\ - printf_systemcall(proc, #NAME, (FMT), args, __VA_ARGS__);\ + printf_systemcall(proc, #NAME, (FMT), __VA_ARGS__);\ proc->ret_type = (RET_TYPE);\ break @@ -26,7 +26,7 @@ find_process(pid_t pid) struct process * -add_process(pid_t pid, int trace_options) +add_process(pid_t pid, unsigned long int trace_options) { struct process *proc; int saved_errno; @@ -45,8 +45,8 @@ add_process(pid_t pid, int trace_options) errno = saved_errno; eprintf("ptrace PTRACE_SETOPTIONS %ju 0 ...:", (uintmax_t)pid); } - if (ptrace(PTRACE_SYSCALL, proc->pid, NULL, 0)) - eprintf("ptrace PTRACE_SYSCALL %ju NULL 0:", (uintmax_t)pid); + if (ptrace(PTRACE_SYSCALL, pid, NULL, 0)) + eprintf("ptrace PTRACE_SYSCALL %ju NULL 0:", (uintmax_t)pid); proc->next = &tail; proc->prev = tail.prev; proc->prev->next = proc; @@ -60,5 +60,9 @@ remove_process(struct process *proc) { proc->prev->next = proc->next; proc->next->prev = proc->prev; + if (proc->vfork_waiting_on) + proc->vfork_waiting_on->continue_on_exit = NULL; + if (proc->continue_on_exit) + proc->continue_on_exit->vfork_waiting_on = NULL; free(proc); } @@ -8,7 +8,7 @@ char *argv0; static void usage(void) { - fprintf(stderr, "usage: %s [-f trace-output-file] [-CFV] command ...\n", argv0); + fprintf(stderr, "usage: %s [-o trace-output-file] [-f] command ...\n", argv0); exit(1); } @@ -18,7 +18,7 @@ handle_syscall(struct process *proc) { struct user_regs_struct regs; - switch (proc->state) { + switch ((int)proc->state) { default: /* Get systemcall arguments */ if (ptrace(PTRACE_GETREGS, proc->pid, NULL, ®s)) @@ -42,10 +42,21 @@ handle_syscall(struct process *proc) break; case Syscall: + case ForkParent: /* Get system call result */ if (ptrace(PTRACE_GETREGS, proc->pid, NULL, ®s)) eprintf("ptrace PTRACE_GETREGS %ju NULL <buffer>:", (uintmax_t)proc->pid); - proc->ret = regs.rax; + + /* Get or set return */ + if (proc->state == Syscall) { + proc->ret = regs.rax; + } else { + regs.rax = proc->ret; + if (ptrace(PTRACE_SETREGS, proc->pid, NULL, ®s)) + eprintf("ptrace PTRACE_SETREGS %ju NULL <buffer>:", (uintmax_t)proc->pid); + if (ptrace(PTRACE_SYSCALL, proc->pid, NULL, 0)) + eprintf("ptrace PTRACE_SYSCALL %ju NULL 0", (uintmax_t)proc->pid); + } /* Print system call result */ print_systemcall_exit(proc); @@ -56,6 +67,18 @@ handle_syscall(struct process *proc) proc->state = Normal; break; + + case VforkParent: + if (ptrace(PTRACE_SYSCALL, proc->pid, NULL, 0)) + eprintf("ptrace PTRACE_SYSCALL %ju NULL 0", (uintmax_t)proc->pid); + proc->state = Syscall; + break; + + case ForkChild: + case VforkChild: + tprintf(proc, "= 0\n"); + proc->state = Normal; + break; } } @@ -68,24 +91,24 @@ main(int argc, char **argv) char *outfile = NULL; FILE *outfp = stderr; const char *num = NULL; - int status, exit_value = 0; + int status, exit_value = 0, trace_event; unsigned long int trace_options = PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD; - struct process *proc; + struct process *proc, *proc2; unsigned long int event; /* TODO add support for exec */ - /* TODO add option to trace threads */ - /* TODO add option to trace vforks */ - /* TODO add option to trace signals */ + /* TODO add option to trace threads (-t) */ + /* TODO add option to trace signals (-s) */ /* TODO add option to specify argv[0] */ ARGBEGIN { - case 'f': + case 'o': if (outfile) usage(); outfile = EARGF(usage()); break; - case 'F': + case 'f': trace_options |= PTRACE_O_TRACEFORK; + trace_options |= PTRACE_O_TRACEVFORK; break; default: usage(); @@ -154,7 +177,6 @@ have_outfp: set_trace_output(outfp); for (;;) { - /* Wait for next syscall enter/exit */ pid = wait(&status); if (pid < 0) { if (errno == ECHILD) @@ -171,6 +193,12 @@ have_outfp: if (pid == orig_pid) exit_value = WEXITSTATUS(status); tprintf(proc, "\nProcess exited with value %i\n", WEXITSTATUS(status)); + proc2 = proc->continue_on_exit; + remove_process(proc); + if (proc2) { + tprintf(proc2, "Process continue do to exit of vfork child\n"); + handle_syscall(proc2); + } } else if (WIFSIGNALED(status)) { tprintf(proc, "\nProcess terminated by signal %i (%s)\n", WTERMSIG(status), strsignal(WTERMSIG(status))); @@ -180,13 +208,28 @@ have_outfp: if (WSTOPSIG(status) == (SIGTRAP | 0x80)) { handle_syscall(proc); } else if (WSTOPSIG(status) == SIGTRAP) { - switch (((status >> 8) ^ SIGTRAP) >> 8) { + trace_event = ((status >> 8) ^ SIGTRAP) >> 8; + switch (trace_event) { + case PTRACE_EVENT_VFORK: + tprintf(proc, "\nProcess stopped by vfork until child exits or exec(2)s\n"); + /* fall thought */ case PTRACE_EVENT_FORK: if (ptrace(PTRACE_GETEVENTMSG, proc->pid, NULL, &event)) eprintf("ptrace PTRACE_GETEVENTMSG %ju NULL <buffer>:", (uintmax_t)proc->pid); - add_process((pid_t)event, trace_options); - handle_syscall(proc); + proc2 = add_process((pid_t)event, trace_options); + 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; + handle_syscall(proc); + } + tprintf(proc2, "\nTracing new process\n"); + proc2->state = trace_event == PTRACE_EVENT_FORK ? ForkChild : VforkChild; + handle_syscall(proc2); break; default: @@ -196,6 +239,9 @@ have_outfp: print_signal: tprintf(proc, "\nProcess stopped by signal %i (%s)\n", WSTOPSIG(status), strsignal(WSTOPSIG(status))); /* TODO print signal name */ + /* TODO handle signals properly */ + if (ptrace(PTRACE_SYSCALL, proc->pid, NULL, 0)) + eprintf("ptrace PTRACE_SYSCALL %ju NULL 0", (uintmax_t)proc->pid); } } else if (WIFCONTINUED(status)) { |