diff options
| -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)) { | 
