Commit Diff


commit - 1927278bfae34067f3006f13d739c0351f14a1d2
commit + 502e1ef880c10f53d5a8c8ea78a8b9f2fd4a5977
blob - 038e3eabdf2b72e8a0eb09c150efc3ad81ad0ebf
blob + bb18a8d865b5c24e0ade1a9488bb36d2f20106de
--- Makefile
+++ Makefile
@@ -30,7 +30,7 @@ run: linurv ${PROGS}
 	cp -f linurv rootfs/bin
 	cp -f ${PROGS} rootfs/bin
 	cp -f test.txt rootfs/
-	${CHROOT} rootfs /bin/linurv /bin/$T.elf
+	${CHROOT} rootfs /bin/linurv -v /bin/$T.elf
 
 distclean: clean
 	(cd tools; ${MAKE} distclean)
blob - 60f901e6468c5e851aa49a7cac9874e15027d194
blob + 4f3bb6e1a4bb70d41d87025a1e948d9fc9a1ce9d
--- examples/test.c
+++ examples/test.c
@@ -1,4 +1,7 @@
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/mman.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
@@ -59,7 +62,7 @@ int main (int argc, char *argv[]) {
 
 	printf ("Result: %u\n", mul (3, 2));
 
-	execl ("/bin/ksh", "/bin/ksh", NULL);
+	execlp ("ksh", "ksh", NULL);
 
 	return 0;
 }
