diff options
| author | Mattias Andrée <maandree@kth.se> | 2020-05-30 17:34:29 +0200 | 
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2020-05-30 17:34:29 +0200 | 
| commit | 712f56fe3369c59d32b9000830b4ed7b25ed24b5 (patch) | |
| tree | 27ddf931fd2d980d0c4dcdfb025f26f5380fb5d6 | |
| parent | Print errno names and strings (diff) | |
| download | sctrace-712f56fe3369c59d32b9000830b4ed7b25ed24b5.tar.gz sctrace-712f56fe3369c59d32b9000830b4ed7b25ed24b5.tar.bz2 sctrace-712f56fe3369c59d32b9000830b4ed7b25ed24b5.tar.xz | |
Add support for tracing fork children
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
| -rw-r--r-- | Makefile | 24 | ||||
| -rw-r--r-- | common.h | 90 | ||||
| -rw-r--r-- | consts.c | 16 | ||||
| -rw-r--r-- | memory.c | 189 | ||||
| -rw-r--r-- | print.c | 560 | ||||
| -rw-r--r-- | process.c | 64 | ||||
| -rw-r--r-- | sctrace.c | 947 | ||||
| -rw-r--r-- | util.c | 56 | 
8 files changed, 1092 insertions, 854 deletions
| @@ -3,10 +3,27 @@  CONFIGFILE = config.mk  include $(CONFIGFILE) +OBJ =\ +	consts.o\ +	memory.o\ +	print.o\ +	process.o\ +	sctrace.o\ +	util.o + +HDR =\ +	arg.h\ +	common.h\ +	list-errnos.h +  all: sctrace +$(OBJ): $(@:.o=.c) $(HDR) -sctrace: sctrace.c arg.h list-errnos.h -	$(CC) -o $@ $@.c $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) +sctrace: $(OBJ) +	$(CC) -o $@ $(OBJ) $(LDFLAGS) + +.c.o: +	$(CC) -c -o $@ $< $(CPPFLAGS) $(CFLAGS)  list-errnos.h:  	printf '#define LIST_ERRNOS(_)\\\n\t' > $@ @@ -25,4 +42,7 @@ uninstall:  clean:  	-rm -f -- *.o list-errnos.h sctrace +.SUFFIXES: +.SUFFIXES: .c .o +  .PHONY: all install uninstall clean diff --git a/common.h b/common.h new file mode 100644 index 0000000..f027327 --- /dev/null +++ b/common.h @@ -0,0 +1,90 @@ +/* See LICENSE file for copyright and license details. */ +#if !defined __x86_64__ || defined __IPL32__ +# error "This program is only implemented for x86-64" +#endif + +#include <sys/ptrace.h> +#include <sys/syscall.h> +#include <sys/uio.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* Constants used in system calls */ +#include <sys/epoll.h> +#include <sys/socket.h> +#include <fcntl.h> + +#include "arg.h" +#include "list-errnos.h" + + +enum type { +	Unknown, +	Void, +	Int, +	UInt, +	OInt, +	XInt, +	Long, +	ULong, +	OLong, +	XLong, +	LLong, +	ULLong, +	OLLong, +	XLLong, +	Ptr +}; + +enum state { +	Normal, +	Syscall +}; + +struct process { +	pid_t pid; +	struct process *next; +	struct process *prev; +	enum state state; + +	/* Syscall data */ +	unsigned long long int scall; +	unsigned long long int args[6]; +	unsigned long long int ret; +	enum type ret_type; +}; + + +/* consts.c */ +const char *get_errno_name(int err); + +/* memory.c */ +char *get_string(pid_t pid, unsigned long int addr, size_t *lenp, const char **errorp); +int get_struct(pid_t pid, unsigned long int addr, void *out, size_t size, const char **errorp); +char *get_memory(pid_t pid, unsigned long int addr, size_t n, const char **errorp); +char *escape_memory(char *str, size_t m); + +/* print.c */ +void print_systemcall(struct process *proc); +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); +void remove_process(struct process *proc); + +/* util.c */ +void set_trace_output(FILE *fp); +void tprintf(struct process *proc, const char *fmt, ...); +_Noreturn void eprintf(const char *fmt, ...); diff --git a/consts.c b/consts.c new file mode 100644 index 0000000..9a7e3fb --- /dev/null +++ b/consts.c @@ -0,0 +1,16 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +const char * +get_errno_name(int err) +{ +	static char buf[3 * sizeof(err) + 2]; + +#define X(N) if (err == N) return #N; +	LIST_ERRNOS(X) +#undef X + +	sprintf(buf, "%i", err); +	return buf; +} diff --git a/memory.c b/memory.c new file mode 100644 index 0000000..1af854f --- /dev/null +++ b/memory.c @@ -0,0 +1,189 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +char * +get_string(pid_t pid, unsigned long int addr, size_t *lenp, const char **errorp) +{ +	struct iovec inv, outv; +	size_t off = 0, size = 0, page_off, read_size; +	char *out = NULL, *in = (char *)addr, *p; +	page_off = (size_t)addr % sizeof(PAGE_SIZE); +	read_size = PAGE_SIZE - page_off; +	*errorp = NULL; +	for (;; read_size = PAGE_SIZE) { +		out = realloc(out, size + PAGE_SIZE); +		if (!out) +			eprintf("realloc:"); +		inv.iov_base  = &in[off]; +		inv.iov_len   = read_size; +		outv.iov_base = &out[off]; +		outv.iov_len  = read_size; +		if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) != (ssize_t)read_size) { +			*errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>"; +			*lenp = 0; +			return 0; +		} +		p = memchr(&out[off], 0, read_size); +		if (p) { +			*lenp = (size_t)(p - out); +			return out; +		} +		off += read_size; +	} +} + + +int +get_struct(pid_t pid, unsigned long int addr, void *out, size_t size, const char **errorp) +{ +	struct iovec inv, outv; +	*errorp = NULL; +	inv.iov_base  = (void *)addr; +	inv.iov_len   = size; +	outv.iov_base = out; +	outv.iov_len  = size; +	if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) == (ssize_t)size) +		return 0; +	*errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>"; +	return -1; +} + + +char * +get_memory(pid_t pid, unsigned long int addr, size_t n, const char **errorp) +{ +	char *out = malloc(n + (size_t)!n); +	if (!out) +		eprintf("malloc:"); +	if (get_struct(pid, addr, out, n, errorp)) { +		free(out); +		return NULL; +	} +	return out; +} + + + +static void +add_char(char **strp, size_t *sizep, size_t *lenp, char c) +{ +	if (*lenp == *sizep) { +		*strp = realloc(*strp, *sizep += 128); +		if (!*strp) +			eprintf("realloc:"); +	} +	(*strp)[(*lenp)++] = c; +} + + +static size_t +utf8len(char *str) +{ +	size_t ext, i, len; +	uint32_t code; +	uint8_t *s = (uint8_t *)str; + +	struct { +		uint8_t  lower; +		uint8_t  upper; +		uint8_t  mask; +		uint32_t lowest; +	} lookup[] = { +		{ 0x00, 0x7F, 0x7F, UINT32_C(0x000000) }, +		{ 0xC0, 0xDF, 0x1F, UINT32_C(0x000080) }, +		{ 0xE0, 0xEF, 0x0F, UINT32_C(0x000800) }, +		{ 0xF0, 0xF7, 0x07, UINT32_C(0x010000) } +	}; + +	for (ext = 0; ext < sizeof(lookup) / sizeof(*lookup); ext++) +		if (lookup[ext].lower <= s[0] && s[0] <= lookup[ext].upper) +			goto found; +	return 0; + +found: +	code = s[0] & lookup[ext].mask; +	len = ext + 1; +	for (i = 1; i < len; i++) { +		if ((s[i] & 0xC0) != 0x80) +			return 0; +		code = (code << 6) | (s[i] ^ 0x80); +	} + +	if (code < lookup[ext].lowest || (0xD800 <= code && code <= 0xDFFF) || code > UINT32_C(0x10FFFF)) +		return 0; +	return len; +} + + +char * +escape_memory(char *str, size_t m) +{ +	char *ret = NULL, *s, *end; +	size_t size = 0; +	size_t len = 0; +	size_t n = 0; +	int need_new_string = 0; +	if (!str) { +		str = strdup("NULL"); +		if (!str) +			eprintf("strdup:"); +		return str; +	} +	add_char(&ret, &size, &len, '"'); +	for (s = str, end = &str[m]; s != end; s++) { +		if (n) { +			add_char(&ret, &size, &len, *s); +			n -= 1; +		} else if (*s == '\r') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, 'r'); +		} else if (*s == '\t') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, 't'); +		} else if (*s == '\a') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, 'a'); +		} else if (*s == '\f') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, 'f'); +		} else if (*s == '\v') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, 'v'); +		} else if (*s == '\b') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, 'b'); +		} else if (*s == '\n') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, 'n'); +		} else if (*s == '\"') { +			add_char(&ret, &size, &len, '\\'); +			add_char(&ret, &size, &len, '"'); +		} else if (*s < ' ' || *s >= 127) { +			n = utf8len(s); +			if (n > 1) { +				add_char(&ret, &size, &len, *s); +				n -= 1; +			} else { +				n = 0; +				add_char(&ret, &size, &len, '\\'); +				add_char(&ret, &size, &len, 'x'); +				add_char(&ret, &size, &len, "0123456789abcdef"[(int)*(unsigned char *)s >> 4]); +				add_char(&ret, &size, &len, "0123456789abcdef"[(int)*(unsigned char *)s & 15]); +				need_new_string = 1; +				continue; +			} +		} else { +			if (need_new_string && isxdigit(*s)) { +				add_char(&ret, &size, &len, '"'); +				add_char(&ret, &size, &len, '"'); +			} +			add_char(&ret, &size, &len, *s); +		} +		need_new_string = 0; +	} +	add_char(&ret, &size, &len, '"'); +	add_char(&ret, &size, &len, '\0'); +	free(str); +	return ret; +} @@ -0,0 +1,560 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static void +print_clockid(struct process *proc, size_t arg_index) /* TODO */ +{ +	tprintf(proc, "%li", (long int)proc->args[arg_index]); +} + + +static void +print_timespec(struct process *proc, size_t arg_index) +{ +	struct timespec ts; +	const char *err; +	if (get_struct(proc->pid, proc->args[arg_index], &ts, sizeof(ts), &err)) { +		tprintf(proc, "%s", err); +		return; +	} +	tprintf(proc, "{.tv_sec = %ji, .tv_nsec = %li}", (intmax_t)ts.tv_sec, ts.tv_nsec); +} + + +static void +printf_systemcall(struct process *proc, const char *scall, const char *fmt, ...) +{ +	typedef char *(*Function)(struct process *proc, size_t arg_index); +	Function funcs[6]; +	size_t i, nfuncs = 0, func, len; +	unsigned long long int *args = proc->args; +	int ells = 0; +	char *str; +	const char *err; +	va_list ap; +	va_start(ap, fmt); +	tprintf(proc, "%s(", scall); +	for (i = 0; *fmt; fmt++) { +		if (*fmt == ' ') +			continue; +		if (*fmt == 'l') { +			ells += 1; +			continue; +		} else if (*fmt == 'L') { +			ells += 2; +			continue; +		} else if (*fmt == 'h') { +			ells -= 1; +			continue; +		} else if (*fmt == 'H') { +			ells -= 2; +			continue; +		} +		if (i) +			tprintf(proc, ", "); +		if (*fmt == 'p') { +			if (args[i]) +				tprintf(proc, "%p", (void *)args[i]); +			else +				tprintf(proc, "NULL"); +		} else if (*fmt >= '1' && *fmt <= '6') { +			func = (size_t)(*fmt - '0'); +			while (nfuncs < func) +				funcs[nfuncs++] = va_arg(ap, Function); +			funcs[func - 1](proc, i); +		} else if (*fmt == 's') { +			str = get_string(proc->pid, args[i], &len, &err); +			str = escape_memory(str, len); +			tprintf(proc, "%s", str ? str : err); +			free(str); +		} else if (*fmt == 'm') { +			str = escape_memory(get_memory(proc->pid, args[i], (size_t)args[i + 1], &err), (size_t)args[i + 1]); +			tprintf(proc, "%s", str ? str : err); +			free(str); +		} else if (*fmt == 'F') { +			if ((int)args[i] == AT_FDCWD) +				tprintf(proc, "AT_FDCWD"); +			else +				tprintf(proc, "%i", (int)args[i]); +		} else if (*fmt == 'u') { +			if (ells == 1) +				tprintf(proc, "%lu", (unsigned long int)args[i]); +			else if (ells > 1) +				tprintf(proc, "%llu", (unsigned long long int)args[i]); +			else +				tprintf(proc, "%u", (unsigned int)args[i]); +		} else if (*fmt == 'x') { +			if (ells == 1) +				tprintf(proc, "%#lx", (unsigned long int)args[i]); +			else if (ells > 1) +				tprintf(proc, "%#llx", (unsigned long long int)args[i]); +			else +				tprintf(proc, "%#x", (unsigned int)args[i]); +		} else if (*fmt == 'o') { +			if (ells == 1) +				tprintf(proc, "%#lo", (unsigned long int)args[i]); +			else if (ells > 1) +				tprintf(proc, "%#llo", (unsigned long long int)args[i]); +			else +				tprintf(proc, "%#o", (unsigned int)args[i]); +		} else { +			if (ells == 1) +				tprintf(proc, "%li", (long int)args[i]); +			else if (ells > 1) +				tprintf(proc, "%lli", (long long int)args[i]); +			else +				tprintf(proc, "%i", (int)args[i]); +		} +		ells = 0; +		i += 1; +	} +	tprintf(proc, ") "); +	va_end(ap); +} + + +void +print_systemcall(struct process *proc) +{ +	char buf1[128], *p, *buf; +	unsigned long int flags; +	unsigned long long int *args = proc->args; + +#define FLAGS_BEGIN(BUF, ARG)\ +	p = buf = (BUF);\ +	flags = (ARG) +#define FLAGS_ADD(FLAG)\ +	if (flags & (unsigned long int)(FLAG))\ +		p = stpcpy(p, "|"#FLAG) +#define FLAGS_END(FMT, TYPE)\ +	if (flags || p == buf)\ +		sprintf(p, "|"FMT, (TYPE)flags); + +#define UNDOCUMENTED(NAME) GENERIC_HANDLER(NAME) +#define UNIMPLEMENTED(NAME) GENERIC_HANDLER(NAME) +#define GENERIC_HANDLER(NAME)\ +	case SYS_##NAME:\ +		tprintf(proc, "%s(raw: %llu, %llu, %llu, %llu, %llu, %llu) ", #NAME,\ +		        args[0], args[1], args[2], args[3], args[4], args[5]);\ +		break +#define SIMPLE(NAME, FMT, RET_TYPE)\ +	case SYS_##NAME:\ +		printf_systemcall(proc, #NAME, (FMT), args);\ +		proc->ret_type = (RET_TYPE);\ +		break	 +#define FORMATTERS(NAME, FMT, RET_TYPE, ...)\ +	case SYS_##NAME:\ +		printf_systemcall(proc, #NAME, (FMT), args, __VA_ARGS__);\ +		proc->ret_type = (RET_TYPE);\ +		break	 + +	proc->ret_type = Unknown; + +	/* TODO replace GENERIC_HANDLER with specific handlers */ +	switch (proc->scall) { +	GENERIC_HANDLER(_sysctl); +	SIMPLE(accept, "ipp", Int); /* TODO output */ +	case SYS_accept4: /* TODO output */ +		FLAGS_BEGIN(buf1, args[3]); +		FLAGS_ADD(SOCK_NONBLOCK); +		FLAGS_ADD(SOCK_CLOEXEC); +		FLAGS_END("%#x", unsigned int); +		tprintf(proc, "accept4(%i, %p, %p, %s) ", (int)args[0], (void *)args[1], (void *)args[2], &buf1[1]); +		proc->ret_type = Int; +		break; +	SIMPLE(access, "si", Int); /* TODO flags */ +	SIMPLE(acct, "s", Int); +	GENERIC_HANDLER(add_key); +	GENERIC_HANDLER(adjtimex); +	UNIMPLEMENTED(afs_syscall); +	SIMPLE(alarm, "", UInt); +	GENERIC_HANDLER(arch_prctl); +	GENERIC_HANDLER(bind); +	GENERIC_HANDLER(bpf); +	SIMPLE(brk, "p", Int); +	GENERIC_HANDLER(capget); +	GENERIC_HANDLER(capset); +	SIMPLE(chdir, "s", Int); +	SIMPLE(chmod, "so", Int); +	SIMPLE(chown, "sii", Int); +	SIMPLE(chroot, "s", Int); +	UNDOCUMENTED(clock_adjtime); +	FORMATTERS(clock_getres, "1p", Int, print_clockid); /* TODO output */ +	FORMATTERS(clock_gettime, "1p", Int, print_clockid); /* TODO output */ +	FORMATTERS(clock_nanosleep, "1i2p", Int, print_clockid, print_timespec); /* TODO output, flags */ +	FORMATTERS(clock_settime, "12", Int, print_clockid, print_timespec); +	GENERIC_HANDLER(clone); +	GENERIC_HANDLER(clone3); +	SIMPLE(close, "i", Int); +	GENERIC_HANDLER(connect); +	GENERIC_HANDLER(copy_file_range); +	SIMPLE(creat, "so", Int); /* TODO flags */ +	SIMPLE(create_module, "slu", Ptr); +	SIMPLE(delete_module, "si", Int); /* TODO flags */ +	SIMPLE(dup, "i", Int); +	SIMPLE(dup2, "ii", Int); +	SIMPLE(dup3, "iii", Int); +	SIMPLE(epoll_create, "i", Int); +	case SYS_epoll_create1:\ +		FLAGS_BEGIN(buf1, args[0]); +		FLAGS_ADD(EPOLL_CLOEXEC); +		FLAGS_END("%#x", unsigned int); +		tprintf(proc, "epoll_create1(%s) ", &buf1[1]); +		proc->ret_type = Int; +		break; +	GENERIC_HANDLER(epoll_ctl); +	GENERIC_HANDLER(epoll_ctl_old); +	GENERIC_HANDLER(epoll_pwait); +	GENERIC_HANDLER(epoll_wait); +	GENERIC_HANDLER(epoll_wait_old); +	GENERIC_HANDLER(eventfd); +	GENERIC_HANDLER(eventfd2); +	GENERIC_HANDLER(execve); +	GENERIC_HANDLER(execveat); +	SIMPLE(exit, "i", Int); +	SIMPLE(exit_group, "i", Int); +	SIMPLE(faccessat, "Fsii", Int); /* TODO flags */ +	GENERIC_HANDLER(fadvise64); +	GENERIC_HANDLER(fallocate); +	GENERIC_HANDLER(fanotify_init); +	GENERIC_HANDLER(fanotify_mark); +	SIMPLE(fchdir, "i", Int); +	SIMPLE(fchmod, "io", Int); +	SIMPLE(fchmodat, "Fsoi", Int); /* TODO flags */ +	SIMPLE(fchown, "iii", Int); +	SIMPLE(fchownat, "Fsiii", Int); /* TODO flags */ +	GENERIC_HANDLER(fcntl); +	SIMPLE(fdatasync, "i", Int); +	SIMPLE(fgetxattr, "isplu", Long); /* TODO output */ +	GENERIC_HANDLER(finit_module); +	GENERIC_HANDLER(flistxattr); +	GENERIC_HANDLER(flock); +	SIMPLE(fork, "", Int); /* TODO fork */ +	SIMPLE(fremovexattr, "is", Int); +	UNDOCUMENTED(fsconfig); +	SIMPLE(fsetxattr, "ismlui", Int); /* TODO flags */ +	UNDOCUMENTED(fsmount); +	UNDOCUMENTED(fsopen); +	UNDOCUMENTED(fspick); +	SIMPLE(fstat, "ip", Int); /* TODO output */ +	SIMPLE(fstatfs, "ip", Int); /* TODO output */ +	SIMPLE(fsync, "i", Int); +	SIMPLE(ftruncate, "illi", Int); +	GENERIC_HANDLER(futex); +	GENERIC_HANDLER(futimesat); +	GENERIC_HANDLER(get_kernel_syms); +	GENERIC_HANDLER(get_mempolicy); +	GENERIC_HANDLER(get_robust_list); +	GENERIC_HANDLER(get_thread_area); +	GENERIC_HANDLER(getcpu); +	GENERIC_HANDLER(getcwd); +	GENERIC_HANDLER(getdents); +	GENERIC_HANDLER(getdents64); +	SIMPLE(getegid, "", Int); +	SIMPLE(geteuid, "", Int); +	SIMPLE(getgid, "", Int); +	GENERIC_HANDLER(getgroups); +	GENERIC_HANDLER(getitimer); +	GENERIC_HANDLER(getpeername); +	SIMPLE(getpgid, "i", Int); +	GENERIC_HANDLER(getpgrp); +	SIMPLE(getpid, "", Int); +	UNIMPLEMENTED(getpmsg); +	SIMPLE(getppid, "", Int); +	SIMPLE(getpriority, "ii", Int); +	SIMPLE(getrandom, "pluu", Long); /* TODO output, flags */ +	SIMPLE(getresgid, "ppp", Int); /* TODO output */ +	SIMPLE(getresuid, "ppp", Int); /* TODO output */ +	GENERIC_HANDLER(getrlimit); +	GENERIC_HANDLER(getrusage); +	SIMPLE(getsid, "i", Int); +	GENERIC_HANDLER(getsockname); +	GENERIC_HANDLER(getsockopt); +	SIMPLE(gettid, "", Int); +	GENERIC_HANDLER(gettimeofday); +	SIMPLE(getuid, "", Int); +	SIMPLE(getxattr, "ssplu", Long); /* TODO output */ +	GENERIC_HANDLER(init_module); +	SIMPLE(inotify_add_watch, "isx", Int); /* TODO flags */ +	SIMPLE(inotify_init, "", Int); +	SIMPLE(inotify_init1, "i", Int); /* TODO flags */ +	SIMPLE(inotify_rm_watch, "ii", Int); +	GENERIC_HANDLER(io_cancel); +	GENERIC_HANDLER(io_destroy); +	GENERIC_HANDLER(io_getevents); +	GENERIC_HANDLER(io_pgetevents); +	GENERIC_HANDLER(io_setup); +	GENERIC_HANDLER(io_submit); +	UNDOCUMENTED(io_uring_enter); +	UNDOCUMENTED(io_uring_register); +	UNDOCUMENTED(io_uring_setup); +	GENERIC_HANDLER(ioctl); +	SIMPLE(ioperm, "lului", Int); +	SIMPLE(iopl, "i", Int); +	GENERIC_HANDLER(ioprio_get); +	GENERIC_HANDLER(ioprio_set); +	GENERIC_HANDLER(kcmp); +	GENERIC_HANDLER(kexec_file_load); +	GENERIC_HANDLER(kexec_load); +	GENERIC_HANDLER(keyctl); +	SIMPLE(kill, "ii", Int); /* TODO flags */ +	SIMPLE(lchown, "sii", Int); +	SIMPLE(lgetxattr, "ssplu", Long); /* TODO output */ +	SIMPLE(link, "ss", Int); +	SIMPLE(linkat, "FsFsi", Int); /* TODO flags */ +	SIMPLE(listen, "ii", Int); +	GENERIC_HANDLER(listxattr); +	GENERIC_HANDLER(llistxattr); +	GENERIC_HANDLER(lookup_dcookie); +	SIMPLE(lremovexattr, "ss", Int); +	SIMPLE(lseek, "illii", LLong); /* TODO flags */ +	SIMPLE(lsetxattr, "ssmlui", Int); /* TODO flags */ +	SIMPLE(lstat, "sp", Int); /* TODO output */ +	SIMPLE(madvise, "plui", Int); /* TODO flags */ +	GENERIC_HANDLER(mbind); +	SIMPLE(membarrier, "ii", Int); /* TODO flags */ +	SIMPLE(memfd_create, "su", Int); /* TODO flags */ +	GENERIC_HANDLER(migrate_pages); +	GENERIC_HANDLER(mincore); +	SIMPLE(mkdir, "so", Int); +	SIMPLE(mkdirat, "Fso", Int); +	GENERIC_HANDLER(mknod); +	GENERIC_HANDLER(mknodat); +	SIMPLE(mlock, "plu", Int); +	SIMPLE(mlock2, "plui", Int); /* TODO flags */ +	SIMPLE(mlockall, "i", Int); /* TODO flags */ +	SIMPLE(mmap, "pluiiilli", Ptr); /* TODO flags */ +	GENERIC_HANDLER(modify_ldt); +	GENERIC_HANDLER(mount); +	UNDOCUMENTED(move_mount); +	GENERIC_HANDLER(move_pages); +	SIMPLE(mprotect, "plui", Int); /* TODO flags */ +	GENERIC_HANDLER(mq_getsetattr); +	GENERIC_HANDLER(mq_notify); +	GENERIC_HANDLER(mq_open); +	GENERIC_HANDLER(mq_timedreceive); +	GENERIC_HANDLER(mq_timedsend); +	GENERIC_HANDLER(mq_unlink); +	GENERIC_HANDLER(mremap); +	GENERIC_HANDLER(msgctl); +	GENERIC_HANDLER(msgget); +	GENERIC_HANDLER(msgrcv); +	GENERIC_HANDLER(msgsnd); +	SIMPLE(msync, "plui", Int); /* TODO flags */ +	SIMPLE(munlock, "plu", Int); +	SIMPLE(munlockall, "", Int); +	SIMPLE(munmap, "plu", Int); +	GENERIC_HANDLER(name_to_handle_at); +	FORMATTERS(nanosleep, "1p", Int, print_timespec); /* TODO output */ +	SIMPLE(newfstatat, "Fspi", Int); /* TODO output, flags */ +	SIMPLE(nfsservctl, "ipp", Long); /* TODO flags, struct, output */ +	GENERIC_HANDLER(open); +	GENERIC_HANDLER(open_by_handle_at); +	UNDOCUMENTED(open_tree); +	GENERIC_HANDLER(openat); +	SIMPLE(pause, "", Int); +	GENERIC_HANDLER(perf_event_open); +	GENERIC_HANDLER(personality); +	SIMPLE(pidfd_open, "iu", Int); +	GENERIC_HANDLER(pidfd_send_signal); +	SIMPLE(pipe, "p", Int); /* TODO output */ +	SIMPLE(pipe2, "pi", Int); /* TODO output, flags */ +	SIMPLE(pivot_root, "ss", Int); +	SIMPLE(pkey_alloc, "lulu", Int); /* TODO flags */ +	SIMPLE(pkey_free, "i", Int); +	SIMPLE(pkey_mprotect, "pluii", Int); /* TODO flags */ +	GENERIC_HANDLER(poll); +	GENERIC_HANDLER(ppoll); +	GENERIC_HANDLER(prctl); +	GENERIC_HANDLER(pread64); +	GENERIC_HANDLER(preadv); +	GENERIC_HANDLER(preadv2); +	GENERIC_HANDLER(prlimit64); +	GENERIC_HANDLER(process_vm_readv); +	GENERIC_HANDLER(process_vm_writev); +	GENERIC_HANDLER(pselect6); +	GENERIC_HANDLER(ptrace); +	UNIMPLEMENTED(putpmsg); +	GENERIC_HANDLER(pwrite64); +	GENERIC_HANDLER(pwritev); +	GENERIC_HANDLER(pwritev2); +	GENERIC_HANDLER(query_module); +	GENERIC_HANDLER(quotactl); +	SIMPLE(read, "iplu", Long); /* TODO output */ +	SIMPLE(readahead, "illilu", Long); +	SIMPLE(readlink, "splu", Long); /* TODO output */ +	SIMPLE(readlinkat, "Fsplu", Long); /* TODO output */ +	GENERIC_HANDLER(readv); +	GENERIC_HANDLER(reboot); +	GENERIC_HANDLER(recvfrom); +	GENERIC_HANDLER(recvmmsg); +	GENERIC_HANDLER(recvmsg); +	GENERIC_HANDLER(remap_file_pages); +	SIMPLE(removexattr, "ss", Int); +	SIMPLE(rename, "ss", Int); +	SIMPLE(renameat, "FsFs", Int); +	SIMPLE(renameat2, "FsFsu", Int); /* TODO flags */ +	GENERIC_HANDLER(request_key); +	SIMPLE(restart_syscall, "", Int); +	SIMPLE(rmdir, "s", Int); +	UNDOCUMENTED(rseq); +	GENERIC_HANDLER(rt_sigaction); +	GENERIC_HANDLER(rt_sigpending); +	GENERIC_HANDLER(rt_sigprocmask); +	GENERIC_HANDLER(rt_sigqueueinfo); +	GENERIC_HANDLER(rt_sigreturn); +	GENERIC_HANDLER(rt_sigsuspend); +	GENERIC_HANDLER(rt_sigtimedwait); +	GENERIC_HANDLER(rt_tgsigqueueinfo); +	SIMPLE(sched_get_priority_max, "i", Int); +	SIMPLE(sched_get_priority_min, "i", Int); +	GENERIC_HANDLER(sched_getaffinity); +	GENERIC_HANDLER(sched_getattr); +	GENERIC_HANDLER(sched_getparam); +	GENERIC_HANDLER(sched_getscheduler); +	GENERIC_HANDLER(sched_rr_get_interval); +	GENERIC_HANDLER(sched_setaffinity); +	GENERIC_HANDLER(sched_setattr); +	GENERIC_HANDLER(sched_setparam); +	GENERIC_HANDLER(sched_setscheduler); +	SIMPLE(sched_yield, "", Int); +	GENERIC_HANDLER(seccomp); +	UNIMPLEMENTED(security); +	GENERIC_HANDLER(select); +	GENERIC_HANDLER(semctl); +	GENERIC_HANDLER(semget); +	GENERIC_HANDLER(semop); +	GENERIC_HANDLER(semtimedop); +	GENERIC_HANDLER(sendfile); +	GENERIC_HANDLER(sendmmsg); +	GENERIC_HANDLER(sendmsg); +	GENERIC_HANDLER(sendto); +	GENERIC_HANDLER(set_mempolicy); +	GENERIC_HANDLER(set_robust_list); +	GENERIC_HANDLER(set_thread_area); +	SIMPLE(set_tid_address, "p", Long); +	GENERIC_HANDLER(setdomainname); +	SIMPLE(setfsgid, "i", Int); +	SIMPLE(setfsuid, "i", Int); +	SIMPLE(setgid, "i", Int); +	GENERIC_HANDLER(setgroups); +	GENERIC_HANDLER(sethostname); +	GENERIC_HANDLER(setitimer); +	GENERIC_HANDLER(setns); +	SIMPLE(setpgid, "ii", Int); +	SIMPLE(setpriority, "iii", Int); +	SIMPLE(setregid, "ii", Int); +	SIMPLE(setresgid, "iii", Int); +	SIMPLE(setresuid, "iii", Int); +	SIMPLE(setreuid, "ii", Int); +	GENERIC_HANDLER(setrlimit); +	SIMPLE(setsid, "", Int); +	GENERIC_HANDLER(setsockopt); +	GENERIC_HANDLER(settimeofday); +	SIMPLE(setuid, "i", Int); +	SIMPLE(setxattr, "ssmlui", Int); /* TODO flags */ +	GENERIC_HANDLER(shmat); +	GENERIC_HANDLER(shmctl); +	GENERIC_HANDLER(shmdt); +	GENERIC_HANDLER(shmget); +	SIMPLE(shutdown, "ii", Int); /* TODO flags */ +	GENERIC_HANDLER(sigaltstack); +	GENERIC_HANDLER(signalfd); +	GENERIC_HANDLER(signalfd4); +	SIMPLE(socket, "iii", Int); /* TODO flags */ +	SIMPLE(socketpair, "iiip", Int); /* TODO output, flags */ +	GENERIC_HANDLER(splice); +	GENERIC_HANDLER(stat); +	GENERIC_HANDLER(statfs); +	GENERIC_HANDLER(statx); +	SIMPLE(swapoff, "s", Int); +	SIMPLE(swapon, "si", Int); /* TODO flags */ +	SIMPLE(symlink, "ss", Int); +	SIMPLE(symlinkat, "sFs", Int); +	SIMPLE(sync, "", Void); +	SIMPLE(sync_file_range, "illilliu", Int); /* TODO flags */ +	SIMPLE(syncfs, "i", Int); +	GENERIC_HANDLER(sysfs); +	GENERIC_HANDLER(sysinfo); +	GENERIC_HANDLER(syslog); +	GENERIC_HANDLER(tee); +	SIMPLE(tgkill, "iii", Int); /* TODO flags */ +	SIMPLE(time, "p", LLong); /* TODO output */ +	GENERIC_HANDLER(timer_create); +	GENERIC_HANDLER(timer_delete); +	GENERIC_HANDLER(timer_getoverrun); +	GENERIC_HANDLER(timer_gettime); +	GENERIC_HANDLER(timer_settime); +	GENERIC_HANDLER(timerfd_create); +	GENERIC_HANDLER(timerfd_gettime); +	GENERIC_HANDLER(timerfd_settime); +	GENERIC_HANDLER(times); +	SIMPLE(tkill, "ii", Int); /* TODO flags */ +	SIMPLE(truncate, "slli", Int); +	UNIMPLEMENTED(tuxcall); +	SIMPLE(umask, "o", OInt); +	SIMPLE(umount2, "si", Int); /* TODO flags */ +	SIMPLE(uname, "p", Int); /* TODO output */ +	SIMPLE(unlink, "s", Int); +	SIMPLE(unlinkat, "Fsi", Int); /* TODO flags */ +	SIMPLE(unshare, "i", Int); /* TODO flags */ +	SIMPLE(uselib, "s", Int); +	SIMPLE(userfaultfd, "i", Int); /* TODO flags */ +	GENERIC_HANDLER(ustat); +	GENERIC_HANDLER(utime); +	GENERIC_HANDLER(utimensat); +	GENERIC_HANDLER(utimes); +	SIMPLE(vfork, "", Int); /* TODO fork */ +	SIMPLE(vhangup, "", Int); +	GENERIC_HANDLER(vmsplice); +	UNIMPLEMENTED(vserver); +	GENERIC_HANDLER(wait4); +	GENERIC_HANDLER(waitid); +	SIMPLE(write, "imlu", Long); +	GENERIC_HANDLER(writev); +	default: +		tprintf(proc, "syscall_0x%lx(raw: %llu, %llu, %llu, %llu, %llu, %llu) ", +		        (unsigned long int)proc->scall, args[0], args[1], args[2], args[3], args[4], args[5]); +		break; +	} +} + + +void +print_systemcall_exit(struct process *proc) +{ +	if (proc->ret_type == Int) +		tprintf(proc, "= %i", (int)proc->ret); +	else if (proc->ret_type == UInt) +		tprintf(proc, "= %u", (unsigned int)proc->ret); +	else if (proc->ret_type == OInt) +		tprintf(proc, "= %#o", (unsigned int)proc->ret); +	else if (proc->ret_type == XInt) +		tprintf(proc, "= %#x", (unsigned int)proc->ret); +	else if (proc->ret_type == Long) +		tprintf(proc, "= %li", (long int)proc->ret); +	else if (proc->ret_type == ULong) +		tprintf(proc, "= %lu", (unsigned long int)proc->ret); +	else if (proc->ret_type == OLong) +		tprintf(proc, "= %#lo", (unsigned long int)proc->ret); +	else if (proc->ret_type == XLong) +		tprintf(proc, "= %#lx", (unsigned long int)proc->ret); +	else if (proc->ret_type == LLong) +		tprintf(proc, "= %lli", (long long int)proc->ret); +	else if (proc->ret_type == ULLong) +		tprintf(proc, "= %llu", (unsigned long long int)proc->ret); +	else if (proc->ret_type == OLLong) +		tprintf(proc, "= %#llo", (unsigned long long int)proc->ret); +	else if (proc->ret_type == XLLong) +		tprintf(proc, "= %#llx", (unsigned long long int)proc->ret); +	else if (proc->ret_type == Ptr && (long long int)proc->ret >= 0) +		tprintf(proc, "= %p", (void *)proc->ret); +	else +		tprintf(proc, "= %li", (long int)proc->ret); + +	if ((unsigned long long int)proc->ret > -(unsigned long long int)PAGE_SIZE) +		tprintf(proc, " (%s: %s)", get_errno_name(-(int)proc->ret), strerror(-(int)proc->ret)); + +	tprintf(proc, "\n"); +} diff --git a/process.c b/process.c new file mode 100644 index 0000000..ea0dfd1 --- /dev/null +++ b/process.c @@ -0,0 +1,64 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static struct process head; +static struct process tail; + + +void +init_process_list(void) +{ +        head.next = &tail; +	tail.prev = &head; +} + + +struct process * +find_process(pid_t pid) +{ +        struct process *p; +        for (p = head.next; p->next; p = p->next) +                if (p->pid == pid) +                        return p; +        return NULL; +} + + +struct process * +add_process(pid_t pid, int trace_options) +{ +        struct process *proc; +	int saved_errno; +        proc = calloc(1, sizeof(*proc)); +	if (!proc) +                eprintf("calloc: %s\n"); +        proc->pid = pid; +	if (waitpid(pid, NULL, 0) < 0) { +		eprintf("waitpid <child> NULL 0:"); +		kill(pid, SIGKILL); +		exit(1); +	} +	if (ptrace(PTRACE_SETOPTIONS, pid, 0, trace_options)) { +		saved_errno = errno; +		kill(pid, SIGKILL); +		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); +        proc->next = &tail; +	proc->prev = tail.prev; +	proc->prev->next = proc; +	tail.prev = proc; +	return proc; +} + + +void +remove_process(struct process *proc) +{ + 	proc->prev->next = proc->next; +	proc->next->prev = proc->prev; +	free(proc); +} @@ -1,784 +1,60 @@  /* See LICENSE file for copyright and license details. */ -#if !defined __x86_64__ || defined __IPL32__ -# error "This program is only implemented for x86-64" -#endif - -#include <sys/ptrace.h> -#include <sys/syscall.h> -#include <sys/uio.h> -#include <sys/user.h> -#include <sys/wait.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <signal.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/* Constants used in system calls */ -#include <sys/epoll.h> -#include <sys/socket.h> -#include <fcntl.h> - -#include "arg.h" -#include "list-errnos.h" +#include "common.h"  char *argv0; -enum Type { -	Unknown, -	Void, -	Int, -	UInt, -	OInt, -	XInt, -	Long, -	ULong, -	OLong, -	XLong, -	LLong, -	ULLong, -	OLLong, -	XLLong, -	Ptr -}; - -  static void  usage(void)  { -	fprintf(stderr, "usage: %s [-f trace-output-file] command ...\n", argv0); +	fprintf(stderr, "usage: %s [-f trace-output-file] [-CFV] command ...\n", argv0);  	exit(1);  } -static const char * -get_errno_name(int err) -{ -	static char buf[3 * sizeof(err) + 2]; - -#define X(N) if (err == N) return #N; -	LIST_ERRNOS(X) -#undef X - -	sprintf(buf, "%i", err); -	return buf; -} - - -static char * -get_string(pid_t pid, unsigned long int addr, size_t *lenp, const char **errorp) -{ -	struct iovec inv, outv; -	size_t off = 0, size = 0, page_off, read_size; -	char *out = NULL, *in = (char *)addr, *p; -	page_off = (size_t)addr % sizeof(PAGE_SIZE); -	read_size = PAGE_SIZE - page_off; -	*errorp = NULL; -	for (;; read_size = PAGE_SIZE) { -		out = realloc(out, size + PAGE_SIZE); -		if (!out) { -			fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno)); -			exit(1); -		} -		inv.iov_base  = &in[off]; -		inv.iov_len   = read_size; -		outv.iov_base = &out[off]; -		outv.iov_len  = read_size; -		if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) != (ssize_t)read_size) { -			*errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>"; -			*lenp = 0; -			return 0; -		} -		p = memchr(&out[off], 0, read_size); -		if (p) { -			*lenp = (size_t)(p - out); -			return out; -		} -		off += read_size; -	} -} - - -static int -get_struct(pid_t pid, unsigned long int addr, void *out, size_t size, const char **errorp) -{ -	struct iovec inv, outv; -	*errorp = NULL; -	inv.iov_base  = (void *)addr; -	inv.iov_len   = size; -	outv.iov_base = out; -	outv.iov_len  = size; -	if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) == (ssize_t)size) -		return 0; -	*errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>"; -	return -1; -} - -static char * -get_memory(pid_t pid, unsigned long int addr, size_t n, const char **errorp) -{ -	char *out = malloc(n + (size_t)!n); -	if (!out) { -		fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno)); -		exit(1); -	} -	if (get_struct(pid, addr, out, n, errorp)) { -		free(out); -		return NULL; -	} -	return out; -} - - -  static void -add_char(char **strp, size_t *sizep, size_t *lenp, char c) +handle_syscall(struct process *proc)  { -	if (*lenp == *sizep) { -		*strp = realloc(*strp, *sizep += 128); -		if (!*strp) { -			fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno)); -			exit(1); -		} -	} -	(*strp)[(*lenp)++] = c; -} - - -static size_t -utf8len(char *str) -{ -	size_t ext, i, len; -	uint32_t code; -	uint8_t *s = (uint8_t *)str; - -	struct { -		uint8_t  lower; -		uint8_t  upper; -		uint8_t  mask; -		uint32_t lowest; -	} lookup[] = { -		{ 0x00, 0x7F, 0x7F, UINT32_C(0x000000) }, -		{ 0xC0, 0xDF, 0x1F, UINT32_C(0x000080) }, -		{ 0xE0, 0xEF, 0x0F, UINT32_C(0x000800) }, -		{ 0xF0, 0xF7, 0x07, UINT32_C(0x010000) } -	}; - -	for (ext = 0; ext < sizeof(lookup) / sizeof(*lookup); ext++) -		if (lookup[ext].lower <= s[0] && s[0] <= lookup[ext].upper) -			goto found; -	return 0; - -found: -	code = s[0] & lookup[ext].mask; -	len = ext + 1; -	for (i = 1; i < len; i++) { -		if ((s[i] & 0xC0) != 0x80) -			return 0; -		code = (code << 6) | (s[i] ^ 0x80); -	} - -	if (code < lookup[ext].lowest || (0xD800 <= code && code <= 0xDFFF) || code > UINT32_C(0x10FFFF)) -		return 0; -	return len; -} - - -static char * -escape_memory(char *str, size_t m) -{ -	char *ret = NULL, *s, *end; -	size_t size = 0; -	size_t len = 0; -	size_t n = 0; -	int need_new_string = 0; -	if (!str) { -		str = strdup("NULL"); -		if (!str) { -			fprintf(stderr, "%s: strdup: %s\n", argv0, strerror(errno)); -			exit(1); -		} -		return str; -	} -	add_char(&ret, &size, &len, '"'); -	for (s = str, end = &str[m]; s != end; s++) { -		if (n) { -			add_char(&ret, &size, &len, *s); -			n -= 1; -		} else if (*s == '\r') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, 'r'); -		} else if (*s == '\t') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, 't'); -		} else if (*s == '\a') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, 'a'); -		} else if (*s == '\f') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, 'f'); -		} else if (*s == '\v') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, 'v'); -		} else if (*s == '\b') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, 'b'); -		} else if (*s == '\n') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, 'n'); -		} else if (*s == '\"') { -			add_char(&ret, &size, &len, '\\'); -			add_char(&ret, &size, &len, '"'); -		} else if (*s < ' ' || *s >= 127) { -			n = utf8len(s); -			if (n > 1) { -				add_char(&ret, &size, &len, *s); -				n -= 1; -			} else { -				n = 0; -				add_char(&ret, &size, &len, '\\'); -				add_char(&ret, &size, &len, 'x'); -				add_char(&ret, &size, &len, "0123456789abcdef"[(int)*(unsigned char *)s >> 4]); -				add_char(&ret, &size, &len, "0123456789abcdef"[(int)*(unsigned char *)s & 15]); -				need_new_string = 1; -				continue; -			} -		} else { -			if (need_new_string && isxdigit(*s)) { -				add_char(&ret, &size, &len, '"'); -				add_char(&ret, &size, &len, '"'); -			} -			add_char(&ret, &size, &len, *s); -		} -		need_new_string = 0; -	} -	add_char(&ret, &size, &len, '"'); -	add_char(&ret, &size, &len, '\0'); -	free(str); -	return ret; -} - - -static void -fprint_clockid(FILE *fp, pid_t pid, unsigned long int args[6], size_t arg_index) /* TODO */ -{ -	(void) pid; -	fprintf(fp, "%li", (long int)args[arg_index]); -} - - -static void -fprint_timespec(FILE *fp, pid_t pid, unsigned long int args[6], size_t arg_index) -{ -	struct timespec ts; -	const char *err; -	if (get_struct(pid, args[arg_index], &ts, sizeof(ts), &err)) { -		fprintf(fp, "%s", err); -		return; -	} -	fprintf(fp, "{.tv_sec = %ji, .tv_nsec = %li}", (intmax_t)ts.tv_sec, ts.tv_nsec); -} +	struct user_regs_struct regs; +	switch (proc->state) { +	default: +		/* Get systemcall arguments */ +		if (ptrace(PTRACE_GETREGS, proc->pid, NULL, ®s)) +			eprintf("ptrace PTRACE_GETREGS %ju NULL <buffer>:", (uintmax_t)proc->pid); +		proc->scall = regs.orig_rax; +		proc->args[0] = regs.rdi; +		proc->args[1] = regs.rsi; +		proc->args[2] = regs.rdx; +		proc->args[3] = regs.r10; +		proc->args[4] = regs.r8; +		proc->args[5] = regs.r9; -static void -fprint_systemcall(FILE *fp, pid_t pid, const char *scall, const char *fmt, unsigned long int args[6], ...) -{ -	typedef char *(*Function)(FILE *fp, pid_t pid, unsigned long int args[6], size_t arg_index); -	Function funcs[6]; -	size_t i, nfuncs = 0, func, len; -	int ells = 0; -	char *str; -	const char *err; -	va_list ap; -	va_start(ap, args); -	fprintf(fp, "%s(", scall); -	for (i = 0; *fmt; fmt++) { -		if (*fmt == ' ') -			continue; -		if (*fmt == 'l') { -			ells += 1; -			continue; -		} else if (*fmt == 'L') { -			ells += 2; -			continue; -		} else if (*fmt == 'h') { -			ells -= 1; -			continue; -		} else if (*fmt == 'H') { -			ells -= 2; -			continue; -		} -		if (i) -			fprintf(fp, ", "); -		if (*fmt == 'p') { -			if (args[i]) -				fprintf(fp, "%p", (void *)args[i]); -			else -				fprintf(fp, "NULL"); -		} else if (*fmt >= '1' && *fmt <= '6') { -			func = (size_t)(*fmt - '0'); -			while (nfuncs < func) -				funcs[nfuncs++] = va_arg(ap, Function); -			funcs[func - 1](fp, pid, args, i); -		} else if (*fmt == 's') { -			str = get_string(pid, args[i], &len, &err); -			str = escape_memory(str, len); -			fprintf(fp, "%s", str ? str : err); -			free(str); -		} else if (*fmt == 'm') { -			str = escape_memory(get_memory(pid, args[i], (size_t)args[i + 1], &err), (size_t)args[i + 1]); -			fprintf(fp, "%s", str ? str : err); -			free(str); -		} else if (*fmt == 'F') { -			if ((int)args[i] == AT_FDCWD) -				fprintf(fp, "AT_FDCWD"); -			else -				fprintf(fp, "%i", (int)args[i]); -		} else if (*fmt == 'u') { -			if (ells == 1) -				fprintf(fp, "%lu", (unsigned long int)args[i]); -			else if (ells > 1) -				fprintf(fp, "%llu", (unsigned long long int)args[i]); -			else -				fprintf(fp, "%u", (unsigned int)args[i]); -		} else if (*fmt == 'x') { -			if (ells == 1) -				fprintf(fp, "%#lx", (unsigned long int)args[i]); -			else if (ells > 1) -				fprintf(fp, "%#llx", (unsigned long long int)args[i]); -			else -				fprintf(fp, "%#x", (unsigned int)args[i]); -		} else if (*fmt == 'o') { -			if (ells == 1) -				fprintf(fp, "%#lo", (unsigned long int)args[i]); -			else if (ells > 1) -				fprintf(fp, "%#llo", (unsigned long long int)args[i]); -			else -				fprintf(fp, "%#o", (unsigned int)args[i]); -		} else { -			if (ells == 1) -				fprintf(fp, "%li", (long int)args[i]); -			else if (ells > 1) -				fprintf(fp, "%lli", (long long int)args[i]); -			else -				fprintf(fp, "%i", (int)args[i]); -		} -		ells = 0; -		i += 1; -	} -	fprintf(fp, ")"); -	va_end(ap); -} +		/* Print system call */ +		print_systemcall(proc); +		/* Run system call */ +		if (ptrace(PTRACE_SYSCALL, proc->pid, NULL, 0)) +			eprintf("ptrace PTRACE_SYSCALL %ju NULL 0:", (uintmax_t)proc->pid); -static void -print_systemcall(FILE *fp, pid_t pid, unsigned long long int scall, unsigned long int args[6], enum Type *ret_type) -{ -	char buf1[128], *p, *buf; -	unsigned long int flags; +		proc->state = Syscall; +		break; -#define FLAGS_BEGIN(BUF, ARG)\ -	p = buf = (BUF);\ -	flags = (ARG) -#define FLAGS_ADD(FLAG)\ -	if (flags & (unsigned long int)(FLAG))\ -		p = stpcpy(p, "|"#FLAG) -#define FLAGS_END(FMT, TYPE)\ -	if (flags || p == buf)\ -		sprintf(p, "|"FMT, (TYPE)flags); +	case Syscall: +		/* 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; -#define UNDOCUMENTED(NAME) GENERIC_HANDLER(NAME) -#define UNIMPLEMENTED(NAME) GENERIC_HANDLER(NAME) -#define GENERIC_HANDLER(NAME)\ -	case SYS_##NAME:\ -		fprintf(fp, "%s(raw: %lu, %lu, %lu, %lu, %lu, %lu)", #NAME,\ -		        args[0], args[1], args[2], args[3], args[4], args[5]);\ -		break -#define SIMPLE(NAME, FMT, RET_TYPE)\ -	case SYS_##NAME:\ -		fprint_systemcall(fp, pid, #NAME, (FMT), args);\ -		*ret_type = (RET_TYPE);\ -		break	 -#define FORMATTERS(NAME, FMT, RET_TYPE, ...)\ -	case SYS_##NAME:\ -		fprint_systemcall(fp, pid, #NAME, (FMT), args, __VA_ARGS__);\ -		*ret_type = (RET_TYPE);\ -		break	 +		/* Print system call result */ +		print_systemcall_exit(proc); -	*ret_type = Unknown; +		/* Make process continue and stop at next syscall */ +		if (ptrace(PTRACE_SYSCALL, proc->pid, NULL, 0)) +			eprintf("ptrace PTRACE_SYSCALL %ju NULL 0", (uintmax_t)proc->pid); -	/* TODO replace GENERIC_HANDLER with specific handlers */ -	switch (scall) { -	GENERIC_HANDLER(_sysctl); -	SIMPLE(accept, "ipp", Int); /* TODO output */ -	case SYS_accept4: /* TODO output */ -		FLAGS_BEGIN(buf1, args[3]); -		FLAGS_ADD(SOCK_NONBLOCK); -		FLAGS_ADD(SOCK_CLOEXEC); -		FLAGS_END("%#x", unsigned int); -		fprintf(fp, "accept4(%i, %p, %p, %s)", (int)args[0], (void *)args[1], (void *)args[2], &buf1[1]); -		*ret_type = Int; -		break; -	SIMPLE(access, "si", Int); /* TODO flags */ -	SIMPLE(acct, "s", Int); -	GENERIC_HANDLER(add_key); -	GENERIC_HANDLER(adjtimex); -	UNIMPLEMENTED(afs_syscall); -	SIMPLE(alarm, "", UInt); -	GENERIC_HANDLER(arch_prctl); -	GENERIC_HANDLER(bind); -	GENERIC_HANDLER(bpf); -	SIMPLE(brk, "p", Int); -	GENERIC_HANDLER(capget); -	GENERIC_HANDLER(capset); -	SIMPLE(chdir, "s", Int); -	SIMPLE(chmod, "so", Int); -	SIMPLE(chown, "sii", Int); -	SIMPLE(chroot, "s", Int); -	UNDOCUMENTED(clock_adjtime); -	FORMATTERS(clock_getres, "1p", Int, fprint_clockid); /* TODO output */ -	FORMATTERS(clock_gettime, "1p", Int, fprint_clockid); /* TODO output */ -	FORMATTERS(clock_nanosleep, "1i2p", Int, fprint_clockid, fprint_timespec); /* TODO output, flags */ -	FORMATTERS(clock_settime, "12", Int, fprint_clockid, fprint_timespec); -	GENERIC_HANDLER(clone); -	GENERIC_HANDLER(clone3); -	SIMPLE(close, "i", Int); -	GENERIC_HANDLER(connect); -	GENERIC_HANDLER(copy_file_range); -	SIMPLE(creat, "so", Int); /* TODO flags */ -	SIMPLE(create_module, "slu", Ptr); -	SIMPLE(delete_module, "si", Int); /* TODO flags */ -	SIMPLE(dup, "i", Int); -	SIMPLE(dup2, "ii", Int); -	SIMPLE(dup3, "iii", Int); -	SIMPLE(epoll_create, "i", Int); -	case SYS_epoll_create1:\ -		FLAGS_BEGIN(buf1, args[0]); -		FLAGS_ADD(EPOLL_CLOEXEC); -		FLAGS_END("%#x", unsigned int); -		fprintf(fp, "epoll_create1(%s)", &buf1[1]); -		*ret_type = Int; -		break; -	GENERIC_HANDLER(epoll_ctl); -	GENERIC_HANDLER(epoll_ctl_old); -	GENERIC_HANDLER(epoll_pwait); -	GENERIC_HANDLER(epoll_wait); -	GENERIC_HANDLER(epoll_wait_old); -	GENERIC_HANDLER(eventfd); -	GENERIC_HANDLER(eventfd2); -	GENERIC_HANDLER(execve); -	GENERIC_HANDLER(execveat); -	SIMPLE(exit, "i", Int); -	SIMPLE(exit_group, "i", Int); -	SIMPLE(faccessat, "Fsii", Int); /* TODO flags */ -	GENERIC_HANDLER(fadvise64); -	GENERIC_HANDLER(fallocate); -	GENERIC_HANDLER(fanotify_init); -	GENERIC_HANDLER(fanotify_mark); -	SIMPLE(fchdir, "i", Int); -	SIMPLE(fchmod, "io", Int); -	SIMPLE(fchmodat, "Fsoi", Int); /* TODO flags */ -	SIMPLE(fchown, "iii", Int); -	SIMPLE(fchownat, "Fsiii", Int); /* TODO flags */ -	GENERIC_HANDLER(fcntl); -	SIMPLE(fdatasync, "i", Int); -	SIMPLE(fgetxattr, "isplu", Long); /* TODO output */ -	GENERIC_HANDLER(finit_module); -	GENERIC_HANDLER(flistxattr); -	GENERIC_HANDLER(flock); -	SIMPLE(fork, "", Int); /* TODO fork */ -	SIMPLE(fremovexattr, "is", Int); -	UNDOCUMENTED(fsconfig); -	SIMPLE(fsetxattr, "ismlui", Int); /* TODO flags */ -	UNDOCUMENTED(fsmount); -	UNDOCUMENTED(fsopen); -	UNDOCUMENTED(fspick); -	SIMPLE(fstat, "ip", Int); /* TODO output */ -	SIMPLE(fstatfs, "ip", Int); /* TODO output */ -	SIMPLE(fsync, "i", Int); -	SIMPLE(ftruncate, "illi", Int); -	GENERIC_HANDLER(futex); -	GENERIC_HANDLER(futimesat); -	GENERIC_HANDLER(get_kernel_syms); -	GENERIC_HANDLER(get_mempolicy); -	GENERIC_HANDLER(get_robust_list); -	GENERIC_HANDLER(get_thread_area); -	GENERIC_HANDLER(getcpu); -	GENERIC_HANDLER(getcwd); -	GENERIC_HANDLER(getdents); -	GENERIC_HANDLER(getdents64); -	SIMPLE(getegid, "", Int); -	SIMPLE(geteuid, "", Int); -	SIMPLE(getgid, "", Int); -	GENERIC_HANDLER(getgroups); -	GENERIC_HANDLER(getitimer); -	GENERIC_HANDLER(getpeername); -	SIMPLE(getpgid, "i", Int); -	GENERIC_HANDLER(getpgrp); -	SIMPLE(getpid, "", Int); -	UNIMPLEMENTED(getpmsg); -	SIMPLE(getppid, "", Int); -	SIMPLE(getpriority, "ii", Int); -	SIMPLE(getrandom, "pluu", Long); /* TODO output, flags */ -	SIMPLE(getresgid, "ppp", Int); /* TODO output */ -	SIMPLE(getresuid, "ppp", Int); /* TODO output */ -	GENERIC_HANDLER(getrlimit); -	GENERIC_HANDLER(getrusage); -	SIMPLE(getsid, "i", Int); -	GENERIC_HANDLER(getsockname); -	GENERIC_HANDLER(getsockopt); -	SIMPLE(gettid, "", Int); -	GENERIC_HANDLER(gettimeofday); -	SIMPLE(getuid, "", Int); -	SIMPLE(getxattr, "ssplu", Long); /* TODO output */ -	GENERIC_HANDLER(init_module); -	SIMPLE(inotify_add_watch, "isx", Int); /* TODO flags */ -	SIMPLE(inotify_init, "", Int); -	SIMPLE(inotify_init1, "i", Int); /* TODO flags */ -	SIMPLE(inotify_rm_watch, "ii", Int); -	GENERIC_HANDLER(io_cancel); -	GENERIC_HANDLER(io_destroy); -	GENERIC_HANDLER(io_getevents); -	GENERIC_HANDLER(io_pgetevents); -	GENERIC_HANDLER(io_setup); -	GENERIC_HANDLER(io_submit); -	UNDOCUMENTED(io_uring_enter); -	UNDOCUMENTED(io_uring_register); -	UNDOCUMENTED(io_uring_setup); -	GENERIC_HANDLER(ioctl); -	SIMPLE(ioperm, "lului", Int); -	SIMPLE(iopl, "i", Int); -	GENERIC_HANDLER(ioprio_get); -	GENERIC_HANDLER(ioprio_set); -	GENERIC_HANDLER(kcmp); -	GENERIC_HANDLER(kexec_file_load); -	GENERIC_HANDLER(kexec_load); -	GENERIC_HANDLER(keyctl); -	SIMPLE(kill, "ii", Int); /* TODO flags */ -	SIMPLE(lchown, "sii", Int); -	SIMPLE(lgetxattr, "ssplu", Long); /* TODO output */ -	SIMPLE(link, "ss", Int); -	SIMPLE(linkat, "FsFsi", Int); /* TODO flags */ -	SIMPLE(listen, "ii", Int); -	GENERIC_HANDLER(listxattr); -	GENERIC_HANDLER(llistxattr); -	GENERIC_HANDLER(lookup_dcookie); -	SIMPLE(lremovexattr, "ss", Int); -	SIMPLE(lseek, "illii", LLong); /* TODO flags */ -	SIMPLE(lsetxattr, "ssmlui", Int); /* TODO flags */ -	SIMPLE(lstat, "sp", Int); /* TODO output */ -	SIMPLE(madvise, "plui", Int); /* TODO flags */ -	GENERIC_HANDLER(mbind); -	SIMPLE(membarrier, "ii", Int); /* TODO flags */ -	SIMPLE(memfd_create, "su", Int); /* TODO flags */ -	GENERIC_HANDLER(migrate_pages); -	GENERIC_HANDLER(mincore); -	SIMPLE(mkdir, "so", Int); -	SIMPLE(mkdirat, "Fso", Int); -	GENERIC_HANDLER(mknod); -	GENERIC_HANDLER(mknodat); -	SIMPLE(mlock, "plu", Int); -	SIMPLE(mlock2, "plui", Int); /* TODO flags */ -	SIMPLE(mlockall, "i", Int); /* TODO flags */ -	SIMPLE(mmap, "pluiiilli", Ptr); /* TODO flags */ -	GENERIC_HANDLER(modify_ldt); -	GENERIC_HANDLER(mount); -	UNDOCUMENTED(move_mount); -	GENERIC_HANDLER(move_pages); -	SIMPLE(mprotect, "plui", Int); /* TODO flags */ -	GENERIC_HANDLER(mq_getsetattr); -	GENERIC_HANDLER(mq_notify); -	GENERIC_HANDLER(mq_open); -	GENERIC_HANDLER(mq_timedreceive); -	GENERIC_HANDLER(mq_timedsend); -	GENERIC_HANDLER(mq_unlink); -	GENERIC_HANDLER(mremap); -	GENERIC_HANDLER(msgctl); -	GENERIC_HANDLER(msgget); -	GENERIC_HANDLER(msgrcv); -	GENERIC_HANDLER(msgsnd); -	SIMPLE(msync, "plui", Int); /* TODO flags */ -	SIMPLE(munlock, "plu", Int); -	SIMPLE(munlockall, "", Int); -	SIMPLE(munmap, "plu", Int); -	GENERIC_HANDLER(name_to_handle_at); -	FORMATTERS(nanosleep, "1p", Int, fprint_timespec); /* TODO output */ -	SIMPLE(newfstatat, "Fspi", Int); /* TODO output, flags */ -	SIMPLE(nfsservctl, "ipp", Long); /* TODO flags, struct, output */ -	GENERIC_HANDLER(open); -	GENERIC_HANDLER(open_by_handle_at); -	UNDOCUMENTED(open_tree); -	GENERIC_HANDLER(openat); -	SIMPLE(pause, "", Int); -	GENERIC_HANDLER(perf_event_open); -	GENERIC_HANDLER(personality); -	SIMPLE(pidfd_open, "iu", Int); -	GENERIC_HANDLER(pidfd_send_signal); -	SIMPLE(pipe, "p", Int); /* TODO output */ -	SIMPLE(pipe2, "pi", Int); /* TODO output, flags */ -	SIMPLE(pivot_root, "ss", Int); -	SIMPLE(pkey_alloc, "lulu", Int); /* TODO flags */ -	SIMPLE(pkey_free, "i", Int); -	SIMPLE(pkey_mprotect, "pluii", Int); /* TODO flags */ -	GENERIC_HANDLER(poll); -	GENERIC_HANDLER(ppoll); -	GENERIC_HANDLER(prctl); -	GENERIC_HANDLER(pread64); -	GENERIC_HANDLER(preadv); -	GENERIC_HANDLER(preadv2); -	GENERIC_HANDLER(prlimit64); -	GENERIC_HANDLER(process_vm_readv); -	GENERIC_HANDLER(process_vm_writev); -	GENERIC_HANDLER(pselect6); -	GENERIC_HANDLER(ptrace); -	UNIMPLEMENTED(putpmsg); -	GENERIC_HANDLER(pwrite64); -	GENERIC_HANDLER(pwritev); -	GENERIC_HANDLER(pwritev2); -	GENERIC_HANDLER(query_module); -	GENERIC_HANDLER(quotactl); -	SIMPLE(read, "iplu", Long); /* TODO output */ -	SIMPLE(readahead, "illilu", Long); -	SIMPLE(readlink, "splu", Long); /* TODO output */ -	SIMPLE(readlinkat, "Fsplu", Long); /* TODO output */ -	GENERIC_HANDLER(readv); -	GENERIC_HANDLER(reboot); -	GENERIC_HANDLER(recvfrom); -	GENERIC_HANDLER(recvmmsg); -	GENERIC_HANDLER(recvmsg); -	GENERIC_HANDLER(remap_file_pages); -	SIMPLE(removexattr, "ss", Int); -	SIMPLE(rename, "ss", Int); -	SIMPLE(renameat, "FsFs", Int); -	SIMPLE(renameat2, "FsFsu", Int); /* TODO flags */ -	GENERIC_HANDLER(request_key); -	SIMPLE(restart_syscall, "", Int); -	SIMPLE(rmdir, "s", Int); -	UNDOCUMENTED(rseq); -	GENERIC_HANDLER(rt_sigaction); -	GENERIC_HANDLER(rt_sigpending); -	GENERIC_HANDLER(rt_sigprocmask); -	GENERIC_HANDLER(rt_sigqueueinfo); -	GENERIC_HANDLER(rt_sigreturn); -	GENERIC_HANDLER(rt_sigsuspend); -	GENERIC_HANDLER(rt_sigtimedwait); -	GENERIC_HANDLER(rt_tgsigqueueinfo); -	SIMPLE(sched_get_priority_max, "i", Int); -	SIMPLE(sched_get_priority_min, "i", Int); -	GENERIC_HANDLER(sched_getaffinity); -	GENERIC_HANDLER(sched_getattr); -	GENERIC_HANDLER(sched_getparam); -	GENERIC_HANDLER(sched_getscheduler); -	GENERIC_HANDLER(sched_rr_get_interval); -	GENERIC_HANDLER(sched_setaffinity); -	GENERIC_HANDLER(sched_setattr); -	GENERIC_HANDLER(sched_setparam); -	GENERIC_HANDLER(sched_setscheduler); -	SIMPLE(sched_yield, "", Int); -	GENERIC_HANDLER(seccomp); -	UNIMPLEMENTED(security); -	GENERIC_HANDLER(select); -	GENERIC_HANDLER(semctl); -	GENERIC_HANDLER(semget); -	GENERIC_HANDLER(semop); -	GENERIC_HANDLER(semtimedop); -	GENERIC_HANDLER(sendfile); -	GENERIC_HANDLER(sendmmsg); -	GENERIC_HANDLER(sendmsg); -	GENERIC_HANDLER(sendto); -	GENERIC_HANDLER(set_mempolicy); -	GENERIC_HANDLER(set_robust_list); -	GENERIC_HANDLER(set_thread_area); -	SIMPLE(set_tid_address, "p", Long); -	GENERIC_HANDLER(setdomainname); -	SIMPLE(setfsgid, "i", Int); -	SIMPLE(setfsuid, "i", Int); -	SIMPLE(setgid, "i", Int); -	GENERIC_HANDLER(setgroups); -	GENERIC_HANDLER(sethostname); -	GENERIC_HANDLER(setitimer); -	GENERIC_HANDLER(setns); -	SIMPLE(setpgid, "ii", Int); -	SIMPLE(setpriority, "iii", Int); -	SIMPLE(setregid, "ii", Int); -	SIMPLE(setresgid, "iii", Int); -	SIMPLE(setresuid, "iii", Int); -	SIMPLE(setreuid, "ii", Int); -	GENERIC_HANDLER(setrlimit); -	SIMPLE(setsid, "", Int); -	GENERIC_HANDLER(setsockopt); -	GENERIC_HANDLER(settimeofday); -	SIMPLE(setuid, "i", Int); -	SIMPLE(setxattr, "ssmlui", Int); /* TODO flags */ -	GENERIC_HANDLER(shmat); -	GENERIC_HANDLER(shmctl); -	GENERIC_HANDLER(shmdt); -	GENERIC_HANDLER(shmget); -	SIMPLE(shutdown, "ii", Int); /* TODO flags */ -	GENERIC_HANDLER(sigaltstack); -	GENERIC_HANDLER(signalfd); -	GENERIC_HANDLER(signalfd4); -	SIMPLE(socket, "iii", Int); /* TODO flags */ -	SIMPLE(socketpair, "iiip", Int); /* TODO output, flags */ -	GENERIC_HANDLER(splice); -	GENERIC_HANDLER(stat); -	GENERIC_HANDLER(statfs); -	GENERIC_HANDLER(statx); -	SIMPLE(swapoff, "s", Int); -	SIMPLE(swapon, "si", Int); /* TODO flags */ -	SIMPLE(symlink, "ss", Int); -	SIMPLE(symlinkat, "sFs", Int); -	SIMPLE(sync, "", Void); -	SIMPLE(sync_file_range, "illilliu", Int); /* TODO flags */ -	SIMPLE(syncfs, "i", Int); -	GENERIC_HANDLER(sysfs); -	GENERIC_HANDLER(sysinfo); -	GENERIC_HANDLER(syslog); -	GENERIC_HANDLER(tee); -	SIMPLE(tgkill, "iii", Int); /* TODO flags */ -	SIMPLE(time, "p", LLong); /* TODO output */ -	GENERIC_HANDLER(timer_create); -	GENERIC_HANDLER(timer_delete); -	GENERIC_HANDLER(timer_getoverrun); -	GENERIC_HANDLER(timer_gettime); -	GENERIC_HANDLER(timer_settime); -	GENERIC_HANDLER(timerfd_create); -	GENERIC_HANDLER(timerfd_gettime); -	GENERIC_HANDLER(timerfd_settime); -	GENERIC_HANDLER(times); -	SIMPLE(tkill, "ii", Int); /* TODO flags */ -	SIMPLE(truncate, "slli", Int); -	UNIMPLEMENTED(tuxcall); -	SIMPLE(umask, "o", OInt); -	SIMPLE(umount2, "si", Int); /* TODO flags */ -	SIMPLE(uname, "p", Int); /* TODO output */ -	SIMPLE(unlink, "s", Int); -	SIMPLE(unlinkat, "Fsi", Int); /* TODO flags */ -	SIMPLE(unshare, "i", Int); /* TODO flags */ -	SIMPLE(uselib, "s", Int); -	SIMPLE(userfaultfd, "i", Int); /* TODO flags */ -	GENERIC_HANDLER(ustat); -	GENERIC_HANDLER(utime); -	GENERIC_HANDLER(utimensat); -	GENERIC_HANDLER(utimes); -	SIMPLE(vfork, "", Int); /* TODO fork */ -	SIMPLE(vhangup, "", Int); -	GENERIC_HANDLER(vmsplice); -	UNIMPLEMENTED(vserver); -	GENERIC_HANDLER(wait4); -	GENERIC_HANDLER(waitid); -	SIMPLE(write, "imlu", Long); -	GENERIC_HANDLER(writev); -	default: -		fprintf(fp, "syscall_0x%lx(raw: %lu, %lu, %lu, %lu, %lu, %lu)", (unsigned long int)scall, -		        args[0], args[1], args[2], args[3], args[4], args[5]); +		proc->state = Normal;  		break;  	}  } @@ -787,19 +63,20 @@ print_systemcall(FILE *fp, pid_t pid, unsigned long long int scall, unsigned lon  int  main(int argc, char **argv)  { -	pid_t pid; -	struct user_regs_struct regs; -	unsigned long long int scall; +	pid_t pid, orig_pid;  	long int tmp; -	unsigned long int args[6]; -	enum Type ret_type;  	char *outfile = NULL;  	FILE *outfp = stderr;  	const char *num = NULL; -	int err; +	int status, exit_value = 0; +	unsigned long int trace_options = PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD; +	struct process *proc; +	unsigned long int event; -	/* TODO add option to trace children */ +	/* 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 specify argv[0] */  	ARGBEGIN {  	case 'f': @@ -807,39 +84,34 @@ main(int argc, char **argv)  			usage();  		outfile = EARGF(usage());  		break; +	case 'F': +		trace_options |= PTRACE_O_TRACEFORK; +		break;  	default:  		usage();  	} ARGEND;  	if (!argc)  		usage(); +	init_process_list(); +  	/* Start program to trace */  	pid = fork();  	switch (pid) {  	case -1: -		fprintf(stderr, "%s: fork: %s\n", argv0, strerror(errno)); +		eprintf("fork:");  		return 1;  	case 0:  		if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) { -			fprintf(stderr, "%s: ptrace PTRACE_TRACEME 0 NULL 0: %s\n", argv0, strerror(errno)); +			eprintf("ptrace PTRACE_TRACEME 0 NULL 0:");  			return 1;  		}  		/* exec will block until parent attaches */  		execvp(*argv, argv); -		fprintf(stderr, "%s: execvp %s: %s\n", argv0, *argv, strerror(errno)); -		exit(1); +		eprintf("execvp %s:", *argv);  	default: -		if (waitpid(pid, NULL, 0) < 0) { /* Wait for exec */ -			fprintf(stderr, "%s: waitpid <tracee> NULL 0: %s\n", argv0, strerror(errno)); -			kill(pid, SIGKILL); -			return 1; -		} -		if (ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL)) { -			fprintf(stderr, "%s: waitpid <tracee> NULL 0: %s\n", argv0, strerror(errno)); -			kill(pid, SIGKILL); -			return 1; -		} -		/* TODO check that tracee is x86-64 */ +		orig_pid = pid; +		add_process(pid, trace_options);  		break;  	} @@ -865,7 +137,7 @@ main(int argc, char **argv)  			    !*num) {  				outfp = fdopen((int)tmp, "wb");  				if (!outfp) { -					fprintf(stderr, "%s: fdopen %li wb: %s\n", argv0, tmp, strerror(errno)); +					eprintf("fdopen %li wb:", tmp);  					return 1;  				}  				goto have_outfp; @@ -873,91 +145,62 @@ main(int argc, char **argv)  		}  		outfp = fopen(outfile, "wb");  		if (!outfp) { -			fprintf(stderr, "%s: fopen %s wb: %s\n", argv0, outfile, strerror(errno)); +			eprintf("fopen %s wb:", outfile);  			return 1;  		}  	} +  have_outfp: +	set_trace_output(outfp);  	for (;;) { -		/* Wait for next syscall */ -		if (ptrace(PTRACE_SYSCALL, pid, NULL, 0)) { -			fprintf(stderr, "%s: ptrace PTRACE_SYSCALL <tracee> NULL 0: %s\n", argv0, strerror(errno)); -			return 1; -		} -		if (waitpid(pid, 0, 0) < 0) { -			fprintf(stderr, "%s: waitpid <tracee> NULL 0: %s\n", argv0, strerror(errno)); +		/* Wait for next syscall enter/exit */ +		pid = wait(&status); +		if (pid < 0) { +			if (errno == ECHILD) +				return exit_value; +			eprintf("wait <buffer>:");  			return 1;  		} -		/* Get systemcall arguments */ -		if (ptrace(PTRACE_GETREGS, pid, NULL, ®s)) { -			fprintf(stderr, "%s: ptrace PTRACE_GETREGS <tracee> NULL <buffer>: %s\n", argv0, strerror(errno)); -			return 1; -		} -		scall = regs.orig_rax; -		args[0] = regs.rdi; -		args[1] = regs.rsi; -		args[2] = regs.rdx; -		args[3] = regs.r10; -		args[4] = regs.r8; -		args[5] = regs.r9; +		proc = find_process(pid); +		if (!proc) +			continue; -		/* Print system call */ -		print_systemcall(outfp, pid, scall, args, &ret_type); +		if (WIFEXITED(status)) { +			if (pid == orig_pid) +				exit_value = WEXITSTATUS(status); +			tprintf(proc, "\nProcess exited with value %i\n", WEXITSTATUS(status)); -		/* Run system call */ -		if (ptrace(PTRACE_SYSCALL, pid, NULL, 0)) { -			fprintf(stderr, "%s: ptrace PTRACE_SYSCALL <tracee> NULL 0: %s\n", argv0, strerror(errno)); -			return 1; -		} -		if (waitpid(pid, 0, 0) == -1) { -			fprintf(stderr, "%s: waitpid <tracee> NULL 0: %s\n", argv0, strerror(errno)); -			return 1; -		} +		} else if (WIFSIGNALED(status)) { +			tprintf(proc, "\nProcess terminated by signal %i (%s)\n", WTERMSIG(status), strsignal(WTERMSIG(status))); +			/* TODO print signal name */ -		/* Get system call result */ -		if (ptrace(PTRACE_GETREGS, pid, NULL, ®s)) { -			fprintf(outfp, " = ?\n"); -			if (errno == ESRCH) -				exit((int)regs.rdi); -			fprintf(stderr, "%s: ptrace PTRACE_GETREGS <tracee> NULL <buffer>: %s\n", argv0, strerror(errno)); -		} +		} else if (WIFSTOPPED(status)) { +			if (WSTOPSIG(status) == (SIGTRAP | 0x80)) { +				handle_syscall(proc); +			} else if (WSTOPSIG(status) == SIGTRAP) { +				switch (((status >> 8) ^ SIGTRAP) >> 8) { -		/* Print system call result */ -		if (ret_type == Int) -			fprintf(outfp, " = %i", (int)regs.rax); -		else if (ret_type == UInt) -			fprintf(outfp, " = %u", (unsigned int)regs.rax); -		else if (ret_type == OInt) -			fprintf(outfp, " = %#o", (unsigned int)regs.rax); -		else if (ret_type == XInt) -			fprintf(outfp, " = %#x", (unsigned int)regs.rax); -		else if (ret_type == Long) -			fprintf(outfp, " = %li", (long int)regs.rax); -		else if (ret_type == ULong) -			fprintf(outfp, " = %lu", (unsigned long int)regs.rax); -		else if (ret_type == OLong) -			fprintf(outfp, " = %#lo", (unsigned long int)regs.rax); -		else if (ret_type == XLong) -			fprintf(outfp, " = %#lx", (unsigned long int)regs.rax); -		else if (ret_type == LLong) -			fprintf(outfp, " = %lli", (long long int)regs.rax); -		else if (ret_type == ULLong) -			fprintf(outfp, " = %llu", (unsigned long long int)regs.rax); -		else if (ret_type == OLLong) -			fprintf(outfp, " = %#llo", (unsigned long long int)regs.rax); -		else if (ret_type == XLLong) -			fprintf(outfp, " = %#llx", (unsigned long long int)regs.rax); -		else if (ret_type == Ptr && (long long int)regs.rax >= 0) -			fprintf(outfp, " = %p", (void *)regs.rax); -		else -			fprintf(outfp, " = %li", (long int)regs.rax); -		if ((unsigned long long int)regs.rax > -(unsigned long long int)PAGE_SIZE) { -			err = -(int)regs.rax; -			fprintf(outfp, " (%s: %s)", get_errno_name(err), strerror(err)); +				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); +					break; + +				default: +					goto print_signal; +				} +			} else { +			print_signal: +				tprintf(proc, "\nProcess stopped by signal %i (%s)\n", WSTOPSIG(status), strsignal(WSTOPSIG(status))); +				/* TODO print signal name */ +			} + +		} else if (WIFCONTINUED(status)) { +			tprintf(proc, "\nProcess continued\n", (uintmax_t)pid);  		} -		fprintf(outfp, "\n");  	}  	fclose(outfp); @@ -0,0 +1,56 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static FILE *trace_fp; +static char last_char = '\n'; +static pid_t last_pid = 0; + + +void +set_trace_output(FILE *fp) +{ +	trace_fp = fp; +} + + +void +tprintf(struct process *proc, const char *fmt, ...) +{ +	va_list ap; +	if (fmt[0] == '\n' && fmt[1]) { +		last_pid = 0; +		fmt = &fmt[1]; +	} +	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); +	last_pid = proc->pid; +	last_char = strchr(fmt, '\0')[-1]; +	va_end(ap); +} + + +_Noreturn void +eprintf(const char *fmt, ...) +{ +	va_list ap; +	va_start(ap, fmt); +	fprintf(stderr, "%s%s: ", last_char == '\n' ? "" : "\n", argv0); +	vfprintf(stderr, fmt, ap); +	switch (strchr(fmt, '\0')[-1]) { +	case ':': +		fprintf(stderr, " %s\n", strerror(errno)); +		break; +	case '\n': +		break; +	default: +		fprintf(stderr, "\n"); +		break; +	} +	va_end(ap); +	exit(1); +} | 
