| /* Copyright (c) 2016 Google Inc. | 
 |  * See LICENSE for details. | 
 |  * | 
 |  * Linux emulation for virtual machines. */ | 
 |  | 
 | #include <sys/stat.h> | 
 | #include <sys/types.h> | 
 | #include <parlib/stdio.h> | 
 | #include <stdlib.h> | 
 | #include <unistd.h> | 
 | #include <fcntl.h> | 
 | #include <vmm/vmm.h> | 
 | #include <errno.h> | 
 | #include <sys/syscall.h> | 
 | #include <vmm/linux_syscalls.h> | 
 | #include <sys/time.h> | 
 | #include <vmm/linuxemu.h> | 
 | #include <dlfcn.h> | 
 | #include <sys/mman.h> | 
 | #include <futex.h> | 
 | #include <sys/epoll.h> | 
 |  | 
 | // This is the maximum fd number we allow opened in dune | 
 | #define DUNE_NR_FILE_DESC 100 | 
 |  | 
 | // Some defines used in linux syscalls | 
 | #define FALLOC_FL_KEEP_SIZE 1 | 
 | #define FALLOC_FL_PUNCH_HOLE 2 | 
 | #define GRND_NONBLOCK 0x0001 | 
 | #define GRND_RANDOM 0x0002 | 
 |  | 
 | static int lemu_debug; | 
 |  | 
 | static uth_mutex_t *lemu_logging_lock; | 
 | static uth_mutex_t *fd_table_lock; | 
 |  | 
 | static FILE *lemu_global_logfile; | 
 |  | 
 | //Records the open fds of files opened with linuxemu | 
 | // TODO: Make this a dynamic array in the future | 
 | char *openfd_filenames[DUNE_NR_FILE_DESC]; | 
 |  | 
 | void init_lemu_logging(int log_level) | 
 | { | 
 | 	const char *logfile_name = "lemu.log"; | 
 | 	FILE *x = fopen(logfile_name, "w"); | 
 |  | 
 | 	lemu_debug = log_level; | 
 | 	lemu_logging_lock = uth_mutex_alloc(); | 
 |  | 
 | 	if (x != NULL) | 
 | 		lemu_global_logfile = x; | 
 | 	else | 
 | 		lemu_global_logfile = stderr; | 
 | } | 
 |  | 
 | void destroy_lemu_logging(void) | 
 | { | 
 | 	if (lemu_logging_lock != NULL) | 
 | 		uth_mutex_free(lemu_logging_lock); | 
 |  | 
 | 	if (lemu_global_logfile != stderr) | 
 | 		fclose(lemu_global_logfile); | 
 | } | 
 |  | 
 | ///////////////////////////////////// | 
 | // BEGIN SYSCALL HELPERS | 
 | ///////////////////////////////////// | 
 |  | 
 | // Checks if path is an absolute path | 
 | // Symlinks are not resolved, we just check if we refer to the root directory | 
 | bool is_absolute_path(const char *path) | 
 | { | 
 | 	if (!path || strlen(path) == 0) | 
 | 		return false; | 
 | 	return (strncmp(path, "/", 1) == 0); | 
 | } | 
 |  | 
 |  | 
 | // This resolves relative paths in syscalls like openat and unlinkat, based on | 
 | // our currently opened fds in dune | 
 | // | 
 | // This function will allocate memory for the string absolute_path, it is the | 
 | // caller's responsibility to free this memory when it is done | 
 | // | 
 | // If path is an absolute path already, we ignore fd and retrun a copy of path | 
 | // in absolute_path | 
 | bool get_absolute_path_from_fd(int fd, const char *path, char **absolute_path) | 
 | { | 
 | 	if (!path) { | 
 | 		fprintf(stderr, "get_absolute_path_from_fd: suffix is null.\n"); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	if (fd >= DUNE_NR_FILE_DESC) { | 
 | 		fprintf(stderr, "get_absolute_path_from_fd: fd too large.\n"); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	int len1 = strlen(path); | 
 |  | 
 | 	if (len1 == 0) { | 
 | 		fprintf(stderr, | 
 | 			"get_absolute_path_from_fd: suffix is empty.\n"); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	if (is_absolute_path(path)) { | 
 | 		*absolute_path = calloc(sizeof(char), len1 + 1); | 
 | 		if (!(*absolute_path)) { | 
 | 			fprintf(stderr, | 
 | 			        "get_absolute_path_from_fd: couldn't allocate memory.\n"); | 
 | 			return false; | 
 | 		} | 
 | 		strcpy(*absolute_path, path); | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	uth_mutex_lock(fd_table_lock); | 
 | 	if (!openfd_filenames[fd]) { | 
 | 		uth_mutex_unlock(fd_table_lock); | 
 | 		fprintf(stderr, | 
 | 			"get_absolute_path_from_fd: no file open at fd.\n"); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	int len2 = strlen(openfd_filenames[fd]); | 
 |  | 
 | 	if (len2 == 0) { | 
 | 		uth_mutex_unlock(fd_table_lock); | 
 | 		fprintf(stderr, | 
 | 		        "get_absolute_path_from_fd: prefix has length 0, fd was probably not open.\n"); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	// Add space for an extra slash and a null terminator | 
 | 	int total_len = len1 + len2 + 2; | 
 |  | 
 | 	*absolute_path = calloc(sizeof(char), total_len); | 
 |  | 
 | 	if (!(*absolute_path)) { | 
 | 		uth_mutex_unlock(fd_table_lock); | 
 | 		fprintf(stderr, | 
 | 		        "get_absolute_path_from_fd: couldn't allocate memory.\n"); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	strcat(*absolute_path, openfd_filenames[fd]); | 
 | 	uth_mutex_unlock(fd_table_lock); | 
 |  | 
 | 	// Add a slash if we don't have one | 
 | 	if ((*absolute_path)[len2 - 1] != '/') | 
 | 		strcat(*absolute_path, "/"); | 
 |  | 
 | 	strcat(*absolute_path, path); | 
 |  | 
 | 	fprintf(stderr, "Constructed full path \"%s\"\n", *absolute_path); | 
 | 	return true; | 
 | } | 
 |  | 
 |  | 
 | //Akaros open flags are different than linux | 
 | //This function converts them | 
 | int convert_open_flags_ltoa(int flags) | 
 | { | 
 | 	int lower3bits = flags & 0x7; | 
 | 	int otherstuff = flags & ~(0x7); | 
 |  | 
 | 	switch (lower3bits) { | 
 | 	case 0: | 
 | 		otherstuff |= O_RDONLY; | 
 | 		break; | 
 | 	case 1: | 
 | 		otherstuff |= O_WRONLY; | 
 | 		break; | 
 | 	case 2: | 
 | 		otherstuff |= O_RDWR; | 
 | 		break; | 
 | 	default: | 
 | 		// TODO(ganshun): We panic here for now if they are trying | 
 | 		// behavior we do not expect | 
 | 		panic("linuxemu, convert_open_flags_ltoa: unknown open flags provided\n"); | 
 | 		break; | 
 | 	} | 
 | 	return otherstuff; | 
 | } | 
 |  | 
 | int convert_open_flags_atol(int flags) | 
 | { | 
 | 	int lower3bits = flags & 0x7; | 
 | 	int otherstuff = flags & ~(0x7); | 
 |  | 
 | 	switch (lower3bits) { | 
 | 	case O_RDONLY: | 
 | 		otherstuff |= 0; | 
 | 		break; | 
 | 	case O_WRONLY: | 
 | 		otherstuff |= 1; | 
 | 		break; | 
 | 	case O_RDWR: | 
 | 		otherstuff |= 2; | 
 | 		break; | 
 | 	default: | 
 | 		// TODO(ganshun): We panic here for now if they are trying | 
 | 		// behavior we do not expect | 
 | 		panic("linuxemu, convert_open_flags_atol: unknown open flags provided\n"); | 
 | 		break; | 
 | 	} | 
 | 	return otherstuff; | 
 | } | 
 |  | 
 | // Updates the fd mapping for a specific fd. Allows the fd mapping to | 
 | // be freed (in the case of a close). Calls to the function may leave | 
 | // values in the fd table as NULL | 
 | bool update_fd_map(int fd, const char *path) | 
 | { | 
 | 	int len = 0; | 
 |  | 
 | 	if (fd >= DUNE_NR_FILE_DESC) | 
 | 		return false; | 
 |  | 
 | 	if (path) | 
 | 		len = strlen(path); | 
 |  | 
 | 	uth_mutex_lock(fd_table_lock); | 
 |  | 
 | 	// If there was a file here before, free the string | 
 | 	// Potential optimization would be to only free when | 
 | 	// we need to grow the size of the string. | 
 | 	if (openfd_filenames[fd]) { | 
 | 		free(openfd_filenames[fd]); | 
 | 		openfd_filenames[fd] = NULL; | 
 | 	} | 
 | 	// If we have a new file to put here, allocate memory | 
 | 	// and copy it in. | 
 | 	if (len) { | 
 | 		openfd_filenames[fd] = (char*) calloc(sizeof(char), len + 1); | 
 | 		if (!openfd_filenames[fd]) { | 
 | 			uth_mutex_unlock(fd_table_lock); | 
 | 			panic("update_fd_map could not allocate memory\n"); | 
 | 			return false; | 
 | 		} | 
 | 		strcpy(openfd_filenames[fd], path); | 
 | 	} | 
 |  | 
 | 	uth_mutex_unlock(fd_table_lock); | 
 | 	return true; | 
 | } | 
 |  | 
 | void convert_stat_akaros_to_linux(struct stat *si_akaros, | 
 |                                   struct linux_stat_amd64 *si) | 
 | { | 
 | 	si->st_dev =  (uint64_t) si_akaros->st_dev; | 
 | 	si->st_ino = (uint64_t) si_akaros->st_ino; | 
 | 	si->st_mode = (uint32_t) si_akaros->st_mode; | 
 | 	si->st_nlink = (uint64_t) si_akaros->st_nlink; | 
 | 	si->st_uid = (uint32_t) si_akaros->st_uid; | 
 | 	si->st_gid = (uint32_t) si_akaros->st_gid; | 
 | 	si->st_rdev = (uint64_t) si_akaros->st_rdev; | 
 | 	si->st_size = (int64_t) si_akaros->st_size; | 
 | 	si->st_blksize = (int64_t) si_akaros->st_blksize; | 
 | 	si->st_blocks = (int64_t) si_akaros->st_blocks; | 
 |  | 
 | 	//For now the akaros timespec works out... this might change | 
 | 	//akaros timespec must be 2x int64_t for this to be valid | 
 | 	si->st_atim = si_akaros->st_atim; | 
 | 	si->st_mtim = si_akaros->st_mtim; | 
 | 	si->st_ctim = si_akaros->st_ctim; | 
 | } | 
 |  | 
 | ///////////////////////////////////// | 
 | // BEGIN DUNE SYSCALL IMPLEMENTATIONS | 
 | ///////////////////////////////////// | 
 |  | 
 | ////////////////////////////////////////////////////// | 
 | // Ported Syscalls (we just call the akaros version) | 
 | ////////////////////////////////////////////////////// | 
 |  | 
 | bool dune_sys_ftruncate(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = ftruncate((int) tf->tf_rdi, (off_t) tf->tf_rsi); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 |  | 
 | } | 
 |  | 
 | bool dune_sys_fcntl(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = fcntl((int) tf->tf_rdi, (int) tf->tf_rsi, (int) tf->tf_rdx); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		// TODO(ganshun): fix fcntl SETFL, ak flags are different. | 
 | 		if (tf->tf_rsi == 3) | 
 | 			retval = convert_open_flags_atol(retval); | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_pread64(struct vm_trapframe *tf) | 
 | { | 
 | 	int fd = (int) tf->tf_rdi; | 
 | 	void *buf = (void*) tf->tf_rsi; | 
 | 	size_t count = tf->tf_rdx; | 
 | 	off_t offset = (off_t) tf->tf_r10; | 
 |  | 
 | 	ssize_t retval = pread(fd, buf, count, offset); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %zd\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %zd\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_read(struct vm_trapframe *tf) | 
 | { | 
 | 	ssize_t retval = read(tf->tf_rdi, (void*) tf->tf_rsi, | 
 | 			      (size_t) tf->tf_rdx); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %zd\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %zd\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_pwrite64(struct vm_trapframe *tf) | 
 | { | 
 | 	int fd = (int) tf->tf_rdi; | 
 | 	const void *buf = (const void*) tf->tf_rsi; | 
 | 	size_t length = (size_t) tf->tf_rdx; | 
 | 	off_t offset = (off_t) tf->tf_r10; | 
 |  | 
 | 	ssize_t retval = pwrite(fd, buf, length, offset); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %zd\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %zd\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_write(struct vm_trapframe *tf) | 
 | { | 
 | 	ssize_t retval = write((int) tf->tf_rdi, (const void *) tf->tf_rsi, | 
 | 	                       (size_t) tf->tf_rdx); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %zd\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %zd\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_getpid(struct vm_trapframe *tf) | 
 | { | 
 | 	// Getpid always suceeds | 
 | 	int retval = getpid(); | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, "SUCCESS %d\n", | 
 | 		  retval); | 
 | 	tf->tf_rax = retval; | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_gettimeofday(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = gettimeofday((struct timeval*) tf->tf_rdi, | 
 | 	                          (struct timezone*) tf->tf_rsi); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_dup(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = dup((int) tf->tf_rdi); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_dup2(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = dup2((int) tf->tf_rdi, (int)tf->tf_rsi); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_umask(struct vm_trapframe *tf) | 
 | { | 
 | 	//Umask always succeeds | 
 | 	int retval = umask((mode_t) tf->tf_rdi); | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, "SUCCESS %d\n", | 
 | 		  retval); | 
 | 	tf->tf_rax = retval; | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_clock_gettime(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = clock_gettime(tf->tf_rdi, (struct timespec*) tf->tf_rsi); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_munmap(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = munmap((void *) tf->tf_rdi, tf->tf_rsi); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_futex(struct vm_trapframe *tf) | 
 | { | 
 | 	int *uaddr = (int*) tf->tf_rdi; | 
 | 	int op = (int) tf->tf_rsi; | 
 | 	int val = (int) tf->tf_rdx; | 
 | 	struct timespec *timeout = (struct timespec *) tf->tf_r10; | 
 | 	int *uaddr2 = (int*) tf->tf_r8; | 
 | 	int val3 = (int) tf->tf_r9; | 
 | 	int retval = futex(uaddr, op, val, timeout, uaddr2, val3); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_gettid(struct vm_trapframe *tf) | 
 | { | 
 | 	// Gettid always succeeds | 
 | 	int retval = tf->tf_guest_pcoreid; | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, "SUCCESS %d\n", | 
 | 		  retval); | 
 | 	tf->tf_rax = retval; | 
 | 	return true; | 
 | } | 
 |  | 
 | ///////////////////////////////////////////////////////// | 
 | // Modified Syscalls (Partially implemented in Akaros) | 
 | //////////////////////////////////////////////////////// | 
 |  | 
 | bool dune_sys_open(struct vm_trapframe *tf) | 
 | { | 
 | 	const char *file = (const char *) tf->tf_rdi; | 
 | 	int flags = tf->tf_rsi; | 
 | 	int mode = tf->tf_rdx; | 
 |  | 
 | 	flags = convert_open_flags_ltoa(flags); | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 	          "Trying to open \"%s\"\n", file); | 
 |  | 
 | 	int retval  = open(file, flags, mode); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	if (!update_fd_map(retval, file)) | 
 | 		panic("[TID %d] %s: ERROR in updating fd_mapping\n", | 
 | 		      tf->tf_guest_pcoreid, dune_syscall_table[tf->tf_rax].name); | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 	          "SUCCESS %d\n", retval); | 
 | 	tf->tf_rax = retval; | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_openat(struct vm_trapframe *tf) | 
 | { | 
 |  | 
 | 	int fd = (int) tf->tf_rdi; | 
 | 	const char *s = (const char *) tf->tf_rsi; | 
 | 	int flags = (int) tf->tf_rdx; | 
 | 	char *s_absolute = NULL; | 
 | 	int retval; | 
 | 	int err; | 
 |  | 
 | 	// TODO: we panic here on failure, but there are probably instances | 
 | 	// where we'd want to recover and return EBADF or ENOTDIR | 
 | 	if (!get_absolute_path_from_fd(fd, s, &s_absolute)) { | 
 | 		panic("[TID %d] %s: ERROR in getting absolute path fd was %d, suffix was %s\n", | 
 | 		      tf->tf_guest_pcoreid, dune_syscall_table[tf->tf_rax].name, | 
 | 		      fd, s); | 
 | 	} | 
 |  | 
 | 	flags = convert_open_flags_ltoa(flags); | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 	          "trying to open absolute path %s with translated flags %p\n", | 
 | 	          s, flags); | 
 | 	retval = open(s_absolute, flags); | 
 | 	err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 		free(s_absolute); | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	if (!update_fd_map(retval, s_absolute)) { | 
 | 		panic("[TID %d] %s: ERROR in updating fd_mapping\n", | 
 | 		      tf->tf_guest_pcoreid, | 
 | 		      dune_syscall_table[tf->tf_rax].name); | 
 | 	} | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 	          "SUCCESS %d\n", retval); | 
 | 	free(s_absolute); | 
 | 	tf->tf_rax = retval; | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_readlinkat(struct vm_trapframe *tf) | 
 | { | 
 | 	int fd = (int) tf->tf_rdi; | 
 | 	const char *s = (const char*) tf->tf_rsi; | 
 | 	char *buf = (char *) tf->tf_rdx; | 
 | 	size_t bufsize = (size_t) tf->tf_r10; | 
 | 	ssize_t retval; | 
 | 	int err; | 
 | 	char *s_absolute = NULL; | 
 |  | 
 |  | 
 | 	if (!get_absolute_path_from_fd(fd, s, &s_absolute)) { | 
 | 		panic("[TID %d] %s: ERROR in getting absolute path fd was %d, suffix was %s\n", | 
 | 		      tf->tf_guest_pcoreid, dune_syscall_table[tf->tf_rax].name, | 
 | 		      fd, s); | 
 | 	} | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 	          "trying to readlink %s\n", s_absolute); | 
 | 	retval = readlink(s_absolute, buf, bufsize); | 
 | 	err = errno; | 
 | 	free(s_absolute); | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %zd\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_unlinkat(struct vm_trapframe *tf) | 
 | { | 
 | 	int fd = (int) tf->tf_rdi; | 
 | 	const char *s = (const char*) tf->tf_rsi; | 
 | 	int flags = (int) tf->tf_rdx; | 
 | 	char *s_absolute = NULL; | 
 | 	int retval, err; | 
 |  | 
 | 	if (!get_absolute_path_from_fd(fd, s, &s_absolute)) { | 
 | 		panic("[TID %d] %s: ERROR in getting absolute path fd was %d, suffix was %s\n", | 
 | 		      tf->tf_guest_pcoreid, dune_syscall_table[tf->tf_rax].name, | 
 | 		      fd, s); | 
 | 	} | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 	          "trying to unlink %s\n", s_absolute); | 
 | 	retval = unlink(s_absolute); | 
 | 	err = errno; | 
 | 	free(s_absolute); | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_close(struct vm_trapframe *tf) | 
 | { | 
 | 	int fd = tf->tf_rdi; | 
 | 	int retval, err; | 
 |  | 
 | 	retval = close(fd); | 
 | 	err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	if (!update_fd_map(fd, NULL)) { | 
 | 		panic("[TID %d] %s: ERROR in updating fd_mapping\n", | 
 | 		      tf->tf_guest_pcoreid, | 
 | 		      dune_syscall_table[tf->tf_rax].name); | 
 | 	} | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 	          "SUCCESS %d\n", retval); | 
 | 	tf->tf_rax = retval; | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_sched_yield(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	uthread_sched_yield(); | 
 | 	return true; | 
 | } | 
 |  | 
 |  | 
 | bool dune_sys_fstat(struct vm_trapframe *tf) | 
 | { | 
 | 	struct stat si_akaros_val; | 
 | 	int fd = tf->tf_rdi; | 
 | 	struct linux_stat_amd64 *si = (struct linux_stat_amd64*) tf->tf_rsi; | 
 |  | 
 | 	// TODO(ganshun): Check if mmaped | 
 | 	if (!si) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", EFAULT); | 
 | 		tf->tf_rax = -EFAULT; | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	struct stat *si_akaros = &si_akaros_val; | 
 |  | 
 | 	// Make sure we zero out the data on the stack | 
 | 	memset((void*) si_akaros, 0, sizeof(struct stat)); | 
 |  | 
 | 	int retval = fstat(fd, si_akaros); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		convert_stat_akaros_to_linux(si_akaros, si); | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_stat(struct vm_trapframe *tf) | 
 | { | 
 | 	struct stat si_akaros_val; | 
 | 	const char *path = (const char*) tf->tf_rdi; | 
 | 	struct linux_stat_amd64 *si = (struct linux_stat_amd64*) tf->tf_rsi; | 
 |  | 
 | 	// TODO(ganshun): Check if mmaped | 
 | 	if (!si) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", EFAULT); | 
 | 		tf->tf_rax = -EFAULT; | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	struct stat *si_akaros = &si_akaros_val; | 
 |  | 
 | 	// Make sure we zero out the data on the stack | 
 | 	memset((void*) si_akaros, 0, sizeof(struct stat)); | 
 |  | 
 | 	int retval = stat(path, si_akaros); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		convert_stat_akaros_to_linux(si_akaros, si); | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | /////////////////////////////////////////////////// | 
 | // Newly Implemented Syscalls | 
 | /////////////////////////////////////////////////// | 
 |  | 
 | // Dune implementation of fallocate, it just writes zeros for now | 
 | int dune_fallocate(int fd, int mode, off_t offset, off_t len) | 
 | { | 
 | 	if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE))) | 
 | 		return posix_fallocate(fd, offset, len); | 
 |  | 
 | 	if (offset < 0 || len <= 0) { | 
 | 		errno = EINVAL; | 
 | 		return -1; | 
 | 	} | 
 | 	struct stat st; | 
 | 	int ret = fstat(fd, &st); | 
 |  | 
 | 	if (ret == -1) { | 
 | 		errno == EBADF; | 
 | 		return -1; | 
 | 	} | 
 | 	if (offset + len >= st.st_size) { | 
 | 		// Panic here as we cannot support changing the size of the file | 
 | 		// right now. | 
 | 		panic("dune_fallocate: would write over the size of the file!"); | 
 | 	} | 
 | 	if (S_ISFIFO(st.st_mode)) { | 
 | 		errno = ESPIPE; | 
 | 		return -1; | 
 | 	} | 
 | 	if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) { | 
 | 		errno = ENODEV; | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	// TODO(ganshun): For punch hole, we just write zeros to the file for | 
 | 	// now | 
 | 	if ((mode & FALLOC_FL_PUNCH_HOLE) && (mode & FALLOC_FL_KEEP_SIZE)) { | 
 | 		const size_t buffer_size = 0x100000; | 
 | 		int pos; | 
 | 		ssize_t amt = 0; | 
 | 		size_t tot = 0; | 
 | 		size_t size; | 
 | 		char *buf = calloc(sizeof(char), buffer_size); | 
 |  | 
 | 		if (!buf) | 
 | 			panic("dune_fallocate: could not allocate a buffer\n"); | 
 |  | 
 | 		for (pos = offset; pos < offset + len; pos += amt) { | 
 | 			size = len + offset - pos; | 
 | 			if (size > buffer_size) | 
 | 				size = buffer_size; | 
 | 			amt = write(fd, buf, size); | 
 | 			if (amt == -1) { | 
 | 				free(buf); | 
 | 				errno = EIO; | 
 | 				return -1; | 
 | 			} | 
 | 			tot += amt; | 
 | 			fprintf(stderr, "%d bytes written so far\n", tot); | 
 | 		} | 
 | 		free(buf); | 
 | 		return tot; | 
 | 	} | 
 |  | 
 | 	// Unsupported otherwise | 
 | 	errno = ENOSYS; | 
 | 	return -1; | 
 | } | 
 |  | 
 | // Fallocate syscall | 
 | bool dune_sys_fallocate(struct vm_trapframe *tf) | 
 | { | 
 | 	int fd = (int) tf->tf_rdi; | 
 | 	int mode = (int) tf->tf_rsi; | 
 | 	off_t offset = (off_t) tf->tf_rdx; | 
 | 	off_t len = (off_t) tf->tf_r10; | 
 |  | 
 | 	int retval = dune_fallocate(fd, mode, offset, len); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | // Currently unsupported | 
 | bool dune_sys_sched_getaffinity(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = -ENOSYS; | 
 | 	return true; | 
 | } | 
 |  | 
 | // We do not implement pselect; however, some applications may try to | 
 | // use it as a portable way to sleep. If that is the case, then we | 
 | // allow it | 
 | bool dune_sys_pselect6(struct vm_trapframe *tf) | 
 | { | 
 | 	int nfds = (int) tf->tf_rdi; | 
 | 	fd_set *readfds = (fd_set *) tf->tf_rsi; | 
 | 	fd_set *writefds = (fd_set *) tf->tf_rdx; | 
 | 	fd_set *exceptfds = (fd_set *) tf->tf_r10; | 
 | 	const struct timespec *timeout = (const struct timespec *) tf->tf_r8; | 
 | 	const sigset_t *sigmask = (const sigset_t *) tf->tf_r9; | 
 |  | 
 | 	// Check if process wants to sleep | 
 | 	if (nfds == 0 && readfds == NULL && writefds == NULL && | 
 | 	    exceptfds == NULL && timeout != NULL) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "Sleeping for %ld seconds, %ld nanoseconds\n", | 
 | 		          timeout->tv_sec, timeout->tv_nsec); | 
 | 		nanosleep(timeout, NULL); | 
 | 		tf->tf_rax = 0; | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 	          "unimplemented, will now fail...\n"); | 
 | 	return false; | 
 | } | 
 |  | 
 | bool dune_sys_getrandom(struct vm_trapframe *tf) | 
 | { | 
 | 	const char *random_source = "/dev/urandom"; | 
 | 	void *buf = (void*) tf->tf_rdi; | 
 | 	size_t len = (size_t) tf->tf_rsi; | 
 | 	unsigned int flags = (unsigned int) tf->tf_rdx; | 
 |  | 
 | 	if (!buf) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "buffer inaccessable\n"); | 
 | 		tf->tf_rax = -EFAULT; | 
 | 		return true; | 
 | 	} | 
 | 	if (flags & GRND_RANDOM || flags & GRND_NONBLOCK) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "unsupported flags specified\n"); | 
 | 		tf->tf_rax = -EINVAL; | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	int fd = open(random_source, O_RDONLY); | 
 | 	int err = errno; | 
 |  | 
 | 	if (fd == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 			  "ERROR opening random source %s, errno=%d\n", | 
 | 			  random_source, err); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	ssize_t retval = read(fd, buf, len); | 
 |  | 
 | 	err = errno; | 
 | 	close(fd); | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR reading from random source %s, errno=%d\n", | 
 | 		          random_source, err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %zd\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | ///////////////////////////////////////////////////////////////// | 
 | /// We don't have a good implementation for these syscalls, | 
 | /// they will not work in all cases | 
 | ///////////////////////////////////////////////////////////////// | 
 |  | 
 | bool dune_sys_getgroups(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	return true; | 
 | } | 
 |  | 
 |  | 
 | bool dune_sys_geteuid(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_getegid(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	return true; | 
 | } | 
 |  | 
 |  | 
 | bool dune_sys_getuid(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	return true; | 
 | } | 
 |  | 
 |  | 
 | bool dune_sys_getgid(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	return true; | 
 | } | 
 |  | 
 | // TODO(ganshun): implement mincore | 
 | bool dune_sys_mincore(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = -ENOMEM; | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_rt_sigprocmask(struct vm_trapframe *tf) | 
 | { | 
 | 	int retval = sigprocmask(tf->tf_rdi, (const sigset_t*) tf->tf_rsi, | 
 | 	                         (sigset_t*) tf->tf_rdx); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | // TODO(ganshun): sigaltstack needs to implemented for the guest | 
 | bool dune_sys_sigaltstack(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	return true; | 
 | } | 
 |  | 
 |  | 
 | // TODO(ganshun): more signal code, we need to be careful with this one, | 
 | // we should not register guest signal handlers in akaros | 
 | bool dune_sys_rt_sigaction(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = 0; | 
 | 	return true; | 
 | } | 
 |  | 
 | //TODO(ganshun): we do not support epoll currently except for create and wait | 
 | bool dune_sys_epoll_create1(struct vm_trapframe *tf) | 
 | { | 
 | 	int flags = 0; | 
 | 	// TODO(ganshun): epoll_create is not fully supported for all flags | 
 | 	// so we ignore the flags variable in the trapframe since it is not used. | 
 | 	int retval = epoll_create1(flags); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | bool dune_sys_epoll_wait(struct vm_trapframe *tf) | 
 | { | 
 | 	int epfd = (int) tf->tf_rdi; | 
 | 	struct epoll_event *events = (struct epoll_event*) tf->tf_rsi; | 
 | 	int maxevents = (int) tf->tf_rdx; | 
 | 	int timeout = (int) tf->tf_r10; | 
 | 	int retval = epoll_wait(epfd, events, maxevents, timeout); | 
 | 	int err = errno; | 
 |  | 
 | 	if (retval == -1) { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, true, | 
 | 		          "ERROR %d\n", err); | 
 | 		tf->tf_rax = -err; | 
 | 	} else { | 
 | 		lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, false, | 
 | 		          "SUCCESS %d\n", retval); | 
 | 		tf->tf_rax = retval; | 
 | 	} | 
 | 	return true; | 
 | } | 
 |  | 
 | // Unimplemented | 
 | bool dune_sys_epoll_ctl(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = -ENOSYS; | 
 | 	return true; | 
 | } | 
 |  | 
 | // Unimplemented | 
 | bool dune_sys_fstatfs(struct vm_trapframe *tf) | 
 | { | 
 | 	tf->tf_rax = -ENOSYS; | 
 | 	return true; | 
 | } | 
 |  | 
 | // Main syscall table | 
 | struct dune_sys_table_entry dune_syscall_table[DUNE_MAX_NUM_SYSCALLS] = { | 
 | 	[DUNE_SYS_READ] = {dune_sys_read, "DUNE_SYS_READ"}, | 
 | 	[DUNE_SYS_WRITE] = {dune_sys_write, "DUNE_SYS_WRITE"}, | 
 | 	[DUNE_SYS_OPEN] = {dune_sys_open, "DUNE_SYS_OPEN"}, | 
 | 	[DUNE_SYS_CLOSE] = {dune_sys_close, "DUNE_SYS_CLOSE"}, | 
 | 	[DUNE_SYS_STAT] = {dune_sys_stat, "DUNE_SYS_STAT"}, | 
 | 	[DUNE_SYS_FSTAT] = {dune_sys_fstat, "DUNE_SYS_FSTAT"}, | 
 | 	[DUNE_SYS_LSTAT] = {NULL, "DUNE_SYS_LSTAT"}, | 
 | 	[DUNE_SYS_POLL] = {NULL, "DUNE_SYS_POLL"}, | 
 | 	[DUNE_SYS_LSEEK] = {NULL, "DUNE_SYS_LSEEK"}, | 
 | 	[DUNE_SYS_MMAP] = {NULL, "DUNE_SYS_MMAP"}, | 
 | 	[DUNE_SYS_MPROTECT] = {NULL, "DUNE_SYS_MPROTECT"}, | 
 | 	[DUNE_SYS_MUNMAP] = {dune_sys_munmap, "DUNE_SYS_MUNMAP"}, | 
 | 	[DUNE_SYS_BRK] = {NULL, "DUNE_SYS_BRK"}, | 
 | 	[DUNE_SYS_RT_SIGACTION] = {dune_sys_rt_sigaction, "DUNE_SYS_RT_SIGACTION"}, | 
 | 	[DUNE_SYS_RT_SIGPROCMASK] = {dune_sys_rt_sigprocmask, | 
 | 	                             "DUNE_SYS_RT_SIGPROCMASK"}, | 
 | 	[DUNE_SYS_RT_SIGRETURN] = {NULL, "DUNE_SYS_RT_SIGRETURN"}, | 
 | 	[DUNE_SYS_IOCTL] = {NULL, "DUNE_SYS_IOCTL"}, | 
 | 	[DUNE_SYS_PREAD64] = {dune_sys_pread64, "DUNE_SYS_PREAD64"}, | 
 | 	[DUNE_SYS_PWRITE64] = {dune_sys_pwrite64, "DUNE_SYS_PWRITE64"}, | 
 | 	[DUNE_SYS_READV] = {NULL, "DUNE_SYS_READV"}, | 
 | 	[DUNE_SYS_WRITEV] = {NULL, "DUNE_SYS_WRITEV"}, | 
 | 	[DUNE_SYS_ACCESS] = {NULL, "DUNE_SYS_ACCESS"}, | 
 | 	[DUNE_SYS_PIPE] = {NULL, "DUNE_SYS_PIPE"}, | 
 | 	[DUNE_SYS_SELECT] = {NULL, "DUNE_SYS_SELECT"}, | 
 | 	[DUNE_SYS_SCHED_YIELD] = {dune_sys_sched_yield, "DUNE_SYS_SCHED_YIELD"}, | 
 | 	[DUNE_SYS_MREMAP] = {NULL, "DUNE_SYS_MREMAP"}, | 
 | 	[DUNE_SYS_MSYNC] = {NULL, "DUNE_SYS_MSYNC"}, | 
 | 	[DUNE_SYS_MINCORE] = {dune_sys_mincore, "DUNE_SYS_MINCORE"}, | 
 | 	[DUNE_SYS_MADVISE] = {NULL, "DUNE_SYS_MADVISE"}, | 
 | 	[DUNE_SYS_SHMGET] = {NULL, "DUNE_SYS_SHMGET"}, | 
 | 	[DUNE_SYS_SHMAT] = {NULL, "DUNE_SYS_SHMAT"}, | 
 | 	[DUNE_SYS_SHMCTL] = {NULL, "DUNE_SYS_SHMCTL"}, | 
 | 	[DUNE_SYS_DUP] = {dune_sys_dup, "DUNE_SYS_DUP"}, | 
 | 	[DUNE_SYS_DUP2] = {dune_sys_dup2, "DUNE_SYS_DUP2"}, | 
 | 	[DUNE_SYS_PAUSE] = {NULL, "DUNE_SYS_PAUSE"}, | 
 | 	[DUNE_SYS_NANOSLEEP] = {NULL, "DUNE_SYS_NANOSLEEP"}, | 
 | 	[DUNE_SYS_GETITIMER] = {NULL, "DUNE_SYS_GETITIMER"}, | 
 | 	[DUNE_SYS_ALARM] = {NULL, "DUNE_SYS_ALARM"}, | 
 | 	[DUNE_SYS_SETITIMER] = {NULL, "DUNE_SYS_SETITIMER"}, | 
 | 	[DUNE_SYS_GETPID] = {dune_sys_getpid, "DUNE_SYS_GETPID"}, | 
 | 	[DUNE_SYS_SENDFILE] = {NULL, "DUNE_SYS_SENDFILE"}, | 
 | 	[DUNE_SYS_SOCKET] = {NULL, "DUNE_SYS_SOCKET"}, | 
 | 	[DUNE_SYS_CONNECT] = {NULL, "DUNE_SYS_CONNECT"}, | 
 | 	[DUNE_SYS_ACCEPT] = {NULL, "DUNE_SYS_ACCEPT"}, | 
 | 	[DUNE_SYS_SENDTO] = {NULL, "DUNE_SYS_SENDTO"}, | 
 | 	[DUNE_SYS_RECVFROM] = {NULL, "DUNE_SYS_RECVFROM"}, | 
 | 	[DUNE_SYS_SENDMSG] = {NULL, "DUNE_SYS_SENDMSG"}, | 
 | 	[DUNE_SYS_RECVMSG] = {NULL, "DUNE_SYS_RECVMSG"}, | 
 | 	[DUNE_SYS_SHUTDOWN] = {NULL, "DUNE_SYS_SHUTDOWN"}, | 
 | 	[DUNE_SYS_BIND] = {NULL, "DUNE_SYS_BIND"}, | 
 | 	[DUNE_SYS_LISTEN] = {NULL, "DUNE_SYS_LISTEN"}, | 
 | 	[DUNE_SYS_GETSOCKNAME] = {NULL, "DUNE_SYS_GETSOCKNAME"}, | 
 | 	[DUNE_SYS_GETPEERNAME] = {NULL, "DUNE_SYS_GETPEERNAME"}, | 
 | 	[DUNE_SYS_SOCKETPAIR] = {NULL, "DUNE_SYS_SOCKETPAIR"}, | 
 | 	[DUNE_SYS_SETSOCKOPT] = {NULL, "DUNE_SYS_SETSOCKOPT"}, | 
 | 	[DUNE_SYS_GETSOCKOPT] = {NULL, "DUNE_SYS_GETSOCKOPT"}, | 
 | 	[DUNE_SYS_CLONE] = {NULL, "DUNE_SYS_CLONE"}, | 
 | 	[DUNE_SYS_FORK] = {NULL, "DUNE_SYS_FORK"}, | 
 | 	[DUNE_SYS_VFORK] = {NULL, "DUNE_SYS_VFORK"}, | 
 | 	[DUNE_SYS_EXECVE] = {NULL, "DUNE_SYS_EXECVE"}, | 
 | 	[DUNE_SYS_EXIT] = {NULL, "DUNE_SYS_EXIT"}, | 
 | 	[DUNE_SYS_WAIT4] = {NULL, "DUNE_SYS_WAIT4"}, | 
 | 	[DUNE_SYS_KILL] = {NULL, "DUNE_SYS_KILL"}, | 
 | 	[DUNE_SYS_UNAME] = {NULL, "DUNE_SYS_UNAME"}, | 
 | 	[DUNE_SYS_SEMGET] = {NULL, "DUNE_SYS_SEMGET"}, | 
 | 	[DUNE_SYS_SEMOP] = {NULL, "DUNE_SYS_SEMOP"}, | 
 | 	[DUNE_SYS_SEMCTL] = {NULL, "DUNE_SYS_SEMCTL"}, | 
 | 	[DUNE_SYS_SHMDT] = {NULL, "DUNE_SYS_SHMDT"}, | 
 | 	[DUNE_SYS_MSGGET] = {NULL, "DUNE_SYS_MSGGET"}, | 
 | 	[DUNE_SYS_MSGSND] = {NULL, "DUNE_SYS_MSGSND"}, | 
 | 	[DUNE_SYS_MSGRCV] = {NULL, "DUNE_SYS_MSGRCV"}, | 
 | 	[DUNE_SYS_MSGCTL] = {NULL, "DUNE_SYS_MSGCTL"}, | 
 | 	[DUNE_SYS_FCNTL] = {dune_sys_fcntl, "DUNE_SYS_FCNTL"}, | 
 | 	[DUNE_SYS_FLOCK] = {NULL, "DUNE_SYS_FLOCK"}, | 
 | 	[DUNE_SYS_FSYNC] = {NULL, "DUNE_SYS_FSYNC"}, | 
 | 	[DUNE_SYS_FDATASYNC] = {NULL, "DUNE_SYS_FDATASYNC"}, | 
 | 	[DUNE_SYS_TRUNCATE] = {NULL, "DUNE_SYS_TRUNCATE"}, | 
 | 	[DUNE_SYS_FTRUNCATE] = {dune_sys_ftruncate, "DUNE_SYS_FTRUNCATE"}, | 
 | 	[DUNE_SYS_GETDENTS] = {NULL, "DUNE_SYS_GETDENTS"}, | 
 | 	[DUNE_SYS_GETCWD] = {NULL, "DUNE_SYS_GETCWD"}, | 
 | 	[DUNE_SYS_CHDIR] = {NULL, "DUNE_SYS_CHDIR"}, | 
 | 	[DUNE_SYS_FCHDIR] = {NULL, "DUNE_SYS_FCHDIR"}, | 
 | 	[DUNE_SYS_RENAME] = {NULL, "DUNE_SYS_RENAME"}, | 
 | 	[DUNE_SYS_MKDIR] = {NULL, "DUNE_SYS_MKDIR"}, | 
 | 	[DUNE_SYS_RMDIR] = {NULL, "DUNE_SYS_RMDIR"}, | 
 | 	[DUNE_SYS_CREAT] = {NULL, "DUNE_SYS_CREAT"}, | 
 | 	[DUNE_SYS_LINK] = {NULL, "DUNE_SYS_LINK"}, | 
 | 	[DUNE_SYS_UNLINK] = {NULL, "DUNE_SYS_UNLINK"}, | 
 | 	[DUNE_SYS_SYMLINK] = {NULL, "DUNE_SYS_SYMLINK"}, | 
 | 	[DUNE_SYS_READLINK] = {NULL, "DUNE_SYS_READLINK"}, | 
 | 	[DUNE_SYS_CHMOD] = {NULL, "DUNE_SYS_CHMOD"}, | 
 | 	[DUNE_SYS_FCHMOD] = {NULL, "DUNE_SYS_FCHMOD"}, | 
 | 	[DUNE_SYS_CHOWN] = {NULL, "DUNE_SYS_CHOWN"}, | 
 | 	[DUNE_SYS_FCHOWN] = {NULL, "DUNE_SYS_FCHOWN"}, | 
 | 	[DUNE_SYS_LCHOWN] = {NULL, "DUNE_SYS_LCHOWN"}, | 
 | 	[DUNE_SYS_UMASK] = {dune_sys_umask, "DUNE_SYS_UMASK"}, | 
 | 	[DUNE_SYS_GETTIMEOFDAY] = {dune_sys_gettimeofday, "DUNE_SYS_GETTIMEOFDAY"}, | 
 | 	[DUNE_SYS_GETRLIMIT] = {NULL, "DUNE_SYS_GETRLIMIT"}, | 
 | 	[DUNE_SYS_GETRUSAGE] = {NULL, "DUNE_SYS_GETRUSAGE"}, | 
 | 	[DUNE_SYS_SYSINFO] = {NULL, "DUNE_SYS_SYSINFO"}, | 
 | 	[DUNE_SYS_TIMES] = {NULL, "DUNE_SYS_TIMES"}, | 
 | 	[DUNE_SYS_PTRACE] = {NULL, "DUNE_SYS_PTRACE"}, | 
 | 	[DUNE_SYS_GETUID] = {dune_sys_getuid, "DUNE_SYS_GETUID"}, | 
 | 	[DUNE_SYS_SYSLOG] = {NULL, "DUNE_SYS_SYSLOG"}, | 
 | 	[DUNE_SYS_GETGID] = {dune_sys_getgid, "DUNE_SYS_GETGID"}, | 
 | 	[DUNE_SYS_SETUID] = {NULL, "DUNE_SYS_SETUID"}, | 
 | 	[DUNE_SYS_SETGID] = {NULL, "DUNE_SYS_SETGID"}, | 
 | 	[DUNE_SYS_GETEUID] = {dune_sys_geteuid, "DUNE_SYS_GETEUID"}, | 
 | 	[DUNE_SYS_GETEGID] = {dune_sys_getegid, "DUNE_SYS_GETEGID"}, | 
 | 	[DUNE_SYS_SETPGID] = {NULL, "DUNE_SYS_SETPGID"}, | 
 | 	[DUNE_SYS_GETPPID] = {NULL, "DUNE_SYS_GETPPID"}, | 
 | 	[DUNE_SYS_GETPGRP] = {NULL, "DUNE_SYS_GETPGRP"}, | 
 | 	[DUNE_SYS_SETSID] = {NULL, "DUNE_SYS_SETSID"}, | 
 | 	[DUNE_SYS_SETREUID] = {NULL, "DUNE_SYS_SETREUID"}, | 
 | 	[DUNE_SYS_SETREGID] = {NULL, "DUNE_SYS_SETREGID"}, | 
 | 	[DUNE_SYS_GETGROUPS] = {dune_sys_getgroups, "DUNE_SYS_GETGROUPS"}, | 
 | 	[DUNE_SYS_SETGROUPS] = {NULL, "DUNE_SYS_SETGROUPS"}, | 
 | 	[DUNE_SYS_SETRESUID] = {NULL, "DUNE_SYS_SETRESUID"}, | 
 | 	[DUNE_SYS_GETRESUID] = {NULL, "DUNE_SYS_GETRESUID"}, | 
 | 	[DUNE_SYS_SETRESGID] = {NULL, "DUNE_SYS_SETRESGID"}, | 
 | 	[DUNE_SYS_GETRESGID] = {NULL, "DUNE_SYS_GETRESGID"}, | 
 | 	[DUNE_SYS_GETPGID] = {NULL, "DUNE_SYS_GETPGID"}, | 
 | 	[DUNE_SYS_SETFSUID] = {NULL, "DUNE_SYS_SETFSUID"}, | 
 | 	[DUNE_SYS_SETFSGID] = {NULL, "DUNE_SYS_SETFSGID"}, | 
 | 	[DUNE_SYS_GETSID] = {NULL, "DUNE_SYS_GETSID"}, | 
 | 	[DUNE_SYS_CAPGET] = {NULL, "DUNE_SYS_CAPGET"}, | 
 | 	[DUNE_SYS_CAPSET] = {NULL, "DUNE_SYS_CAPSET"}, | 
 | 	[DUNE_SYS_RT_SIGPENDING] = {NULL, "DUNE_SYS_RT_SIGPENDING"}, | 
 | 	[DUNE_SYS_RT_SIGTIMEDWAIT] = {NULL, "DUNE_SYS_RT_SIGTIMEDWAIT"}, | 
 | 	[DUNE_SYS_RT_SIGQUEUEINFO] = {NULL, "DUNE_SYS_RT_SIGQUEUEINFO"}, | 
 | 	[DUNE_SYS_RT_SIGSUSPEND] = {NULL, "DUNE_SYS_RT_SIGSUSPEND"}, | 
 | 	[DUNE_SYS_SIGALTSTACK] = {dune_sys_sigaltstack, "DUNE_SYS_SIGALTSTACK"}, | 
 | 	[DUNE_SYS_UTIME] = {NULL, "DUNE_SYS_UTIME"}, | 
 | 	[DUNE_SYS_MKNOD] = {NULL, "DUNE_SYS_MKNOD"}, | 
 | 	[DUNE_SYS_USELIB] = {NULL, "DUNE_SYS_USELIB"}, | 
 | 	[DUNE_SYS_PERSONALITY] = {NULL, "DUNE_SYS_PERSONALITY"}, | 
 | 	[DUNE_SYS_USTAT] = {NULL, "DUNE_SYS_USTAT"}, | 
 | 	[DUNE_SYS_STATFS] = {NULL, "DUNE_SYS_STATFS"}, | 
 | 	[DUNE_SYS_FSTATFS] = {dune_sys_fstatfs, "DUNE_SYS_FSTATFS"}, | 
 | 	[DUNE_SYS_SYSFS] = {NULL, "DUNE_SYS_SYSFS"}, | 
 | 	[DUNE_SYS_GETPRIORITY] = {NULL, "DUNE_SYS_GETPRIORITY"}, | 
 | 	[DUNE_SYS_SETPRIORITY] = {NULL, "DUNE_SYS_SETPRIORITY"}, | 
 | 	[DUNE_SYS_SCHED_SETPARAM] = {NULL, "DUNE_SYS_SCHED_SETPARAM"}, | 
 | 	[DUNE_SYS_SCHED_GETPARAM] = {NULL, "DUNE_SYS_SCHED_GETPARAM"}, | 
 | 	[DUNE_SYS_SCHED_SETSCHEDULER] = {NULL, "DUNE_SYS_SCHED_SETSCHEDULER"}, | 
 | 	[DUNE_SYS_SCHED_GETSCHEDULER] = {NULL, "DUNE_SYS_SCHED_GETSCHEDULER"}, | 
 | 	[DUNE_SYS_SCHED_GET_PRIORITY_MAX] = {NULL, | 
 | 	                                    "DUNE_SYS_SCHED_GET_PRIORITY_MAX"}, | 
 | 	[DUNE_SYS_SCHED_GET_PRIORITY_MIN] = {NULL, | 
 | 	                                    "DUNE_SYS_SCHED_GET_PRIORITY_MIN"}, | 
 | 	[DUNE_SYS_SCHED_RR_GET_INTERVAL] = {NULL, "DUNE_SYS_SCHED_RR_GET_INTERVAL"}, | 
 | 	[DUNE_SYS_MLOCK] = {NULL, "DUNE_SYS_MLOCK"}, | 
 | 	[DUNE_SYS_MUNLOCK] = {NULL, "DUNE_SYS_MUNLOCK"}, | 
 | 	[DUNE_SYS_MLOCKALL] = {NULL, "DUNE_SYS_MLOCKALL"}, | 
 | 	[DUNE_SYS_MUNLOCKALL] = {NULL, "DUNE_SYS_MUNLOCKALL"}, | 
 | 	[DUNE_SYS_VHANGUP] = {NULL, "DUNE_SYS_VHANGUP"}, | 
 | 	[DUNE_SYS_MODIFY_LDT] = {NULL, "DUNE_SYS_MODIFY_LDT"}, | 
 | 	[DUNE_SYS_PIVOT_ROOT] = {NULL, "DUNE_SYS_PIVOT_ROOT"}, | 
 | 	[DUNE_SYS__SYSCTL] = {NULL, "DUNE_SYS__SYSCTL"}, | 
 | 	[DUNE_SYS_PRCTL] = {NULL, "DUNE_SYS_PRCTL"}, | 
 | 	[DUNE_SYS_ARCH_PRCTL] = {NULL, "DUNE_SYS_ARCH_PRCTL"}, | 
 | 	[DUNE_SYS_ADJTIMEX] = {NULL, "DUNE_SYS_ADJTIMEX"}, | 
 | 	[DUNE_SYS_SETRLIMIT] = {NULL, "DUNE_SYS_SETRLIMIT"}, | 
 | 	[DUNE_SYS_CHROOT] = {NULL, "DUNE_SYS_CHROOT"}, | 
 | 	[DUNE_SYS_SYNC] = {NULL, "DUNE_SYS_SYNC"}, | 
 | 	[DUNE_SYS_ACCT] = {NULL, "DUNE_SYS_ACCT"}, | 
 | 	[DUNE_SYS_SETTIMEOFDAY] = {NULL, "DUNE_SYS_SETTIMEOFDAY"}, | 
 | 	[DUNE_SYS_MOUNT] = {NULL, "DUNE_SYS_MOUNT"}, | 
 | 	[DUNE_SYS_UMOUNT2] = {NULL, "DUNE_SYS_UMOUNT2"}, | 
 | 	[DUNE_SYS_SWAPON] = {NULL, "DUNE_SYS_SWAPON"}, | 
 | 	[DUNE_SYS_SWAPOFF] = {NULL, "DUNE_SYS_SWAPOFF"}, | 
 | 	[DUNE_SYS_REBOOT] = {NULL, "DUNE_SYS_REBOOT"}, | 
 | 	[DUNE_SYS_SETHOSTNAME] = {NULL, "DUNE_SYS_SETHOSTNAME"}, | 
 | 	[DUNE_SYS_SETDOMAINNAME] = {NULL, "DUNE_SYS_SETDOMAINNAME"}, | 
 | 	[DUNE_SYS_IOPL] = {NULL, "DUNE_SYS_IOPL"}, | 
 | 	[DUNE_SYS_IOPERM] = {NULL, "DUNE_SYS_IOPERM"}, | 
 | 	[DUNE_SYS_CREATE_MODULE] = {NULL, "DUNE_SYS_CREATE_MODULE"}, | 
 | 	[DUNE_SYS_INIT_MODULE] = {NULL, "DUNE_SYS_INIT_MODULE"}, | 
 | 	[DUNE_SYS_DELETE_MODULE] = {NULL, "DUNE_SYS_DELETE_MODULE"}, | 
 | 	[DUNE_SYS_GET_KERNEL_SYMS] = {NULL, "DUNE_SYS_GET_KERNEL_SYMS"}, | 
 | 	[DUNE_SYS_QUERY_MODULE] = {NULL, "DUNE_SYS_QUERY_MODULE"}, | 
 | 	[DUNE_SYS_QUOTACTL] = {NULL, "DUNE_SYS_QUOTACTL"}, | 
 | 	[DUNE_SYS_NFSSERVCTL] = {NULL, "DUNE_SYS_NFSSERVCTL"}, | 
 | 	[DUNE_SYS_GETPMSG] = {NULL, "DUNE_SYS_GETPMSG"}, | 
 | 	[DUNE_SYS_PUTPMSG] = {NULL, "DUNE_SYS_PUTPMSG"}, | 
 | 	[DUNE_SYS_AFS_SYSCALL] = {NULL, "DUNE_SYS_AFS_SYSCALL"}, | 
 | 	[DUNE_SYS_TUXCALL] = {NULL, "DUNE_SYS_TUXCALL"}, | 
 | 	[DUNE_SYS_SECURITY] = {NULL, "DUNE_SYS_SECURITY"}, | 
 | 	[DUNE_SYS_GETTID] = {dune_sys_gettid, "DUNE_SYS_GETTID"}, | 
 | 	[DUNE_SYS_READAHEAD] = {NULL, "DUNE_SYS_READAHEAD"}, | 
 | 	[DUNE_SYS_SETXATTR] = {NULL, "DUNE_SYS_SETXATTR"}, | 
 | 	[DUNE_SYS_LSETXATTR] = {NULL, "DUNE_SYS_LSETXATTR"}, | 
 | 	[DUNE_SYS_FSETXATTR] = {NULL, "DUNE_SYS_FSETXATTR"}, | 
 | 	[DUNE_SYS_GETXATTR] = {NULL, "DUNE_SYS_GETXATTR"}, | 
 | 	[DUNE_SYS_LGETXATTR] = {NULL, "DUNE_SYS_LGETXATTR"}, | 
 | 	[DUNE_SYS_FGETXATTR] = {NULL, "DUNE_SYS_FGETXATTR"}, | 
 | 	[DUNE_SYS_LISTXATTR] = {NULL, "DUNE_SYS_LISTXATTR"}, | 
 | 	[DUNE_SYS_LLISTXATTR] = {NULL, "DUNE_SYS_LLISTXATTR"}, | 
 | 	[DUNE_SYS_FLISTXATTR] = {NULL, "DUNE_SYS_FLISTXATTR"}, | 
 | 	[DUNE_SYS_REMOVEXATTR] = {NULL, "DUNE_SYS_REMOVEXATTR"}, | 
 | 	[DUNE_SYS_LREMOVEXATTR] = {NULL, "DUNE_SYS_LREMOVEXATTR"}, | 
 | 	[DUNE_SYS_FREMOVEXATTR] = {NULL, "DUNE_SYS_FREMOVEXATTR"}, | 
 | 	[DUNE_SYS_TKILL] = {NULL, "DUNE_SYS_TKILL"}, | 
 | 	[DUNE_SYS_TIME] = {NULL, "DUNE_SYS_TIME"}, | 
 | 	[DUNE_SYS_FUTEX] = {dune_sys_futex, "DUNE_SYS_FUTEX"}, | 
 | 	[DUNE_SYS_SCHED_SETAFFINITY] = {NULL, "DUNE_SYS_SCHED_SETAFFINITY"}, | 
 | 	[DUNE_SYS_SCHED_GETAFFINITY] = {dune_sys_sched_getaffinity, | 
 | 	                                "DUNE_SYS_SCHED_GETAFFINITY"}, | 
 | 	[DUNE_SYS_SET_THREAD_AREA] = {NULL, "DUNE_SYS_SET_THREAD_AREA"}, | 
 | 	[DUNE_SYS_IO_SETUP] = {NULL, "DUNE_SYS_IO_SETUP"}, | 
 | 	[DUNE_SYS_IO_DESTROY] = {NULL, "DUNE_SYS_IO_DESTROY"}, | 
 | 	[DUNE_SYS_IO_GETEVENTS] = {NULL, "DUNE_SYS_IO_GETEVENTS"}, | 
 | 	[DUNE_SYS_IO_SUBMIT] = {NULL, "DUNE_SYS_IO_SUBMIT"}, | 
 | 	[DUNE_SYS_IO_CANCEL] = {NULL, "DUNE_SYS_IO_CANCEL"}, | 
 | 	[DUNE_SYS_GET_THREAD_AREA] = {NULL, "DUNE_SYS_GET_THREAD_AREA"}, | 
 | 	[DUNE_SYS_LOOKUP_DCOOKIE] = {NULL, "DUNE_SYS_LOOKUP_DCOOKIE"}, | 
 | 	[DUNE_SYS_EPOLL_CREATE] = {NULL, "DUNE_SYS_EPOLL_CREATE"}, | 
 | 	[DUNE_SYS_EPOLL_CTL_OLD] = {NULL, "DUNE_SYS_EPOLL_CTL_OLD"}, | 
 | 	[DUNE_SYS_EPOLL_WAIT_OLD] = {NULL, "DUNE_SYS_EPOLL_WAIT_OLD"}, | 
 | 	[DUNE_SYS_REMAP_FILE_PAGES] = {NULL, "DUNE_SYS_REMAP_FILE_PAGES"}, | 
 | 	[DUNE_SYS_GETDENTS64] = {NULL, "DUNE_SYS_GETDENTS64"}, | 
 | 	[DUNE_SYS_SET_TID_ADDRESS] = {NULL, "DUNE_SYS_SET_TID_ADDRESS"}, | 
 | 	[DUNE_SYS_RESTART_SYSCALL] = {NULL, "DUNE_SYS_RESTART_SYSCALL"}, | 
 | 	[DUNE_SYS_SEMTIMEDOP] = {NULL, "DUNE_SYS_SEMTIMEDOP"}, | 
 | 	[DUNE_SYS_FADVISE64] = {NULL, "DUNE_SYS_FADVISE64"}, | 
 | 	[DUNE_SYS_TIMER_CREATE] = {NULL, "DUNE_SYS_TIMER_CREATE"}, | 
 | 	[DUNE_SYS_TIMER_SETTIME] = {NULL, "DUNE_SYS_TIMER_SETTIME"}, | 
 | 	[DUNE_SYS_TIMER_GETTIME] = {NULL, "DUNE_SYS_TIMER_GETTIME"}, | 
 | 	[DUNE_SYS_TIMER_GETOVERRUN] = {NULL, "DUNE_SYS_TIMER_GETOVERRUN"}, | 
 | 	[DUNE_SYS_TIMER_DELETE] = {NULL, "DUNE_SYS_TIMER_DELETE"}, | 
 | 	[DUNE_SYS_CLOCK_SETTIME] = {NULL, "DUNE_SYS_CLOCK_SETTIME"}, | 
 | 	[DUNE_SYS_CLOCK_GETTIME] = {dune_sys_clock_gettime, | 
 | 	                            "DUNE_SYS_CLOCK_GETTIME"}, | 
 | 	[DUNE_SYS_CLOCK_GETRES] = {NULL, "DUNE_SYS_CLOCK_GETRES"}, | 
 | 	[DUNE_SYS_CLOCK_NANOSLEEP] = {NULL, "DUNE_SYS_CLOCK_NANOSLEEP"}, | 
 | 	[DUNE_SYS_EXIT_GROUP] = {NULL, "DUNE_SYS_EXIT_GROUP"}, | 
 | 	[DUNE_SYS_EPOLL_WAIT] = {dune_sys_epoll_wait, "DUNE_SYS_EPOLL_WAIT"}, | 
 | 	[DUNE_SYS_EPOLL_CTL] = {dune_sys_epoll_ctl, "DUNE_SYS_EPOLL_CTL"}, | 
 | 	[DUNE_SYS_TGKILL] = {NULL, "DUNE_SYS_TGKILL"}, | 
 | 	[DUNE_SYS_UTIMES] = {NULL, "DUNE_SYS_UTIMES"}, | 
 | 	[DUNE_SYS_VSERVER] = {NULL, "DUNE_SYS_VSERVER"}, | 
 | 	[DUNE_SYS_MBIND] = {NULL, "DUNE_SYS_MBIND"}, | 
 | 	[DUNE_SYS_SET_MEMPOLICY] = {NULL, "DUNE_SYS_SET_MEMPOLICY"}, | 
 | 	[DUNE_SYS_GET_MEMPOLICY] = {NULL, "DUNE_SYS_GET_MEMPOLICY"}, | 
 | 	[DUNE_SYS_MQ_OPEN] = {NULL, "DUNE_SYS_MQ_OPEN"}, | 
 | 	[DUNE_SYS_MQ_UNLINK] = {NULL, "DUNE_SYS_MQ_UNLINK"}, | 
 | 	[DUNE_SYS_MQ_TIMEDSEND] = {NULL, "DUNE_SYS_MQ_TIMEDSEND"}, | 
 | 	[DUNE_SYS_MQ_TIMEDRECEIVE] = {NULL, "DUNE_SYS_MQ_TIMEDRECEIVE"}, | 
 | 	[DUNE_SYS_MQ_NOTIFY] = {NULL, "DUNE_SYS_MQ_NOTIFY"}, | 
 | 	[DUNE_SYS_MQ_GETSETATTR] = {NULL, "DUNE_SYS_MQ_GETSETATTR"}, | 
 | 	[DUNE_SYS_KEXEC_LOAD] = {NULL, "DUNE_SYS_KEXEC_LOAD"}, | 
 | 	[DUNE_SYS_WAITID] = {NULL, "DUNE_SYS_WAITID"}, | 
 | 	[DUNE_SYS_ADD_KEY] = {NULL, "DUNE_SYS_ADD_KEY"}, | 
 | 	[DUNE_SYS_REQUEST_KEY] = {NULL, "DUNE_SYS_REQUEST_KEY"}, | 
 | 	[DUNE_SYS_KEYCTL] = {NULL, "DUNE_SYS_KEYCTL"}, | 
 | 	[DUNE_SYS_IOPRIO_SET] = {NULL, "DUNE_SYS_IOPRIO_SET"}, | 
 | 	[DUNE_SYS_IOPRIO_GET] = {NULL, "DUNE_SYS_IOPRIO_GET"}, | 
 | 	[DUNE_SYS_INOTIFY_INIT] = {NULL, "DUNE_SYS_INOTIFY_INIT"}, | 
 | 	[DUNE_SYS_INOTIFY_ADD_WATCH] = {NULL, "DUNE_SYS_INOTIFY_ADD_WATCH"}, | 
 | 	[DUNE_SYS_INOTIFY_RM_WATCH] = {NULL, "DUNE_SYS_INOTIFY_RM_WATCH"}, | 
 | 	[DUNE_SYS_MIGRATE_PAGES] = {NULL, "DUNE_SYS_MIGRATE_PAGES"}, | 
 | 	[DUNE_SYS_OPENAT] = {dune_sys_openat, "DUNE_SYS_OPENAT"}, | 
 | 	[DUNE_SYS_MKDIRAT] = {NULL, "DUNE_SYS_MKDIRAT"}, | 
 | 	[DUNE_SYS_MKNODAT] = {NULL, "DUNE_SYS_MKNODAT"}, | 
 | 	[DUNE_SYS_FCHOWNAT] = {NULL, "DUNE_SYS_FCHOWNAT"}, | 
 | 	[DUNE_SYS_FUTIMESAT] = {NULL, "DUNE_SYS_FUTIMESAT"}, | 
 | 	[DUNE_SYS_NEWFSTATAT] = {NULL, "DUNE_SYS_NEWFSTATAT"}, | 
 | 	[DUNE_SYS_UNLINKAT] = {dune_sys_unlinkat, "DUNE_SYS_UNLINKAT"}, | 
 | 	[DUNE_SYS_RENAMEAT] = {NULL, "DUNE_SYS_RENAMEAT"}, | 
 | 	[DUNE_SYS_LINKAT] = {NULL, "DUNE_SYS_LINKAT"}, | 
 | 	[DUNE_SYS_SYMLINKAT] = {NULL, "DUNE_SYS_SYMLINKAT"}, | 
 | 	[DUNE_SYS_READLINKAT] = {dune_sys_readlinkat, "DUNE_SYS_READLINKAT"}, | 
 | 	[DUNE_SYS_FCHMODAT] = {NULL, "DUNE_SYS_FCHMODAT"}, | 
 | 	[DUNE_SYS_FACCESSAT] = {NULL, "DUNE_SYS_FACCESSAT"}, | 
 | 	[DUNE_SYS_PSELECT6] = {dune_sys_pselect6, "DUNE_SYS_PSELECT6"}, | 
 | 	[DUNE_SYS_PPOLL] = {NULL, "DUNE_SYS_PPOLL"}, | 
 | 	[DUNE_SYS_UNSHARE] = {NULL, "DUNE_SYS_UNSHARE"}, | 
 | 	[DUNE_SYS_SET_ROBUST_LIST] = {NULL, "DUNE_SYS_SET_ROBUST_LIST"}, | 
 | 	[DUNE_SYS_GET_ROBUST_LIST] = {NULL, "DUNE_SYS_GET_ROBUST_LIST"}, | 
 | 	[DUNE_SYS_SPLICE] = {NULL, "DUNE_SYS_SPLICE"}, | 
 | 	[DUNE_SYS_TEE] = {NULL, "DUNE_SYS_TEE"}, | 
 | 	[DUNE_SYS_SYNC_FILE_RANGE] = {NULL, "DUNE_SYS_SYNC_FILE_RANGE"}, | 
 | 	[DUNE_SYS_VMSPLICE] = {NULL, "DUNE_SYS_VMSPLICE"}, | 
 | 	[DUNE_SYS_MOVE_PAGES] = {NULL, "DUNE_SYS_MOVE_PAGES"}, | 
 | 	[DUNE_SYS_UTIMENSAT] = {NULL, "DUNE_SYS_UTIMENSAT"}, | 
 | 	[DUNE_SYS_EPOLL_PWAIT] = {NULL, "DUNE_SYS_EPOLL_PWAIT"}, | 
 | 	[DUNE_SYS_SIGNALFD] = {NULL, "DUNE_SYS_SIGNALFD"}, | 
 | 	[DUNE_SYS_TIMERFD_CREATE] = {NULL, "DUNE_SYS_TIMERFD_CREATE"}, | 
 | 	[DUNE_SYS_EVENTFD] = {NULL, "DUNE_SYS_EVENTFD"}, | 
 | 	[DUNE_SYS_FALLOCATE] = {dune_sys_fallocate, "DUNE_SYS_FALLOCATE"}, | 
 | 	[DUNE_SYS_TIMERFD_SETTIME] = {NULL, "DUNE_SYS_TIMERFD_SETTIME"}, | 
 | 	[DUNE_SYS_TIMERFD_GETTIME] = {NULL, "DUNE_SYS_TIMERFD_GETTIME"}, | 
 | 	[DUNE_SYS_ACCEPT4] = {NULL, "DUNE_SYS_ACCEPT4"}, | 
 | 	[DUNE_SYS_SIGNALFD4] = {NULL, "DUNE_SYS_SIGNALFD4"}, | 
 | 	[DUNE_SYS_EVENTFD2] = {NULL, "DUNE_SYS_EVENTFD2"}, | 
 | 	[DUNE_SYS_EPOLL_CREATE1] = {dune_sys_epoll_create1, | 
 | 	                            "DUNE_SYS_EPOLL_CREATE1"}, | 
 | 	[DUNE_SYS_DUP3] = {NULL, "DUNE_SYS_DUP3"}, | 
 | 	[DUNE_SYS_PIPE2] = {NULL, "DUNE_SYS_PIPE2"}, | 
 | 	[DUNE_SYS_INOTIFY_INIT1] = {NULL, "DUNE_SYS_INOTIFY_INIT1"}, | 
 | 	[DUNE_SYS_PREADV] = {NULL, "DUNE_SYS_PREADV"}, | 
 | 	[DUNE_SYS_PWRITEV] = {NULL, "DUNE_SYS_PWRITEV"}, | 
 | 	[DUNE_SYS_RT_TGSIGQUEUEINFO] = {NULL, "DUNE_SYS_RT_TGSIGQUEUEINFO"}, | 
 | 	[DUNE_SYS_PERF_EVENT_OPEN] = {NULL, "DUNE_SYS_PERF_EVENT_OPEN"}, | 
 | 	[DUNE_SYS_RECVMMSG] = {NULL, "DUNE_SYS_RECVMMSG"}, | 
 | 	[DUNE_SYS_FANOTIFY_INIT] = {NULL, "DUNE_SYS_FANOTIFY_INIT"}, | 
 | 	[DUNE_SYS_FANOTIFY_MARK] = {NULL, "DUNE_SYS_FANOTIFY_MARK"}, | 
 | 	[DUNE_SYS_PRLIMIT64] = {NULL, "DUNE_SYS_PRLIMIT64"}, | 
 | 	[DUNE_SYS_NAME_TO_HANDLE_AT] = {NULL, "DUNE_SYS_NAME_TO_HANDLE_AT"}, | 
 | 	[DUNE_SYS_OPEN_BY_HANDLE_AT] = {NULL, "DUNE_SYS_OPEN_BY_HANDLE_AT"}, | 
 | 	[DUNE_SYS_CLOCK_ADJTIME] = {NULL, "DUNE_SYS_CLOCK_ADJTIME"}, | 
 | 	[DUNE_SYS_SYNCFS] = {NULL, "DUNE_SYS_SYNCFS"}, | 
 | 	[DUNE_SYS_SENDMMSG] = {NULL, "DUNE_SYS_SENDMMSG"}, | 
 | 	[DUNE_SYS_SETNS] = {NULL, "DUNE_SYS_SETNS"}, | 
 | 	[DUNE_SYS_GETCPU] = {NULL, "DUNE_SYS_GETCPU"}, | 
 | 	[DUNE_SYS_PROCESS_VM_READV] = {NULL, "DUNE_SYS_PROCESS_VM_READV"}, | 
 | 	[DUNE_SYS_PROCESS_VM_WRITEV] = {NULL, "DUNE_SYS_PROCESS_VM_WRITEV"}, | 
 | 	[DUNE_SYS_KCMP] = {NULL, "DUNE_KCMP"}, | 
 | 	[DUNE_SYS_FINIT_MODULE] = {NULL, "DUNE_SYS_FINIT_MODULE"}, | 
 | 	[DUNE_SYS_SCHED_SETATTR] = {NULL, "DUNE_SYS_SCHED_SETATTR"}, | 
 | 	[DUNE_SYS_SCHED_GETATTR] = {NULL, "DUNE_SYS_SCHED_GETATTR"}, | 
 | 	[DUNE_SYS_RENAMEAT2] = {NULL, "DUNE_SYS_RENAMEAT2"}, | 
 | 	[DUNE_SYS_SECCOMP] = {NULL, "DUNE_SYS_SECCOMP"}, | 
 | 	[DUNE_SYS_GETRANDOM] = {dune_sys_getrandom, "DUNE_SYS_GETRANDOM"}, | 
 | 	[DUNE_SYS_MEMFD_CREATE] = {NULL, "DUNE_SYS_MEMFD_CREATE"}, | 
 | 	[DUNE_SYS_KEXEC_FILE_LOAD] = {NULL, "DUNE_SYS_KEXEC_FILE_LOAD"}, | 
 | 	[DUNE_SYS_BPF] = {NULL, "DUNE_SYS_BPF"}, | 
 | 	[DUNE_STUB_EXECVEAT] = {NULL, "DUNE_STUB_EXECVEAT"}, | 
 | 	[DUNE_USERFAULTFD] = {NULL, "DUNE_USERFAULTFD"}, | 
 | 	[DUNE_MEMBARRIER] = {NULL, "DUNE_MEMBARRIER"}, | 
 | 	[DUNE_MLOCK2] = {NULL, "DUNE_MLOCK2"}, | 
 | 	[DUNE_COPY_FILE_RANGE] = {NULL, "DUNE_COPY_FILE_RANGE"}, | 
 | 	[DUNE_PREADV2] = {NULL, "DUNE_PREADV2"}, | 
 | 	[DUNE_PWRITEV2] = {NULL, "DUNE_PWRITEV2"}, | 
 |  | 
 | }; | 
 |  | 
 | bool init_linuxemu(void) | 
 | { | 
 | 	fd_table_lock = uth_mutex_alloc(); | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < DUNE_MAX_NUM_SYSCALLS ; ++i) { | 
 | 		if (dune_syscall_table[i].name == NULL) | 
 | 			dune_syscall_table[i].name = "nosyscall"; | 
 | 	} | 
 |  | 
 | 	if (dlopen("liblinuxemu_extend.so", RTLD_NOW) == NULL) { | 
 | 		fprintf(stderr, | 
 | 			"Not using any syscall extensions\n Reason: %s\n", | 
 | 		        dlerror()); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	return true; | 
 | } | 
 |  | 
 | void lemuprint(const uint32_t tid, uint64_t syscall_number, | 
 |                const bool isError, const char *fmt, ...) | 
 | { | 
 | 	va_list valist; | 
 | 	const char *prefix = "[TID %d] %s: "; | 
 | 	bool double_logging = false; | 
 |  | 
 | 	// Do not use global variable as a check to acquire lock. | 
 | 	// make sure it is not changed during our acquire/release. | 
 | 	int debug = lemu_debug; | 
 |  | 
 | 	// If we are not going to log anything anyway, just bail out. | 
 | 	if (!(debug > 0 || isError)) | 
 | 		return; | 
 |  | 
 | 	const char *syscall_name; | 
 |  | 
 | 	if (syscall_number >= DUNE_MAX_NUM_SYSCALLS) | 
 | 		panic("lemuprint: Illegal Syscall #%d!\n", syscall_number); | 
 | 	else | 
 | 		syscall_name = dune_syscall_table[syscall_number].name; | 
 |  | 
 | 	va_start(valist, fmt); | 
 |  | 
 | 	uth_mutex_lock(lemu_logging_lock); | 
 |  | 
 | 	// Print to stderr if debug level is sufficient | 
 | 	if (debug > 1) { | 
 | 		fprintf(stderr, prefix, tid, syscall_name); | 
 | 		vfprintf(stderr, fmt, valist); | 
 | 		// Checks if we will double log to stderr | 
 | 		if (lemu_global_logfile == stderr) | 
 | 			double_logging = true; | 
 | 	} | 
 |  | 
 | 	// Log to the global logfile, if we defaulted the global logging to | 
 | 	// stderr then we don't want to log 2 times to stderr. | 
 | 	if (lemu_global_logfile != NULL && !double_logging) { | 
 | 		fprintf(lemu_global_logfile, prefix, tid, syscall_name); | 
 | 		vfprintf(lemu_global_logfile, fmt, valist); | 
 | 	} | 
 |  | 
 | 	uth_mutex_unlock(lemu_logging_lock); | 
 |  | 
 | 	va_end(valist); | 
 | } | 
 |  | 
 |  | 
 | /* TODO: have an array which classifies syscall args | 
 |  * and "special" system calls (ones with weird return | 
 |  * values etc.). For some cases, we don't even do a system | 
 |  * call, and in many cases we have to rearrange arguments | 
 |  * since Linux and Akaros don't share signatures, so this | 
 |  * gets tricky. */ | 
 | bool linuxemu(struct guest_thread *gth, struct vm_trapframe *tf) | 
 | { | 
 | 	bool ret = false; | 
 |  | 
 | 	if (tf->tf_rax >= DUNE_MAX_NUM_SYSCALLS) { | 
 | 		fprintf(stderr, "System call %d is out of range\n", tf->tf_rax); | 
 | 		return false; | 
 | 	} | 
 |  | 
 |  | 
 | 	if (dune_syscall_table[tf->tf_rax].call == NULL) { | 
 | 		fprintf(stderr, "System call #%d (%s) is not implemented\n", | 
 | 		        tf->tf_rax, dune_syscall_table[tf->tf_rax].name); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	lemuprint(tf->tf_guest_pcoreid, tf->tf_rax, | 
 | 	          false, "vmcall(%d, %p, %p, %p, %p, %p, %p);\n", tf->tf_rax, | 
 | 	          tf->tf_rdi, tf->tf_rsi, tf->tf_rdx, tf->tf_r10, tf->tf_r8, | 
 | 	          tf->tf_r9); | 
 |  | 
 | 	tf->tf_rip += 3; | 
 |  | 
 | 	return (dune_syscall_table[tf->tf_rax].call)(tf); | 
 | } |