aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2020-05-30 17:34:29 +0200
committerMattias Andrée <maandree@kth.se>2020-05-30 17:34:29 +0200
commit712f56fe3369c59d32b9000830b4ed7b25ed24b5 (patch)
tree27ddf931fd2d980d0c4dcdfb025f26f5380fb5d6
parentPrint errno names and strings (diff)
downloadsctrace-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>
-rw-r--r--Makefile24
-rw-r--r--common.h90
-rw-r--r--consts.c16
-rw-r--r--memory.c189
-rw-r--r--print.c560
-rw-r--r--process.c64
-rw-r--r--sctrace.c951
-rw-r--r--util.c56
8 files changed, 1094 insertions, 856 deletions
diff --git a/Makefile b/Makefile
index 1d032bc..3631779 100644
--- a/Makefile
+++ b/Makefile
@@ -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: $(OBJ)
+ $(CC) -o $@ $(OBJ) $(LDFLAGS)
-sctrace: sctrace.c arg.h list-errnos.h
- $(CC) -o $@ $@.c $(CPPFLAGS) $(CFLAGS) $(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;
+}
diff --git a/print.c b/print.c
new file mode 100644
index 0000000..aee9c51
--- /dev/null
+++ b/print.c
@@ -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);
+}
diff --git a/sctrace.c b/sctrace.c
index fa991d4..8000413 100644
--- a/sctrace.c
+++ b/sctrace.c
@@ -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, &regs))
+ 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, &regs))
+ 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));
- return 1;
- }
-
- /* Get systemcall arguments */
- if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
- fprintf(stderr, "%s: ptrace PTRACE_GETREGS <tracee> NULL <buffer>: %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;
}
- 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;
- /* Print system call */
- print_systemcall(outfp, pid, scall, args, &ret_type);
-
- /* 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;
- }
+ proc = find_process(pid);
+ if (!proc)
+ continue;
- /* Get system call result */
- if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
- fprintf(outfp, " = ?\n");
- if (errno == ESRCH)
- exit((int)regs.rdi);
- fprintf(stderr, "%s: ptrace PTRACE_GETREGS <tracee> NULL <buffer>: %s\n", argv0, strerror(errno));
- }
+ if (WIFEXITED(status)) {
+ if (pid == orig_pid)
+ exit_value = WEXITSTATUS(status);
+ tprintf(proc, "\nProcess exited with value %i\n", WEXITSTATUS(status));
+
+ } else if (WIFSIGNALED(status)) {
+ tprintf(proc, "\nProcess terminated by signal %i (%s)\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
+ /* TODO print signal name */
+
+ } else if (WIFSTOPPED(status)) {
+ if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
+ handle_syscall(proc);
+ } else if (WSTOPSIG(status) == SIGTRAP) {
+ switch (((status >> 8) ^ SIGTRAP) >> 8) {
+
+ 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 */
+ }
- /* 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));
+ } else if (WIFCONTINUED(status)) {
+ tprintf(proc, "\nProcess continued\n", (uintmax_t)pid);
}
- fprintf(outfp, "\n");
}
fclose(outfp);
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..76a8a36
--- /dev/null
+++ b/util.c
@@ -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);
+}