aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common.h30
-rw-r--r--config.mk4
-rw-r--r--consts.c12
-rw-r--r--print.c4
-rw-r--r--process.c10
-rw-r--r--sctrace.c74
6 files changed, 111 insertions, 23 deletions
diff --git a/common.h b/common.h
index f027327..376e0f9 100644
--- a/common.h
+++ b/common.h
@@ -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 */
diff --git a/config.mk b/config.mk
index dbd8a92..9d233fb 100644
--- a/config.mk
+++ b/config.mk
@@ -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 =
diff --git a/consts.c b/consts.c
index 9a7e3fb..567a6e7 100644
--- a/consts.c
+++ b/consts.c
@@ -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);
diff --git a/print.c b/print.c
index aee9c51..7519a36 100644
--- a/print.c
+++ b/print.c
@@ -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
diff --git a/process.c b/process.c
index ea0dfd1..c5a09be 100644
--- a/process.c
+++ b/process.c
@@ -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);
}
diff --git a/sctrace.c b/sctrace.c
index 8000413..4e0e37b 100644
--- a/sctrace.c
+++ b/sctrace.c
@@ -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, &regs))
@@ -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, &regs))
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, &regs))
+ 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)) {