blob - 9531dd891e95809b8f341424073df5a2e1596f40
blob + bc34f26155fd92483965e8e475cd02bf467bb46d
--- src/ecall.c
+++ src/ecall.c
@@ -104,15 +104,15 @@ static void stat_to_linux_stat (struct linux_stat64 *l
 {
 	memset (lst, 0, sizeof (*lst));
 	lst->dev	= st->st_dev;
-	lst->ino	= st->st_dev;
-	lst->mode	= st->st_dev;
-	lst->nlink	= st->st_dev;
-	lst->uid	= st->st_dev;
-	lst->gid	= st->st_dev;
-	lst->rdev	= st->st_dev;
-	lst->size	= st->st_dev;
-	lst->blksize	= st->st_dev;
-	lst->blocks	= st->st_dev;
+	lst->ino	= st->st_ino;
+	lst->mode	= st->st_mode;
+	lst->nlink	= st->st_nlink;
+	lst->uid	= st->st_uid;
+	lst->gid	= st->st_gid;
+	lst->rdev	= st->st_rdev;
+	lst->size	= st->st_size;
+	lst->blksize	= st->st_blksize;
+	lst->blocks	= st->st_blocks;
 	lst->atime	= st->st_atim.tv_sec;
 	lst->atime_ns	= st->st_atim.tv_nsec;
 	lst->mtime	= st->st_mtim.tv_sec;
@@ -249,11 +249,35 @@ static int mmap_prot (int x)
 		o |= PROT_READ;
 	if (x & 0x02)
 		o |= PROT_WRITE;
+	return o;
+}
+
+static int map_at (int fd)
+{
+	return fd == -100 ? AT_FDCWD : fd;
+}
+
+static int map_access (int x)
+{
+	int o = 0;
+
+	if (x == 0)
+		return F_OK;
+
+	if (x & 1)
+		o |= X_OK;
+	if (x & 2)
+		o |= W_OK;
+	if (x & 4)
+		o |= R_OK;
+
 	return o;
 }
 
 #define ptr(T, x) ((T *)(x))
 #define str(x) ptr (const char, x)
+#define dbg0(fmt) debug (fmt ": %ld", ret)
+#define dbg(fmt, ...) debug (fmt ": %ld", __VA_ARGS__, ret)
 void ecall (void)
 {
 	struct linux_stat64 lst;
@@ -268,27 +292,36 @@ void ecall (void)
 	const u64 a4 = cpu_get (14);
 	const u64 a5 = cpu_get (15);
 	const u64 a7 = cpu_get (17);
+	const int i0 = (int)a0;
+	const int i1 = (int)a1;
+	const int i2 = (int)a2;
+	const int i3 = (int)a3;
+	const int i4 = (int)a4;
 	const char *name = NULL;
 
 	if (a7 <= SYS_debug)
 		name = syscall_names[a7];
 
-	debug (
-			"ecall a7=%"PRIu64" [%s], a0=%"PRIu64", a1=%"PRIu64", a2=%"PRIu64", a3=%"PRIu64", a4=%"PRIu64", a5=%"PRIu64,
-			a7, name, a0, a1, a2, a3, a4, a5
-	);
+	//debug (
+	//		"ecall a7=%"PRIu64" [%s], a0=%"PRIu64", a1=%"PRIu64", a2=%"PRIu64", a3=%"PRIu64", a4=%"PRIu64", a5=%"PRIu64,
+	//		a7, name, a0, a1, a2, a3, a4, a5
+	//);
 
-	int tmp, tmp2;
-	i64 ret;
+	int tmp, tmp2, tmp3;
+	long ret;
+	_Static_assert (sizeof (ret) == sizeof (i64));
 	switch (a7) {
 	case SYS_getcwd:
 		ret = map (getcwd ((char *)a0, (size_t)a1) != NULL ? 0 : -1);
+		dbg0 ("getcwd()");
 		break;
 	case SYS_dup:
-		ret = map (dup ((int)a0));
+		ret = map (dup (i0));
+		dbg ("dup(%d)", i0);
 		break;
 	case SYS_dup3:
-		ret = map (dup3 ((int)a0, (int)a1, (int)a2));
+		ret = map (dup3 (i0, i1, i2));
+		dbg ("dup3(%d, %d, %d)", i0, i1, i2);
 		break;
 	case SYS_fcntl:
 		ret = enosys ("fcntl");
@@ -297,25 +330,32 @@ void ecall (void)
 		ret = enosys ("ioctl");
 		break;
 	case SYS_flock:
-		ret = map (flock ((int)a0, (int)a1));
+		ret = map (flock (i0, i1));
+		dbg ("flock(%d, %d)", i0, i1);
 		break;
 	case SYS_mknodat:
-		ret = map (mknodat ((int)a0, str (a1), (mode_t)a2, (dev_t)a3));
+		ret = map (mknodat (i0, str (a1), (mode_t)a2, (dev_t)a3));
+		dbg ("mknodat(%d, \"%s\", %o, %d)", i0, str (a1), i2, i3);
 		break;
 	case SYS_mkdirat:
-		ret = map (mkdirat ((int)a0, str (a1), (mode_t)a2));
+		ret = map (mkdirat (i0, str (a1), (mode_t)a2));
+		dbg ("mkdirat(%d, \"%s\", %o)", i0, str (a1), i2);
 		break;
 	case SYS_unlinkat:
-		ret = map (unlinkat ((int)a0, str (a1), (int)a2));
+		ret = map (unlinkat (i0, str (a1), i2));
+		dbg ("unlinkat(%d, \"%s\", %d)", i0, str (a1), i2);
 		break;
 	case SYS_symlinkat:
-		ret = map (symlinkat (str (a0), (int)a1, str (a2)));
+		ret = map (symlinkat (str (a0), i1, str (a2)));
+		dbg ("symlinkat(\"%s\", %d, \"%s\")", str (a0), i1, str (a2));
 		break;
 	case SYS_linkat:
-		ret = map (linkat ((int)a0, str (a1), (int)a2, str (a3), (int)a4));
+		ret = map (linkat (i0, str (a1), i2, str (a3), i4));
+		dbg ("linkat(%d, \"%s\", %d, \"%s\", %d)", i0, str (a1), i2, str (a3), i4);
 		break;
 	case SYS_renameat:
-		ret = map (renameat ((int)a0, str (a1), (int)a2, str (a3)));
+		ret = map (renameat (i0, str (a1), i2, str (a3)));
+		dbg ("renameat(%d, \"%s\", %d, \"%s\")", i0, str (a1), i2, str (a3));
 		break;
 	case SYS_umount:
 		ret = enosys ("umount");
@@ -337,54 +377,70 @@ void ecall (void)
 		break;
 	case SYS_truncate:
 		ret = map (truncate (str (a0), (off_t)a1));
+		dbg ("truncate(\"%s\", %llu)", str (a0), (unsigned long long)a1);
 		break;
-		break;
 	case SYS_ftruncate:
-		ret = map (ftruncate ((int)a0, (off_t)a1));
+		ret = map (ftruncate (i0, (off_t)a1));
+		dbg ("ftruncate(%d, %llu)", i0, (unsigned long long)a1);
 		break;
 	case SYS_fallocate:
 		ret = enosys ("fallocate");
 		break;
 	case SYS_faccessat:
-		ret = map (faccessat ((int)a0, str (a1), (int)a2, (int)a3));
+		tmp = map_at (i0);
+		tmp2 = map_access (i2);
+		tmp3 = 0;
+		if (i3 & 0x200)
+			tmp3 |= AT_EACCESS;
+		ret = map (faccessat (tmp, str (a1), tmp2, tmp3));
+		dbg ("faccessat(%d, \"%s\", %o, %d)", tmp, str (a1), tmp2, tmp3);
 		break;
 	case SYS_chdir:
 		ret = map (chdir (str (a0)));
+		dbg ("chdir(\"%s\")", str (a0));
 		break;
 	case SYS_fchdir:
-		ret = map (fchdir ((int)a0));
+		ret = map (fchdir (i0));
+		dbg ("fchdir(%d)", i0);
 		break;
 	case SYS_chroot:
 		ret = map (chroot (str (a0)));
+		dbg ("chroot(\"%s\")", str (a0));
 		break;
 	case SYS_fchmod:
-		ret = map (fchmod ((int)a0, (mode_t)a1));
+		ret = map (fchmod (i0, (mode_t)a1));
+		dbg ("fchmod(%d, %o)", i0, i1);
 		break;
 	case SYS_fchmodat:
-		ret = map (fchmodat ((int)a0, str (a1), (mode_t)a2, (int)a3));
+		tmp = map_at (i0);
+		ret = map (fchmodat (tmp, str (a1), (mode_t)a2, i3));
+		dbg ("fchmodat(%d, \"%s\", %o, %d)", tmp, str (a1), i2, i3);
 		break;
 	case SYS_fchownat:
-		ret = map (fchownat ((int)a0, str (a1), (uid_t)a2, (gid_t)a3, (int)a4));
+		tmp = map_at (i0);
+		ret = map (fchownat (tmp, str (a1), (uid_t)a2, (gid_t)a3, i4));
+		dbg ("fchownat(%d, \"%s\", %d, %d, %d)", tmp, str (a1), i2, i3, i4);
 		break;
 	case SYS_fchown:
-		ret = map (fchown ((int)a0, (uid_t)a1, (gid_t)a2));
+		ret = map (fchown (i0, (uid_t)a1, (gid_t)a2));
+		dbg ("fchown(%d, %d, %d)", i0, i1, i2);
 		break;
 	case SYS_openat:
-		tmp = (int)a0;
-		if (tmp == -100)
-			tmp = AT_FDCWD;
-		tmp2 = open_flags ((int)a2);
-		debug ("openat(%d, %s, %d, %d);", tmp, str (a1), tmp2, (int)a3);
-		ret = map (openat (tmp, str (a1), tmp2, (int)a3));
+		tmp = map_at (i0);
+		tmp2 = open_flags (i2);
+		ret = map (openat (tmp, str (a1), tmp2, i3));
+		dbg ("openat(%d, %s, %d, %d)", tmp, str (a1), tmp2, i3);
 		break;
 	case SYS_close:
-		ret = map (close ((int)a0));
+		ret = map (close (i0));
+		dbg ("close(%d)", i0);
 		break;
 	case SYS_vhangup:
 		ret = enosys ("vhangup");
 		break;
 	case SYS_pipe2:
-		ret = map (pipe2 (ptr (int, a0), (int)a1));
+		ret = map (pipe2 (ptr (int, a0), i1));
+		dbg ("pipe2(%p, %d)", ptr (int, a0), i1);
 		break;
 	case SYS_quotactl:
 		ret = enosys ("quotactl");
@@ -393,25 +449,32 @@ void ecall (void)
 		ret = enosys ("getdents64");
 		break;
 	case SYS_lseek:
-		ret = map (lseek ((int)a0, (off_t)a1, (int)a2));
+		ret = map (lseek (i0, (off_t)a1, i2));
+		dbg ("lseek(%d, %llu, %d)", i0, (unsigned long long)a1, i2);
 		break;
 	case SYS_read:
-		ret = map (read ((int)a0, ptr (void, a1), (size_t)a2));
+		ret = map (read (i0, ptr (void, a1), (size_t)a2));
+		dbg ("read(%d, %p, %zu)", i0, ptr (void, a1), (size_t)a2);
 		break;
 	case SYS_write:
-		ret = map (write ((int)a0, ptr (const void, a1), (size_t)a2));
+		ret = map (write (i0, ptr (const void, a1), (size_t)a2));
+		dbg ("write(%d, %p, %zu)", i0, ptr (const void, a1), (size_t)a2);
 		break;
 	case SYS_readv:
-		ret = map (readv ((int)a0, ptr (const struct iovec, a1), (int)a2));
+		ret = map (readv (i0, ptr (const struct iovec, a1), i2));
+		dbg ("readv(%d, %p, %d)", i0, ptr (const struct iovec, a1), i2);
 		break;
 	case SYS_writev:
-		ret = map (writev ((int)a0, ptr (const struct iovec, a1), (int)a2));
+		ret = map (writev (i0, ptr (const struct iovec, a1), i2));
+		dbg ("writev(%d, %p, %d)", i0, ptr (const struct iovec, a1), i2);
 		break;
 	case SYS_pread:
-		ret = map (pread ((int)a0, ptr (void, a1), (size_t)a2, (off_t)a3));
+		ret = map (pread (i0, ptr (void, a1), (size_t)a2, (off_t)a3));
+		dbg ("pread(%d, %p, %zu, %llu)", i0, ptr (void, a1), (size_t)a2, (unsigned long long)a3);
 		break;
 	case SYS_pwrite:
-		ret = map (pwrite ((int)a0, ptr (const void, a1), (size_t)a2, (off_t)a3));
+		ret = map (pwrite (i0, ptr (const void, a1), (size_t)a2, (off_t)a3));
+		dbg ("pwrite(%d, %p, %zu, %llu)", i0, ptr (const void, a1), (size_t)a2, (unsigned long long)a3);
 		break;
 	case SYS_preadv:
 		ret = enosys ("preadv");
@@ -441,27 +504,35 @@ void ecall (void)
 		ret = enosys ("tee");
 		break;
 	case SYS_readlinkat:
-		ret = map (readlinkat ((int)a0, str (a1), ptr (char, a2), (size_t)a3));
+		ret = map (readlinkat (i0, str (a1), ptr (char, a2), (size_t)a3));
+		dbg ("readlinkat(%d, \"%s\", %p, %zu)", i0, str (a1), ptr (char, a2), (size_t)a3);
 		break;
 	case SYS_fstatat:
-		ret = map (fstatat ((int)a0, str (a1), &st, (int)a3));
+		tmp = map_at (i0);
+		ret = map (fstatat (tmp, str (a1), &st, i3));
 		stat_to_linux_stat (&lst, &st);
 		memcpy (ptr (void, a2), &lst, sizeof (lst));
+		dbg ("fstatat(%d, \"%s\", %p, %d)", tmp, str (a1), ptr (void, a2), i3);
 		break;
 	case SYS_fstat:
-		ret = map (fstat ((int)a0, &st));
+		tmp = map_at (i0);
+		ret = map (fstat (tmp, &st));
 		stat_to_linux_stat (&lst, &st);
 		memcpy (ptr (void, a1), &lst, sizeof (lst));
+		dbg ("fstat(%d, %p)", tmp, ptr (void, a1));
 		break;
 	case SYS_sync:
 		sync ();
+		debug ("sync()");
 		ret = 0;
 		break;
 	case SYS_fsync:
-		ret = map (fsync ((int)a0));
+		ret = map (fsync (i0));
+		dbg ("fsync(%d)", i0);
 		break;
 	case SYS_fdatasync:
-		ret = map (fdatasync ((int)a0));
+		ret = map (fdatasync (i0));
+		dbg ("fdatasync(%d)", i0);
 		break;
 	case SYS_sync_file_range:
 		ret = enosys ("sync_file_range");
@@ -480,6 +551,7 @@ void ecall (void)
 		break;
 	case SYS_acct:
 		ret = acct (str (a0));
+		dbg ("acct(\"%s\")", str (a0));
 		break;
 	case SYS_capget:
 		ret = enosys ("capget");
@@ -491,7 +563,8 @@ void ecall (void)
 		ret = enosys ("personality");
 		break;
 	case SYS_exit:
-		exit (a0);
+		debug ("exit(%d)", i0);
+		exit (i0);
 		ret = -1;
 		break;
 	case SYS_exit_group:
@@ -587,12 +660,15 @@ void ecall (void)
 		break;
 	case SYS_sched_yield:
 		ret = map (sched_yield ());
+		dbg0 ("sched_yield()");
 		break;
 	case SYS_sched_get_priority_max:
-		ret = map (sched_get_priority_max ((int)a0));
+		ret = map (sched_get_priority_max (i0));
+		dbg ("sched_get_priority_max(%d)", i0);
 		break;
 	case SYS_sched_get_priority_min:
-		ret = map (sched_get_priority_min ((int)a0));
+		ret = map (sched_get_priority_min (i0));
+		dbg ("sched_get_priority_min(%d)", i0);
 		break;
 	case SYS_sched_rr_get_interval:
 		ret = enosys ("sched_rr_get_interval");
@@ -601,7 +677,8 @@ void ecall (void)
 		ret = enosys ("restart_syscall");
 		break;
 	case SYS_kill:
-		ret = map (kill ((pid_t)a0, (int)a1));
+		ret = map (kill ((pid_t)a0, i1));
+		dbg ("kill(%d, %d)", i0, i1);
 		break;
 	case SYS_tkill:
 		ret = enosys ("tkill");
@@ -613,7 +690,8 @@ void ecall (void)
 		ret = enosys ("signalstack");
 		break;
 	case SYS_sigsuspend:
-		ret = enosys ("sigsuspend");
+		//ret = enosys ("sigsuspend");
+		ret = 0;
 		break;
 	case SYS_sigaction:
 		ret = enosys ("sigaction");
@@ -634,33 +712,43 @@ void ecall (void)
 		ret = enosys ("sigreturn");
 		break;
 	case SYS_setpriority:
-		ret = map (setpriority ((int)a0, (id_t)a1, (int)a2));
+		ret = map (setpriority (i0, (id_t)a1, i2));
+		dbg ("setpriority(%d, %d, %d)", i0, i1, i2);
 		break;
 	case SYS_getpriority:
-		ret = map (getpriority ((int)a0, (id_t)a1));
+		ret = map (getpriority (i0, (id_t)a1));
+		dbg ("getpriority(%d, %d)", i0, i1);
 		break;
 	case SYS_reboot:
 		ret = enosys ("reboot");
 		break;
 	case SYS_setregid:
 		ret = map (setregid ((gid_t)a0, (gid_t)a1));
+		dbg ("setregid(%d, %d)", i0, i1);
 		break;
 	case SYS_setgid:
 		ret = map (setgid ((gid_t)a0));
+		dbg ("setgid(%d)", i0);
 		break;
 	case SYS_setreuid:
 		ret = map (setreuid ((uid_t)a0, (uid_t)a1));
+		dbg ("setreuid(%d, %d)", i0, i1);
 		break;
 	case SYS_setuid:
 		ret = map (setuid ((uid_t)a0));
+		dbg ("setuid(%d)", i0);
 		break;
 	case SYS_setresuid:
 #ifdef __NetBSD__
-		if (a0 != a1 || a0 != a2)
+		if (a0 != a1 || a0 != a2) {
 			ret = enosys ("setresuid");
-		ret = map (setuid ((uid_t)a0));
+		} else {
+			ret = map (setuid ((uid_t)a0));
+			dbg ("setresuid(%d, %d, %d)", i0, i1, i2);
+		}
 #else
 		ret = map (setresuid ((uid_t)a0, (uid_t)a1, (uid_t)a2));
+		dbg ("setresuid(%d, %d, %d)", i0, i1, i2);
 #endif
 		break;
 	case SYS_getresuid:
@@ -668,22 +756,28 @@ void ecall (void)
 		ret = enosys ("getresuid");
 #else
 		ret = map (getresuid (ptr (uid_t, a0), ptr (uid_t, a1), ptr (uid_t, a2)));
+		dbg ("getresuid(%p, %p, %p)", ptr (uid_t, a0), ptr (uid_t, a1), ptr (uid_t, a2));
 #endif
 		break;
 	case SYS_setresgid:
 #ifdef __NetBSD__
-		if (a0 != a1 || a0 != a2)
+		if (a0 != a1 || a0 != a2) {
 			ret = enosys ("setresgid");
-		ret = map (setgid ((uid_t)a0));
+		} else {
+			ret = map (setgid ((uid_t)a0));
+			dbg ("setresgid(%d, %d, %d)", i0, i1, i2);
+		}
 #else
 		ret = map (setresgid ((gid_t)a0, (gid_t)a1, (gid_t)a2));
+		dbg ("setresgid(%d, %d, %d)", i0, i1, i2);
 #endif
 		break;
 	case SYS_getresgid:
 #ifdef __NetBSD__
-		ret = -enosys ("getresgid");
+		ret = enosys ("getresgid");
 #else
 		ret = map (getresgid (ptr (gid_t, a0), ptr (gid_t, a1), ptr (gid_t, a2)));
+		dbg ("getresgid(%p, %p, %p)", ptr (gid_t, a0), ptr (gid_t, a1), ptr (gid_t, a2));
 #endif
 		break;
 	case SYS_setfsuid:
@@ -697,15 +791,19 @@ void ecall (void)
 		break;
 	case SYS_setpgid:
 		ret = map (setpgid ((pid_t)a0, (pid_t)a1));
+		dbg ("setpgid(%d, %d)", i0, i1);
 		break;
 	case SYS_getpgid:
 		ret = map (getpgid ((pid_t)a0));
+		dbg ("getpgid(%d)", i0);
 		break;
 	case SYS_getsid:
 		ret = map (getsid ((pid_t)a0));
+		dbg ("getsid(%d)", i0);
 		break;
 	case SYS_setsid:
 		ret = map (setsid ());
+		dbg0 ("setsid()");
 		break;
 	case SYS_setgroups:
 		ret = enosys ("setgroups");
@@ -714,6 +812,7 @@ void ecall (void)
 		ret = map (uname (&un));
 		utsname_to_linux_utsname (&lun, &un);
 		memcpy (ptr (void, a0), &lun, sizeof (lun));
+		dbg ("uname(%p)", ptr (void, a0));
 		break;
 	case SYS_sethostname:
 		ret = enosys ("sethostname");
@@ -732,6 +831,7 @@ void ecall (void)
 		break;
 	case SYS_umask:
 		ret = map (umask ((mode_t)a0));
+		dbg ("umask(%o)", i0);
 		break;
 	case SYS_prctl:
 		ret = enosys ("prctl");
@@ -750,21 +850,27 @@ void ecall (void)
 		break;
 	case SYS_getpid:
 		ret = map (getpid ());
+		dbg0 ("getpid()");
 		break;
 	case SYS_getppid:
 		ret = map (getppid ());
+		dbg0 ("getppid()");
 		break;
 	case SYS_getuid:
 		ret = map (getuid ());
+		dbg0 ("getuid()");
 		break;
 	case SYS_geteuid:
 		ret = map (geteuid ());
+		dbg0 ("geteuid()");
 		break;
 	case SYS_getgid:
 		ret = map (getgid ());
+		dbg0 ("getgid()");
 		break;
 	case SYS_getegid:
 		ret = map (getegid ());
+		dbg0 ("getegid()");
 		break;
 	case SYS_gettid:
 		ret = enosys ("gettid");
@@ -781,19 +887,23 @@ void ecall (void)
 		ret = enosys ("mq_*");
 		break;
 	case SYS_msgget:
-		ret = map(msgget ((key_t)a0, (int)a1));
+		ret = map(msgget ((key_t)a0, i1));
+		dbg ("msgget(%d, %d)", i0, i1);
 		break;
 	case SYS_msgctl:
 		ret = enosys ("msgctl");
 		break;
 	case SYS_msgrcv:
-		ret = map (msgrcv ((int)a0, ptr (void, a1), (size_t)a2, (long)a3, (int)a4));
+		ret = map (msgrcv (i0, ptr (void, a1), (size_t)a2, (long)a3, i4));
+		dbg ("msgrcv(%d, %p, %zu, %ld, %d)", i0, ptr (void, a1), (size_t)a2, (long)a3, i4);
 		break;
 	case SYS_msgsnd:
-		ret = map (msgsnd ((int)a0, ptr (const void, a1), (size_t)a2, (int)a3));
+		ret = map (msgsnd (i0, ptr (const void, a1), (size_t)a2, i3));
+		dbg ("msgsnd(%d, %p, %zu, %d)", i0, ptr (const void, a1), (size_t)a2, i3);
 		break;
 	case SYS_semget:
-		ret = map (semget ((key_t)a0, (int)a1, (int)a2));
+		ret = map (semget ((key_t)a0, i1, i2));
+		dbg ("semget(%d, %d, %d)", i0, i1, i2);
 		break;
 	case SYS_semctl:
 		ret = enosys ("semctl");
@@ -832,9 +942,11 @@ void ecall (void)
 		break;
 	case SYS_brk:
 		ret = map (my_brk (a0));
+		debug ("brk(%p): %p", ptr (void, a0), (void *)ret);
 		break;
 	case SYS_munmap:
 		ret = map (munmap (ptr (void, a0), (size_t)a1));
+		dbg ("munmap(%p, %zu)", ptr (void, a0), (size_t)a1);
 		break;
 	case SYS_mremap:
 		ret = enosys ("mremap");
@@ -850,26 +962,28 @@ void ecall (void)
 		break;
 	case SYS_clone:
 		if (a0 == 17 && a1 == 0) {
-			// fork
 			ret = map (fork ());
+			if (ret != 0)
+				dbg0 ("fork()");
 		} else {
 			ret = enosys ("clone");
 		}
 		break;
 	case SYS_execve:
+		debug ("execve(\"%s\", %p, %p)", str (a0), ptr (char *, a1), ptr (char *, a2));
 		ret = map (my_execve (str (a0), ptr (char *, a1), ptr (char *, a2)));
+		debug ("execve failed with %d", ret);
 		break;
 	case SYS_mmap:
-		tmp = mmap_flags ((int)a3);
-		tmp2 = mmap_prot ((int)a2);
-		debug ("mmap (%p, %zu, %d, %d, %d, %lld);", ptr (void, a0), (size_t)a1, tmp2, tmp, (int)a4, (off_t)a5);
-		ptr = mmap (ptr (void, a0), (size_t)a1, tmp2, tmp, (int)a4, (off_t)a5);
-		debug ("ptr = %p", ptr);
+		tmp = mmap_flags (i3);
+		tmp2 = mmap_prot (i2);
+		ptr = mmap (ptr (void, a0), (size_t)a1, tmp2, tmp, i4, (off_t)a5);
 		if (ptr == NULL) {
 			ret = -map_errno (errno);
 		} else {
 			ret = (u64)ptr;
 		}
+		debug ("mmap(%p, %zu, %o, %d, %d, %llu): %p", ptr (void, a0), (size_t)a1, tmp2, tmp, i4, (unsigned long long)a5, (void *)ret);
 		break;
 	case SYS_fadvise64:
 		ret = enosys ("fadvise64");
@@ -881,29 +995,37 @@ void ecall (void)
 		ret = enosys ("swapoff");
 		break;
 	case SYS_mprotect:
-		tmp = mmap_prot ((int)a2);
+		tmp = mmap_prot (a2);
 		ret = map (mprotect (ptr (void, a0), (size_t)a1, tmp));
+		dbg ("mprotect(%p, %zu, %d)", ptr (void, a0), (size_t)a1, tmp);
 		break;
 	case SYS_msync:
-		ret = map (msync (ptr (void, a0), (size_t)a1, (int)a2));
+		ret = map (msync (ptr (void, a0), (size_t)a1, i2));
+		dbg ("msync(%p, %zu, %d)", ptr (void, a0), (size_t)a1, i2);
 		break;
 	case SYS_mlock:
 		ret = map (mlock (ptr (void, a0), (size_t)a1));
+		dbg ("mlock(%p, %zu)", ptr (void, a0), (size_t)a1);
 		break;
 	case SYS_munlock:
 		ret = map (munlock (ptr (void, a0), (size_t)a1));
+		dbg ("munlock(%p, %zu)", ptr (void, a0), (size_t)a1);
 		break;
 	case SYS_mlockall:
-		ret = map (mlockall ((int)a0));
+		ret = map (mlockall (i0));
+		dbg ("mlockall(%d)", i0);
 		break;
 	case SYS_munlockall:
 		ret = map (munlockall ());
+		dbg0 ("munlockall()");
 		break;
 	case SYS_mincore:
 		ret = enosys ("mincore");
 		break;
 	case SYS_madvise:
-		ret = map (madvise (ptr (void, a0), (size_t)a1, (int)a2));
+		// TODO: MADV_*
+		ret = map (madvise (ptr (void, a0), (size_t)a1, i2));
+		dbg ("madvise(%p, %zu, %d)", ptr (void, a0), (size_t)a1, i2);
 		break;
 	case SYS_remap_file_pages:
 		ret = enosys ("remap_file_pages");
@@ -1059,30 +1181,39 @@ void ecall (void)
 		ret = enosys ("kexec_file_load");
 		break;
 	case SYS_open:
-		tmp = open_flags ((int)a1);
-		ret = map (open ((const char *)(size_t)a0, tmp, (int)a2));
+		tmp = open_flags (i1);
+		ret = map (open (str (a0), tmp, i2));
+		dbg ("open(\"%s\", %o, %d)", str (a0), tmp, i2);
 		break;
 	case SYS_link:
 		ret = map (link (str (a0), str (a1)));
+		dbg ("link(\"%s\", \"%s\")", str (a0), str (a1));
 		break;
 	case SYS_unlink:
 		ret = map (unlink (str (a0)));
+		dbg ("unlink(\"%s\")", str (a0));
 		break;
 	case SYS_mkdir:
 		ret = map (mkdir (str (a0), (mode_t)a1));
+		dbg ("mkdir(\"%s\", %o)", str (a0), i1);
 		break;
 	case SYS_access:
-		ret = map (access (str (a0), (int)a1));
+		// TODO: *_OK
+		tmp = map_access (i1);
+		ret = map (access (str (a0), tmp));
+		dbg ("access(\"%s\", %d)", str (a0), tmp);
 		break;
 	case SYS_stat:
 		ret = map (stat (str (a0), &st));
 		stat_to_linux_stat (&lst, &st);
 		memcpy (ptr (void, a1), &lst, sizeof (lst));
+		dbg ("stat(\"%s\", %p)", str (a0), ptr (void, a1));
 		break;
 	case SYS_lstat:
 		ret = map (lstat (str (a0), &st));
 		stat_to_linux_stat (&lst, &st);
 		memcpy (ptr (void, a1), &lst, sizeof (lst));
+		dbg ("lstat(\"%s\", %p)", str (a0), ptr (void, a1));
 		break;
 	case SYS_time:
 		ret = enosys ("time");
blob - bfafe890605229b56f681ae7470de4cf224f94fe
blob + cb238ae4659091f4c53a5e07cf31b2bb9ecc5897
--- src/exec.c
+++ src/exec.c
@@ -21,7 +21,6 @@ int is_executable (const Elf64_Ehdr *ehdr)
 
 int my_execve (const char *path, char **argv, char **envp)
 {
-
 	Elf64_Ehdr ehdr;
 	char buffer[256], *nl, *s;
 	int fd;
@@ -29,6 +28,7 @@ int my_execve (const char *path, char **argv, char **e
 	fd = open (path, O_RDONLY);
 	if (fd < 0)
 		return -1;
+
 	
 	memset (buffer, 0, sizeof (buffer));
 	read (fd, buffer, 2);
@@ -58,8 +58,9 @@ int my_execve (const char *path, char **argv, char **e
 	close (fd);
 
 	if (is_executable (&ehdr)) {
+		// TODO: otherwise the emulator can't find the executable
+		argv[0] = strdup (path);
 #if defined(__FreeBSD__)
-		extern char **environ;
 		char **old_env;
 		int st;
 
blob - 61c6296fb607bcc75bf8caf387157710c9e5b6f3
blob + 71aa357d88b64ae841025838798dd4c7ccb427ad
--- src/linurv.c
+++ src/linurv.c
@@ -11,7 +11,7 @@
 #include <errno.h>
 #include "linurv.h"
 
-static const char *levelstr[] = {
+const char *levelstr[] = {
 	[LOG_SILENT]	= "FATAL",
 	[LOG_ERROR]	= "ERROR",
 	[LOG_WARN]	= "WARN ",
@@ -183,7 +183,35 @@ static int usage (void)
 	return 1;
 }
 
-int main (int argc, char *argv[], char *envp[])
+static void set_loglevel(enum log_level level)
+{
+	curlevel = level;
+	setenv ("LINURV_LOGLEVEL", levelstr[level], 1);
+}
+
+static void parse_loglevel (const char *s)
+{
+	for (int i = 0; i <= LOG_VDEBUG; ++i) {
+		if (strcasecmp (s, levelstr[i]) == 0) {
+			set_loglevel (i);
+			return;
+		}
+	}
+	errx (1, "invalid loglevel: %s", s);
+}
+
+static void parse_env (void)
+{
+	char *s = getenv ("LINURV_LOGLEVEL");
+
+	if (s != NULL) {
+		parse_loglevel (s);
+	} else {
+		set_loglevel (LOG_WARN);
+	}
+}
+
+int main (int argc, char *argv[])
 {
 	const char *filename;
 	struct rlimit rl;
@@ -192,25 +220,22 @@ int main (int argc, char *argv[], char *envp[])
 	char *base;
 	int option;
 
-	curlevel = LOG_WARN;
+	parse_env ();
 	base = basename (argv[0]);
 
+	printf ("progname: %s\n", getprogname ());
+
 	if (strcmp (base, "linurv") == 0) {
 		while ((option = getopt (argc, argv, "vl:")) != -1) {
 			switch (option) {
 			case 'l':
-				for (int i = 0; i <= LOG_VDEBUG; ++i) {
-					if (strcmp (optarg, levelstr[i]) == 0) {
-						curlevel = i;
-						break;
-					}
-				}
+				parse_loglevel (optarg);
 				break;
 			case 'v':
 				if (curlevel < LOG_DEBUG) {
-					curlevel = LOG_DEBUG;
+					set_loglevel (LOG_DEBUG);
 				} else if (curlevel == LOG_DEBUG) {
-					curlevel = LOG_VDEBUG;
+					set_loglevel (LOG_VDEBUG);
 				}
 				break;
 			default:
@@ -221,6 +246,7 @@ int main (int argc, char *argv[], char *envp[])
 		argc -= optind;
 	}
 
+
 	if (argc < 1)
 		return usage ();
 
@@ -233,9 +259,9 @@ int main (int argc, char *argv[], char *envp[])
 		stack_size = 1 << 20;
 	}
 
-	for (envc = 0; envp[envc] != NULL; ++envc);
+	for (envc = 0; environ[envc] != NULL; ++envc);
 
-	setup_stack (stack_size, argc, argv, envc, envp);
+	setup_stack (stack_size, argc, argv, envc, environ);
 
 	while (1) {
 		const u32 instr = cpu_fetch ();
blob - 9d4d706388fd3ee14b387733af2623db578b5fc2
blob + e139c889771a6f6a503315250cf80acbad06cd75
--- src/linurv.h
+++ src/linurv.h
@@ -64,7 +64,9 @@ typedef unsigned int uint;
 extern u64 pc;
 extern u64 brkval;
 extern const char *interpreter;
+extern const char *levelstr[];
 extern enum log_level curlevel;
+extern char **environ;
 
 u32 cpu_fetch (void);
 u64 cpu_get (size_t reg);