Mirroring proot at v 5.1.0

See: https://sources.debian.org/src/proot/5.1.0-1.3

Change-Id: I614f2b51eced88d3e3840c7e35a38f769c9d1765
diff --git a/5.1.0/.pc/.quilt_patches b/5.1.0/.pc/.quilt_patches
new file mode 100644
index 0000000..6857a8d
--- /dev/null
+++ b/5.1.0/.pc/.quilt_patches
@@ -0,0 +1 @@
+debian/patches
diff --git a/5.1.0/.pc/.quilt_series b/5.1.0/.pc/.quilt_series
new file mode 100644
index 0000000..c206706
--- /dev/null
+++ b/5.1.0/.pc/.quilt_series
@@ -0,0 +1 @@
+series
diff --git a/5.1.0/.pc/.version b/5.1.0/.pc/.version
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/5.1.0/.pc/.version
@@ -0,0 +1 @@
+2
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/extension/kompat/kompat.c b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/extension/kompat/kompat.c
new file mode 100644
index 0000000..c4e25a2
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/extension/kompat/kompat.c
@@ -0,0 +1,1044 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdint.h>        /* intptr_t, */
+#include <stdlib.h>        /* strtoul(3), */
+#include <linux/version.h> /* KERNEL_VERSION, */
+#include <assert.h>        /* assert(3), */
+#include <sys/utsname.h>   /* uname(2), utsname, */
+#include <string.h>        /* str*(3), memcpy(3), */
+#include <talloc.h>        /* talloc_*, */
+#include <fcntl.h>         /* AT_*,  */
+#include <sys/ptrace.h>    /* linux.git:c0a3a20b  */
+#include <errno.h>         /* errno,  */
+#include <linux/auxvec.h>  /* AT_,  */
+#include <linux/futex.h>   /* FUTEX_PRIVATE_FLAG */
+#include <sys/param.h>     /* MIN, */
+
+#include "extension/extension.h"
+#include "syscall/seccomp.h"
+#include "syscall/sysnum.h"
+#include "syscall/chain.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/abi.h"
+#include "tracee/mem.h"
+#include "execve/auxv.h"
+#include "cli/note.h"
+#include "arch.h"
+
+#include "attribute.h"
+#include "compat.h"
+
+#define MAX_ARG_SHIFT 2
+typedef struct {
+	int expected_release;
+	word_t new_sysarg_num;
+	struct {
+		Reg sysarg;     /* first argument to be moved.  */
+		size_t nb_args; /* number of arguments to be moved.  */
+		int offset;     /* offset to be applied.  */
+	} shifts[MAX_ARG_SHIFT];
+} Modif;
+
+#define NONE {{0, 0, 0}}
+
+typedef struct {
+	int actual_release;
+	int virtual_release;
+	struct utsname utsname;
+	word_t hwcap;
+} Config;
+
+/**
+ * Return whether the @expected_release is newer than
+ * @config->actual_release and older than @config->virtual_release.
+ */
+static bool needs_kompat(const Config *config, int expected_release)
+{
+	return (expected_release > config->actual_release
+		&& expected_release <= config->virtual_release);
+}
+
+/**
+ * Modify the current syscall of @tracee as described by @modif
+ * regarding the given @config.  This function returns whether the
+ * syscall was modified or not.
+ */
+static bool modify_syscall(Tracee *tracee, const Config *config, const Modif *modif)
+{
+	size_t i, j;
+	word_t syscall;
+
+	assert(config != NULL);
+
+	if (!needs_kompat(config, modif->expected_release))
+		return false;
+
+	/* Check if this syscall is supported on this architecture.  */
+	syscall = detranslate_sysnum(get_abi(tracee), modif->new_sysarg_num);
+	if (syscall == SYSCALL_AVOIDER)
+		return false;
+
+	set_sysnum(tracee, modif->new_sysarg_num);
+
+	/* Shift syscall arguments.  */
+	for (i = 0; i < MAX_ARG_SHIFT; i++) {
+		Reg sysarg     = modif->shifts[i].sysarg;
+		size_t nb_args = modif->shifts[i].nb_args;
+		int offset     = modif->shifts[i].offset;
+
+		for (j = 0; j < nb_args; j++) {
+			word_t arg = peek_reg(tracee, CURRENT, sysarg + j);
+			poke_reg(tracee, sysarg + j + offset, arg);
+		}
+	}
+
+	return true;
+}
+
+/**
+ * Return the numeric value for the given kernel @release.
+ */
+static int parse_kernel_release(const char *release)
+{
+	unsigned long major = 0;
+	unsigned long minor = 0;
+	unsigned long revision = 0;
+	char *cursor = (char *)release;
+
+	major = strtoul(cursor, &cursor, 10);
+
+	if (*cursor == '.') {
+		cursor++;
+		minor = strtoul(cursor, &cursor, 10);
+	}
+
+	if (*cursor == '.') {
+		cursor++;
+		revision = strtoul(cursor, &cursor, 10);
+	}
+
+	return KERNEL_VERSION(major, minor, revision);
+}
+
+/**
+ * Remove @discarded_flags from the given @tracee's @sysarg register
+ * if the actual kernel release is not compatible with the
+ * @expected_release.
+ */
+static void discard_fd_flags(Tracee *tracee, const Config *config,
+			int discarded_flags, int expected_release, Reg sysarg)
+{
+	word_t flags;
+
+	if (!needs_kompat(config, expected_release))
+		return;
+
+	flags = peek_reg(tracee, CURRENT, sysarg);
+	poke_reg(tracee, sysarg, flags & ~discarded_flags);
+}
+
+/**
+ * Replace current @tracee's syscall with an older and compatible one
+ * whenever it's required, i.e. when the syscall is supported by the
+ * kernel as specified by @config->virtual_release but it isn't
+ * supported by the actual kernel.
+ */
+static int handle_sysenter_end(Tracee *tracee, Config *config)
+{
+	/* Note: syscalls like "openat" can be replaced by "open" since PRoot
+	 * has canonicalized "fd + path" into "path".  */
+	switch (get_sysnum(tracee, ORIGINAL)) {
+	case PR_accept4: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,28),
+			.new_sysarg_num   = PR_accept,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_dup3: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_dup2,
+			.shifts		  = NONE
+		};
+
+		/* "If oldfd equals newfd, then dup3() fails with the
+		 * error EINVAL" -- man dup3 */
+		if (peek_reg(tracee, CURRENT, SYSARG_1) == peek_reg(tracee, CURRENT, SYSARG_2))
+			return -EINVAL;
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_epoll_create1: {
+		bool modified;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_epoll_create,
+			.shifts		  = NONE
+		};
+
+		/* "the size argument is ignored, but must be greater
+		 * than zero" -- man epoll_create */
+		modified = modify_syscall(tracee, config, &modif);
+		if (modified)
+			poke_reg(tracee, SYSARG_1, 1);
+		return 0;
+	}
+
+	case PR_epoll_pwait: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,19),
+			.new_sysarg_num   = PR_epoll_wait,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_eventfd2: {
+		bool modified;
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_eventfd,
+			.shifts		  = NONE
+		};
+
+		modified = modify_syscall(tracee, config, &modif);
+		if (modified) {
+			/* EFD_SEMAPHORE can't be emulated with eventfd.  */
+			flags = peek_reg(tracee, CURRENT, SYSARG_2);
+			if ((flags & EFD_SEMAPHORE) != 0)
+				return -EINVAL;
+		}
+		return 0;
+	}
+
+	case PR_faccessat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_access,
+			.shifts	= { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_fchmodat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_chmod,
+			.shifts	= { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_fchownat: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts	= { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1 }
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_5);
+		modif.new_sysarg_num = ((flags & AT_SYMLINK_NOFOLLOW) != 0
+					? PR_lchown
+					: PR_chown);
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_fcntl: {
+		word_t command;
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,24)))
+			return 0;
+
+		command = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (command == F_DUPFD_CLOEXEC)
+			poke_reg(tracee, SYSARG_2, F_DUPFD);
+
+		return 0;
+	}
+
+	case PR_newfstatat:
+	case PR_fstatat64: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_4);
+		if ((flags & ~AT_SYMLINK_NOFOLLOW) != 0)
+			return -EINVAL; /* Exposed by LTP.  */
+
+#if defined(ARCH_X86_64)
+		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
+			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_lstat : PR_lstat64);
+		else
+			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_stat : PR_stat64);
+#else
+		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
+			modif.new_sysarg_num = PR_lstat64;
+		else
+			modif.new_sysarg_num = PR_stat64;
+#endif
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_futex: {
+		word_t operation;
+		static bool warned = false;
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,22)) || config->actual_release == 0)
+			return 0;
+
+		operation = peek_reg(tracee, CURRENT, SYSARG_2);
+		if ((operation & FUTEX_PRIVATE_FLAG) == 0)
+			return 0;
+
+		if (!warned) {
+			warned = true;
+			note(tracee, WARNING, USER,
+				"kompat: this kernel doesn't support private futexes "
+				"and PRoot can't emulate them.  Expect some troubles...");
+		}
+
+		poke_reg(tracee, SYSARG_2, operation & ~FUTEX_PRIVATE_FLAG);
+		return 0;
+	}
+
+	case PR_futimesat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_utimes,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_inotify_init1: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_inotify_init,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_linkat: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_link,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 1,
+					.offset  = -1 },
+				    [1] = {
+					.sysarg  = SYSARG_4,
+					.nb_args = 1,
+					.offset  = -2 }
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_5);
+		if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
+			return -EINVAL; /* Exposed by LTP.  */
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_mkdirat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_mkdir,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_mknodat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_mknod,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_openat: {
+		bool modified;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_open,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1 }
+			}
+		};
+		modified = modify_syscall(tracee, config, &modif);
+		discard_fd_flags(tracee, config, O_CLOEXEC, KERNEL_VERSION(2,6,23),
+				modified ? SYSARG_2 : SYSARG_3);
+		return 0;
+	}
+
+	case PR_open:
+		discard_fd_flags(tracee, config, O_CLOEXEC, KERNEL_VERSION(2,6,23), SYSARG_2);
+		return 0;
+
+	case PR_pipe2: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_pipe,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_pselect6: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts		  = NONE
+		};
+#if defined(ARCH_X86_64)
+		modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_select : PR__newselect);
+#else
+		modif.new_sysarg_num = PR__newselect;
+#endif
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_readlinkat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_readlink,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1}
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_renameat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_rename,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 1,
+					.offset  =-1 },
+				    [1] = {
+					    .sysarg  = SYSARG_4,
+					    .nb_args = 1,
+					    .offset  = -2 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_signalfd4: {
+		bool modified;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_signalfd,
+			.shifts		  = NONE
+		};
+
+		/* "In Linux up to version 2.6.26, the flags argument
+		 * is unused, and must be specified as zero." -- man
+		 * signalfd */
+		modified = modify_syscall(tracee, config, &modif);
+		if (modified)
+			poke_reg(tracee, SYSARG_4, 0);
+		return 0;
+	}
+
+	case PR_socket:
+	case PR_socketpair:
+	case PR_timerfd_create:
+		discard_fd_flags(tracee, config, O_CLOEXEC | O_NONBLOCK,
+				KERNEL_VERSION(2,6,27), SYSARG_2);
+		return 0;
+
+	case PR_symlinkat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_symlink,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_3,
+					.nb_args = 1,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_unlinkat: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 1,
+					.offset  = -1
+				}
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_3);
+		modif.new_sysarg_num = ((flags & AT_REMOVEDIR) != 0
+					? PR_rmdir
+					: PR_unlink);
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Adjust some ELF auxiliary vectors to improve the compatibility.
+ * This function assumes the "argv, envp, auxv" stuff is pointed to by
+ * @tracee's stack pointer, as expected right after a successful call
+ * to execve(2).
+ */
+static void adjust_elf_auxv(Tracee *tracee, Config *config)
+{
+	ElfAuxVector *vectors;
+	ElfAuxVector *vector;
+	word_t vectors_address;
+	word_t stack_pointer;
+	void *argv_envp;
+	size_t size;
+	int status;
+
+	vectors_address = get_elf_aux_vectors_address(tracee);
+	if (vectors_address == 0)
+		return;
+
+	vectors = fetch_elf_aux_vectors(tracee, vectors_address);
+	if (vectors == NULL)
+		return;
+
+	for (vector = vectors; vector->type != AT_NULL; vector++) {
+		switch (vector->type) {
+		/* Discard AT_SYSINFO* vectors: they can be used to
+		 * get the OS release number from memory instead of
+		 * from the uname syscall, and only this latter is
+		 * currently hooked by PRoot.  */
+		case AT_SYSINFO_EHDR:
+		case AT_SYSINFO:
+			vector->type  = AT_IGNORE;
+			vector->value = 0;
+			break;
+
+		case AT_HWCAP:
+			if (config->hwcap != (word_t) -1)
+				vector->value = config->hwcap;
+			break;
+
+		case AT_RANDOM:
+			/* Skip only if not in forced mode.  */
+			if (config->actual_release != 0)
+				goto end;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	/* Add the AT_RANDOM vector only if needed.  */
+	if (!needs_kompat(config, KERNEL_VERSION(2,6,29)))
+		goto end;
+
+	status = add_elf_aux_vector(&vectors, AT_RANDOM, vectors_address);
+	if (status < 0)
+		goto end; /* Not fatal.  */
+
+	/* Since a new vector needs to be added, the ELF auxiliary
+	 * vectors array can't be pushed in place.  As a consequence,
+	 * argv[] and envp[] arrays are moved one vector downward to
+	 * make room for the new ELF auxiliary vectors array.
+	 * Remember, the stack layout is as follow right after execve:
+	 *
+	 *     argv[], envp[], auxv[]
+	 */
+	stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER);
+	size = vectors_address - stack_pointer;
+	argv_envp = talloc_size(tracee->ctx, size);
+	if (argv_envp == NULL)
+		goto end;
+
+	status = read_data(tracee, argv_envp, stack_pointer, size);
+	if (status < 0)
+		goto end;
+
+	/* Allocate enough room in tracee's stack for the new ELF
+	 * auxiliary vector.  */
+	stack_pointer   -= 2 * sizeof_word(tracee);
+	vectors_address -= 2 * sizeof_word(tracee);
+
+	/* Note that it is safe to update the stack pointer manually
+	 * since we are in execve sysexit.  However it should be done
+	 * before transfering data since the kernel might not allow
+	 * page faults below the stack pointer.  */
+	poke_reg(tracee, STACK_POINTER, stack_pointer);
+
+	status = write_data(tracee, stack_pointer, argv_envp, size);
+	if (status < 0)
+		return;
+
+end:
+	push_elf_aux_vectors(tracee, vectors, vectors_address);
+	return;
+}
+
+/**
+ * Append to the @tracee's current syscall enough calls to fcntl(@fd)
+ * in order to set the flags from the original @sysarg register, if
+ * there are also set in @emulated_flags.
+ */
+static void emulate_fd_flags(Tracee *tracee, word_t fd, Reg sysarg, int emulated_flags)
+{
+	word_t flags;
+
+	flags = peek_reg(tracee, ORIGINAL, sysarg);
+	if (flags == 0)
+		return;
+
+	if ((emulated_flags & flags & O_CLOEXEC) != 0)
+		register_chained_syscall(tracee, PR_fcntl, fd, F_SETFD, FD_CLOEXEC, 0, 0, 0);
+
+	if ((emulated_flags & flags & O_NONBLOCK) != 0)
+		register_chained_syscall(tracee, PR_fcntl, fd, F_SETFL, O_NONBLOCK, 0, 0, 0);
+
+	force_chain_final_result(tracee, peek_reg(tracee, CURRENT, SYSARG_RESULT));
+}
+
+/**
+ * Adjust the results/output parameters for syscalls that were
+ * modified in handle_sysenter_end().  This function returns -errno if
+ * an error occured, otherwise 0.
+ */
+static int handle_sysexit_end(Tracee *tracee, Config *config)
+{
+	word_t result;
+	word_t sysnum;
+	int status;
+
+	result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+	sysnum = get_sysnum(tracee, ORIGINAL);
+
+	/* Error reported by the kernel.  */
+	status = (int) result;
+	if (status < 0)
+		return 0;
+
+	switch (sysnum) {
+	case PR_uname: {
+		word_t address;
+
+		address = peek_reg(tracee, ORIGINAL, SYSARG_1);
+
+		/* The layout of struct utsname does not depend on the
+		 * architecture, it only depends on the kernel
+		 * version.  In this regards, this structure is stable
+		 * since < 2.6.0.  */
+		status = write_data(tracee, address, &config->utsname, sizeof(config->utsname));
+		if (status < 0)
+			return status;
+		return 0;
+	}
+
+	case PR_setdomainname:
+	case PR_sethostname: {
+		word_t address;
+		word_t length;
+		char *name;
+
+		name = (sysnum == PR_setdomainname
+			? config->utsname.domainname
+			: config->utsname.nodename);
+
+		length = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (length > sizeof(config->utsname.domainname) - 1)
+			return -EINVAL;
+
+		/* Because of the test above.  */
+		assert(sizeof(config->utsname.domainname) == sizeof(config->utsname.nodename));
+
+		address = peek_reg(tracee, ORIGINAL, SYSARG_1);
+		status  = read_data(tracee, name, address, length);
+		if (status < 0)
+			return status;
+
+		/* "name does not require a terminating null byte." --
+		 * man 2 set{domain,host}name.  */
+		name[length] = '\0';
+
+		return 0;
+	}
+
+	case PR_accept4:
+		if (get_sysnum(tracee, MODIFIED) == PR_accept)
+			emulate_fd_flags(tracee, result, SYSARG_4, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_dup3:
+		if (get_sysnum(tracee, MODIFIED) == PR_dup2)
+			emulate_fd_flags(tracee, peek_reg(tracee, ORIGINAL, SYSARG_2),
+					SYSARG_3, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_epoll_create1:
+		if (get_sysnum(tracee, MODIFIED) == PR_epoll_create)
+			emulate_fd_flags(tracee, result, SYSARG_1, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_eventfd2:
+		if (get_sysnum(tracee, MODIFIED) == PR_eventfd)
+			emulate_fd_flags(tracee, result, SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_fcntl: {
+		word_t command;
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,24)))
+			return 0;
+
+		command = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (command != F_DUPFD_CLOEXEC)
+			return 0;
+
+		register_chained_syscall(tracee, PR_fcntl, result, F_SETFD, FD_CLOEXEC, 0, 0, 0);
+		force_chain_final_result(tracee, peek_reg(tracee, CURRENT, SYSARG_RESULT));
+		return 0;
+	}
+
+	case PR_inotify_init1:
+		if (get_sysnum(tracee, MODIFIED) == PR_inotify_init)
+			emulate_fd_flags(tracee, result, SYSARG_1, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_open:
+		if (needs_kompat(config, KERNEL_VERSION(2,6,23)))
+			emulate_fd_flags(tracee, result, SYSARG_2, O_CLOEXEC);
+		return 0;
+
+	case PR_openat:
+		if (needs_kompat(config, KERNEL_VERSION(2,6,23)))
+			emulate_fd_flags(tracee, result, SYSARG_3, O_CLOEXEC);
+		return 0;
+
+	case PR_pipe2: {
+		int fds[2];
+
+		if (get_sysnum(tracee, MODIFIED) != PR_pipe)
+			return 0;
+
+		status = read_data(tracee, fds, peek_reg(tracee, MODIFIED, SYSARG_1), sizeof(fds));
+		if (status < 0)
+			return 0;
+
+		emulate_fd_flags(tracee, fds[0], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		emulate_fd_flags(tracee, fds[1], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+
+		return 0;
+	}
+
+	case PR_signalfd4:
+		if (get_sysnum(tracee, MODIFIED) == PR_signalfd)
+			emulate_fd_flags(tracee, result, SYSARG_4, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_socket:
+	case PR_timerfd_create:
+		if (needs_kompat(config, KERNEL_VERSION(2,6,27)))
+			emulate_fd_flags(tracee, result, SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_socketpair: {
+		int fds[2];
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,27)))
+			return 0;
+
+		status = read_data(tracee, fds, peek_reg(tracee, MODIFIED, SYSARG_4), sizeof(fds));
+		if (status < 0)
+			return 0;
+
+		emulate_fd_flags(tracee, fds[0], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		emulate_fd_flags(tracee, fds[1], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Fill @config->utsname and @config->hwcap according to the content
+ * of @string.  This function returns -1 if there is a parsing error,
+ * otherwise 0.
+ */
+static int parse_utsname(Config *config, const char *string)
+{
+	struct utsname utsname;
+	int status;
+
+	assert(string != NULL);
+
+	status = uname(&utsname);
+	if (status < 0 || getenv("PROOT_FORCE_KOMPAT") != NULL)
+		config->actual_release = 0;
+	else
+		config->actual_release = parse_kernel_release(utsname.release);
+
+	/* Check whether it is the simple format (ie. release number),
+	 * or the complex one:
+	 *
+	 *     '\sysname\nodename\release\version\machine\domainname\hwcap\'
+	 *
+	 * This complex format is ugly on purpose: it ain't to be used
+	 * directly by users.  */
+	if (string[0] == '\\') {
+		const char *start;
+		const char *end;
+		char *end2;
+
+		/* Initial state of the parser.  */
+		end = string;
+
+#define PARSE(field) do {						\
+			size_t length;					\
+									\
+			start = end + 1;				\
+			end   = strchr(start, '\\');			\
+			if (end == NULL) {				\
+				note(NULL, ERROR, USER,			\
+					"can't find %s field in '%s'", #field, string);	\
+				return -1;				\
+			}						\
+									\
+			length = end - start;				\
+			length = MIN(length, sizeof(config->utsname.field) - 1); \
+			strncpy(config->utsname.field, start, length);	\
+			config->utsname.field[length] = '\0';		\
+		} while(0)
+
+		PARSE(sysname);
+		PARSE(nodename);
+		PARSE(release);
+		PARSE(version);
+		PARSE(machine);
+		PARSE(domainname);
+
+#undef PARSE
+
+		/* The hwcap field is parsed as an hexadecimal value.  */
+		errno = 0;
+		config->hwcap = strtol(end + 1, &end2, 16);
+		if (errno != 0 || end2[0] != '\\') {
+			note(NULL, ERROR, USER, "can't find hwcap field in '%s'", string);
+			return -1;
+		}
+	}
+	else {
+		size_t length;
+
+		memcpy(&config->utsname, &utsname, sizeof(config->utsname));
+
+		length = MIN(strlen(string), sizeof(config->utsname.release) - 1);
+		strncpy(config->utsname.release, string, length);
+		config->utsname.release[length] = '\0';
+
+		config->hwcap = (word_t) -1;
+	}
+
+	config->virtual_release = parse_kernel_release(config->utsname.release);
+
+	return 0;
+}
+
+/* List of syscalls handled by this extensions.  */
+static FilteredSysnum filtered_sysnums[] = {
+	{ PR_accept4,		FILTER_SYSEXIT },
+	{ PR_dup3,		FILTER_SYSEXIT },
+	{ PR_epoll_create1,	FILTER_SYSEXIT },
+	{ PR_epoll_pwait, 	0 },
+	{ PR_eventfd2, 		FILTER_SYSEXIT },
+	{ PR_execve, 		FILTER_SYSEXIT },
+	{ PR_faccessat, 	0 },
+	{ PR_fchmodat, 		0 },
+	{ PR_fchownat, 		0 },
+	{ PR_fcntl, 		FILTER_SYSEXIT },
+	{ PR_fstatat64, 	0 },
+	{ PR_futimesat, 	0 },
+	{ PR_futex, 		0 },
+	{ PR_inotify_init1, 	FILTER_SYSEXIT },
+	{ PR_linkat, 		0 },
+	{ PR_mkdirat, 		0 },
+	{ PR_mknodat, 		0 },
+	{ PR_newfstatat, 	0 },
+	{ PR_open, 		FILTER_SYSEXIT },
+	{ PR_openat, 		FILTER_SYSEXIT },
+	{ PR_pipe2, 		FILTER_SYSEXIT },
+	{ PR_pselect6, 		0 },
+	{ PR_readlinkat, 	0 },
+	{ PR_renameat, 		0 },
+	{ PR_setdomainname,	FILTER_SYSEXIT },
+	{ PR_sethostname,	FILTER_SYSEXIT },
+	{ PR_signalfd4, 	FILTER_SYSEXIT },
+	{ PR_socket,		FILTER_SYSEXIT },
+	{ PR_socketpair,	FILTER_SYSEXIT },
+	{ PR_symlinkat, 	0 },
+	{ PR_timerfd_create,	FILTER_SYSEXIT },
+	{ PR_uname, 		FILTER_SYSEXIT },
+	{ PR_unlinkat, 		0 },
+	FILTERED_SYSNUM_END,
+};
+
+/**
+ * Handler for this @extension.  It is triggered each time an @event
+ * occured.  See ExtensionEvent for the meaning of @data1 and @data2.
+ */
+int kompat_callback(Extension *extension, ExtensionEvent event,
+		intptr_t data1, intptr_t data2 UNUSED)
+{
+	int status;
+
+	switch (event) {
+	case INITIALIZATION: {
+		Config *config;
+
+		extension->config = talloc_zero(extension, Config);
+		if (extension->config == NULL)
+			return -1;
+		config = extension->config;
+
+		status = parse_utsname(config, (const char *) data1);
+		if (status < 0)
+			return -1;
+
+		extension->filtered_sysnums = filtered_sysnums;
+		return 0;
+	}
+
+	case SYSCALL_ENTER_END: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+
+		/* Nothing to do if this syscall is being discarded
+		 * (because of an error detected by PRoot).  */
+		if ((int) data1 < 0)
+			return 0;
+
+		return handle_sysenter_end(tracee, config);
+	}
+
+	case SYSCALL_EXIT_END: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+
+		return handle_sysexit_end(tracee, config);
+	}
+
+	case SYSCALL_EXIT_START: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+		word_t result = peek_reg(tracee, CURRENT, SYSARG_RESULT);;
+		word_t sysnum = get_sysnum(tracee, ORIGINAL);
+
+		/* Note: this can be done only before PRoot pushes the
+		 * load script into tracee's stack.  */
+		if ((int) result >= 0 && sysnum == PR_execve)
+			adjust_elf_auxv(tracee, config);
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+}
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/enter.c b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/enter.c
new file mode 100644
index 0000000..c133b72
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/enter.c
@@ -0,0 +1,575 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <errno.h>       /* errno(3), E* */
+#include <talloc.h>      /* talloc_*, */
+#include <sys/un.h>      /* struct sockaddr_un, */
+#include <linux/net.h>   /* SYS_*, */
+#include <fcntl.h>       /* AT_FDCWD, */
+#include <limits.h>      /* PATH_MAX, */
+
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "syscall/socket.h"
+#include "ptrace/ptrace.h"
+#include "ptrace/wait.h"
+#include "syscall/heap.h"
+#include "extension/extension.h"
+#include "execve/execve.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+#include "tracee/abi.h"
+#include "path/path.h"
+#include "path/canon.h"
+#include "arch.h"
+
+/**
+ * Translate @path and put the result in the @tracee's memory address
+ * space pointed to by the @reg argument of the current syscall. See
+ * the documentation of translate_path() about the meaning of
+ * @type. This function returns -errno if an error occured, otherwise
+ * 0.
+ */
+static int translate_path2(Tracee *tracee, int dir_fd, char path[PATH_MAX], Reg reg, Type type)
+{
+	char new_path[PATH_MAX];
+	int status;
+
+	/* Special case where the argument was NULL. */
+	if (path[0] == '\0')
+		return 0;
+
+	/* Translate the original path. */
+	status = translate_path(tracee, new_path, dir_fd, path, type != SYMLINK);
+	if (status < 0)
+		return status;
+
+	return set_sysarg_path(tracee, new_path, reg);
+}
+
+/**
+ * A helper, see the comment of the function above.
+ */
+static int translate_sysarg(Tracee *tracee, Reg reg, Type type)
+{
+	char old_path[PATH_MAX];
+	int status;
+
+	/* Extract the original path. */
+	status = get_sysarg_path(tracee, old_path, reg);
+	if (status < 0)
+		return status;
+
+	return translate_path2(tracee, AT_FDCWD, old_path, reg, type);
+}
+
+/**
+ * Translate the input arguments of the current @tracee's syscall in the
+ * @tracee->pid process area. This function sets @tracee->status to
+ * -errno if an error occured from the tracee's point-of-view (EFAULT
+ * for instance), otherwise 0.
+ */
+int translate_syscall_enter(Tracee *tracee)
+{
+	int flags;
+	int dirfd;
+	int olddirfd;
+	int newdirfd;
+
+	int status;
+	int status2;
+
+	char path[PATH_MAX];
+	char oldpath[PATH_MAX];
+	char newpath[PATH_MAX];
+
+	word_t syscall_number;
+	bool special = false;
+
+	status = notify_extensions(tracee, SYSCALL_ENTER_START, 0, 0);
+	if (status < 0)
+		goto end;
+	if (status > 0)
+		return 0;
+
+	/* Translate input arguments. */
+	syscall_number = get_sysnum(tracee, ORIGINAL);
+	switch (syscall_number) {
+	default:
+		/* Nothing to do. */
+		status = 0;
+		break;
+
+	case PR_execve:
+		status = translate_execve_enter(tracee);
+		break;
+
+	case PR_ptrace:
+		status = translate_ptrace_enter(tracee);
+		break;
+
+	case PR_wait4:
+	case PR_waitpid:
+		status = translate_wait_enter(tracee);
+		break;
+
+	case PR_brk:
+		status = translate_brk_enter(tracee);
+		break;
+
+	case PR_getcwd:
+		set_sysnum(tracee, PR_void);
+		status = 0;
+		break;
+
+	case PR_fchdir:
+	case PR_chdir: {
+		struct stat statl;
+		char *tmp;
+
+		/* The ending "." ensures an error will be reported if
+		 * path does not exist or if it is not a directory.  */
+		if (syscall_number == PR_chdir) {
+			status = get_sysarg_path(tracee, path, SYSARG_1);
+			if (status < 0)
+				break;
+
+			status = join_paths(2, oldpath, path, ".");
+			if (status < 0)
+				break;
+
+			dirfd = AT_FDCWD;
+		}
+		else {
+			strcpy(oldpath, ".");
+			dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		}
+
+		status = translate_path(tracee, path, dirfd, oldpath, true);
+		if (status < 0)
+			break;
+
+		status = lstat(path, &statl);
+		if (status < 0)
+			break;
+
+		/* Check this directory is accessible.  */
+		if ((statl.st_mode & S_IXUSR) == 0)
+			return -EACCES;
+
+		/* Sadly this method doesn't detranslate statefully,
+		 * this means that there's an ambiguity when several
+		 * bindings are from the same host path:
+		 *
+		 *    $ proot -m /tmp:/a -m /tmp:/b fchdir_getcwd /a
+		 *    /b
+		 *
+		 *    $ proot -m /tmp:/b -m /tmp:/a fchdir_getcwd /a
+		 *    /a
+		 *
+		 * A solution would be to follow each file descriptor
+		 * just like it is done for cwd.
+		 */
+
+		status = detranslate_path(tracee, path, NULL);
+		if (status < 0)
+			break;
+
+		/* Remove the trailing "/" or "/.".  */
+		chop_finality(path);
+
+		tmp = talloc_strdup(tracee->fs, path);
+		if (tmp == NULL) {
+			status = -ENOMEM;
+			break;
+		}
+		TALLOC_FREE(tracee->fs->cwd);
+
+		tracee->fs->cwd = tmp;
+		talloc_set_name_const(tracee->fs->cwd, "$cwd");
+
+		set_sysnum(tracee, PR_void);
+		status = 0;
+		break;
+	}
+
+	case PR_bind:
+	case PR_connect: {
+		word_t address;
+		word_t size;
+
+		address = peek_reg(tracee, CURRENT, SYSARG_2);
+		size    = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		status = translate_socketcall_enter(tracee, &address, size);
+		if (status <= 0)
+			break;
+
+		poke_reg(tracee, SYSARG_2, address);
+		poke_reg(tracee, SYSARG_3, sizeof(struct sockaddr_un));
+
+		status = 0;
+		break;
+	}
+
+#define SYSARG_ADDR(n) (args_addr + ((n) - 1) * sizeof_word(tracee))
+
+#define PEEK_WORD(addr, forced_errno)		\
+	peek_word(tracee, addr);		\
+	if (errno != 0) {			\
+		status = forced_errno ?: -errno; \
+		break;				\
+	}
+
+#define POKE_WORD(addr, value)			\
+	poke_word(tracee, addr, value);		\
+	if (errno != 0) {			\
+		status = -errno;		\
+		break;				\
+	}
+
+	case PR_accept:
+	case PR_accept4:
+		/* Nothing special to do if no sockaddr was specified.  */
+		if (peek_reg(tracee, ORIGINAL, SYSARG_2) == 0) {
+			status = 0;
+			break;
+		}
+		special = true;
+		/* Fall through.  */
+	case PR_getsockname:
+	case PR_getpeername:{
+		int size;
+
+		/* Remember: PEEK_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		size = (int) PEEK_WORD(peek_reg(tracee, ORIGINAL, SYSARG_3), special ? -EINVAL : 0);
+
+		/* The "size" argument is both used as an input parameter
+		 * (max. size) and as an output parameter (actual size).  The
+		 * exit stage needs to know the max. size to not overwrite
+		 * anything, that's why it is copied in the 6th argument
+		 * (unused) before the kernel updates it.  */
+		poke_reg(tracee, SYSARG_6, size);
+
+		status = 0;
+		break;
+	}
+
+	case PR_socketcall: {
+		word_t args_addr;
+		word_t sock_addr_saved;
+		word_t sock_addr;
+		word_t size_addr;
+		word_t size;
+
+		args_addr = peek_reg(tracee, CURRENT, SYSARG_2);
+
+		switch (peek_reg(tracee, CURRENT, SYSARG_1)) {
+		case SYS_BIND:
+		case SYS_CONNECT:
+			/* Handle these cases below.  */
+			status = 1;
+			break;
+
+		case SYS_ACCEPT:
+		case SYS_ACCEPT4:
+			/* Nothing special to do if no sockaddr was specified.  */
+			sock_addr = PEEK_WORD(SYSARG_ADDR(2), 0);
+			if (sock_addr == 0) {
+				status = 0;
+				break;
+			}
+			special = true;
+			/* Fall through.  */
+		case SYS_GETSOCKNAME:
+		case SYS_GETPEERNAME:
+			/* Remember: PEEK_WORD puts -errno in status and breaks
+			 * if an error occured.  */
+			size_addr =  PEEK_WORD(SYSARG_ADDR(3), 0);
+			size = (int) PEEK_WORD(size_addr, special ? -EINVAL : 0);
+
+			/* See case PR_accept for explanation.  */
+			poke_reg(tracee, SYSARG_6, size);
+			status = 0;
+			break;
+
+		default:
+			status = 0;
+			break;
+		}
+
+		/* An error occured or there's nothing else to do.  */
+		if (status <= 0)
+			break;
+
+		/* Remember: PEEK_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		sock_addr = PEEK_WORD(SYSARG_ADDR(2), 0);
+		size      = PEEK_WORD(SYSARG_ADDR(3), 0);
+
+		sock_addr_saved = sock_addr;
+		status = translate_socketcall_enter(tracee, &sock_addr, size);
+		if (status <= 0)
+			break;
+
+		/* These parameters are used/restored at the exit stage.  */
+		poke_reg(tracee, SYSARG_5, sock_addr_saved);
+		poke_reg(tracee, SYSARG_6, size);
+
+		/* Remember: POKE_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		POKE_WORD(SYSARG_ADDR(2), sock_addr);
+		POKE_WORD(SYSARG_ADDR(3), sizeof(struct sockaddr_un));
+
+		status = 0;
+		break;
+	}
+
+#undef SYSARG_ADDR
+#undef PEEK_WORD
+#undef POKE_WORD
+
+	case PR_access:
+	case PR_acct:
+	case PR_chmod:
+	case PR_chown:
+	case PR_chown32:
+	case PR_chroot:
+	case PR_getxattr:
+	case PR_listxattr:
+	case PR_mknod:
+	case PR_oldstat:
+	case PR_creat:
+	case PR_removexattr:
+	case PR_setxattr:
+	case PR_stat:
+	case PR_stat64:
+	case PR_statfs:
+	case PR_statfs64:
+	case PR_swapoff:
+	case PR_swapon:
+	case PR_truncate:
+	case PR_truncate64:
+	case PR_umount:
+	case PR_umount2:
+	case PR_uselib:
+	case PR_utime:
+	case PR_utimes:
+		status = translate_sysarg(tracee, SYSARG_1, REGULAR);
+		break;
+
+	case PR_open:
+		flags = peek_reg(tracee, CURRENT, SYSARG_2);
+
+		if (   ((flags & O_NOFOLLOW) != 0)
+		    || ((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0))
+			status = translate_sysarg(tracee, SYSARG_1, SYMLINK);
+		else
+			status = translate_sysarg(tracee, SYSARG_1, REGULAR);
+		break;
+
+	case PR_fchownat:
+	case PR_fstatat64:
+	case PR_newfstatat:
+	case PR_utimensat:
+	case PR_name_to_handle_at:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		flags = (  syscall_number == PR_fchownat
+			|| syscall_number == PR_name_to_handle_at)
+			? peek_reg(tracee, CURRENT, SYSARG_5)
+			: peek_reg(tracee, CURRENT, SYSARG_4);
+
+		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, SYMLINK);
+		else
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, REGULAR);
+		break;
+
+	case PR_fchmodat:
+	case PR_faccessat:
+	case PR_futimesat:
+	case PR_mknodat:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, dirfd, path, SYSARG_2, REGULAR);
+		break;
+
+	case PR_inotify_add_watch:
+		flags = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		if ((flags & IN_DONT_FOLLOW) != 0)
+			status = translate_sysarg(tracee, SYSARG_2, SYMLINK);
+		else
+			status = translate_sysarg(tracee, SYSARG_2, REGULAR);
+		break;
+
+	case PR_readlink:
+	case PR_lchown:
+	case PR_lchown32:
+	case PR_lgetxattr:
+	case PR_llistxattr:
+	case PR_lremovexattr:
+	case PR_lsetxattr:
+	case PR_lstat:
+	case PR_lstat64:
+	case PR_oldlstat:
+	case PR_unlink:
+	case PR_rmdir:
+	case PR_mkdir:
+		status = translate_sysarg(tracee, SYSARG_1, SYMLINK);
+		break;
+
+	case PR_pivot_root:
+		status = translate_sysarg(tracee, SYSARG_1, REGULAR);
+		if (status < 0)
+			break;
+
+		status = translate_sysarg(tracee, SYSARG_2, REGULAR);
+		break;
+
+	case PR_linkat:
+		olddirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		newdirfd = peek_reg(tracee, CURRENT, SYSARG_3);
+		flags    = peek_reg(tracee, CURRENT, SYSARG_5);
+
+		status = get_sysarg_path(tracee, oldpath, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = get_sysarg_path(tracee, newpath, SYSARG_4);
+		if (status < 0)
+			break;
+
+		if ((flags & AT_SYMLINK_FOLLOW) != 0)
+			status = translate_path2(tracee, olddirfd, oldpath, SYSARG_2, REGULAR);
+		else
+			status = translate_path2(tracee, olddirfd, oldpath, SYSARG_2, SYMLINK);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, newdirfd, newpath, SYSARG_4, SYMLINK);
+		break;
+
+	case PR_mount:
+		status = get_sysarg_path(tracee, path, SYSARG_1);
+		if (status < 0)
+			break;
+
+		/* The following check covers only 90% of the cases. */
+		if (path[0] == '/' || path[0] == '.') {
+			status = translate_path2(tracee, AT_FDCWD, path, SYSARG_1, REGULAR);
+			if (status < 0)
+				break;
+		}
+
+		status = translate_sysarg(tracee, SYSARG_2, REGULAR);
+		break;
+
+	case PR_openat:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		flags = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		if (   ((flags & O_NOFOLLOW) != 0)
+			|| ((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0))
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, SYMLINK);
+		else
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, REGULAR);
+		break;
+
+	case PR_readlinkat:
+	case PR_unlinkat:
+	case PR_mkdirat:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, dirfd, path, SYSARG_2, SYMLINK);
+		break;
+
+	case PR_link:
+	case PR_rename:
+		status = translate_sysarg(tracee, SYSARG_1, SYMLINK);
+		if (status < 0)
+			break;
+
+		status = translate_sysarg(tracee, SYSARG_2, SYMLINK);
+		break;
+
+	case PR_renameat:
+		olddirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		newdirfd = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		status = get_sysarg_path(tracee, oldpath, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = get_sysarg_path(tracee, newpath, SYSARG_4);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, olddirfd, oldpath, SYSARG_2, SYMLINK);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, newdirfd, newpath, SYSARG_4, SYMLINK);
+		break;
+
+	case PR_symlink:
+		status = translate_sysarg(tracee, SYSARG_2, SYMLINK);
+		break;
+
+	case PR_symlinkat:
+		newdirfd = peek_reg(tracee, CURRENT, SYSARG_2);
+
+		status = get_sysarg_path(tracee, newpath, SYSARG_3);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, newdirfd, newpath, SYSARG_3, SYMLINK);
+		break;
+	}
+
+end:
+	status2 = notify_extensions(tracee, SYSCALL_ENTER_END, status, 0);
+	if (status2 < 0)
+		status = status2;
+
+	return status;
+}
+
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/exit.c b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/exit.c
new file mode 100644
index 0000000..5243824
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/exit.c
@@ -0,0 +1,454 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <errno.h>       /* errno(3), E* */
+#include <sys/utsname.h> /* struct utsname, */
+#include <linux/net.h>   /* SYS_*, */
+#include <string.h>      /* strlen(3), */
+
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "syscall/socket.h"
+#include "syscall/chain.h"
+#include "syscall/heap.h"
+#include "execve/execve.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+#include "tracee/abi.h"
+#include "path/path.h"
+#include "ptrace/ptrace.h"
+#include "ptrace/wait.h"
+#include "extension/extension.h"
+#include "arch.h"
+
+/**
+ * Translate the output arguments of the current @tracee's syscall in
+ * the @tracee->pid process area. This function sets the result of
+ * this syscall to @tracee->status if an error occured previously
+ * during the translation, that is, if @tracee->status is less than 0.
+ */
+void translate_syscall_exit(Tracee *tracee)
+{
+	word_t syscall_number;
+	word_t syscall_result;
+	int status;
+
+	status = notify_extensions(tracee, SYSCALL_EXIT_START, 0, 0);
+	if (status < 0) {
+		poke_reg(tracee, SYSARG_RESULT, (word_t) status);
+		goto end;
+	}
+	if (status > 0)
+		return;
+
+	/* Set the tracee's errno if an error occured previously during
+	 * the translation. */
+	if (tracee->status < 0) {
+		poke_reg(tracee, SYSARG_RESULT, (word_t) tracee->status);
+		goto end;
+	}
+
+	/* Translate output arguments:
+	 * - break: update the syscall result register with "status"
+	 * - goto end: nothing else to do.
+	 */
+	syscall_number = get_sysnum(tracee, ORIGINAL);
+	syscall_result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+	switch (syscall_number) {
+	case PR_brk:
+		translate_brk_exit(tracee);
+		goto end;
+
+	case PR_getcwd: {
+		char path[PATH_MAX];
+		size_t new_size;
+		size_t size;
+		word_t output;
+
+		size = (size_t) peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (size == 0) {
+			status = -EINVAL;
+			break;
+		}
+
+		/* Ensure cwd still exists.  */
+		status = translate_path(tracee, path, AT_FDCWD, ".", false);
+		if (status < 0)
+			break;
+
+		new_size = strlen(tracee->fs->cwd) + 1;
+		if (size < new_size) {
+			status = -ERANGE;
+			break;
+		}
+
+		/* Overwrite the path.  */
+		output = peek_reg(tracee, ORIGINAL, SYSARG_1);
+		status = write_data(tracee, output, tracee->fs->cwd, new_size);
+		if (status < 0)
+			break;
+
+		/* The value of "status" is used to update the returned value
+		 * in translate_syscall_exit().  */
+		status = new_size;
+		break;
+	}
+
+	case PR_accept:
+	case PR_accept4:
+		/* Nothing special to do if no sockaddr was specified.  */
+		if (peek_reg(tracee, ORIGINAL, SYSARG_2) == 0)
+			goto end;
+		/* Fall through.  */
+	case PR_getsockname:
+	case PR_getpeername: {
+		word_t sock_addr;
+		word_t size_addr;
+		word_t max_size;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		sock_addr = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		size_addr = peek_reg(tracee, MODIFIED, SYSARG_3);
+		max_size  = peek_reg(tracee, MODIFIED, SYSARG_6);
+
+		status = translate_socketcall_exit(tracee, sock_addr, size_addr, max_size);
+		if (status < 0)
+			break;
+
+		/* Don't overwrite the syscall result.  */
+		goto end;
+	}
+
+#define SYSARG_ADDR(n) (args_addr + ((n) - 1) * sizeof_word(tracee))
+
+#define POKE_WORD(addr, value)			\
+	poke_word(tracee, addr, value);		\
+	if (errno != 0)	{			\
+		status = -errno;		\
+		break;				\
+	}
+
+#define PEEK_WORD(addr)				\
+	peek_word(tracee, addr);		\
+	if (errno != 0) {			\
+		status = -errno;		\
+		break;				\
+	}
+
+	case PR_socketcall: {
+		word_t args_addr;
+		word_t sock_addr;
+		word_t size_addr;
+		word_t max_size;
+
+		args_addr = peek_reg(tracee, ORIGINAL, SYSARG_2);
+
+		switch (peek_reg(tracee, ORIGINAL, SYSARG_1)) {
+		case SYS_ACCEPT:
+		case SYS_ACCEPT4:
+			/* Nothing special to do if no sockaddr was specified.  */
+			sock_addr = PEEK_WORD(SYSARG_ADDR(2));
+			if (sock_addr == 0)
+				goto end;
+			/* Fall through.  */
+		case SYS_GETSOCKNAME:
+		case SYS_GETPEERNAME:
+			/* Handle these cases below.  */
+			status = 1;
+			break;
+
+		case SYS_BIND:
+		case SYS_CONNECT:
+			/* Restore the initial parameters: this memory was
+			 * overwritten at the enter stage.  Remember: POKE_WORD
+			 * puts -errno in status and breaks if an error
+			 * occured.  */
+			POKE_WORD(SYSARG_ADDR(2), peek_reg(tracee, MODIFIED, SYSARG_5));
+			POKE_WORD(SYSARG_ADDR(3), peek_reg(tracee, MODIFIED, SYSARG_6));
+
+			status = 0;
+			break;
+
+		default:
+			status = 0;
+			break;
+		}
+
+		/* Error reported by the kernel or there's nothing else to do.  */
+		if ((int) syscall_result < 0 || status == 0)
+			goto end;
+
+		/* An error occured in SYS_BIND or SYS_CONNECT.  */
+		if (status < 0)
+			break;
+
+		/* Remember: PEEK_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		sock_addr = PEEK_WORD(SYSARG_ADDR(2));
+		size_addr = PEEK_WORD(SYSARG_ADDR(3));
+		max_size  = peek_reg(tracee, MODIFIED, SYSARG_6);
+
+		status = translate_socketcall_exit(tracee, sock_addr, size_addr, max_size);
+		if (status < 0)
+			break;
+
+		/* Don't overwrite the syscall result.  */
+		goto end;
+	}
+
+#undef SYSARG_ADDR
+#undef PEEK_WORD
+#undef POKE_WORD
+
+	case PR_fchdir:
+	case PR_chdir:
+		/* These syscalls are fully emulated, see enter.c for details
+		 * (like errors).  */
+		status = 0;
+		break;
+
+	case PR_rename:
+	case PR_renameat: {
+		char old_path[PATH_MAX];
+		char new_path[PATH_MAX];
+		ssize_t old_length;
+		ssize_t new_length;
+		Comparison comparison;
+		Reg old_reg;
+		Reg new_reg;
+		char *tmp;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		if (syscall_number == PR_rename) {
+			old_reg = SYSARG_1;
+			new_reg = SYSARG_2;
+		}
+		else {
+			old_reg = SYSARG_2;
+			new_reg = SYSARG_4;
+		}
+
+		/* Get the old path, then convert it to the same
+		 * "point-of-view" as tracee->fs->cwd (guest).  */
+		status = read_path(tracee, old_path, peek_reg(tracee, MODIFIED, old_reg));
+		if (status < 0)
+			break;
+
+		status = detranslate_path(tracee, old_path, NULL);
+		if (status < 0)
+			break;
+		old_length = (status > 0 ? status - 1 : (ssize_t) strlen(old_path));
+
+		/* Nothing special to do if the moved path is not the
+		 * current working directory.  */
+		comparison = compare_paths(old_path, tracee->fs->cwd);
+		if (comparison != PATH1_IS_PREFIX && comparison != PATHS_ARE_EQUAL) {
+			status = 0;
+			break;
+		}
+
+		/* Get the new path, then convert it to the same
+		 * "point-of-view" as tracee->fs->cwd (guest).  */
+		status = read_path(tracee, new_path, peek_reg(tracee, MODIFIED, new_reg));
+		if (status < 0)
+			break;
+
+		status = detranslate_path(tracee, new_path, NULL);
+		if (status < 0)
+			break;
+		new_length = (status > 0 ? status - 1 : (ssize_t) strlen(new_path));
+
+		/* Sanity check.  */
+		if (strlen(tracee->fs->cwd) >= PATH_MAX) {
+			status = 0;
+			break;
+		}
+		strcpy(old_path, tracee->fs->cwd);
+
+		/* Update the virtual current working directory.  */
+		substitute_path_prefix(old_path, old_length, new_path, new_length);
+
+		tmp = talloc_strdup(tracee->fs, old_path);
+		if (tmp == NULL) {
+			status = -ENOMEM;
+			break;
+		}
+
+		TALLOC_FREE(tracee->fs->cwd);
+		tracee->fs->cwd = tmp;
+
+		status = 0;
+		break;
+	}
+
+	case PR_readlink:
+	case PR_readlinkat: {
+		char referee[PATH_MAX];
+		char referer[PATH_MAX];
+		size_t old_size;
+		size_t new_size;
+		size_t max_size;
+		word_t input;
+		word_t output;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		old_size = syscall_result;
+
+		if (syscall_number == PR_readlink) {
+			output   = peek_reg(tracee, ORIGINAL, SYSARG_2);
+			max_size = peek_reg(tracee, ORIGINAL, SYSARG_3);
+			input    = peek_reg(tracee, MODIFIED, SYSARG_1);
+		}
+		else {
+			output   = peek_reg(tracee, ORIGINAL,  SYSARG_3);
+			max_size = peek_reg(tracee, ORIGINAL, SYSARG_4);
+			input    = peek_reg(tracee, MODIFIED, SYSARG_2);
+		}
+
+		if (max_size > PATH_MAX)
+			max_size = PATH_MAX;
+
+		if (max_size == 0) {
+			status = -EINVAL;
+			break;
+		}
+
+		/* The kernel does NOT put the NULL terminating byte for
+		 * readlink(2).  */
+		status = read_data(tracee, referee, output, old_size);
+		if (status < 0)
+			break;
+		referee[old_size] = '\0';
+
+		/* Not optimal but safe (path is fully translated).  */
+		status = read_path(tracee, referer, input);
+		if (status < 0)
+			break;
+
+		if (status >= PATH_MAX) {
+			status = -ENAMETOOLONG;
+			break;
+		}
+
+		status = detranslate_path(tracee, referee, referer);
+		if (status < 0)
+			break;
+
+		/* The original path doesn't require any transformation, i.e
+		 * it is a symetric binding.  */
+		if (status == 0)
+			goto end;
+
+		/* Overwrite the path.  Note: the output buffer might be
+		 * initialized with zeros but it was updated with the kernel
+		 * result, and then with the detranslated result.  This later
+		 * might be shorter than the former, so it's safier to add a
+		 * NULL terminating byte when possible.  This problem was
+		 * exposed by IDA Demo 6.3.  */
+		if ((size_t) status < max_size) {
+			new_size = status - 1;
+			status = write_data(tracee, output, referee, status);
+		}
+		else {
+			new_size = max_size;
+			status = write_data(tracee, output, referee, max_size);
+		}
+		if (status < 0)
+			break;
+
+		/* The value of "status" is used to update the returned value
+		 * in translate_syscall_exit().  */
+		status = new_size;
+		break;
+	}
+
+#if defined(ARCH_X86_64)
+	case PR_uname: {
+		struct utsname utsname;
+		word_t address;
+		size_t size;
+
+		if (get_abi(tracee) != ABI_2)
+			goto end;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		address = peek_reg(tracee, ORIGINAL, SYSARG_1);
+
+		status = read_data(tracee, &utsname, address, sizeof(utsname));
+		if (status < 0)
+			break;
+
+		/* Some 32-bit programs like package managers can be
+		 * confused when the kernel reports "x86_64".  */
+		size = sizeof(utsname.machine);
+		strncpy(utsname.machine, "i686", size);
+		utsname.machine[size - 1] = '\0';
+
+		status = write_data(tracee, address, &utsname, sizeof(utsname));
+		if (status < 0)
+			break;
+
+		status = 0;
+		break;
+	}
+#endif
+
+	case PR_execve:
+		translate_execve_exit(tracee);
+		goto end;
+
+	case PR_ptrace:
+		status = translate_ptrace_exit(tracee);
+		break;
+
+	case PR_wait4:
+	case PR_waitpid:
+		if (tracee->as_ptracer.waits_in != WAITS_IN_PROOT)
+			goto end;
+
+		status = translate_wait_exit(tracee);
+		break;
+
+	default:
+		goto end;
+	}
+
+	poke_reg(tracee, SYSARG_RESULT, (word_t) status);
+
+end:
+	status = notify_extensions(tracee, SYSCALL_EXIT_END, 0, 0);
+	if (status < 0)
+		poke_reg(tracee, SYSARG_RESULT, (word_t) status);
+}
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/seccomp.c b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/seccomp.c
new file mode 100644
index 0000000..4b86fe8
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/seccomp.c
@@ -0,0 +1,511 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include "build.h"
+#include "arch.h"
+
+#if defined(HAVE_SECCOMP_FILTER)
+
+#include <sys/prctl.h>     /* prctl(2), PR_* */
+#include <linux/filter.h>  /* struct sock_*, */
+#include <linux/seccomp.h> /* SECCOMP_MODE_FILTER, */
+#include <linux/filter.h>  /* struct sock_*, */
+#include <linux/audit.h>   /* AUDIT_, */
+#include <sys/queue.h>     /* LIST_FOREACH, */
+#include <sys/types.h>     /* size_t, */
+#include <talloc.h>        /* talloc_*, */
+#include <errno.h>         /* E*, */
+#include <string.h>        /* memcpy(3), */
+#include <stddef.h>        /* offsetof(3), */
+#include <stdint.h>        /* uint*_t, UINT*_MAX, */
+#include <assert.h>        /* assert(3), */
+
+#include "syscall/seccomp.h"
+#include "tracee/tracee.h"
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "extension/extension.h"
+#include "cli/note.h"
+
+#include "compat.h"
+#include "attribute.h"
+
+#define DEBUG_FILTER(...) /* fprintf(stderr, __VA_ARGS__) */
+
+/**
+ * Allocate an empty @program->filter.  This function returns -errno
+ * if an error occurred, otherwise 0.
+ */
+static int new_program_filter(struct sock_fprog *program)
+{
+	program->filter = talloc_array(NULL, struct sock_filter, 0);
+	if (program->filter == NULL)
+		return -ENOMEM;
+
+	program->len = 0;
+	return 0;
+}
+
+/**
+ * Append to @program->filter the given @statements (@nb_statements
+ * items).  This function returns -errno if an error occurred,
+ * otherwise 0.
+ */
+static int add_statements(struct sock_fprog *program, size_t nb_statements,
+			struct sock_filter *statements)
+{
+	size_t length;
+	void *tmp;
+	size_t i;
+
+	length = talloc_array_length(program->filter);
+	tmp  = talloc_realloc(NULL, program->filter, struct sock_filter, length + nb_statements);
+	if (tmp == NULL)
+		return -ENOMEM;
+	program->filter = tmp;
+
+	for (i = 0; i < nb_statements; i++, length++)
+		memcpy(&program->filter[length], &statements[i], sizeof(struct sock_filter));
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements required to notify PRoot
+ * about the given @syscall made by a tracee, with the given @flag.
+ * This function returns -errno if an error occurred, otherwise 0.
+ */
+static int add_trace_syscall(struct sock_fprog *program, word_t syscall, int flag)
+{
+	int status;
+
+	/* Sanity check.  */
+	if (syscall > UINT32_MAX)
+		return -ERANGE;
+
+	#define LENGTH_TRACE_SYSCALL 2
+	struct sock_filter statements[LENGTH_TRACE_SYSCALL] = {
+		/* Compare the accumulator with the expected syscall:
+		 * skip the next statement if not equal.  */
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, syscall, 0, 1),
+
+		/* Notify the tracer.  */
+		BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE + flag)
+	};
+
+	DEBUG_FILTER("FILTER:     trace if syscall == %ld\n", syscall);
+
+	status = add_statements(program, LENGTH_TRACE_SYSCALL, statements);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements that allow anything (if
+ * unfiltered).  Note that @nb_traced_syscalls is used to make a
+ * sanity check.  This function returns -errno if an error occurred,
+ * otherwise 0.
+ */
+static int end_arch_section(struct sock_fprog *program, size_t nb_traced_syscalls)
+{
+	int status;
+
+	#define LENGTH_END_SECTION 1
+	struct sock_filter statements[LENGTH_END_SECTION] = {
+		BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW)
+	};
+
+	DEBUG_FILTER("FILTER:     allow\n");
+
+	status = add_statements(program, LENGTH_END_SECTION, statements);
+	if (status < 0)
+		return status;
+
+	/* Sanity check, see start_arch_section().  */
+	if (   talloc_array_length(program->filter) - program->len
+	    != LENGTH_END_SECTION + nb_traced_syscalls * LENGTH_TRACE_SYSCALL)
+		return -ERANGE;
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements that check the current
+ * @architecture.  Note that @nb_traced_syscalls is used to make a
+ * sanity check.  This function returns -errno if an error occurred,
+ * otherwise 0.
+ */
+static int start_arch_section(struct sock_fprog *program, uint32_t arch, size_t nb_traced_syscalls)
+{
+	const size_t arch_offset    = offsetof(struct seccomp_data, arch);
+	const size_t syscall_offset = offsetof(struct seccomp_data, nr);
+	const size_t section_length = LENGTH_END_SECTION +
+					nb_traced_syscalls * LENGTH_TRACE_SYSCALL;
+	int status;
+
+	/* Sanity checks.  */
+	if (   arch_offset    > UINT32_MAX
+	    || syscall_offset > UINT32_MAX
+	    || section_length > UINT32_MAX - 1)
+		return -ERANGE;
+
+	#define LENGTH_START_SECTION 4
+	struct sock_filter statements[LENGTH_START_SECTION] = {
+		/* Load the current architecture into the
+		 * accumulator.  */
+		BPF_STMT(BPF_LD + BPF_W + BPF_ABS, arch_offset),
+
+		/* Compare the accumulator with the expected
+		 * architecture: skip the following statement if
+		 * equal.  */
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 1, 0),
+
+		/* This is not the expected architecture, so jump
+		 * unconditionally to the end of this section.  */
+		BPF_STMT(BPF_JMP + BPF_JA + BPF_K, section_length + 1),
+
+		/* This is the expected architecture, so load the
+		 * current syscall into the accumulator.  */
+		BPF_STMT(BPF_LD + BPF_W + BPF_ABS, syscall_offset)
+	};
+
+	DEBUG_FILTER("FILTER: if arch == %ld, up to %zdth statement\n",
+		arch, nb_traced_syscalls);
+
+	status = add_statements(program, LENGTH_START_SECTION, statements);
+	if (status < 0)
+		return status;
+
+	/* See the sanity check in end_arch_section().  */
+	program->len = talloc_array_length(program->filter);
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements that forbid anything (if
+ * unfiltered) and update @program->len.  This function returns -errno
+ * if an error occurred, otherwise 0.
+ */
+static int finalize_program_filter(struct sock_fprog *program)
+{
+	int status;
+
+	#define LENGTH_FINALIZE 1
+	struct sock_filter statements[LENGTH_FINALIZE] = {
+		BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL)
+	};
+
+	DEBUG_FILTER("FILTER: kill\n");
+
+	status = add_statements(program, LENGTH_FINALIZE, statements);
+	if (status < 0)
+		return status;
+
+	program->len = talloc_array_length(program->filter);
+
+	return 0;
+}
+
+/**
+ * Free @program->filter and set @program->len to 0.
+ */
+static void free_program_filter(struct sock_fprog *program)
+{
+	TALLOC_FREE(program->filter);
+	program->len = 0;
+}
+
+/**
+ * Convert the given @sysnums into BPF filters according to the
+ * following pseudo-code, then enabled them for the given @tracee and
+ * all of its future children:
+ *
+ *     for each handled architectures
+ *         for each filtered syscall
+ *             trace
+ *         allow
+ *     kill
+ *
+ * This function returns -errno if an error occurred, otherwise 0.
+ */
+static int set_seccomp_filters(const FilteredSysnum *sysnums)
+{
+	SeccompArch seccomp_archs[] = SECCOMP_ARCHS;
+	size_t nb_archs = sizeof(seccomp_archs) / sizeof(SeccompArch);
+
+	struct sock_fprog program = { .len = 0, .filter = NULL };
+	size_t nb_traced_syscalls;
+	size_t i, j, k;
+	int status;
+
+	status = new_program_filter(&program);
+	if (status < 0)
+		goto end;
+
+	/* For each handled architectures */
+	for (i = 0; i < nb_archs; i++) {
+		word_t syscall;
+
+		nb_traced_syscalls = 0;
+
+		/* Pre-compute the number of traced syscalls for this architecture.  */
+		for (j = 0; j < seccomp_archs[i].nb_abis; j++) {
+			for (k = 0; sysnums[k].value != PR_void; k++) {
+				syscall = detranslate_sysnum(seccomp_archs[i].abis[j], sysnums[k].value);
+				if (syscall != SYSCALL_AVOIDER)
+					nb_traced_syscalls++;
+			}
+		}
+
+		/* Filter: if handled architecture */
+		status = start_arch_section(&program, seccomp_archs[i].value, nb_traced_syscalls);
+		if (status < 0)
+			goto end;
+
+		for (j = 0; j < seccomp_archs[i].nb_abis; j++) {
+			for (k = 0; sysnums[k].value != PR_void; k++) {
+				/* Get the architecture specific syscall number.  */
+				syscall = detranslate_sysnum(seccomp_archs[i].abis[j], sysnums[k].value);
+				if (syscall == SYSCALL_AVOIDER)
+					continue;
+
+				/* Filter: trace if handled syscall */
+				status = add_trace_syscall(&program, syscall, sysnums[k].flags);
+				if (status < 0)
+					goto end;
+			}
+		}
+
+		/* Filter: allow untraced syscalls for this architecture */
+		status = end_arch_section(&program, nb_traced_syscalls);
+		if (status < 0)
+			goto end;
+	}
+
+	status = finalize_program_filter(&program);
+	if (status < 0)
+		goto end;
+
+	status = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+	if (status < 0)
+		goto end;
+
+	/* To output this BPF program for debug purpose:
+	 *
+	 *     write(2, program.filter, program.len * sizeof(struct sock_filter));
+	 */
+
+	status = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &program);
+	if (status < 0)
+		goto end;
+
+	status = 0;
+end:
+	free_program_filter(&program);
+	return status;
+}
+
+/* List of sysnums handled by PRoot.  */
+static FilteredSysnum proot_sysnums[] = {
+	{ PR_accept,		FILTER_SYSEXIT },
+	{ PR_accept4,		FILTER_SYSEXIT },
+	{ PR_access,		0 },
+	{ PR_acct,		0 },
+	{ PR_bind,		0 },
+	{ PR_brk,		FILTER_SYSEXIT },
+	{ PR_chdir,		FILTER_SYSEXIT },
+	{ PR_chmod,		0 },
+	{ PR_chown,		0 },
+	{ PR_chown32,		0 },
+	{ PR_chroot,		0 },
+	{ PR_connect,		0 },
+	{ PR_creat,		0 },
+	{ PR_execve,		FILTER_SYSEXIT },
+	{ PR_faccessat,		0 },
+	{ PR_fchdir,		FILTER_SYSEXIT },
+	{ PR_fchmodat,		0 },
+	{ PR_fchownat,		0 },
+	{ PR_fstatat64,		0 },
+	{ PR_futimesat,		0 },
+	{ PR_getcwd,		FILTER_SYSEXIT },
+	{ PR_getpeername,	FILTER_SYSEXIT },
+	{ PR_getsockname,	FILTER_SYSEXIT },
+	{ PR_getxattr,		0 },
+	{ PR_inotify_add_watch,	0 },
+	{ PR_lchown,		0 },
+	{ PR_lchown32,		0 },
+	{ PR_lgetxattr,		0 },
+	{ PR_link,		0 },
+	{ PR_linkat,		0 },
+	{ PR_listxattr,		0 },
+	{ PR_llistxattr,	0 },
+	{ PR_lremovexattr,	0 },
+	{ PR_lsetxattr,		0 },
+	{ PR_lstat,		0 },
+	{ PR_lstat64,		0 },
+	{ PR_mkdir,		0 },
+	{ PR_mkdirat,		0 },
+	{ PR_mknod,		0 },
+	{ PR_mknodat,		0 },
+	{ PR_mount,		0 },
+	{ PR_name_to_handle_at,	0 },
+	{ PR_newfstatat,	0 },
+	{ PR_oldlstat,		0 },
+	{ PR_oldstat,		0 },
+	{ PR_open,		0 },
+	{ PR_openat,		0 },
+	{ PR_pivot_root,	0 },
+	{ PR_ptrace,		FILTER_SYSEXIT },
+	{ PR_readlink,		FILTER_SYSEXIT },
+	{ PR_readlinkat,	FILTER_SYSEXIT },
+	{ PR_removexattr,	0 },
+	{ PR_rename,		FILTER_SYSEXIT },
+	{ PR_renameat,		FILTER_SYSEXIT },
+	{ PR_rmdir,		0 },
+	{ PR_setxattr,		0 },
+	{ PR_socketcall,	FILTER_SYSEXIT },
+	{ PR_stat,		0 },
+	{ PR_stat64,		0 },
+	{ PR_statfs,		0 },
+	{ PR_statfs64,		0 },
+	{ PR_swapoff,		0 },
+	{ PR_swapon,		0 },
+	{ PR_symlink,		0 },
+	{ PR_symlinkat,		0 },
+	{ PR_truncate,		0 },
+	{ PR_truncate64,	0 },
+	{ PR_umount,		0 },
+	{ PR_umount2,		0 },
+	{ PR_uname,		FILTER_SYSEXIT },
+	{ PR_unlink,		0 },
+	{ PR_unlinkat,		0 },
+	{ PR_uselib,		0 },
+	{ PR_utime,		0 },
+	{ PR_utimensat,		0 },
+	{ PR_utimes,		0 },
+	{ PR_wait4,		FILTER_SYSEXIT },
+	{ PR_waitpid,		FILTER_SYSEXIT },
+	FILTERED_SYSNUM_END,
+};
+
+/**
+ * Add the @new_sysnums to the list of filtered @sysnums, using the
+ * given Talloc @context.  This function returns -errno if an error
+ * occurred, otherwise 0.
+ */
+static int merge_filtered_sysnums(TALLOC_CTX *context, FilteredSysnum **sysnums,
+				const FilteredSysnum *new_sysnums)
+{
+	size_t i, j;
+
+	assert(sysnums != NULL);
+
+	if (*sysnums == NULL) {
+		/* Start with no sysnums but the terminator.  */
+		*sysnums = talloc_array(context, FilteredSysnum, 1);
+		if (*sysnums == NULL)
+			return -ENOMEM;
+
+		(*sysnums)[0].value = PR_void;
+	}
+
+	for (i = 0; new_sysnums[i].value != PR_void; i++) {
+		/* Search for the given sysnum.  */
+		for (j = 0; (*sysnums)[j].value != PR_void
+			 && (*sysnums)[j].value != new_sysnums[i].value; j++)
+			;
+
+		if ((*sysnums)[j].value == PR_void) {
+			/* No such sysnum, allocate a new entry.  */
+			(*sysnums) = talloc_realloc(context, (*sysnums), FilteredSysnum, j + 2);
+			if ((*sysnums) == NULL)
+				return -ENOMEM;
+
+			(*sysnums)[j] = new_sysnums[i];
+
+			/* The last item is the terminator.  */
+			(*sysnums)[j + 1].value = PR_void;
+		}
+		else
+			/* The sysnum is already filtered, merge the
+			 * flags.  */
+			(*sysnums)[j].flags |= new_sysnums[i].flags;
+	}
+
+	return 0;
+}
+
+/**
+ * Tell the kernel to trace only syscalls handled by PRoot and its
+ * extensions.  This filter will be enabled for the given @tracee and
+ * all of its future children.  This function returns -errno if an
+ * error occurred, otherwise 0.
+ */
+int enable_syscall_filtering(const Tracee *tracee)
+{
+	FilteredSysnum *filtered_sysnums = NULL;
+	Extension *extension;
+	int status;
+
+	assert(tracee != NULL && tracee->ctx != NULL);
+
+	/* Add the sysnums required by PRoot to the list of filtered
+	 * sysnums.  TODO: only if path translation is required.  */
+	status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums, proot_sysnums);
+	if (status < 0)
+		return status;
+
+	/* Merge the sysnums required by the extensions to the list
+	 * of filtered sysnums.  */
+	if (tracee->extensions != NULL) {
+		LIST_FOREACH(extension, tracee->extensions, link) {
+			if (extension->filtered_sysnums == NULL)
+				continue;
+
+			status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums,
+							extension->filtered_sysnums);
+			if (status < 0)
+				return status;
+		}
+	}
+
+	status = set_seccomp_filters(filtered_sysnums);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+#else
+
+#include "tracee/tracee.h"
+#include "attribute.h"
+
+int enable_syscall_filtering(const Tracee *tracee UNUSED)
+{
+	return 0;
+}
+
+#endif /* defined(HAVE_SECCOMP_FILTER) */
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-arm.h b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-arm.h
new file mode 100644
index 0000000..d779327
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-arm.h
@@ -0,0 +1,338 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_arm[] = {
+	[ 0 ] = PR_restart_syscall,
+	[ 1 ] = PR_exit,
+	[ 2 ] = PR_fork,
+	[ 3 ] = PR_read,
+	[ 4 ] = PR_write,
+	[ 5 ] = PR_open,
+	[ 6 ] = PR_close,
+	[ 8 ] = PR_creat,
+	[ 9 ] = PR_link,
+	[ 10 ] = PR_unlink,
+	[ 11 ] = PR_execve,
+	[ 12 ] = PR_chdir,
+	[ 14 ] = PR_mknod,
+	[ 15 ] = PR_chmod,
+	[ 16 ] = PR_lchown,
+	[ 19 ] = PR_lseek,
+	[ 20 ] = PR_getpid,
+	[ 21 ] = PR_mount,
+	[ 23 ] = PR_setuid,
+	[ 24 ] = PR_getuid,
+	[ 26 ] = PR_ptrace,
+	[ 29 ] = PR_pause,
+	[ 33 ] = PR_access,
+	[ 34 ] = PR_nice,
+	[ 36 ] = PR_sync,
+	[ 37 ] = PR_kill,
+	[ 38 ] = PR_rename,
+	[ 39 ] = PR_mkdir,
+	[ 40 ] = PR_rmdir,
+	[ 41 ] = PR_dup,
+	[ 42 ] = PR_pipe,
+	[ 43 ] = PR_times,
+	[ 45 ] = PR_brk,
+	[ 46 ] = PR_setgid,
+	[ 47 ] = PR_getgid,
+	[ 49 ] = PR_geteuid,
+	[ 50 ] = PR_getegid,
+	[ 51 ] = PR_acct,
+	[ 52 ] = PR_umount2,
+	[ 54 ] = PR_ioctl,
+	[ 55 ] = PR_fcntl,
+	[ 57 ] = PR_setpgid,
+	[ 60 ] = PR_umask,
+	[ 61 ] = PR_chroot,
+	[ 62 ] = PR_ustat,
+	[ 63 ] = PR_dup2,
+	[ 64 ] = PR_getppid,
+	[ 65 ] = PR_getpgrp,
+	[ 66 ] = PR_setsid,
+	[ 67 ] = PR_sigaction,
+	[ 70 ] = PR_setreuid,
+	[ 71 ] = PR_setregid,
+	[ 72 ] = PR_sigsuspend,
+	[ 73 ] = PR_sigpending,
+	[ 74 ] = PR_sethostname,
+	[ 75 ] = PR_setrlimit,
+	[ 77 ] = PR_getrusage,
+	[ 78 ] = PR_gettimeofday,
+	[ 79 ] = PR_settimeofday,
+	[ 80 ] = PR_getgroups,
+	[ 81 ] = PR_setgroups,
+	[ 83 ] = PR_symlink,
+	[ 85 ] = PR_readlink,
+	[ 86 ] = PR_uselib,
+	[ 87 ] = PR_swapon,
+	[ 88 ] = PR_reboot,
+	[ 91 ] = PR_munmap,
+	[ 92 ] = PR_truncate,
+	[ 93 ] = PR_ftruncate,
+	[ 94 ] = PR_fchmod,
+	[ 95 ] = PR_fchown,
+	[ 96 ] = PR_getpriority,
+	[ 97 ] = PR_setpriority,
+	[ 99 ] = PR_statfs,
+	[ 100 ] = PR_fstatfs,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_setitimer,
+	[ 105 ] = PR_getitimer,
+	[ 106 ] = PR_stat,
+	[ 107 ] = PR_lstat,
+	[ 108 ] = PR_fstat,
+	[ 111 ] = PR_vhangup,
+	[ 114 ] = PR_wait4,
+	[ 115 ] = PR_swapoff,
+	[ 116 ] = PR_sysinfo,
+	[ 118 ] = PR_fsync,
+	[ 119 ] = PR_sigreturn,
+	[ 120 ] = PR_clone,
+	[ 121 ] = PR_setdomainname,
+	[ 122 ] = PR_uname,
+	[ 124 ] = PR_adjtimex,
+	[ 125 ] = PR_mprotect,
+	[ 126 ] = PR_sigprocmask,
+	[ 128 ] = PR_init_module,
+	[ 129 ] = PR_delete_module,
+	[ 131 ] = PR_quotactl,
+	[ 132 ] = PR_getpgid,
+	[ 133 ] = PR_fchdir,
+	[ 134 ] = PR_bdflush,
+	[ 135 ] = PR_sysfs,
+	[ 136 ] = PR_personality,
+	[ 138 ] = PR_setfsuid,
+	[ 139 ] = PR_setfsgid,
+	[ 140 ] = PR__llseek,
+	[ 141 ] = PR_getdents,
+	[ 142 ] = PR__newselect,
+	[ 143 ] = PR_flock,
+	[ 144 ] = PR_msync,
+	[ 145 ] = PR_readv,
+	[ 146 ] = PR_writev,
+	[ 147 ] = PR_getsid,
+	[ 148 ] = PR_fdatasync,
+	[ 149 ] = PR__sysctl,
+	[ 150 ] = PR_mlock,
+	[ 151 ] = PR_munlock,
+	[ 152 ] = PR_mlockall,
+	[ 153 ] = PR_munlockall,
+	[ 154 ] = PR_sched_setparam,
+	[ 155 ] = PR_sched_getparam,
+	[ 156 ] = PR_sched_setscheduler,
+	[ 157 ] = PR_sched_getscheduler,
+	[ 158 ] = PR_sched_yield,
+	[ 159 ] = PR_sched_get_priority_max,
+	[ 160 ] = PR_sched_get_priority_min,
+	[ 161 ] = PR_sched_rr_get_interval,
+	[ 162 ] = PR_nanosleep,
+	[ 163 ] = PR_mremap,
+	[ 164 ] = PR_setresuid,
+	[ 165 ] = PR_getresuid,
+	[ 168 ] = PR_poll,
+	[ 169 ] = PR_nfsservctl,
+	[ 170 ] = PR_setresgid,
+	[ 171 ] = PR_getresgid,
+	[ 172 ] = PR_prctl,
+	[ 173 ] = PR_rt_sigreturn,
+	[ 174 ] = PR_rt_sigaction,
+	[ 175 ] = PR_rt_sigprocmask,
+	[ 176 ] = PR_rt_sigpending,
+	[ 177 ] = PR_rt_sigtimedwait,
+	[ 178 ] = PR_rt_sigqueueinfo,
+	[ 179 ] = PR_rt_sigsuspend,
+	[ 180 ] = PR_pread64,
+	[ 181 ] = PR_pwrite64,
+	[ 182 ] = PR_chown,
+	[ 183 ] = PR_getcwd,
+	[ 184 ] = PR_capget,
+	[ 185 ] = PR_capset,
+	[ 186 ] = PR_sigaltstack,
+	[ 187 ] = PR_sendfile,
+	[ 190 ] = PR_vfork,
+	[ 191 ] = PR_ugetrlimit,
+	[ 192 ] = PR_mmap2,
+	[ 193 ] = PR_truncate64,
+	[ 194 ] = PR_ftruncate64,
+	[ 195 ] = PR_stat64,
+	[ 196 ] = PR_lstat64,
+	[ 197 ] = PR_fstat64,
+	[ 198 ] = PR_lchown32,
+	[ 199 ] = PR_getuid32,
+	[ 200 ] = PR_getgid32,
+	[ 201 ] = PR_geteuid32,
+	[ 202 ] = PR_getegid32,
+	[ 203 ] = PR_setreuid32,
+	[ 204 ] = PR_setregid32,
+	[ 205 ] = PR_getgroups32,
+	[ 206 ] = PR_setgroups32,
+	[ 207 ] = PR_fchown32,
+	[ 208 ] = PR_setresuid32,
+	[ 209 ] = PR_getresuid32,
+	[ 210 ] = PR_setresgid32,
+	[ 211 ] = PR_getresgid32,
+	[ 212 ] = PR_chown32,
+	[ 213 ] = PR_setuid32,
+	[ 214 ] = PR_setgid32,
+	[ 215 ] = PR_setfsuid32,
+	[ 216 ] = PR_setfsgid32,
+	[ 217 ] = PR_getdents64,
+	[ 218 ] = PR_pivot_root,
+	[ 219 ] = PR_mincore,
+	[ 220 ] = PR_madvise,
+	[ 221 ] = PR_fcntl64,
+	[ 222 ] = PR_void,
+	[ 224 ] = PR_gettid,
+	[ 225 ] = PR_readahead,
+	[ 226 ] = PR_setxattr,
+	[ 227 ] = PR_lsetxattr,
+	[ 228 ] = PR_fsetxattr,
+	[ 229 ] = PR_getxattr,
+	[ 230 ] = PR_lgetxattr,
+	[ 231 ] = PR_fgetxattr,
+	[ 232 ] = PR_listxattr,
+	[ 233 ] = PR_llistxattr,
+	[ 234 ] = PR_flistxattr,
+	[ 235 ] = PR_removexattr,
+	[ 236 ] = PR_lremovexattr,
+	[ 237 ] = PR_fremovexattr,
+	[ 238 ] = PR_tkill,
+	[ 239 ] = PR_sendfile64,
+	[ 240 ] = PR_futex,
+	[ 241 ] = PR_sched_setaffinity,
+	[ 242 ] = PR_sched_getaffinity,
+	[ 243 ] = PR_io_setup,
+	[ 244 ] = PR_io_destroy,
+	[ 245 ] = PR_io_getevents,
+	[ 246 ] = PR_io_submit,
+	[ 247 ] = PR_io_cancel,
+	[ 248 ] = PR_exit_group,
+	[ 249 ] = PR_lookup_dcookie,
+	[ 250 ] = PR_epoll_create,
+	[ 251 ] = PR_epoll_ctl,
+	[ 252 ] = PR_epoll_wait,
+	[ 253 ] = PR_remap_file_pages,
+	[ 256 ] = PR_set_tid_address,
+	[ 257 ] = PR_timer_create,
+	[ 258 ] = PR_timer_settime,
+	[ 259 ] = PR_timer_gettime,
+	[ 260 ] = PR_timer_getoverrun,
+	[ 261 ] = PR_timer_delete,
+	[ 262 ] = PR_clock_settime,
+	[ 263 ] = PR_clock_gettime,
+	[ 264 ] = PR_clock_getres,
+	[ 265 ] = PR_clock_nanosleep,
+	[ 266 ] = PR_statfs64,
+	[ 267 ] = PR_fstatfs64,
+	[ 268 ] = PR_tgkill,
+	[ 269 ] = PR_utimes,
+	[ 270 ] = PR_arm_fadvise64_64,
+	[ 271 ] = PR_pciconfig_iobase,
+	[ 272 ] = PR_pciconfig_read,
+	[ 273 ] = PR_pciconfig_write,
+	[ 274 ] = PR_mq_open,
+	[ 275 ] = PR_mq_unlink,
+	[ 276 ] = PR_mq_timedsend,
+	[ 277 ] = PR_mq_timedreceive,
+	[ 278 ] = PR_mq_notify,
+	[ 279 ] = PR_mq_getsetattr,
+	[ 280 ] = PR_waitid,
+	[ 281 ] = PR_socket,
+	[ 282 ] = PR_bind,
+	[ 283 ] = PR_connect,
+	[ 284 ] = PR_listen,
+	[ 285 ] = PR_accept,
+	[ 286 ] = PR_getsockname,
+	[ 287 ] = PR_getpeername,
+	[ 288 ] = PR_socketpair,
+	[ 289 ] = PR_send,
+	[ 290 ] = PR_sendto,
+	[ 291 ] = PR_recv,
+	[ 292 ] = PR_recvfrom,
+	[ 293 ] = PR_shutdown,
+	[ 294 ] = PR_setsockopt,
+	[ 295 ] = PR_getsockopt,
+	[ 296 ] = PR_sendmsg,
+	[ 297 ] = PR_recvmsg,
+	[ 298 ] = PR_semop,
+	[ 299 ] = PR_semget,
+	[ 300 ] = PR_semctl,
+	[ 301 ] = PR_msgsnd,
+	[ 302 ] = PR_msgrcv,
+	[ 303 ] = PR_msgget,
+	[ 304 ] = PR_msgctl,
+	[ 305 ] = PR_shmat,
+	[ 306 ] = PR_shmdt,
+	[ 307 ] = PR_shmget,
+	[ 308 ] = PR_shmctl,
+	[ 309 ] = PR_add_key,
+	[ 310 ] = PR_request_key,
+	[ 311 ] = PR_keyctl,
+	[ 312 ] = PR_semtimedop,
+	[ 313 ] = PR_vserver,
+	[ 314 ] = PR_ioprio_set,
+	[ 315 ] = PR_ioprio_get,
+	[ 316 ] = PR_inotify_init,
+	[ 317 ] = PR_inotify_add_watch,
+	[ 318 ] = PR_inotify_rm_watch,
+	[ 319 ] = PR_mbind,
+	[ 320 ] = PR_get_mempolicy,
+	[ 321 ] = PR_set_mempolicy,
+	[ 322 ] = PR_openat,
+	[ 323 ] = PR_mkdirat,
+	[ 324 ] = PR_mknodat,
+	[ 325 ] = PR_fchownat,
+	[ 326 ] = PR_futimesat,
+	[ 327 ] = PR_fstatat64,
+	[ 328 ] = PR_unlinkat,
+	[ 329 ] = PR_renameat,
+	[ 330 ] = PR_linkat,
+	[ 331 ] = PR_symlinkat,
+	[ 332 ] = PR_readlinkat,
+	[ 333 ] = PR_fchmodat,
+	[ 334 ] = PR_faccessat,
+	[ 335 ] = PR_pselect6,
+	[ 336 ] = PR_ppoll,
+	[ 337 ] = PR_unshare,
+	[ 338 ] = PR_set_robust_list,
+	[ 339 ] = PR_get_robust_list,
+	[ 340 ] = PR_splice,
+	[ 341 ] = PR_arm_sync_file_range,
+	[ 342 ] = PR_tee,
+	[ 343 ] = PR_vmsplice,
+	[ 344 ] = PR_move_pages,
+	[ 345 ] = PR_getcpu,
+	[ 346 ] = PR_epoll_pwait,
+	[ 347 ] = PR_kexec_load,
+	[ 348 ] = PR_utimensat,
+	[ 349 ] = PR_signalfd,
+	[ 350 ] = PR_timerfd_create,
+	[ 351 ] = PR_eventfd,
+	[ 352 ] = PR_fallocate,
+	[ 353 ] = PR_timerfd_settime,
+	[ 354 ] = PR_timerfd_gettime,
+	[ 355 ] = PR_signalfd4,
+	[ 356 ] = PR_eventfd2,
+	[ 357 ] = PR_epoll_create1,
+	[ 358 ] = PR_dup3,
+	[ 359 ] = PR_pipe2,
+	[ 360 ] = PR_inotify_init1,
+	[ 361 ] = PR_preadv,
+	[ 362 ] = PR_pwritev,
+	[ 363 ] = PR_rt_tgsigqueueinfo,
+	[ 364 ] = PR_perf_event_open,
+	[ 365 ] = PR_recvmmsg,
+	[ 366 ] = PR_accept4,
+	[ 367 ] = PR_fanotify_init,
+	[ 368 ] = PR_fanotify_mark,
+	[ 369 ] = PR_prlimit64,
+	[ 370 ] = PR_name_to_handle_at,
+	[ 371 ] = PR_open_by_handle_at,
+	[ 372 ] = PR_clock_adjtime,
+	[ 373 ] = PR_syncfs,
+	[ 374 ] = PR_sendmmsg,
+	[ 375 ] = PR_setns,
+	[ 376 ] = PR_process_vm_readv,
+	[ 377 ] = PR_process_vm_writev,
+};
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-arm64.h b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-arm64.h
new file mode 100644
index 0000000..9476c53
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-arm64.h
@@ -0,0 +1,263 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_arm64[] = {
+	[ 0 ] = PR_io_setup,
+	[ 1 ] = PR_io_destroy,
+	[ 2 ] = PR_io_submit,
+	[ 3 ] = PR_io_cancel,
+	[ 4 ] = PR_io_getevents,
+	[ 5 ] = PR_setxattr,
+	[ 6 ] = PR_lsetxattr,
+	[ 7 ] = PR_fsetxattr,
+	[ 8 ] = PR_getxattr,
+	[ 9 ] = PR_lgetxattr,
+	[ 10 ] = PR_fgetxattr,
+	[ 11 ] = PR_listxattr,
+	[ 12 ] = PR_llistxattr,
+	[ 13 ] = PR_flistxattr,
+	[ 14 ] = PR_removexattr,
+	[ 15 ] = PR_lremovexattr,
+	[ 16 ] = PR_fremovexattr,
+	[ 17 ] = PR_getcwd,
+	[ 18 ] = PR_lookup_dcookie,
+	[ 19 ] = PR_eventfd2,
+	[ 20 ] = PR_epoll_create1,
+	[ 21 ] = PR_epoll_ctl,
+	[ 22 ] = PR_epoll_pwait,
+	[ 23 ] = PR_dup,
+	[ 24 ] = PR_dup3,
+	[ 25 ] = PR_fcntl,
+	[ 26 ] = PR_inotify_init1,
+	[ 27 ] = PR_inotify_add_watch,
+	[ 28 ] = PR_inotify_rm_watch,
+	[ 29 ] = PR_ioctl,
+	[ 30 ] = PR_ioprio_set,
+	[ 31 ] = PR_ioprio_get,
+	[ 32 ] = PR_flock,
+	[ 33 ] = PR_mknodat,
+	[ 34 ] = PR_mkdirat,
+	[ 35 ] = PR_unlinkat,
+	[ 36 ] = PR_symlinkat,
+	[ 37 ] = PR_linkat,
+	[ 38 ] = PR_renameat,
+	[ 39 ] = PR_umount2,
+	[ 40 ] = PR_mount,
+	[ 41 ] = PR_pivot_root,
+	[ 42 ] = PR_nfsservctl,
+	[ 43 ] = PR_statfs,
+	[ 44 ] = PR_fstatfs,
+	[ 45 ] = PR_truncate,
+	[ 46 ] = PR_ftruncate,
+	[ 47 ] = PR_fallocate,
+	[ 48 ] = PR_faccessat,
+	[ 49 ] = PR_chdir,
+	[ 50 ] = PR_fchdir,
+	[ 51 ] = PR_chroot,
+	[ 52 ] = PR_fchmod,
+	[ 53 ] = PR_fchmodat,
+	[ 54 ] = PR_fchownat,
+	[ 55 ] = PR_fchown,
+	[ 56 ] = PR_openat,
+	[ 57 ] = PR_close,
+	[ 58 ] = PR_vhangup,
+	[ 59 ] = PR_pipe2,
+	[ 60 ] = PR_quotactl,
+	[ 61 ] = PR_getdents64,
+	[ 62 ] = PR_lseek,
+	[ 63 ] = PR_read,
+	[ 64 ] = PR_write,
+	[ 65 ] = PR_readv,
+	[ 66 ] = PR_writev,
+	[ 67 ] = PR_pread64,
+	[ 68 ] = PR_pwrite64,
+	[ 69 ] = PR_preadv,
+	[ 70 ] = PR_pwritev,
+	[ 71 ] = PR_sendfile,
+	[ 72 ] = PR_pselect6,
+	[ 73 ] = PR_ppoll,
+	[ 74 ] = PR_signalfd4,
+	[ 75 ] = PR_vmsplice,
+	[ 76 ] = PR_splice,
+	[ 77 ] = PR_tee,
+	[ 78 ] = PR_readlinkat,
+	[ 79 ] = PR_fstatat64,
+	[ 80 ] = PR_fstat,
+	[ 81 ] = PR_sync,
+	[ 82 ] = PR_fsync,
+	[ 83 ] = PR_fdatasync,
+	[ 84 ] = PR_sync_file_range,
+	[ 85 ] = PR_timerfd_create,
+	[ 86 ] = PR_timerfd_settime,
+	[ 87 ] = PR_timerfd_gettime,
+	[ 88 ] = PR_utimensat,
+	[ 89 ] = PR_acct,
+	[ 90 ] = PR_capget,
+	[ 91 ] = PR_capset,
+	[ 92 ] = PR_personality,
+	[ 93 ] = PR_exit,
+	[ 94 ] = PR_exit_group,
+	[ 95 ] = PR_waitid,
+	[ 96 ] = PR_set_tid_address,
+	[ 97 ] = PR_unshare,
+	[ 98 ] = PR_futex,
+	[ 99 ] = PR_set_robust_list,
+	[ 100 ] = PR_get_robust_list,
+	[ 101 ] = PR_nanosleep,
+	[ 102 ] = PR_getitimer,
+	[ 103 ] = PR_setitimer,
+	[ 104 ] = PR_kexec_load,
+	[ 105 ] = PR_init_module,
+	[ 106 ] = PR_delete_module,
+	[ 107 ] = PR_timer_create,
+	[ 108 ] = PR_timer_gettime,
+	[ 109 ] = PR_timer_getoverrun,
+	[ 110 ] = PR_timer_settime,
+	[ 111 ] = PR_timer_delete,
+	[ 112 ] = PR_clock_settime,
+	[ 113 ] = PR_clock_gettime,
+	[ 114 ] = PR_clock_getres,
+	[ 115 ] = PR_clock_nanosleep,
+	[ 116 ] = PR_syslog,
+	[ 117 ] = PR_ptrace,
+	[ 118 ] = PR_sched_setparam,
+	[ 119 ] = PR_sched_setscheduler,
+	[ 120 ] = PR_sched_getscheduler,
+	[ 121 ] = PR_sched_getparam,
+	[ 122 ] = PR_sched_setaffinity,
+	[ 123 ] = PR_sched_getaffinity,
+	[ 124 ] = PR_sched_yield,
+	[ 125 ] = PR_sched_get_priority_max,
+	[ 126 ] = PR_sched_get_priority_min,
+	[ 127 ] = PR_sched_rr_get_interval,
+	[ 128 ] = PR_restart_syscall,
+	[ 129 ] = PR_kill,
+	[ 130 ] = PR_tkill,
+	[ 131 ] = PR_tgkill,
+	[ 132 ] = PR_sigaltstack,
+	[ 133 ] = PR_rt_sigsuspend,
+	[ 134 ] = PR_rt_sigaction,
+	[ 135 ] = PR_rt_sigprocmask,
+	[ 136 ] = PR_rt_sigpending,
+	[ 137 ] = PR_rt_sigtimedwait,
+	[ 138 ] = PR_rt_sigqueueinfo,
+	[ 139 ] = PR_rt_sigreturn,
+	[ 140 ] = PR_setpriority,
+	[ 141 ] = PR_getpriority,
+	[ 142 ] = PR_reboot,
+	[ 143 ] = PR_setregid,
+	[ 144 ] = PR_setgid,
+	[ 145 ] = PR_setreuid,
+	[ 146 ] = PR_setuid,
+	[ 147 ] = PR_setresuid,
+	[ 148 ] = PR_getresuid,
+	[ 149 ] = PR_setresgid,
+	[ 150 ] = PR_getresgid,
+	[ 151 ] = PR_setfsuid,
+	[ 152 ] = PR_setfsgid,
+	[ 153 ] = PR_times,
+	[ 154 ] = PR_setpgid,
+	[ 155 ] = PR_getpgid,
+	[ 156 ] = PR_getsid,
+	[ 157 ] = PR_setsid,
+	[ 158 ] = PR_getgroups,
+	[ 159 ] = PR_setgroups,
+	[ 160 ] = PR_uname,
+	[ 161 ] = PR_sethostname,
+	[ 162 ] = PR_setdomainname,
+	[ 163 ] = PR_getrlimit,
+	[ 164 ] = PR_setrlimit,
+	[ 165 ] = PR_getrusage,
+	[ 166 ] = PR_umask,
+	[ 167 ] = PR_prctl,
+	[ 168 ] = PR_getcpu,
+	[ 169 ] = PR_gettimeofday,
+	[ 170 ] = PR_settimeofday,
+	[ 171 ] = PR_adjtimex,
+	[ 172 ] = PR_getpid,
+	[ 173 ] = PR_getppid,
+	[ 174 ] = PR_getuid,
+	[ 175 ] = PR_geteuid,
+	[ 176 ] = PR_getgid,
+	[ 177 ] = PR_getegid,
+	[ 178 ] = PR_gettid,
+	[ 179 ] = PR_sysinfo,
+	[ 180 ] = PR_mq_open,
+	[ 181 ] = PR_mq_unlink,
+	[ 182 ] = PR_mq_timedsend,
+	[ 183 ] = PR_mq_timedreceive,
+	[ 184 ] = PR_mq_notify,
+	[ 185 ] = PR_mq_getsetattr,
+	[ 186 ] = PR_msgget,
+	[ 187 ] = PR_msgctl,
+	[ 188 ] = PR_msgrcv,
+	[ 189 ] = PR_msgsnd,
+	[ 190 ] = PR_semget,
+	[ 191 ] = PR_semctl,
+	[ 192 ] = PR_semtimedop,
+	[ 193 ] = PR_semop,
+	[ 194 ] = PR_shmget,
+	[ 195 ] = PR_shmctl,
+	[ 196 ] = PR_shmat,
+	[ 197 ] = PR_shmdt,
+	[ 198 ] = PR_socket,
+	[ 199 ] = PR_socketpair,
+	[ 200 ] = PR_bind,
+	[ 201 ] = PR_listen,
+	[ 202 ] = PR_accept,
+	[ 203 ] = PR_connect,
+	[ 204 ] = PR_getsockname,
+	[ 205 ] = PR_getpeername,
+	[ 206 ] = PR_sendto,
+	[ 207 ] = PR_recvfrom,
+	[ 208 ] = PR_setsockopt,
+	[ 209 ] = PR_getsockopt,
+	[ 210 ] = PR_shutdown,
+	[ 211 ] = PR_sendmsg,
+	[ 212 ] = PR_recvmsg,
+	[ 213 ] = PR_readahead,
+	[ 214 ] = PR_brk,
+	[ 215 ] = PR_munmap,
+	[ 216 ] = PR_mremap,
+	[ 217 ] = PR_add_key,
+	[ 218 ] = PR_request_key,
+	[ 219 ] = PR_keyctl,
+	[ 220 ] = PR_clone,
+	[ 221 ] = PR_execve,
+	[ 222 ] = PR_mmap,
+	[ 223 ] = PR_fadvise64,
+	[ 224 ] = PR_swapon,
+	[ 225 ] = PR_swapoff,
+	[ 226 ] = PR_mprotect,
+	[ 227 ] = PR_msync,
+	[ 228 ] = PR_mlock,
+	[ 229 ] = PR_munlock,
+	[ 230 ] = PR_mlockall,
+	[ 231 ] = PR_munlockall,
+	[ 232 ] = PR_mincore,
+	[ 233 ] = PR_madvise,
+	[ 234 ] = PR_remap_file_pages,
+	[ 235 ] = PR_mbind,
+	[ 236 ] = PR_get_mempolicy,
+	[ 237 ] = PR_set_mempolicy,
+	[ 238 ] = PR_migrate_pages,
+	[ 239 ] = PR_move_pages,
+	[ 240 ] = PR_rt_tgsigqueueinfo,
+	[ 241 ] = PR_perf_event_open,
+	[ 242 ] = PR_accept4,
+	[ 243 ] = PR_recvmmsg,
+	[ 244 ] = PR_arch_specific_syscall,
+	[ 260 ] = PR_wait4,
+	[ 261 ] = PR_prlimit64,
+	[ 262 ] = PR_fanotify_init,
+	[ 263 ] = PR_fanotify_mark,
+	[ 264 ] = PR_name_to_handle_at,
+	[ 265 ] = PR_open_by_handle_at,
+	[ 266 ] = PR_clock_adjtime,
+	[ 267 ] = PR_syncfs,
+	[ 268 ] = PR_setns,
+	[ 269 ] = PR_sendmmsg,
+	[ 270 ] = PR_process_vm_readv,
+	[ 271 ] = PR_process_vm_writev,
+	[ 272 ] = PR_kcmp,
+	[ 273 ] = PR_syscalls,
+};
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-i386.h b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-i386.h
new file mode 100644
index 0000000..9f2d88b
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-i386.h
@@ -0,0 +1,350 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_i386[] = {
+	[ 0 ] = PR_restart_syscall,
+	[ 1 ] = PR_exit,
+	[ 2 ] = PR_fork,
+	[ 3 ] = PR_read,
+	[ 4 ] = PR_write,
+	[ 5 ] = PR_open,
+	[ 6 ] = PR_close,
+	[ 7 ] = PR_waitpid,
+	[ 8 ] = PR_creat,
+	[ 9 ] = PR_link,
+	[ 10 ] = PR_unlink,
+	[ 11 ] = PR_execve,
+	[ 12 ] = PR_chdir,
+	[ 13 ] = PR_time,
+	[ 14 ] = PR_mknod,
+	[ 15 ] = PR_chmod,
+	[ 16 ] = PR_lchown,
+	[ 17 ] = PR_break,
+	[ 18 ] = PR_oldstat,
+	[ 19 ] = PR_lseek,
+	[ 20 ] = PR_getpid,
+	[ 21 ] = PR_mount,
+	[ 22 ] = PR_umount,
+	[ 23 ] = PR_setuid,
+	[ 24 ] = PR_getuid,
+	[ 25 ] = PR_stime,
+	[ 26 ] = PR_ptrace,
+	[ 27 ] = PR_alarm,
+	[ 28 ] = PR_oldfstat,
+	[ 29 ] = PR_pause,
+	[ 30 ] = PR_utime,
+	[ 31 ] = PR_stty,
+	[ 32 ] = PR_gtty,
+	[ 33 ] = PR_access,
+	[ 34 ] = PR_nice,
+	[ 35 ] = PR_ftime,
+	[ 36 ] = PR_sync,
+	[ 37 ] = PR_kill,
+	[ 38 ] = PR_rename,
+	[ 39 ] = PR_mkdir,
+	[ 40 ] = PR_rmdir,
+	[ 41 ] = PR_dup,
+	[ 42 ] = PR_pipe,
+	[ 43 ] = PR_times,
+	[ 44 ] = PR_prof,
+	[ 45 ] = PR_brk,
+	[ 46 ] = PR_setgid,
+	[ 47 ] = PR_getgid,
+	[ 48 ] = PR_signal,
+	[ 49 ] = PR_geteuid,
+	[ 50 ] = PR_getegid,
+	[ 51 ] = PR_acct,
+	[ 52 ] = PR_umount2,
+	[ 53 ] = PR_lock,
+	[ 54 ] = PR_ioctl,
+	[ 55 ] = PR_fcntl,
+	[ 56 ] = PR_mpx,
+	[ 57 ] = PR_setpgid,
+	[ 58 ] = PR_ulimit,
+	[ 59 ] = PR_oldolduname,
+	[ 60 ] = PR_umask,
+	[ 61 ] = PR_chroot,
+	[ 62 ] = PR_ustat,
+	[ 63 ] = PR_dup2,
+	[ 64 ] = PR_getppid,
+	[ 65 ] = PR_getpgrp,
+	[ 66 ] = PR_setsid,
+	[ 67 ] = PR_sigaction,
+	[ 68 ] = PR_sgetmask,
+	[ 69 ] = PR_ssetmask,
+	[ 70 ] = PR_setreuid,
+	[ 71 ] = PR_setregid,
+	[ 72 ] = PR_sigsuspend,
+	[ 73 ] = PR_sigpending,
+	[ 74 ] = PR_sethostname,
+	[ 75 ] = PR_setrlimit,
+	[ 76 ] = PR_getrlimit,
+	[ 77 ] = PR_getrusage,
+	[ 78 ] = PR_gettimeofday,
+	[ 79 ] = PR_settimeofday,
+	[ 80 ] = PR_getgroups,
+	[ 81 ] = PR_setgroups,
+	[ 82 ] = PR_select,
+	[ 83 ] = PR_symlink,
+	[ 84 ] = PR_oldlstat,
+	[ 85 ] = PR_readlink,
+	[ 86 ] = PR_uselib,
+	[ 87 ] = PR_swapon,
+	[ 88 ] = PR_reboot,
+	[ 89 ] = PR_readdir,
+	[ 90 ] = PR_mmap,
+	[ 91 ] = PR_munmap,
+	[ 92 ] = PR_truncate,
+	[ 93 ] = PR_ftruncate,
+	[ 94 ] = PR_fchmod,
+	[ 95 ] = PR_fchown,
+	[ 96 ] = PR_getpriority,
+	[ 97 ] = PR_setpriority,
+	[ 98 ] = PR_profil,
+	[ 99 ] = PR_statfs,
+	[ 100 ] = PR_fstatfs,
+	[ 101 ] = PR_ioperm,
+	[ 102 ] = PR_socketcall,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_setitimer,
+	[ 105 ] = PR_getitimer,
+	[ 106 ] = PR_stat,
+	[ 107 ] = PR_lstat,
+	[ 108 ] = PR_fstat,
+	[ 109 ] = PR_olduname,
+	[ 110 ] = PR_iopl,
+	[ 111 ] = PR_vhangup,
+	[ 112 ] = PR_idle,
+	[ 113 ] = PR_vm86old,
+	[ 114 ] = PR_wait4,
+	[ 115 ] = PR_swapoff,
+	[ 116 ] = PR_sysinfo,
+	[ 117 ] = PR_ipc,
+	[ 118 ] = PR_fsync,
+	[ 119 ] = PR_sigreturn,
+	[ 120 ] = PR_clone,
+	[ 121 ] = PR_setdomainname,
+	[ 122 ] = PR_uname,
+	[ 123 ] = PR_modify_ldt,
+	[ 124 ] = PR_adjtimex,
+	[ 125 ] = PR_mprotect,
+	[ 126 ] = PR_sigprocmask,
+	[ 127 ] = PR_create_module,
+	[ 128 ] = PR_init_module,
+	[ 129 ] = PR_delete_module,
+	[ 130 ] = PR_get_kernel_syms,
+	[ 131 ] = PR_quotactl,
+	[ 132 ] = PR_getpgid,
+	[ 133 ] = PR_fchdir,
+	[ 134 ] = PR_bdflush,
+	[ 135 ] = PR_sysfs,
+	[ 136 ] = PR_personality,
+	[ 137 ] = PR_afs_syscall,
+	[ 138 ] = PR_setfsuid,
+	[ 139 ] = PR_setfsgid,
+	[ 140 ] = PR__llseek,
+	[ 141 ] = PR_getdents,
+	[ 142 ] = PR__newselect,
+	[ 143 ] = PR_flock,
+	[ 144 ] = PR_msync,
+	[ 145 ] = PR_readv,
+	[ 146 ] = PR_writev,
+	[ 147 ] = PR_getsid,
+	[ 148 ] = PR_fdatasync,
+	[ 149 ] = PR__sysctl,
+	[ 150 ] = PR_mlock,
+	[ 151 ] = PR_munlock,
+	[ 152 ] = PR_mlockall,
+	[ 153 ] = PR_munlockall,
+	[ 154 ] = PR_sched_setparam,
+	[ 155 ] = PR_sched_getparam,
+	[ 156 ] = PR_sched_setscheduler,
+	[ 157 ] = PR_sched_getscheduler,
+	[ 158 ] = PR_sched_yield,
+	[ 159 ] = PR_sched_get_priority_max,
+	[ 160 ] = PR_sched_get_priority_min,
+	[ 161 ] = PR_sched_rr_get_interval,
+	[ 162 ] = PR_nanosleep,
+	[ 163 ] = PR_mremap,
+	[ 164 ] = PR_setresuid,
+	[ 165 ] = PR_getresuid,
+	[ 166 ] = PR_vm86,
+	[ 167 ] = PR_query_module,
+	[ 168 ] = PR_poll,
+	[ 169 ] = PR_nfsservctl,
+	[ 170 ] = PR_setresgid,
+	[ 171 ] = PR_getresgid,
+	[ 172 ] = PR_prctl,
+	[ 173 ] = PR_rt_sigreturn,
+	[ 174 ] = PR_rt_sigaction,
+	[ 175 ] = PR_rt_sigprocmask,
+	[ 176 ] = PR_rt_sigpending,
+	[ 177 ] = PR_rt_sigtimedwait,
+	[ 178 ] = PR_rt_sigqueueinfo,
+	[ 179 ] = PR_rt_sigsuspend,
+	[ 180 ] = PR_pread64,
+	[ 181 ] = PR_pwrite64,
+	[ 182 ] = PR_chown,
+	[ 183 ] = PR_getcwd,
+	[ 184 ] = PR_capget,
+	[ 185 ] = PR_capset,
+	[ 186 ] = PR_sigaltstack,
+	[ 187 ] = PR_sendfile,
+	[ 188 ] = PR_getpmsg,
+	[ 189 ] = PR_putpmsg,
+	[ 190 ] = PR_vfork,
+	[ 191 ] = PR_ugetrlimit,
+	[ 192 ] = PR_mmap2,
+	[ 193 ] = PR_truncate64,
+	[ 194 ] = PR_ftruncate64,
+	[ 195 ] = PR_stat64,
+	[ 196 ] = PR_lstat64,
+	[ 197 ] = PR_fstat64,
+	[ 198 ] = PR_lchown32,
+	[ 199 ] = PR_getuid32,
+	[ 200 ] = PR_getgid32,
+	[ 201 ] = PR_geteuid32,
+	[ 202 ] = PR_getegid32,
+	[ 203 ] = PR_setreuid32,
+	[ 204 ] = PR_setregid32,
+	[ 205 ] = PR_getgroups32,
+	[ 206 ] = PR_setgroups32,
+	[ 207 ] = PR_fchown32,
+	[ 208 ] = PR_setresuid32,
+	[ 209 ] = PR_getresuid32,
+	[ 210 ] = PR_setresgid32,
+	[ 211 ] = PR_getresgid32,
+	[ 212 ] = PR_chown32,
+	[ 213 ] = PR_setuid32,
+	[ 214 ] = PR_setgid32,
+	[ 215 ] = PR_setfsuid32,
+	[ 216 ] = PR_setfsgid32,
+	[ 217 ] = PR_pivot_root,
+	[ 218 ] = PR_mincore,
+	[ 219 ] = PR_madvise,
+	[ 220 ] = PR_getdents64,
+	[ 221 ] = PR_fcntl64,
+	[ 224 ] = PR_gettid,
+	[ 225 ] = PR_readahead,
+	[ 226 ] = PR_setxattr,
+	[ 227 ] = PR_lsetxattr,
+	[ 228 ] = PR_fsetxattr,
+	[ 229 ] = PR_getxattr,
+	[ 230 ] = PR_lgetxattr,
+	[ 231 ] = PR_fgetxattr,
+	[ 232 ] = PR_listxattr,
+	[ 233 ] = PR_llistxattr,
+	[ 234 ] = PR_flistxattr,
+	[ 235 ] = PR_removexattr,
+	[ 236 ] = PR_lremovexattr,
+	[ 237 ] = PR_fremovexattr,
+	[ 238 ] = PR_tkill,
+	[ 239 ] = PR_sendfile64,
+	[ 240 ] = PR_futex,
+	[ 241 ] = PR_sched_setaffinity,
+	[ 242 ] = PR_sched_getaffinity,
+	[ 243 ] = PR_set_thread_area,
+	[ 244 ] = PR_get_thread_area,
+	[ 245 ] = PR_io_setup,
+	[ 246 ] = PR_io_destroy,
+	[ 247 ] = PR_io_getevents,
+	[ 248 ] = PR_io_submit,
+	[ 249 ] = PR_io_cancel,
+	[ 250 ] = PR_fadvise64,
+	[ 252 ] = PR_exit_group,
+	[ 253 ] = PR_lookup_dcookie,
+	[ 254 ] = PR_epoll_create,
+	[ 255 ] = PR_epoll_ctl,
+	[ 256 ] = PR_epoll_wait,
+	[ 257 ] = PR_remap_file_pages,
+	[ 258 ] = PR_set_tid_address,
+	[ 259 ] = PR_timer_create,
+	[ 260 ] = PR_timer_settime,
+	[ 261 ] = PR_timer_gettime,
+	[ 262 ] = PR_timer_getoverrun,
+	[ 263 ] = PR_timer_delete,
+	[ 264 ] = PR_clock_settime,
+	[ 265 ] = PR_clock_gettime,
+	[ 266 ] = PR_clock_getres,
+	[ 267 ] = PR_clock_nanosleep,
+	[ 268 ] = PR_statfs64,
+	[ 269 ] = PR_fstatfs64,
+	[ 270 ] = PR_tgkill,
+	[ 271 ] = PR_utimes,
+	[ 272 ] = PR_fadvise64_64,
+	[ 273 ] = PR_vserver,
+	[ 274 ] = PR_mbind,
+	[ 275 ] = PR_get_mempolicy,
+	[ 276 ] = PR_set_mempolicy,
+	[ 277 ] = PR_mq_open,
+	[ 278 ] = PR_mq_unlink,
+	[ 279 ] = PR_mq_timedsend,
+	[ 280 ] = PR_mq_timedreceive,
+	[ 281 ] = PR_mq_notify,
+	[ 282 ] = PR_mq_getsetattr,
+	[ 283 ] = PR_kexec_load,
+	[ 284 ] = PR_waitid,
+	[ 286 ] = PR_add_key,
+	[ 287 ] = PR_request_key,
+	[ 288 ] = PR_keyctl,
+	[ 289 ] = PR_ioprio_set,
+	[ 290 ] = PR_ioprio_get,
+	[ 291 ] = PR_inotify_init,
+	[ 292 ] = PR_inotify_add_watch,
+	[ 293 ] = PR_inotify_rm_watch,
+	[ 294 ] = PR_migrate_pages,
+	[ 295 ] = PR_openat,
+	[ 296 ] = PR_mkdirat,
+	[ 297 ] = PR_mknodat,
+	[ 298 ] = PR_fchownat,
+	[ 299 ] = PR_futimesat,
+	[ 300 ] = PR_fstatat64,
+	[ 301 ] = PR_unlinkat,
+	[ 302 ] = PR_renameat,
+	[ 303 ] = PR_linkat,
+	[ 304 ] = PR_symlinkat,
+	[ 305 ] = PR_readlinkat,
+	[ 306 ] = PR_fchmodat,
+	[ 307 ] = PR_faccessat,
+	[ 308 ] = PR_pselect6,
+	[ 309 ] = PR_ppoll,
+	[ 310 ] = PR_unshare,
+	[ 311 ] = PR_set_robust_list,
+	[ 312 ] = PR_get_robust_list,
+	[ 313 ] = PR_splice,
+	[ 314 ] = PR_sync_file_range,
+	[ 315 ] = PR_tee,
+	[ 316 ] = PR_vmsplice,
+	[ 317 ] = PR_move_pages,
+	[ 318 ] = PR_getcpu,
+	[ 319 ] = PR_epoll_pwait,
+	[ 320 ] = PR_utimensat,
+	[ 321 ] = PR_signalfd,
+	[ 322 ] = PR_timerfd_create,
+	[ 323 ] = PR_eventfd,
+	[ 324 ] = PR_fallocate,
+	[ 325 ] = PR_timerfd_settime,
+	[ 326 ] = PR_timerfd_gettime,
+	[ 327 ] = PR_signalfd4,
+	[ 328 ] = PR_eventfd2,
+	[ 329 ] = PR_epoll_create1,
+	[ 330 ] = PR_dup3,
+	[ 331 ] = PR_pipe2,
+	[ 332 ] = PR_inotify_init1,
+	[ 333 ] = PR_preadv,
+	[ 334 ] = PR_pwritev,
+	[ 335 ] = PR_rt_tgsigqueueinfo,
+	[ 336 ] = PR_perf_event_open,
+	[ 337 ] = PR_recvmmsg,
+	[ 338 ] = PR_fanotify_init,
+	[ 339 ] = PR_fanotify_mark,
+	[ 340 ] = PR_prlimit64,
+	[ 341 ] = PR_name_to_handle_at,
+	[ 342 ] = PR_open_by_handle_at,
+	[ 343 ] = PR_clock_adjtime,
+	[ 344 ] = PR_syncfs,
+	[ 345 ] = PR_sendmmsg,
+	[ 346 ] = PR_setns,
+	[ 347 ] = PR_process_vm_readv,
+	[ 348 ] = PR_process_vm_writev,
+	[ 349 ] = PR_kcmp,
+};
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-sh4.h b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-sh4.h
new file mode 100644
index 0000000..8546839
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-sh4.h
@@ -0,0 +1,342 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_sh4[] = {
+	[ 0 ] = PR_restart_syscall,
+	[ 1 ] = PR_exit,
+	[ 2 ] = PR_fork,
+	[ 3 ] = PR_read,
+	[ 4 ] = PR_write,
+	[ 5 ] = PR_open,
+	[ 6 ] = PR_close,
+	[ 7 ] = PR_waitpid,
+	[ 8 ] = PR_creat,
+	[ 9 ] = PR_link,
+	[ 10 ] = PR_unlink,
+	[ 11 ] = PR_execve,
+	[ 12 ] = PR_chdir,
+	[ 13 ] = PR_time,
+	[ 14 ] = PR_mknod,
+	[ 15 ] = PR_chmod,
+	[ 16 ] = PR_lchown,
+	[ 18 ] = PR_oldstat,
+	[ 19 ] = PR_lseek,
+	[ 20 ] = PR_getpid,
+	[ 21 ] = PR_mount,
+	[ 22 ] = PR_umount,
+	[ 23 ] = PR_setuid,
+	[ 24 ] = PR_getuid,
+	[ 25 ] = PR_stime,
+	[ 26 ] = PR_ptrace,
+	[ 27 ] = PR_alarm,
+	[ 28 ] = PR_oldfstat,
+	[ 29 ] = PR_pause,
+	[ 30 ] = PR_utime,
+	[ 33 ] = PR_access,
+	[ 34 ] = PR_nice,
+	[ 36 ] = PR_sync,
+	[ 37 ] = PR_kill,
+	[ 38 ] = PR_rename,
+	[ 39 ] = PR_mkdir,
+	[ 40 ] = PR_rmdir,
+	[ 41 ] = PR_dup,
+	[ 42 ] = PR_pipe,
+	[ 43 ] = PR_times,
+	[ 45 ] = PR_brk,
+	[ 46 ] = PR_setgid,
+	[ 47 ] = PR_getgid,
+	[ 48 ] = PR_signal,
+	[ 49 ] = PR_geteuid,
+	[ 50 ] = PR_getegid,
+	[ 51 ] = PR_acct,
+	[ 52 ] = PR_umount2,
+	[ 54 ] = PR_ioctl,
+	[ 55 ] = PR_fcntl,
+	[ 57 ] = PR_setpgid,
+	[ 60 ] = PR_umask,
+	[ 61 ] = PR_chroot,
+	[ 62 ] = PR_ustat,
+	[ 63 ] = PR_dup2,
+	[ 64 ] = PR_getppid,
+	[ 65 ] = PR_getpgrp,
+	[ 66 ] = PR_setsid,
+	[ 67 ] = PR_sigaction,
+	[ 68 ] = PR_sgetmask,
+	[ 69 ] = PR_ssetmask,
+	[ 70 ] = PR_setreuid,
+	[ 71 ] = PR_setregid,
+	[ 72 ] = PR_sigsuspend,
+	[ 73 ] = PR_sigpending,
+	[ 74 ] = PR_sethostname,
+	[ 75 ] = PR_setrlimit,
+	[ 76 ] = PR_getrlimit,
+	[ 77 ] = PR_getrusage,
+	[ 78 ] = PR_gettimeofday,
+	[ 79 ] = PR_settimeofday,
+	[ 80 ] = PR_getgroups,
+	[ 81 ] = PR_setgroups,
+	[ 83 ] = PR_symlink,
+	[ 84 ] = PR_oldlstat,
+	[ 85 ] = PR_readlink,
+	[ 86 ] = PR_uselib,
+	[ 87 ] = PR_swapon,
+	[ 88 ] = PR_reboot,
+	[ 89 ] = PR_readdir,
+	[ 90 ] = PR_mmap,
+	[ 91 ] = PR_munmap,
+	[ 92 ] = PR_truncate,
+	[ 93 ] = PR_ftruncate,
+	[ 94 ] = PR_fchmod,
+	[ 95 ] = PR_fchown,
+	[ 96 ] = PR_getpriority,
+	[ 97 ] = PR_setpriority,
+	[ 99 ] = PR_statfs,
+	[ 100 ] = PR_fstatfs,
+	[ 102 ] = PR_socketcall,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_setitimer,
+	[ 105 ] = PR_getitimer,
+	[ 106 ] = PR_stat,
+	[ 107 ] = PR_lstat,
+	[ 108 ] = PR_fstat,
+	[ 109 ] = PR_olduname,
+	[ 111 ] = PR_vhangup,
+	[ 114 ] = PR_wait4,
+	[ 115 ] = PR_swapoff,
+	[ 116 ] = PR_sysinfo,
+	[ 117 ] = PR_ipc,
+	[ 118 ] = PR_fsync,
+	[ 119 ] = PR_sigreturn,
+	[ 120 ] = PR_clone,
+	[ 121 ] = PR_setdomainname,
+	[ 122 ] = PR_uname,
+	[ 123 ] = PR_cacheflush,
+	[ 124 ] = PR_adjtimex,
+	[ 125 ] = PR_mprotect,
+	[ 126 ] = PR_sigprocmask,
+	[ 128 ] = PR_init_module,
+	[ 129 ] = PR_delete_module,
+	[ 131 ] = PR_quotactl,
+	[ 132 ] = PR_getpgid,
+	[ 133 ] = PR_fchdir,
+	[ 134 ] = PR_bdflush,
+	[ 135 ] = PR_sysfs,
+	[ 136 ] = PR_personality,
+	[ 138 ] = PR_setfsuid,
+	[ 139 ] = PR_setfsgid,
+	[ 140 ] = PR__llseek,
+	[ 141 ] = PR_getdents,
+	[ 142 ] = PR__newselect,
+	[ 143 ] = PR_flock,
+	[ 144 ] = PR_msync,
+	[ 145 ] = PR_readv,
+	[ 146 ] = PR_writev,
+	[ 147 ] = PR_getsid,
+	[ 148 ] = PR_fdatasync,
+	[ 149 ] = PR__sysctl,
+	[ 150 ] = PR_mlock,
+	[ 151 ] = PR_munlock,
+	[ 152 ] = PR_mlockall,
+	[ 153 ] = PR_munlockall,
+	[ 154 ] = PR_sched_setparam,
+	[ 155 ] = PR_sched_getparam,
+	[ 156 ] = PR_sched_setscheduler,
+	[ 157 ] = PR_sched_getscheduler,
+	[ 158 ] = PR_sched_yield,
+	[ 159 ] = PR_sched_get_priority_max,
+	[ 160 ] = PR_sched_get_priority_min,
+	[ 161 ] = PR_sched_rr_get_interval,
+	[ 162 ] = PR_nanosleep,
+	[ 163 ] = PR_mremap,
+	[ 164 ] = PR_setresuid,
+	[ 165 ] = PR_getresuid,
+	[ 168 ] = PR_poll,
+	[ 169 ] = PR_nfsservctl,
+	[ 170 ] = PR_setresgid,
+	[ 171 ] = PR_getresgid,
+	[ 172 ] = PR_prctl,
+	[ 173 ] = PR_rt_sigreturn,
+	[ 174 ] = PR_rt_sigaction,
+	[ 175 ] = PR_rt_sigprocmask,
+	[ 176 ] = PR_rt_sigpending,
+	[ 177 ] = PR_rt_sigtimedwait,
+	[ 178 ] = PR_rt_sigqueueinfo,
+	[ 179 ] = PR_rt_sigsuspend,
+	[ 180 ] = PR_pread64,
+	[ 181 ] = PR_pwrite64,
+	[ 182 ] = PR_chown,
+	[ 183 ] = PR_getcwd,
+	[ 184 ] = PR_capget,
+	[ 185 ] = PR_capset,
+	[ 186 ] = PR_sigaltstack,
+	[ 187 ] = PR_sendfile,
+	[ 190 ] = PR_vfork,
+	[ 191 ] = PR_ugetrlimit,
+	[ 192 ] = PR_mmap2,
+	[ 193 ] = PR_truncate64,
+	[ 194 ] = PR_ftruncate64,
+	[ 195 ] = PR_stat64,
+	[ 196 ] = PR_lstat64,
+	[ 197 ] = PR_fstat64,
+	[ 198 ] = PR_lchown32,
+	[ 199 ] = PR_getuid32,
+	[ 200 ] = PR_getgid32,
+	[ 201 ] = PR_geteuid32,
+	[ 202 ] = PR_getegid32,
+	[ 203 ] = PR_setreuid32,
+	[ 204 ] = PR_setregid32,
+	[ 205 ] = PR_getgroups32,
+	[ 206 ] = PR_setgroups32,
+	[ 207 ] = PR_fchown32,
+	[ 208 ] = PR_setresuid32,
+	[ 209 ] = PR_getresuid32,
+	[ 210 ] = PR_setresgid32,
+	[ 211 ] = PR_getresgid32,
+	[ 212 ] = PR_chown32,
+	[ 213 ] = PR_setuid32,
+	[ 214 ] = PR_setgid32,
+	[ 215 ] = PR_setfsuid32,
+	[ 216 ] = PR_setfsgid32,
+	[ 217 ] = PR_pivot_root,
+	[ 218 ] = PR_mincore,
+	[ 219 ] = PR_madvise,
+	[ 220 ] = PR_getdents64,
+	[ 221 ] = PR_fcntl64,
+	[ 224 ] = PR_gettid,
+	[ 225 ] = PR_readahead,
+	[ 226 ] = PR_setxattr,
+	[ 227 ] = PR_lsetxattr,
+	[ 228 ] = PR_fsetxattr,
+	[ 229 ] = PR_getxattr,
+	[ 230 ] = PR_lgetxattr,
+	[ 231 ] = PR_fgetxattr,
+	[ 232 ] = PR_listxattr,
+	[ 233 ] = PR_llistxattr,
+	[ 234 ] = PR_flistxattr,
+	[ 235 ] = PR_removexattr,
+	[ 236 ] = PR_lremovexattr,
+	[ 237 ] = PR_fremovexattr,
+	[ 238 ] = PR_tkill,
+	[ 239 ] = PR_sendfile64,
+	[ 240 ] = PR_futex,
+	[ 241 ] = PR_sched_setaffinity,
+	[ 242 ] = PR_sched_getaffinity,
+	[ 245 ] = PR_io_setup,
+	[ 246 ] = PR_io_destroy,
+	[ 247 ] = PR_io_getevents,
+	[ 248 ] = PR_io_submit,
+	[ 249 ] = PR_io_cancel,
+	[ 250 ] = PR_fadvise64,
+	[ 252 ] = PR_exit_group,
+	[ 253 ] = PR_lookup_dcookie,
+	[ 254 ] = PR_epoll_create,
+	[ 255 ] = PR_epoll_ctl,
+	[ 256 ] = PR_epoll_wait,
+	[ 257 ] = PR_remap_file_pages,
+	[ 258 ] = PR_set_tid_address,
+	[ 259 ] = PR_timer_create,
+	[ 260 ] = PR_timer_settime,
+	[ 261 ] = PR_timer_gettime,
+	[ 262 ] = PR_timer_getoverrun,
+	[ 263 ] = PR_timer_delete,
+	[ 264 ] = PR_clock_settime,
+	[ 265 ] = PR_clock_gettime,
+	[ 266 ] = PR_clock_getres,
+	[ 267 ] = PR_clock_nanosleep,
+	[ 268 ] = PR_statfs64,
+	[ 269 ] = PR_fstatfs64,
+	[ 270 ] = PR_tgkill,
+	[ 271 ] = PR_utimes,
+	[ 272 ] = PR_fadvise64_64,
+	[ 274 ] = PR_mbind,
+	[ 275 ] = PR_get_mempolicy,
+	[ 276 ] = PR_set_mempolicy,
+	[ 277 ] = PR_mq_open,
+	[ 278 ] = PR_mq_unlink,
+	[ 279 ] = PR_mq_timedsend,
+	[ 280 ] = PR_mq_timedreceive,
+	[ 281 ] = PR_mq_notify,
+	[ 282 ] = PR_mq_getsetattr,
+	[ 283 ] = PR_kexec_load,
+	[ 284 ] = PR_waitid,
+	[ 285 ] = PR_add_key,
+	[ 286 ] = PR_request_key,
+	[ 287 ] = PR_keyctl,
+	[ 288 ] = PR_ioprio_set,
+	[ 289 ] = PR_ioprio_get,
+	[ 290 ] = PR_inotify_init,
+	[ 291 ] = PR_inotify_add_watch,
+	[ 292 ] = PR_inotify_rm_watch,
+	[ 294 ] = PR_migrate_pages,
+	[ 295 ] = PR_openat,
+	[ 296 ] = PR_mkdirat,
+	[ 297 ] = PR_mknodat,
+	[ 298 ] = PR_fchownat,
+	[ 299 ] = PR_futimesat,
+	[ 300 ] = PR_fstatat64,
+	[ 301 ] = PR_unlinkat,
+	[ 302 ] = PR_renameat,
+	[ 303 ] = PR_linkat,
+	[ 304 ] = PR_symlinkat,
+	[ 305 ] = PR_readlinkat,
+	[ 306 ] = PR_fchmodat,
+	[ 307 ] = PR_faccessat,
+	[ 308 ] = PR_pselect6,
+	[ 309 ] = PR_ppoll,
+	[ 310 ] = PR_unshare,
+	[ 311 ] = PR_set_robust_list,
+	[ 312 ] = PR_get_robust_list,
+	[ 313 ] = PR_splice,
+	[ 314 ] = PR_sync_file_range,
+	[ 315 ] = PR_tee,
+	[ 316 ] = PR_vmsplice,
+	[ 317 ] = PR_move_pages,
+	[ 318 ] = PR_getcpu,
+	[ 319 ] = PR_epoll_pwait,
+	[ 320 ] = PR_utimensat,
+	[ 321 ] = PR_signalfd,
+	[ 322 ] = PR_timerfd_create,
+	[ 323 ] = PR_eventfd,
+	[ 324 ] = PR_fallocate,
+	[ 325 ] = PR_timerfd_settime,
+	[ 326 ] = PR_timerfd_gettime,
+	[ 327 ] = PR_signalfd4,
+	[ 328 ] = PR_eventfd2,
+	[ 329 ] = PR_epoll_create1,
+	[ 330 ] = PR_dup3,
+	[ 331 ] = PR_pipe2,
+	[ 332 ] = PR_inotify_init1,
+	[ 333 ] = PR_preadv,
+	[ 334 ] = PR_pwritev,
+	[ 335 ] = PR_rt_tgsigqueueinfo,
+	[ 336 ] = PR_perf_event_open,
+	[ 337 ] = PR_fanotify_init,
+	[ 338 ] = PR_fanotify_mark,
+	[ 339 ] = PR_prlimit64,
+	[ 340 ] = PR_socket,
+	[ 341 ] = PR_bind,
+	[ 342 ] = PR_connect,
+	[ 343 ] = PR_listen,
+	[ 344 ] = PR_accept,
+	[ 345 ] = PR_getsockname,
+	[ 346 ] = PR_getpeername,
+	[ 347 ] = PR_socketpair,
+	[ 348 ] = PR_send,
+	[ 349 ] = PR_sendto,
+	[ 350 ] = PR_recv,
+	[ 351 ] = PR_recvfrom,
+	[ 352 ] = PR_shutdown,
+	[ 353 ] = PR_setsockopt,
+	[ 354 ] = PR_getsockopt,
+	[ 355 ] = PR_sendmsg,
+	[ 356 ] = PR_recvmsg,
+	[ 357 ] = PR_recvmmsg,
+	[ 358 ] = PR_accept4,
+	[ 359 ] = PR_name_to_handle_at,
+	[ 360 ] = PR_open_by_handle_at,
+	[ 361 ] = PR_clock_adjtime,
+	[ 362 ] = PR_syncfs,
+	[ 363 ] = PR_sendmmsg,
+	[ 364 ] = PR_setns,
+	[ 365 ] = PR_process_vm_readv,
+	[ 366 ] = PR_process_vm_writev,
+};
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-x32.h b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-x32.h
new file mode 100644
index 0000000..ff68414
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-x32.h
@@ -0,0 +1,306 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_x32[] = {
+	[ 0 ] = PR_read,
+	[ 1 ] = PR_write,
+	[ 2 ] = PR_open,
+	[ 3 ] = PR_close,
+	[ 4 ] = PR_stat,
+	[ 5 ] = PR_fstat,
+	[ 6 ] = PR_lstat,
+	[ 7 ] = PR_poll,
+	[ 8 ] = PR_lseek,
+	[ 9 ] = PR_mmap,
+	[ 10 ] = PR_mprotect,
+	[ 11 ] = PR_munmap,
+	[ 12 ] = PR_brk,
+	[ 14 ] = PR_rt_sigprocmask,
+	[ 17 ] = PR_pread64,
+	[ 18 ] = PR_pwrite64,
+	[ 21 ] = PR_access,
+	[ 22 ] = PR_pipe,
+	[ 23 ] = PR_select,
+	[ 24 ] = PR_sched_yield,
+	[ 25 ] = PR_mremap,
+	[ 26 ] = PR_msync,
+	[ 27 ] = PR_mincore,
+	[ 28 ] = PR_madvise,
+	[ 29 ] = PR_shmget,
+	[ 30 ] = PR_shmat,
+	[ 31 ] = PR_shmctl,
+	[ 32 ] = PR_dup,
+	[ 33 ] = PR_dup2,
+	[ 34 ] = PR_pause,
+	[ 35 ] = PR_nanosleep,
+	[ 36 ] = PR_getitimer,
+	[ 37 ] = PR_alarm,
+	[ 38 ] = PR_setitimer,
+	[ 39 ] = PR_getpid,
+	[ 40 ] = PR_sendfile,
+	[ 41 ] = PR_socket,
+	[ 42 ] = PR_connect,
+	[ 43 ] = PR_accept,
+	[ 44 ] = PR_sendto,
+	[ 48 ] = PR_shutdown,
+	[ 49 ] = PR_bind,
+	[ 50 ] = PR_listen,
+	[ 51 ] = PR_getsockname,
+	[ 52 ] = PR_getpeername,
+	[ 53 ] = PR_socketpair,
+	[ 56 ] = PR_clone,
+	[ 57 ] = PR_fork,
+	[ 58 ] = PR_vfork,
+	[ 60 ] = PR_exit,
+	[ 61 ] = PR_wait4,
+	[ 62 ] = PR_kill,
+	[ 63 ] = PR_uname,
+	[ 64 ] = PR_semget,
+	[ 65 ] = PR_semop,
+	[ 66 ] = PR_semctl,
+	[ 67 ] = PR_shmdt,
+	[ 68 ] = PR_msgget,
+	[ 69 ] = PR_msgsnd,
+	[ 70 ] = PR_msgrcv,
+	[ 71 ] = PR_msgctl,
+	[ 72 ] = PR_fcntl,
+	[ 73 ] = PR_flock,
+	[ 74 ] = PR_fsync,
+	[ 75 ] = PR_fdatasync,
+	[ 76 ] = PR_truncate,
+	[ 77 ] = PR_ftruncate,
+	[ 78 ] = PR_getdents,
+	[ 79 ] = PR_getcwd,
+	[ 80 ] = PR_chdir,
+	[ 81 ] = PR_fchdir,
+	[ 82 ] = PR_rename,
+	[ 83 ] = PR_mkdir,
+	[ 84 ] = PR_rmdir,
+	[ 85 ] = PR_creat,
+	[ 86 ] = PR_link,
+	[ 87 ] = PR_unlink,
+	[ 88 ] = PR_symlink,
+	[ 89 ] = PR_readlink,
+	[ 90 ] = PR_chmod,
+	[ 91 ] = PR_fchmod,
+	[ 92 ] = PR_chown,
+	[ 93 ] = PR_fchown,
+	[ 94 ] = PR_lchown,
+	[ 95 ] = PR_umask,
+	[ 96 ] = PR_gettimeofday,
+	[ 97 ] = PR_getrlimit,
+	[ 98 ] = PR_getrusage,
+	[ 99 ] = PR_sysinfo,
+	[ 100 ] = PR_times,
+	[ 102 ] = PR_getuid,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_getgid,
+	[ 105 ] = PR_setuid,
+	[ 106 ] = PR_setgid,
+	[ 107 ] = PR_geteuid,
+	[ 108 ] = PR_getegid,
+	[ 109 ] = PR_setpgid,
+	[ 110 ] = PR_getppid,
+	[ 111 ] = PR_getpgrp,
+	[ 112 ] = PR_setsid,
+	[ 113 ] = PR_setreuid,
+	[ 114 ] = PR_setregid,
+	[ 115 ] = PR_getgroups,
+	[ 116 ] = PR_setgroups,
+	[ 117 ] = PR_setresuid,
+	[ 118 ] = PR_getresuid,
+	[ 119 ] = PR_setresgid,
+	[ 120 ] = PR_getresgid,
+	[ 121 ] = PR_getpgid,
+	[ 122 ] = PR_setfsuid,
+	[ 123 ] = PR_setfsgid,
+	[ 124 ] = PR_getsid,
+	[ 125 ] = PR_capget,
+	[ 126 ] = PR_capset,
+	[ 130 ] = PR_rt_sigsuspend,
+	[ 132 ] = PR_utime,
+	[ 133 ] = PR_mknod,
+	[ 135 ] = PR_personality,
+	[ 136 ] = PR_ustat,
+	[ 137 ] = PR_statfs,
+	[ 138 ] = PR_fstatfs,
+	[ 139 ] = PR_sysfs,
+	[ 140 ] = PR_getpriority,
+	[ 141 ] = PR_setpriority,
+	[ 142 ] = PR_sched_setparam,
+	[ 143 ] = PR_sched_getparam,
+	[ 144 ] = PR_sched_setscheduler,
+	[ 145 ] = PR_sched_getscheduler,
+	[ 146 ] = PR_sched_get_priority_max,
+	[ 147 ] = PR_sched_get_priority_min,
+	[ 148 ] = PR_sched_rr_get_interval,
+	[ 149 ] = PR_mlock,
+	[ 150 ] = PR_munlock,
+	[ 151 ] = PR_mlockall,
+	[ 152 ] = PR_munlockall,
+	[ 153 ] = PR_vhangup,
+	[ 154 ] = PR_modify_ldt,
+	[ 155 ] = PR_pivot_root,
+	[ 157 ] = PR_prctl,
+	[ 158 ] = PR_arch_prctl,
+	[ 159 ] = PR_adjtimex,
+	[ 160 ] = PR_setrlimit,
+	[ 161 ] = PR_chroot,
+	[ 162 ] = PR_sync,
+	[ 163 ] = PR_acct,
+	[ 164 ] = PR_settimeofday,
+	[ 165 ] = PR_mount,
+	[ 166 ] = PR_umount2,
+	[ 167 ] = PR_swapon,
+	[ 168 ] = PR_swapoff,
+	[ 169 ] = PR_reboot,
+	[ 170 ] = PR_sethostname,
+	[ 171 ] = PR_setdomainname,
+	[ 172 ] = PR_iopl,
+	[ 173 ] = PR_ioperm,
+	[ 175 ] = PR_init_module,
+	[ 176 ] = PR_delete_module,
+	[ 179 ] = PR_quotactl,
+	[ 181 ] = PR_getpmsg,
+	[ 182 ] = PR_putpmsg,
+	[ 183 ] = PR_afs_syscall,
+	[ 184 ] = PR_tuxcall,
+	[ 185 ] = PR_security,
+	[ 186 ] = PR_gettid,
+	[ 187 ] = PR_readahead,
+	[ 188 ] = PR_setxattr,
+	[ 189 ] = PR_lsetxattr,
+	[ 190 ] = PR_fsetxattr,
+	[ 191 ] = PR_getxattr,
+	[ 192 ] = PR_lgetxattr,
+	[ 193 ] = PR_fgetxattr,
+	[ 194 ] = PR_listxattr,
+	[ 195 ] = PR_llistxattr,
+	[ 196 ] = PR_flistxattr,
+	[ 197 ] = PR_removexattr,
+	[ 198 ] = PR_lremovexattr,
+	[ 199 ] = PR_fremovexattr,
+	[ 200 ] = PR_tkill,
+	[ 201 ] = PR_time,
+	[ 202 ] = PR_futex,
+	[ 203 ] = PR_sched_setaffinity,
+	[ 204 ] = PR_sched_getaffinity,
+	[ 206 ] = PR_io_setup,
+	[ 207 ] = PR_io_destroy,
+	[ 208 ] = PR_io_getevents,
+	[ 209 ] = PR_io_submit,
+	[ 210 ] = PR_io_cancel,
+	[ 212 ] = PR_lookup_dcookie,
+	[ 213 ] = PR_epoll_create,
+	[ 216 ] = PR_remap_file_pages,
+	[ 217 ] = PR_getdents64,
+	[ 218 ] = PR_set_tid_address,
+	[ 219 ] = PR_restart_syscall,
+	[ 220 ] = PR_semtimedop,
+	[ 221 ] = PR_fadvise64,
+	[ 223 ] = PR_timer_settime,
+	[ 224 ] = PR_timer_gettime,
+	[ 225 ] = PR_timer_getoverrun,
+	[ 226 ] = PR_timer_delete,
+	[ 227 ] = PR_clock_settime,
+	[ 228 ] = PR_clock_gettime,
+	[ 229 ] = PR_clock_getres,
+	[ 230 ] = PR_clock_nanosleep,
+	[ 231 ] = PR_exit_group,
+	[ 232 ] = PR_epoll_wait,
+	[ 233 ] = PR_epoll_ctl,
+	[ 234 ] = PR_tgkill,
+	[ 235 ] = PR_utimes,
+	[ 237 ] = PR_mbind,
+	[ 238 ] = PR_set_mempolicy,
+	[ 239 ] = PR_get_mempolicy,
+	[ 240 ] = PR_mq_open,
+	[ 241 ] = PR_mq_unlink,
+	[ 242 ] = PR_mq_timedsend,
+	[ 243 ] = PR_mq_timedreceive,
+	[ 245 ] = PR_mq_getsetattr,
+	[ 248 ] = PR_add_key,
+	[ 249 ] = PR_request_key,
+	[ 250 ] = PR_keyctl,
+	[ 251 ] = PR_ioprio_set,
+	[ 252 ] = PR_ioprio_get,
+	[ 253 ] = PR_inotify_init,
+	[ 254 ] = PR_inotify_add_watch,
+	[ 255 ] = PR_inotify_rm_watch,
+	[ 256 ] = PR_migrate_pages,
+	[ 257 ] = PR_openat,
+	[ 258 ] = PR_mkdirat,
+	[ 259 ] = PR_mknodat,
+	[ 260 ] = PR_fchownat,
+	[ 261 ] = PR_futimesat,
+	[ 262 ] = PR_newfstatat,
+	[ 263 ] = PR_unlinkat,
+	[ 264 ] = PR_renameat,
+	[ 265 ] = PR_linkat,
+	[ 266 ] = PR_symlinkat,
+	[ 267 ] = PR_readlinkat,
+	[ 268 ] = PR_fchmodat,
+	[ 269 ] = PR_faccessat,
+	[ 270 ] = PR_pselect6,
+	[ 271 ] = PR_ppoll,
+	[ 272 ] = PR_unshare,
+	[ 275 ] = PR_splice,
+	[ 276 ] = PR_tee,
+	[ 277 ] = PR_sync_file_range,
+	[ 280 ] = PR_utimensat,
+	[ 281 ] = PR_epoll_pwait,
+	[ 282 ] = PR_signalfd,
+	[ 283 ] = PR_timerfd_create,
+	[ 284 ] = PR_eventfd,
+	[ 285 ] = PR_fallocate,
+	[ 286 ] = PR_timerfd_settime,
+	[ 287 ] = PR_timerfd_gettime,
+	[ 288 ] = PR_accept4,
+	[ 289 ] = PR_signalfd4,
+	[ 290 ] = PR_eventfd2,
+	[ 291 ] = PR_epoll_create1,
+	[ 292 ] = PR_dup3,
+	[ 293 ] = PR_pipe2,
+	[ 294 ] = PR_inotify_init1,
+	[ 298 ] = PR_perf_event_open,
+	[ 300 ] = PR_fanotify_init,
+	[ 301 ] = PR_fanotify_mark,
+	[ 302 ] = PR_prlimit64,
+	[ 303 ] = PR_name_to_handle_at,
+	[ 304 ] = PR_open_by_handle_at,
+	[ 305 ] = PR_clock_adjtime,
+	[ 306 ] = PR_syncfs,
+	[ 308 ] = PR_setns,
+	[ 309 ] = PR_getcpu,
+	[ 312 ] = PR_kcmp,
+	[ 512 ] = PR_rt_sigaction,
+	[ 513 ] = PR_rt_sigreturn,
+	[ 514 ] = PR_ioctl,
+	[ 515 ] = PR_readv,
+	[ 516 ] = PR_writev,
+	[ 517 ] = PR_recvfrom,
+	[ 518 ] = PR_sendmsg,
+	[ 519 ] = PR_recvmsg,
+	[ 520 ] = PR_execve,
+	[ 521 ] = PR_ptrace,
+	[ 522 ] = PR_rt_sigpending,
+	[ 523 ] = PR_rt_sigtimedwait,
+	[ 524 ] = PR_rt_sigqueueinfo,
+	[ 525 ] = PR_sigaltstack,
+	[ 526 ] = PR_timer_create,
+	[ 527 ] = PR_mq_notify,
+	[ 528 ] = PR_kexec_load,
+	[ 529 ] = PR_waitid,
+	[ 530 ] = PR_set_robust_list,
+	[ 531 ] = PR_get_robust_list,
+	[ 532 ] = PR_vmsplice,
+	[ 533 ] = PR_move_pages,
+	[ 534 ] = PR_preadv,
+	[ 535 ] = PR_pwritev,
+	[ 536 ] = PR_rt_tgsigqueueinfo,
+	[ 537 ] = PR_recvmmsg,
+	[ 538 ] = PR_sendmmsg,
+	[ 539 ] = PR_process_vm_readv,
+	[ 540 ] = PR_process_vm_writev,
+	[ 541 ] = PR_setsockopt,
+	[ 542 ] = PR_getsockopt,
+};
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-x86_64.h b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-x86_64.h
new file mode 100644
index 0000000..fe3f822
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums-x86_64.h
@@ -0,0 +1,317 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_x86_64[] = {
+	[ 0 ] = PR_read,
+	[ 1 ] = PR_write,
+	[ 2 ] = PR_open,
+	[ 3 ] = PR_close,
+	[ 4 ] = PR_stat,
+	[ 5 ] = PR_fstat,
+	[ 6 ] = PR_lstat,
+	[ 7 ] = PR_poll,
+	[ 8 ] = PR_lseek,
+	[ 9 ] = PR_mmap,
+	[ 10 ] = PR_mprotect,
+	[ 11 ] = PR_munmap,
+	[ 12 ] = PR_brk,
+	[ 13 ] = PR_rt_sigaction,
+	[ 14 ] = PR_rt_sigprocmask,
+	[ 15 ] = PR_rt_sigreturn,
+	[ 16 ] = PR_ioctl,
+	[ 17 ] = PR_pread64,
+	[ 18 ] = PR_pwrite64,
+	[ 19 ] = PR_readv,
+	[ 20 ] = PR_writev,
+	[ 21 ] = PR_access,
+	[ 22 ] = PR_pipe,
+	[ 23 ] = PR_select,
+	[ 24 ] = PR_sched_yield,
+	[ 25 ] = PR_mremap,
+	[ 26 ] = PR_msync,
+	[ 27 ] = PR_mincore,
+	[ 28 ] = PR_madvise,
+	[ 29 ] = PR_shmget,
+	[ 30 ] = PR_shmat,
+	[ 31 ] = PR_shmctl,
+	[ 32 ] = PR_dup,
+	[ 33 ] = PR_dup2,
+	[ 34 ] = PR_pause,
+	[ 35 ] = PR_nanosleep,
+	[ 36 ] = PR_getitimer,
+	[ 37 ] = PR_alarm,
+	[ 38 ] = PR_setitimer,
+	[ 39 ] = PR_getpid,
+	[ 40 ] = PR_sendfile,
+	[ 41 ] = PR_socket,
+	[ 42 ] = PR_connect,
+	[ 43 ] = PR_accept,
+	[ 44 ] = PR_sendto,
+	[ 45 ] = PR_recvfrom,
+	[ 46 ] = PR_sendmsg,
+	[ 47 ] = PR_recvmsg,
+	[ 48 ] = PR_shutdown,
+	[ 49 ] = PR_bind,
+	[ 50 ] = PR_listen,
+	[ 51 ] = PR_getsockname,
+	[ 52 ] = PR_getpeername,
+	[ 53 ] = PR_socketpair,
+	[ 54 ] = PR_setsockopt,
+	[ 55 ] = PR_getsockopt,
+	[ 56 ] = PR_clone,
+	[ 57 ] = PR_fork,
+	[ 58 ] = PR_vfork,
+	[ 59 ] = PR_execve,
+	[ 60 ] = PR_exit,
+	[ 61 ] = PR_wait4,
+	[ 62 ] = PR_kill,
+	[ 63 ] = PR_uname,
+	[ 64 ] = PR_semget,
+	[ 65 ] = PR_semop,
+	[ 66 ] = PR_semctl,
+	[ 67 ] = PR_shmdt,
+	[ 68 ] = PR_msgget,
+	[ 69 ] = PR_msgsnd,
+	[ 70 ] = PR_msgrcv,
+	[ 71 ] = PR_msgctl,
+	[ 72 ] = PR_fcntl,
+	[ 73 ] = PR_flock,
+	[ 74 ] = PR_fsync,
+	[ 75 ] = PR_fdatasync,
+	[ 76 ] = PR_truncate,
+	[ 77 ] = PR_ftruncate,
+	[ 78 ] = PR_getdents,
+	[ 79 ] = PR_getcwd,
+	[ 80 ] = PR_chdir,
+	[ 81 ] = PR_fchdir,
+	[ 82 ] = PR_rename,
+	[ 83 ] = PR_mkdir,
+	[ 84 ] = PR_rmdir,
+	[ 85 ] = PR_creat,
+	[ 86 ] = PR_link,
+	[ 87 ] = PR_unlink,
+	[ 88 ] = PR_symlink,
+	[ 89 ] = PR_readlink,
+	[ 90 ] = PR_chmod,
+	[ 91 ] = PR_fchmod,
+	[ 92 ] = PR_chown,
+	[ 93 ] = PR_fchown,
+	[ 94 ] = PR_lchown,
+	[ 95 ] = PR_umask,
+	[ 96 ] = PR_gettimeofday,
+	[ 97 ] = PR_getrlimit,
+	[ 98 ] = PR_getrusage,
+	[ 99 ] = PR_sysinfo,
+	[ 100 ] = PR_times,
+	[ 101 ] = PR_ptrace,
+	[ 102 ] = PR_getuid,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_getgid,
+	[ 105 ] = PR_setuid,
+	[ 106 ] = PR_setgid,
+	[ 107 ] = PR_geteuid,
+	[ 108 ] = PR_getegid,
+	[ 109 ] = PR_setpgid,
+	[ 110 ] = PR_getppid,
+	[ 111 ] = PR_getpgrp,
+	[ 112 ] = PR_setsid,
+	[ 113 ] = PR_setreuid,
+	[ 114 ] = PR_setregid,
+	[ 115 ] = PR_getgroups,
+	[ 116 ] = PR_setgroups,
+	[ 117 ] = PR_setresuid,
+	[ 118 ] = PR_getresuid,
+	[ 119 ] = PR_setresgid,
+	[ 120 ] = PR_getresgid,
+	[ 121 ] = PR_getpgid,
+	[ 122 ] = PR_setfsuid,
+	[ 123 ] = PR_setfsgid,
+	[ 124 ] = PR_getsid,
+	[ 125 ] = PR_capget,
+	[ 126 ] = PR_capset,
+	[ 127 ] = PR_rt_sigpending,
+	[ 128 ] = PR_rt_sigtimedwait,
+	[ 129 ] = PR_rt_sigqueueinfo,
+	[ 130 ] = PR_rt_sigsuspend,
+	[ 131 ] = PR_sigaltstack,
+	[ 132 ] = PR_utime,
+	[ 133 ] = PR_mknod,
+	[ 134 ] = PR_uselib,
+	[ 135 ] = PR_personality,
+	[ 136 ] = PR_ustat,
+	[ 137 ] = PR_statfs,
+	[ 138 ] = PR_fstatfs,
+	[ 139 ] = PR_sysfs,
+	[ 140 ] = PR_getpriority,
+	[ 141 ] = PR_setpriority,
+	[ 142 ] = PR_sched_setparam,
+	[ 143 ] = PR_sched_getparam,
+	[ 144 ] = PR_sched_setscheduler,
+	[ 145 ] = PR_sched_getscheduler,
+	[ 146 ] = PR_sched_get_priority_max,
+	[ 147 ] = PR_sched_get_priority_min,
+	[ 148 ] = PR_sched_rr_get_interval,
+	[ 149 ] = PR_mlock,
+	[ 150 ] = PR_munlock,
+	[ 151 ] = PR_mlockall,
+	[ 152 ] = PR_munlockall,
+	[ 153 ] = PR_vhangup,
+	[ 154 ] = PR_modify_ldt,
+	[ 155 ] = PR_pivot_root,
+	[ 156 ] = PR__sysctl,
+	[ 157 ] = PR_prctl,
+	[ 158 ] = PR_arch_prctl,
+	[ 159 ] = PR_adjtimex,
+	[ 160 ] = PR_setrlimit,
+	[ 161 ] = PR_chroot,
+	[ 162 ] = PR_sync,
+	[ 163 ] = PR_acct,
+	[ 164 ] = PR_settimeofday,
+	[ 165 ] = PR_mount,
+	[ 166 ] = PR_umount2,
+	[ 167 ] = PR_swapon,
+	[ 168 ] = PR_swapoff,
+	[ 169 ] = PR_reboot,
+	[ 170 ] = PR_sethostname,
+	[ 171 ] = PR_setdomainname,
+	[ 172 ] = PR_iopl,
+	[ 173 ] = PR_ioperm,
+	[ 174 ] = PR_create_module,
+	[ 175 ] = PR_init_module,
+	[ 176 ] = PR_delete_module,
+	[ 177 ] = PR_get_kernel_syms,
+	[ 178 ] = PR_query_module,
+	[ 179 ] = PR_quotactl,
+	[ 180 ] = PR_nfsservctl,
+	[ 181 ] = PR_getpmsg,
+	[ 182 ] = PR_putpmsg,
+	[ 183 ] = PR_afs_syscall,
+	[ 184 ] = PR_tuxcall,
+	[ 185 ] = PR_security,
+	[ 186 ] = PR_gettid,
+	[ 187 ] = PR_readahead,
+	[ 188 ] = PR_setxattr,
+	[ 189 ] = PR_lsetxattr,
+	[ 190 ] = PR_fsetxattr,
+	[ 191 ] = PR_getxattr,
+	[ 192 ] = PR_lgetxattr,
+	[ 193 ] = PR_fgetxattr,
+	[ 194 ] = PR_listxattr,
+	[ 195 ] = PR_llistxattr,
+	[ 196 ] = PR_flistxattr,
+	[ 197 ] = PR_removexattr,
+	[ 198 ] = PR_lremovexattr,
+	[ 199 ] = PR_fremovexattr,
+	[ 200 ] = PR_tkill,
+	[ 201 ] = PR_time,
+	[ 202 ] = PR_futex,
+	[ 203 ] = PR_sched_setaffinity,
+	[ 204 ] = PR_sched_getaffinity,
+	[ 205 ] = PR_set_thread_area,
+	[ 206 ] = PR_io_setup,
+	[ 207 ] = PR_io_destroy,
+	[ 208 ] = PR_io_getevents,
+	[ 209 ] = PR_io_submit,
+	[ 210 ] = PR_io_cancel,
+	[ 211 ] = PR_get_thread_area,
+	[ 212 ] = PR_lookup_dcookie,
+	[ 213 ] = PR_epoll_create,
+	[ 214 ] = PR_epoll_ctl_old,
+	[ 215 ] = PR_epoll_wait_old,
+	[ 216 ] = PR_remap_file_pages,
+	[ 217 ] = PR_getdents64,
+	[ 218 ] = PR_set_tid_address,
+	[ 219 ] = PR_restart_syscall,
+	[ 220 ] = PR_semtimedop,
+	[ 221 ] = PR_fadvise64,
+	[ 222 ] = PR_timer_create,
+	[ 223 ] = PR_timer_settime,
+	[ 224 ] = PR_timer_gettime,
+	[ 225 ] = PR_timer_getoverrun,
+	[ 226 ] = PR_timer_delete,
+	[ 227 ] = PR_clock_settime,
+	[ 228 ] = PR_clock_gettime,
+	[ 229 ] = PR_clock_getres,
+	[ 230 ] = PR_clock_nanosleep,
+	[ 231 ] = PR_exit_group,
+	[ 232 ] = PR_epoll_wait,
+	[ 233 ] = PR_epoll_ctl,
+	[ 234 ] = PR_tgkill,
+	[ 235 ] = PR_utimes,
+	[ 236 ] = PR_vserver,
+	[ 237 ] = PR_mbind,
+	[ 238 ] = PR_set_mempolicy,
+	[ 239 ] = PR_get_mempolicy,
+	[ 240 ] = PR_mq_open,
+	[ 241 ] = PR_mq_unlink,
+	[ 242 ] = PR_mq_timedsend,
+	[ 243 ] = PR_mq_timedreceive,
+	[ 244 ] = PR_mq_notify,
+	[ 245 ] = PR_mq_getsetattr,
+	[ 246 ] = PR_kexec_load,
+	[ 247 ] = PR_waitid,
+	[ 248 ] = PR_add_key,
+	[ 249 ] = PR_request_key,
+	[ 250 ] = PR_keyctl,
+	[ 251 ] = PR_ioprio_set,
+	[ 252 ] = PR_ioprio_get,
+	[ 253 ] = PR_inotify_init,
+	[ 254 ] = PR_inotify_add_watch,
+	[ 255 ] = PR_inotify_rm_watch,
+	[ 256 ] = PR_migrate_pages,
+	[ 257 ] = PR_openat,
+	[ 258 ] = PR_mkdirat,
+	[ 259 ] = PR_mknodat,
+	[ 260 ] = PR_fchownat,
+	[ 261 ] = PR_futimesat,
+	[ 262 ] = PR_newfstatat,
+	[ 263 ] = PR_unlinkat,
+	[ 264 ] = PR_renameat,
+	[ 265 ] = PR_linkat,
+	[ 266 ] = PR_symlinkat,
+	[ 267 ] = PR_readlinkat,
+	[ 268 ] = PR_fchmodat,
+	[ 269 ] = PR_faccessat,
+	[ 270 ] = PR_pselect6,
+	[ 271 ] = PR_ppoll,
+	[ 272 ] = PR_unshare,
+	[ 273 ] = PR_set_robust_list,
+	[ 274 ] = PR_get_robust_list,
+	[ 275 ] = PR_splice,
+	[ 276 ] = PR_tee,
+	[ 277 ] = PR_sync_file_range,
+	[ 278 ] = PR_vmsplice,
+	[ 279 ] = PR_move_pages,
+	[ 280 ] = PR_utimensat,
+	[ 281 ] = PR_epoll_pwait,
+	[ 282 ] = PR_signalfd,
+	[ 283 ] = PR_timerfd_create,
+	[ 284 ] = PR_eventfd,
+	[ 285 ] = PR_fallocate,
+	[ 286 ] = PR_timerfd_settime,
+	[ 287 ] = PR_timerfd_gettime,
+	[ 288 ] = PR_accept4,
+	[ 289 ] = PR_signalfd4,
+	[ 290 ] = PR_eventfd2,
+	[ 291 ] = PR_epoll_create1,
+	[ 292 ] = PR_dup3,
+	[ 293 ] = PR_pipe2,
+	[ 294 ] = PR_inotify_init1,
+	[ 295 ] = PR_preadv,
+	[ 296 ] = PR_pwritev,
+	[ 297 ] = PR_rt_tgsigqueueinfo,
+	[ 298 ] = PR_perf_event_open,
+	[ 299 ] = PR_recvmmsg,
+	[ 300 ] = PR_fanotify_init,
+	[ 301 ] = PR_fanotify_mark,
+	[ 302 ] = PR_prlimit64,
+	[ 303 ] = PR_name_to_handle_at,
+	[ 304 ] = PR_open_by_handle_at,
+	[ 305 ] = PR_clock_adjtime,
+	[ 306 ] = PR_syncfs,
+	[ 307 ] = PR_sendmmsg,
+	[ 308 ] = PR_setns,
+	[ 309 ] = PR_getcpu,
+	[ 310 ] = PR_process_vm_readv,
+	[ 311 ] = PR_process_vm_writev,
+	[ 312 ] = PR_kcmp,
+};
diff --git a/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums.list b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums.list
new file mode 100644
index 0000000..0457f07
--- /dev/null
+++ b/5.1.0/.pc/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch/src/syscall/sysnums.list
@@ -0,0 +1,427 @@
+SYSNUM(ARM_BASE)
+SYSNUM(ARM_breakpoint)
+SYSNUM(ARM_cacheflush)
+SYSNUM(ARM_set_tls)
+SYSNUM(ARM_usr26)
+SYSNUM(ARM_usr32)
+SYSNUM(X32_SYSCALL_BIT)
+SYSNUM(_llseek)
+SYSNUM(_newselect)
+SYSNUM(_sysctl)
+SYSNUM(accept)
+SYSNUM(accept4)
+SYSNUM(access)
+SYSNUM(acct)
+SYSNUM(add_key)
+SYSNUM(adjtimex)
+SYSNUM(afs_syscall)
+SYSNUM(alarm)
+SYSNUM(arch_prctl)
+SYSNUM(arch_specific_syscall)
+SYSNUM(arm_fadvise64_64)
+SYSNUM(arm_sync_file_range)
+SYSNUM(bdflush)
+SYSNUM(bind)
+SYSNUM(break)
+SYSNUM(brk)
+SYSNUM(cacheflush)
+SYSNUM(capget)
+SYSNUM(capset)
+SYSNUM(chdir)
+SYSNUM(chmod)
+SYSNUM(chown)
+SYSNUM(chown32)
+SYSNUM(chroot)
+SYSNUM(clock_adjtime)
+SYSNUM(clock_getres)
+SYSNUM(clock_gettime)
+SYSNUM(clock_nanosleep)
+SYSNUM(clock_settime)
+SYSNUM(clone)
+SYSNUM(close)
+SYSNUM(connect)
+SYSNUM(creat)
+SYSNUM(create_module)
+SYSNUM(delete_module)
+SYSNUM(dup)
+SYSNUM(dup2)
+SYSNUM(dup3)
+SYSNUM(epoll_create)
+SYSNUM(epoll_create1)
+SYSNUM(epoll_ctl)
+SYSNUM(epoll_ctl_old)
+SYSNUM(epoll_pwait)
+SYSNUM(epoll_wait)
+SYSNUM(epoll_wait_old)
+SYSNUM(eventfd)
+SYSNUM(eventfd2)
+SYSNUM(execve)
+SYSNUM(exit)
+SYSNUM(exit_group)
+SYSNUM(faccessat)
+SYSNUM(fadvise64)
+SYSNUM(fadvise64_64)
+SYSNUM(fallocate)
+SYSNUM(fanotify_init)
+SYSNUM(fanotify_mark)
+SYSNUM(fchdir)
+SYSNUM(fchmod)
+SYSNUM(fchmodat)
+SYSNUM(fchown)
+SYSNUM(fchown32)
+SYSNUM(fchownat)
+SYSNUM(fcntl)
+SYSNUM(fcntl64)
+SYSNUM(fdatasync)
+SYSNUM(fgetxattr)
+SYSNUM(flistxattr)
+SYSNUM(flock)
+SYSNUM(fork)
+SYSNUM(fremovexattr)
+SYSNUM(fsetxattr)
+SYSNUM(fstat)
+SYSNUM(fstat64)
+SYSNUM(fstatat64)
+SYSNUM(fstatfs)
+SYSNUM(fstatfs64)
+SYSNUM(fsync)
+SYSNUM(ftime)
+SYSNUM(ftruncate)
+SYSNUM(ftruncate64)
+SYSNUM(futex)
+SYSNUM(futimesat)
+SYSNUM(get_kernel_syms)
+SYSNUM(get_mempolicy)
+SYSNUM(get_robust_list)
+SYSNUM(get_thread_area)
+SYSNUM(getcpu)
+SYSNUM(getcwd)
+SYSNUM(getdents)
+SYSNUM(getdents64)
+SYSNUM(getegid)
+SYSNUM(getegid32)
+SYSNUM(geteuid)
+SYSNUM(geteuid32)
+SYSNUM(getgid)
+SYSNUM(getgid32)
+SYSNUM(getgroups)
+SYSNUM(getgroups32)
+SYSNUM(getitimer)
+SYSNUM(getpeername)
+SYSNUM(getpgid)
+SYSNUM(getpgrp)
+SYSNUM(getpid)
+SYSNUM(getpmsg)
+SYSNUM(getppid)
+SYSNUM(getpriority)
+SYSNUM(getresgid)
+SYSNUM(getresgid32)
+SYSNUM(getresuid)
+SYSNUM(getresuid32)
+SYSNUM(getrlimit)
+SYSNUM(getrusage)
+SYSNUM(getsid)
+SYSNUM(getsockname)
+SYSNUM(getsockopt)
+SYSNUM(gettid)
+SYSNUM(gettimeofday)
+SYSNUM(getuid)
+SYSNUM(getuid32)
+SYSNUM(getxattr)
+SYSNUM(gtty)
+SYSNUM(idle)
+SYSNUM(init_module)
+SYSNUM(inotify_add_watch)
+SYSNUM(inotify_init)
+SYSNUM(inotify_init1)
+SYSNUM(inotify_rm_watch)
+SYSNUM(io_cancel)
+SYSNUM(io_destroy)
+SYSNUM(io_getevents)
+SYSNUM(io_setup)
+SYSNUM(io_submit)
+SYSNUM(ioctl)
+SYSNUM(ioperm)
+SYSNUM(iopl)
+SYSNUM(ioprio_get)
+SYSNUM(ioprio_set)
+SYSNUM(ipc)
+SYSNUM(kcmp)
+SYSNUM(kexec_load)
+SYSNUM(keyctl)
+SYSNUM(kill)
+SYSNUM(lchown)
+SYSNUM(lchown32)
+SYSNUM(lgetxattr)
+SYSNUM(link)
+SYSNUM(linkat)
+SYSNUM(listen)
+SYSNUM(listxattr)
+SYSNUM(llistxattr)
+SYSNUM(lock)
+SYSNUM(lookup_dcookie)
+SYSNUM(lremovexattr)
+SYSNUM(lseek)
+SYSNUM(lsetxattr)
+SYSNUM(lstat)
+SYSNUM(lstat64)
+SYSNUM(madvise)
+SYSNUM(mbind)
+SYSNUM(migrate_pages)
+SYSNUM(mincore)
+SYSNUM(mkdir)
+SYSNUM(mkdirat)
+SYSNUM(mknod)
+SYSNUM(mknodat)
+SYSNUM(mlock)
+SYSNUM(mlockall)
+SYSNUM(mmap)
+SYSNUM(mmap2)
+SYSNUM(modify_ldt)
+SYSNUM(mount)
+SYSNUM(move_pages)
+SYSNUM(mprotect)
+SYSNUM(mpx)
+SYSNUM(mq_getsetattr)
+SYSNUM(mq_notify)
+SYSNUM(mq_open)
+SYSNUM(mq_timedreceive)
+SYSNUM(mq_timedsend)
+SYSNUM(mq_unlink)
+SYSNUM(mremap)
+SYSNUM(msgctl)
+SYSNUM(msgget)
+SYSNUM(msgrcv)
+SYSNUM(msgsnd)
+SYSNUM(msync)
+SYSNUM(munlock)
+SYSNUM(munlockall)
+SYSNUM(munmap)
+SYSNUM(name_to_handle_at)
+SYSNUM(nanosleep)
+SYSNUM(newfstatat)
+SYSNUM(nfsservctl)
+SYSNUM(nice)
+SYSNUM(oldfstat)
+SYSNUM(oldlstat)
+SYSNUM(oldolduname)
+SYSNUM(oldstat)
+SYSNUM(olduname)
+SYSNUM(open)
+SYSNUM(open_by_handle_at)
+SYSNUM(openat)
+SYSNUM(pause)
+SYSNUM(pciconfig_iobase)
+SYSNUM(pciconfig_read)
+SYSNUM(pciconfig_write)
+SYSNUM(perf_event_open)
+SYSNUM(personality)
+SYSNUM(pipe)
+SYSNUM(pipe2)
+SYSNUM(pivot_root)
+SYSNUM(poll)
+SYSNUM(ppoll)
+SYSNUM(prctl)
+SYSNUM(pread64)
+SYSNUM(preadv)
+SYSNUM(prlimit64)
+SYSNUM(process_vm_readv)
+SYSNUM(process_vm_writev)
+SYSNUM(prof)
+SYSNUM(profil)
+SYSNUM(pselect6)
+SYSNUM(ptrace)
+SYSNUM(putpmsg)
+SYSNUM(pwrite64)
+SYSNUM(pwritev)
+SYSNUM(query_module)
+SYSNUM(quotactl)
+SYSNUM(read)
+SYSNUM(readahead)
+SYSNUM(readdir)
+SYSNUM(readlink)
+SYSNUM(readlinkat)
+SYSNUM(readv)
+SYSNUM(reboot)
+SYSNUM(recv)
+SYSNUM(recvfrom)
+SYSNUM(recvmmsg)
+SYSNUM(recvmsg)
+SYSNUM(remap_file_pages)
+SYSNUM(removexattr)
+SYSNUM(rename)
+SYSNUM(renameat)
+SYSNUM(request_key)
+SYSNUM(restart_syscall)
+SYSNUM(rmdir)
+SYSNUM(rt_sigaction)
+SYSNUM(rt_sigpending)
+SYSNUM(rt_sigprocmask)
+SYSNUM(rt_sigqueueinfo)
+SYSNUM(rt_sigreturn)
+SYSNUM(rt_sigsuspend)
+SYSNUM(rt_sigtimedwait)
+SYSNUM(rt_tgsigqueueinfo)
+SYSNUM(sched_get_priority_max)
+SYSNUM(sched_get_priority_min)
+SYSNUM(sched_getaffinity)
+SYSNUM(sched_getparam)
+SYSNUM(sched_getscheduler)
+SYSNUM(sched_rr_get_interval)
+SYSNUM(sched_setaffinity)
+SYSNUM(sched_setparam)
+SYSNUM(sched_setscheduler)
+SYSNUM(sched_yield)
+SYSNUM(security)
+SYSNUM(select)
+SYSNUM(semctl)
+SYSNUM(semget)
+SYSNUM(semop)
+SYSNUM(semtimedop)
+SYSNUM(send)
+SYSNUM(sendfile)
+SYSNUM(sendfile64)
+SYSNUM(sendmmsg)
+SYSNUM(sendmsg)
+SYSNUM(sendto)
+SYSNUM(set_mempolicy)
+SYSNUM(set_robust_list)
+SYSNUM(set_thread_area)
+SYSNUM(set_tid_address)
+SYSNUM(setdomainname)
+SYSNUM(setfsgid)
+SYSNUM(setfsgid32)
+SYSNUM(setfsuid)
+SYSNUM(setfsuid32)
+SYSNUM(setgid)
+SYSNUM(setgid32)
+SYSNUM(setgroups)
+SYSNUM(setgroups32)
+SYSNUM(sethostname)
+SYSNUM(setitimer)
+SYSNUM(setns)
+SYSNUM(setpgid)
+SYSNUM(setpriority)
+SYSNUM(setregid)
+SYSNUM(setregid32)
+SYSNUM(setresgid)
+SYSNUM(setresgid32)
+SYSNUM(setresuid)
+SYSNUM(setresuid32)
+SYSNUM(setreuid)
+SYSNUM(setreuid32)
+SYSNUM(setrlimit)
+SYSNUM(setsid)
+SYSNUM(setsockopt)
+SYSNUM(settimeofday)
+SYSNUM(setuid)
+SYSNUM(setuid32)
+SYSNUM(setxattr)
+SYSNUM(sgetmask)
+SYSNUM(shmat)
+SYSNUM(shmctl)
+SYSNUM(shmdt)
+SYSNUM(shmget)
+SYSNUM(shutdown)
+SYSNUM(sigaction)
+SYSNUM(sigaltstack)
+SYSNUM(signal)
+SYSNUM(signalfd)
+SYSNUM(signalfd4)
+SYSNUM(sigpending)
+SYSNUM(sigprocmask)
+SYSNUM(sigreturn)
+SYSNUM(sigsuspend)
+SYSNUM(socket)
+SYSNUM(socketcall)
+SYSNUM(socketpair)
+SYSNUM(splice)
+SYSNUM(ssetmask)
+SYSNUM(stat)
+SYSNUM(stat64)
+SYSNUM(statfs)
+SYSNUM(statfs64)
+SYSNUM(stime)
+SYSNUM(stty)
+SYSNUM(swapoff)
+SYSNUM(swapon)
+SYSNUM(symlink)
+SYSNUM(symlinkat)
+SYSNUM(sync)
+SYSNUM(sync_file_range)
+SYSNUM(sync_file_range2)
+SYSNUM(syncfs)
+SYSNUM(syscalls)
+SYSNUM(sysfs)
+SYSNUM(sysinfo)
+SYSNUM(syslog)
+SYSNUM(tee)
+SYSNUM(tgkill)
+SYSNUM(time)
+SYSNUM(timer_create)
+SYSNUM(timer_delete)
+SYSNUM(timer_getoverrun)
+SYSNUM(timer_gettime)
+SYSNUM(timer_settime)
+SYSNUM(timerfd_create)
+SYSNUM(timerfd_gettime)
+SYSNUM(timerfd_settime)
+SYSNUM(times)
+SYSNUM(tkill)
+SYSNUM(truncate)
+SYSNUM(truncate64)
+SYSNUM(tuxcall)
+SYSNUM(ugetrlimit)
+SYSNUM(ulimit)
+SYSNUM(umask)
+SYSNUM(umount)
+SYSNUM(umount2)
+SYSNUM(uname)
+SYSNUM(unlink)
+SYSNUM(unlinkat)
+SYSNUM(unshare)
+SYSNUM(uselib)
+SYSNUM(ustat)
+SYSNUM(utime)
+SYSNUM(utimensat)
+SYSNUM(utimes)
+SYSNUM(vfork)
+SYSNUM(vhangup)
+SYSNUM(vm86)
+SYSNUM(vm86old)
+SYSNUM(vmsplice)
+SYSNUM(vserver)
+SYSNUM(wait4)
+SYSNUM(waitid)
+SYSNUM(waitpid)
+SYSNUM(write)
+SYSNUM(writev)
+SYSNUM(x32_execve)
+SYSNUM(x32_get_robust_list)
+SYSNUM(x32_ioctl)
+SYSNUM(x32_kexec_load)
+SYSNUM(x32_move_pages)
+SYSNUM(x32_mq_notify)
+SYSNUM(x32_preadv)
+SYSNUM(x32_process_vm_readv)
+SYSNUM(x32_process_vm_writev)
+SYSNUM(x32_ptrace)
+SYSNUM(x32_pwritev)
+SYSNUM(x32_readv)
+SYSNUM(x32_recvfrom)
+SYSNUM(x32_recvmmsg)
+SYSNUM(x32_recvmsg)
+SYSNUM(x32_rt_sigaction)
+SYSNUM(x32_rt_sigpending)
+SYSNUM(x32_rt_sigqueueinfo)
+SYSNUM(x32_rt_sigreturn)
+SYSNUM(x32_rt_sigtimedwait)
+SYSNUM(x32_rt_tgsigqueueinfo)
+SYSNUM(x32_sendmmsg)
+SYSNUM(x32_sendmsg)
+SYSNUM(x32_set_robust_list)
+SYSNUM(x32_sigaltstack)
+SYSNUM(x32_timer_create)
+SYSNUM(x32_vmsplice)
+SYSNUM(x32_waitid)
+SYSNUM(x32_writev)
diff --git a/5.1.0/.pc/Fix-man-syntax.diff/doc/proot/man.1 b/5.1.0/.pc/Fix-man-syntax.diff/doc/proot/man.1
new file mode 100644
index 0000000..e83b9f2
--- /dev/null
+++ b/5.1.0/.pc/Fix-man-syntax.diff/doc/proot/man.1
@@ -0,0 +1,727 @@
+.\" Man page generated from reStructuredText.
+.
+.TH PROOT 1 "2014-12-12" "5.1.0" ""
+.SH NAME
+PRoot \- chroot, mount --bind, and binfmt_misc without privilege/setup
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH SYNOPSIS
+.sp
+\fBproot\fP [\fIoption\fP] ... [\fIcommand\fP]
+.SH DESCRIPTION
+.sp
+PRoot is a user\-space implementation of \fBchroot\fP, \fBmount \-\-bind\fP,
+and \fBbinfmt_misc\fP\&.  This means that users don\(aqt need any privileges
+or setup to do things like using an arbitrary directory as the new
+root filesystem, making files accessible somewhere else in the
+filesystem hierarchy, or executing programs built for another CPU
+architecture transparently through QEMU user\-mode.  Also, developers
+can use PRoot as a generic Linux process instrumentation engine thanks
+to its extension mechanism, see \fI\%CARE\fP for an example.  Technically
+PRoot relies on \fBptrace\fP, an unprivileged system\-call available in
+every Linux kernel.
+.sp
+The new root file\-system, a.k.a \fIguest rootfs\fP, typically contains a
+Linux distribution.  By default PRoot confines the execution of
+programs to the guest rootfs only, however users can use the built\-in
+\fImount/bind\fP mechanism to access files and directories from the actual
+root file\-system, a.k.a \fIhost rootfs\fP, just as if they were part of
+the guest rootfs.
+.sp
+When the guest Linux distribution is made for a CPU architecture
+incompatible with the host one, PRoot uses the CPU emulator QEMU
+user\-mode to execute transparently guest programs.  It\(aqs a convenient
+way to develop, to build, and to validate any guest Linux packages
+seamlessly on users\(aq computer, just as if they were in a \fInative\fP
+guest environment.  That way all of the cross\-compilation issues are
+avoided.
+.sp
+PRoot can also \fImix\fP the execution of host programs and the execution
+of guest programs emulated by QEMU user\-mode.  This is useful to use
+host equivalents of programs that are missing from the guest rootfs
+and to speed up build\-time by using cross\-compilation tools or
+CPU\-independent programs, like interpreters.
+.sp
+It is worth noting that the guest kernel is never involved, regardless
+of whether QEMU user\-mode is used or not.  Technically, when guest
+programs perform access to system resources, PRoot translates their
+requests before sending them to the host kernel.  This means that
+guest programs can use host resources (devices, network, ...) just as
+if they were "normal" host programs.
+.SH OPTIONS
+.sp
+The command\-line interface is composed of two parts: first PRoot\(aqs
+options (optional), then the command to launch (\fB/bin/sh\fP if not
+specified).  This section describes the options supported by PRoot,
+that is, the first part of its command\-line interface.
+.SS Regular options
+.INDENT 0.0
+.TP
+.BI \-r \ path\fP,\fB \ \-\-rootfs\fB= path
+Use \fIpath\fP as the new guest root file\-system, default is \fB/\fP\&.
+.sp
+The specified \fIpath\fP typically contains a Linux distribution where
+all new programs will be confined.  The default rootfs is \fB/\fP
+when none is specified, this makes sense when the bind mechanism
+is used to relocate host files and directories, see the \fB\-b\fP
+option and the \fBExamples\fP section for details.
+.sp
+It is recommended to use the \fB\-R\fP or \fB\-S\fP options instead.
+.TP
+.BI \-b \ path\fP,\fB \ \-\-bind\fB= path\fP,\fB \ \-m \ path\fP,\fB \ \-\-mount\fB= path
+Make the content of \fIpath\fP accessible in the guest rootfs.
+.sp
+This option makes any file or directory of the host rootfs
+accessible in the confined environment just as if it were part of
+the guest rootfs.  By default the host path is bound to the same
+path in the guest rootfs but users can specify any other location
+with the syntax: \fB\-b *host_path*:*guest_location*\fP\&.  If the
+guest location is a symbolic link, it is dereferenced to ensure
+the new content is accessible through all the symbolic links that
+point to the overlaid content.  In most cases this default
+behavior shouldn\(aqt be a problem, although it is possible to
+explicitly not dereference the guest location by appending it the
+\fB!\fP character: \fB\-b *host_path*:*guest_location!*\fP\&.
+.TP
+.BI \-q \ command\fP,\fB \ \-\-qemu\fB= command
+Execute guest programs through QEMU as specified by \fIcommand\fP\&.
+.sp
+Each time a guest program is going to be executed, PRoot inserts
+the QEMU user\-mode \fIcommand\fP in front of the initial request.
+That way, guest programs actually run on a virtual guest CPU
+emulated by QEMU user\-mode.  The native execution of host programs
+is still effective and the whole host rootfs is bound to
+\fB/host\-rootfs\fP in the guest environment.
+.TP
+.BI \-w \ path\fP,\fB \ \-\-pwd\fB= path\fP,\fB \ \-\-cwd\fB= path
+Set the initial working directory to \fIpath\fP\&.
+.sp
+Some programs expect to be launched from a given directory but do
+not perform any \fBchdir\fP by themselves.  This option avoids the
+need for running a shell and then entering the directory manually.
+.TP
+.BI \-v \ value\fP,\fB \ \-\-verbose\fB= value
+Set the level of debug information to \fIvalue\fP\&.
+.sp
+The higher the integer \fIvalue\fP is, the more detailed debug
+information is printed to the standard error stream.  A negative
+\fIvalue\fP makes PRoot quiet except on fatal errors.
+.TP
+.B \-V\fP,\fB  \-\-version\fP,\fB  \-\-about
+Print version, copyright, license and contact, then exit.
+.TP
+.B \-h\fP,\fB  \-\-help\fP,\fB  \-\-usage
+Print the version and the command\-line usage, then exit.
+.UNINDENT
+.SS Extension options
+.sp
+The following options enable built\-in extensions.  Technically
+developers can add their own features to PRoot or use it as a Linux
+process instrumentation engine thanks to its extension mechanism, see
+the sources for further details.
+.INDENT 0.0
+.TP
+.BI \-k \ string\fP,\fB \ \-\-kernel\-release\fB= string
+Make current kernel appear as kernel release \fIstring\fP\&.
+.sp
+If a program is run on a kernel older than the one expected by its
+GNU C library, the following error is reported: "FATAL: kernel too
+old".  To be able to run such programs, PRoot can emulate some of
+the features that are available in the kernel release specified by
+\fIstring\fP but that are missing in the current kernel.
+.TP
+.B \-0\fP,\fB  \-\-root\-id
+Make current user appear as "root" and fake its privileges.
+.sp
+Some programs will refuse to work if they are not run with "root"
+privileges, even if there is no technical reason for that.  This
+is typically the case with package managers.  This option allows
+users to bypass this kind of limitation by faking the user/group
+identity, and by faking the success of some operations like
+changing the ownership of files, changing the root directory to
+\fB/\fP, ...  Note that this option is quite limited compared to
+\fBfakeroot\fP\&.
+.TP
+.BI \-i \ string\fP,\fB \ \-\-change\-id\fB= string
+Make current user and group appear as \fIstring\fP "uid:gid".
+.sp
+This option makes the current user and group appear as \fIuid\fP and
+\fIgid\fP\&.  Likewise, files actually owned by the current user and
+group appear as if they were owned by \fIuid\fP and \fIgid\fP instead.
+Note that the \fB\-0\fP option is the same as \fB\-i 0:0\fP\&.
+.UNINDENT
+.SS Alias options
+.sp
+The following options are aliases for handy sets of options.
+.INDENT 0.0
+.TP
+.BI \-R \ path
+Alias: \fB\-r *path*\fP + a couple of recommended \fB\-b\fP\&.
+.sp
+Programs isolated in \fIpath\fP, a guest rootfs, might still need to
+access information about the host system, as it is illustrated in
+the \fBExamples\fP section of the manual.  These host information
+are typically: user/group definition, network setup, run\-time
+information, users\(aq files, ...  On all Linux distributions, they
+all lie in a couple of host files and directories that are
+automatically bound by this option:
+.INDENT 7.0
+.IP \(bu 2
+/etc/host.conf
+.IP \(bu 2
+/etc/hosts
+.IP \(bu 2
+/etc/hosts.equiv
+.IP \(bu 2
+/etc/mtab
+.IP \(bu 2
+/etc/netgroup
+.IP \(bu 2
+/etc/networks
+.IP \(bu 2
+/etc/passwd
+.IP \(bu 2
+/etc/group
+.IP \(bu 2
+/etc/nsswitch.conf
+.IP \(bu 2
+/etc/resolv.conf
+.IP \(bu 2
+/etc/localtime
+.IP \(bu 2
+/dev/
+.IP \(bu 2
+/sys/
+.IP \(bu 2
+/proc/
+.IP \(bu 2
+/tmp/
+.IP \(bu 2
+/run/
+.IP \(bu 2
+/var/run/dbus/system_bus_socket
+.IP \(bu 2
+$HOME
+.IP \(bu 2
+\fIpath\fP
+.UNINDENT
+.TP
+.BI \-S \ path
+Alias: \fB\-0 \-r *path*\fP + a couple of recommended \fB\-b\fP\&.
+.sp
+This option is useful to safely create and install packages into
+the guest rootfs.  It is similar to the \fB\-R\fP option expect it
+enables the \fB\-0\fP option and binds only the following minimal set
+of paths to avoid unexpected changes on host files:
+.INDENT 7.0
+.IP \(bu 2
+/etc/host.conf
+.IP \(bu 2
+/etc/hosts
+.IP \(bu 2
+/etc/nsswitch.conf
+.IP \(bu 2
+/etc/resolv.conf
+.IP \(bu 2
+/dev/
+.IP \(bu 2
+/sys/
+.IP \(bu 2
+/proc/
+.IP \(bu 2
+/tmp/
+.IP \(bu 2
+/run/shm
+.IP \(bu 2
+$HOME
+.IP \(bu 2
+\fIpath\fP
+.UNINDENT
+.UNINDENT
+.SH EXIT STATUS
+.sp
+If an internal error occurs, \fBproot\fP returns a non\-zero exit status,
+otherwise it returns the exit status of the last terminated
+program. When an error has occurred, the only way to know if it comes
+from the last terminated program or from \fBproot\fP itself is to have a
+look at the error message.
+.SH FILES
+.sp
+PRoot reads links in \fB/proc/<pid>/fd/\fP to support \fIopenat(2)\fP\-like
+syscalls made by the guest programs.
+.SH EXAMPLES
+.sp
+In the following examples the directories \fB/mnt/slackware\-8.0\fP and
+\fB/mnt/armslack\-12.2/\fP contain a Linux distribution respectively made
+for x86 CPUs and ARM CPUs.
+.SS \fBchroot\fP equivalent
+.sp
+To execute a command inside a given Linux distribution, just give
+\fBproot\fP the path to the guest rootfs followed by the desired
+command.  The example below executes the program \fBcat\fP to print the
+content of a file:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/ cat /etc/motd
+
+Welcome to Slackware Linux 8.0
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+The default command is \fB/bin/sh\fP when none is specified. Thus the
+shortest way to confine an interactive shell and all its sub\-programs
+is:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/
+
+$ cat /etc/motd
+Welcome to Slackware Linux 8.0
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBmount \-\-bind\fP equivalent
+.sp
+The bind mechanism enables one to relocate files and directories.  This is
+typically useful to trick programs that perform access to hard\-coded
+locations, like some installation scripts:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b /tmp/alternate_opt:/opt
+
+$ cd to/sources
+$ make install
+[...]
+install \-m 755 prog "/opt/bin"
+[...] # prog is installed in "/tmp/alternate_opt/bin" actually
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+As shown in this example, it is possible to bind over files not even
+owned by the user.  This can be used to \fIoverlay\fP system configuration
+files, for instance the DNS setting:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+ls \-l /etc/hosts
+\-rw\-r\-\-r\-\- 1 root root 675 Mar  4  2011 /etc/hosts
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b ~/alternate_hosts:/etc/hosts
+
+$ echo \(aq1.2.3.4 google.com\(aq > /etc/hosts
+$ resolveip google.com
+IP address of google.com is 1.2.3.4
+$ echo \(aq5.6.7.8 google.com\(aq > /etc/hosts
+$ resolveip google.com
+IP address of google.com is 5.6.7.8
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Another example: on most Linux distributions \fB/bin/sh\fP is a symbolic
+link to \fB/bin/bash\fP, whereas it points to \fB/bin/dash\fP on Debian
+and Ubuntu.  As a consequence a \fB#!/bin/sh\fP script tested with Bash
+might not work with Dash.  In this case, the binding mechanism of
+PRoot can be used to set non\-disruptively \fB/bin/bash\fP as the default
+\fB/bin/sh\fP on these two Linux distributions:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b /bin/bash:/bin/sh [...]
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Because \fB/bin/sh\fP is initially a symbolic link to \fB/bin/dash\fP, the
+content of \fB/bin/bash\fP is actually bound over this latter:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b /bin/bash:/bin/sh
+
+$ md5sum /bin/sh
+089ed56cd74e63f461bef0fdfc2d159a  /bin/sh
+$ md5sum /bin/bash
+089ed56cd74e63f461bef0fdfc2d159a  /bin/bash
+$ md5sum /bin/dash
+089ed56cd74e63f461bef0fdfc2d159a  /bin/dash
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+In most cases this shouldn\(aqt be a problem, but it is still possible to
+strictly bind \fB/bin/bash\fP over \fB/bin/sh\fP \-\- without dereferencing
+it \-\- by specifying the \fB!\fP character at the end:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b \(aq/bin/bash:/bin/sh!\(aq
+
+$ md5sum /bin/sh
+089ed56cd74e63f461bef0fdfc2d159a  /bin/sh
+$ md5sum /bin/bash
+089ed56cd74e63f461bef0fdfc2d159a  /bin/bash
+$ md5sum /bin/dash
+c229085928dc19e8d9bd29fe88268504  /bin/dash
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBchroot\fP + \fBmount \-\-bind\fP equivalent
+.sp
+The two features above can be combined to make any file from the host
+rootfs accessible in the confined environment just as if it were
+initially part of the guest rootfs.  It is sometimes required to run
+programs that rely on some specific files:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/
+
+$ ps \-o tty,command
+Error, do this: mount \-t proc none /proc
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+works better with:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/ \-b /proc
+
+$ ps \-o tty,command
+TT       COMMAND
+?        \-bash
+?        proot \-b /proc /mnt/slackware\-8.0/
+?        \-
+?        ps \-o tty,command
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Actually there\(aqs a bunch of such specific files, that\(aqs why PRoot
+provides the option \fB\-R\fP to bind automatically a pre\-defined list of
+recommended paths:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/slackware\-8.0/
+
+$ ps \-o tty,command
+TT       COMMAND
+pts/6    \-bash
+pts/6    proot \-R /mnt/slackware\-8.0/
+pts/6    \-
+pts/6    ps \-o tty,command
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBchroot\fP + \fBmount \-\-bind\fP + \fBsu\fP equivalent
+.sp
+Some programs will not work correctly if they are not run by the
+"root" user, this is typically the case with package managers.  PRoot
+can fake the root identity and its privileges when the \fB\-0\fP (zero)
+option is specified:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/ \-0
+
+# id
+uid=0(root) gid=0(root) [...]
+
+# mkdir /tmp/foo
+# chmod a\-rwx /tmp/foo
+# echo \(aqI bypass file\-system permissions.\(aq > /tmp/foo/bar
+# cat /tmp/foo/bar
+I bypass file\-system permissions.
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+This option is typically required to create or install packages into
+the guest rootfs.  Note it is \fInot\fP recommended to use the \fB\-R\fP
+option when installing packages since they may try to update bound
+system files, like \fB/etc/group\fP\&.  Instead, it is recommended to use
+the \fB\-S\fP option.  This latter enables the \fB\-0\fP option and binds
+only paths that are known to not be updated by packages:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-S /mnt/slackware\-8.0/
+
+# installpkg perl.tgz
+Installing package perl...
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBchroot\fP + \fBmount \-\-bind\fP + \fBbinfmt_misc\fP equivalent
+.sp
+PRoot uses QEMU user\-mode to execute programs built for a CPU
+architecture incompatible with the host one.  From users\(aq
+point\-of\-view, guest programs handled by QEMU user\-mode are executed
+transparently, that is, just like host programs.  To enable this
+feature users just have to specify which instance of QEMU user\-mode
+they want to use with the option \fB\-q\fP:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm
+
+$ cat /etc/motd
+Welcome to ARMedSlack Linux 12.2
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+The parameter of the \fB\-q\fP option is actually a whole QEMU user\-mode
+command, for instance to enable its GDB server on port 1234:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q "qemu\-arm \-g 1234" emacs
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+PRoot allows one to mix transparently the emulated execution of guest
+programs and the native execution of host programs in the same
+file\-system namespace.  It\(aqs typically useful to extend the list of
+available programs and to speed up build\-time significantly.  This
+mixed\-execution feature is enabled by default when using QEMU
+user\-mode, and the content of the host rootfs is made accessible
+through \fB/host\-rootfs\fP:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm
+
+$ file /bin/echo
+[...] ELF 32\-bit LSB executable, ARM [...]
+$ /bin/echo \(aqHello world!\(aq
+Hello world!
+
+$ file /host\-rootfs/bin/echo
+[...] ELF 64\-bit LSB executable, x86\-64 [...]
+$ /host\-rootfs/bin/echo \(aqHello mixed world!\(aq
+Hello mixed world!
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Since both host and guest programs use the guest rootfs as \fB/\fP,
+users may want to deactivate explicitly cross\-filesystem support found
+in most GNU cross\-compilation tools.  For example with GCC configured
+to cross\-compile to the ARM target:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm
+
+$ export CC=/host\-rootfs/opt/cross\-tools/arm\-linux/bin/gcc
+$ export CFLAGS="\-\-sysroot=/"   # could be optional indeed
+$ ./configure; make
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+As with regular files, a host instance of a program can be bound over
+its guest instance.  Here is an example where the guest binary of
+\fBmake\fP is overlaid by the host one:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm \-b /usr/bin/make
+
+$ which make
+/usr/bin/make
+$ make \-\-version # overlaid
+GNU Make 3.82
+Built for x86_64\-slackware\-linux\-gnu
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+It\(aqs worth mentioning that even when mixing the native execution of
+host programs and the emulated execution of guest programs, they still
+believe they are running in a native guest environment.  As a
+demonstration, here is a partial output of a typical \fB\&./configure\fP
+script:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+checking whether the C compiler is a cross\-compiler... no
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SH DOWNLOADS
+.SS PRoot
+.sp
+The latest release of PRoot is packaged on \fI\%http://packages.proot.me\fP
+and sources are hosted on \fI\%http://github.proot.me\fP\&.  It is also
+available as highly compatible static binaries:
+.INDENT 0.0
+.IP \(bu 2
+for x86_64: \fI\%http://static.proot.me/proot\-x86_64\fP
+.IP \(bu 2
+for x86: \fI\%http://static.proot.me/proot\-x86\fP
+.IP \(bu 2
+for ARM: \fI\%http://static.proot.me/proot\-arm\fP
+.IP \(bu 2
+other architectures: on demand.
+.UNINDENT
+.SS Rootfs
+.sp
+Here follows a couple of URLs where some rootfs archives can be freely
+downloaded.  Note that \fBmknod\fP errors reported by \fBtar\fP when
+extracting these archives can be safely ignored since special files
+are typically bound (see \fB\-R\fP option for details).
+.INDENT 0.0
+.IP \(bu 2
+\fI\%http://download.openvz.org/template/precreated/\fP
+.IP \(bu 2
+\fI\%https://images.linuxcontainers.org/images/\fP
+.IP \(bu 2
+\fI\%http://distfiles.gentoo.org/releases/\fP
+.IP \(bu 2
+\fI\%http://cdimage.ubuntu.com/ubuntu\-core/releases/\fP
+.IP \(bu 2
+\fI\%http://archlinuxarm.org/developers/downloads\fP
+.UNINDENT
+.sp
+Technically such rootfs archive can be created by running the
+following command on the expected Linux distribution:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+tar \-\-one\-file\-system \-\-create \-\-gzip \-\-file my_rootfs.tar.gz /
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS QEMU user\-mode
+.sp
+QEMU user\-mode is required only if the guest rootfs was made for a CPU
+architecture incompatible with the host one, for instance when using a
+ARM rootfs on a x86_64 computer.  This package can be installed either
+from \fI\%http://qemu.proot.me\fP or from the host package manager under the
+name of "qemu\-user" on most Linux distro.  In case one would like to
+build QEMU user\-mode from sources, the \fB\-\-enable\-linux\-user\fP option
+has to be specified to the \fB\&./configure\fP script.
+.SH SEE ALSO
+.sp
+chroot(1), mount(8), binfmt_misc, ptrace(2), qemu(1), sb2(1),
+bindfs(1), fakeroot(1), fakechroot(1)
+.SH COLOPHON
+.sp
+Visit \fI\%http://proot.me\fP for help, bug reports, suggestions, patches, ...
+Copyright (C) 2014 STMicroelectronics, licensed under GPL v2 or later.
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+ _____ _____              ___
+|  __ \e  __ \e_____  _____|   |_
+|   __/     /  _  \e/  _  \e    _|
+|__|  |__|__\e_____/\e_____/\e____|
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.\" Generated by docutils manpage writer.
+.
diff --git a/5.1.0/.pc/Install-proot-into-DESTDIR-usr-bin.patch/src/GNUmakefile b/5.1.0/.pc/Install-proot-into-DESTDIR-usr-bin.patch/src/GNUmakefile
new file mode 100644
index 0000000..af318da
--- /dev/null
+++ b/5.1.0/.pc/Install-proot-into-DESTDIR-usr-bin.patch/src/GNUmakefile
@@ -0,0 +1,242 @@
+# If you want to build outside of the source tree, use the -f option:
+#     make -f ${SOMEWHERE}/proot/src/GNUmakefile
+
+# the VPATH variable must point to the actual makefile directory
+VPATH := $(dir $(lastword $(MAKEFILE_LIST)))
+SRC    = $(dir $(firstword $(MAKEFILE_LIST)))
+
+GIT      = git
+RM       = rm
+INSTALL  = install
+CC       = $(CROSS_COMPILE)gcc
+LD       = $(CC)
+STRIP    = $(CROSS_COMPILE)strip
+OBJCOPY  = $(CROSS_COMPILE)objcopy
+OBJDUMP  = $(CROSS_COMPILE)objdump
+
+CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I. -I$(VPATH)
+CFLAGS   += -Wall -Wextra -O2
+LDFLAGS  += -ltalloc
+
+CARE_LDFLAGS = -larchive
+
+OBJECTS += \
+	cli/cli.o		\
+	cli/proot.o		\
+	cli/note.o		\
+	execve/enter.o		\
+	execve/exit.o		\
+	execve/shebang.o	\
+	execve/elf.o		\
+	execve/ldso.o		\
+	execve/auxv.o		\
+	execve/aoxp.o		\
+	path/binding.o		\
+	path/glue.o		\
+	path/canon.o		\
+	path/path.o		\
+	path/proc.o		\
+	path/temp.o		\
+	syscall/seccomp.o	\
+	syscall/syscall.o	\
+	syscall/chain.o		\
+	syscall/enter.o		\
+	syscall/exit.o		\
+	syscall/sysnum.o	\
+	syscall/socket.o	\
+	syscall/heap.o		\
+	tracee/tracee.o		\
+	tracee/mem.o		\
+	tracee/reg.o		\
+	tracee/event.o		\
+	ptrace/ptrace.o		\
+	ptrace/user.o		\
+	ptrace/wait.o		\
+	extension/extension.o	\
+	extension/kompat/kompat.o \
+	extension/fake_id0/fake_id0.o \
+	loader/loader-wrapped.o
+
+define define_from_arch.h
+$2$1 := $(shell $(CC) $1 -E -dM -DNO_LIBC_HEADER $(SRC)/arch.h | grep -w $2 | cut -f 3 -d ' ')
+endef
+
+$(eval $(call define_from_arch.h,,HAS_LOADER_32BIT))
+
+ifdef HAS_LOADER_32BIT
+  OBJECTS += loader/loader-m32-wrapped.o
+endif
+
+CARE_OBJECTS = 				\
+	cli/care.o			\
+	cli/care-manual.o		\
+	extension/care/care.o		\
+	extension/care/final.o		\
+	extension/care/extract.o	\
+	extension/care/archive.o
+
+.DEFAULT_GOAL = proot
+all: proot
+
+######################################################################
+# Beautified output
+
+quiet_GEN = @echo "  GEN	$@"; $(GEN)
+quiet_CC  = @echo "  CC	$@"; $(CC)
+quiet_LD  = @echo "  LD	$@"; $(LD)
+quiet_INSTALL = @echo "  INSTALL	$?"; $(INSTALL)
+
+V = 0
+ifeq ($(V), 0)
+    quiet = quiet_
+    Q     = @
+    silently = >/dev/null 2>&1
+else
+    quiet = 
+    Q     = 
+    silently = 
+endif
+
+######################################################################
+# Auto-configuration
+
+CHECK_VERSION = VERSION=$$($(GIT) describe --tags --dirty --abbrev=8 --always 2>/dev/null); \
+		if [ ! -z "$${VERSION}" ]; \
+		then /bin/echo -e "\#undef VERSION\n\#define VERSION \"$${VERSION}\""; \
+		fi;
+
+CHECK_FEATURES = process_vm seccomp_filter
+CHECK_PROGRAMS = $(foreach feature,$(CHECK_FEATURES),.check_$(feature))
+CHECK_OBJECTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).o)
+CHECK_RESULTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).res)
+
+.SILENT .IGNORE .INTERMEDIATE: $(CHECK_OBJECTS) $(CHECK_PROGRAMS)
+
+.check_%.o: .check_%.c
+	-$(COMPILE:echo=false) $(silently)
+
+.check_%: .check_%.o
+	-$(LINK:echo=false) $(silently)
+
+.check_%.res: .check_%
+	$(Q)if [ -e $< ]; then echo "#define HAVE_$(shell echo $* | tr a-z A-Z)" > $@; else echo "" > $@; fi
+
+build.h: $(CHECK_RESULTS)
+	$($(quiet)GEN)
+	$(Q)echo "/* This file is auto-generated, edit at your own risk.  */" > $@
+	$(Q)echo "#ifndef BUILD_H"      >> $@
+	$(Q)echo "#define BUILD_H"      >> $@
+	$(Q)sh -c '$(CHECK_VERSION)'    >> $@
+	$(Q)cat $^                      >> $@
+	$(Q)echo "#endif /* BUILD_H */" >> $@
+
+BUILD_ID_NONE := $(shell if ld --build-id=none --version >/dev/null 2>&1; then echo ',--build-id=none'; fi)
+
+######################################################################
+# Build rules
+
+COMPILE = $($(quiet)CC) $(CPPFLAGS) $(CFLAGS) -MD -c $(SRC)$< -o $@
+LINK    = $($(quiet)LD) -o $@ $^ $(LDFLAGS)
+
+OBJIFY = $($(quiet)GEN)									\
+	$(OBJCOPY)									\
+		--input binary								\
+		--output `env LANG=C $(OBJDUMP) -f cli/cli.o |				\
+			grep 'file format' | awk '{print $$4}'`				\
+		--binary-architecture `env LANG=C $(OBJDUMP) -f cli/cli.o |		\
+				grep architecture | cut -f 1 -d , | awk '{print $$2}'`	\
+		$< $@
+
+proot: $(OBJECTS)
+	$(LINK)
+
+care: $(OBJECTS) $(CARE_OBJECTS)
+	$(LINK) $(CARE_LDFLAGS)
+
+# Special case to compute which files depend on the auto-generated
+# file "build.h".
+USE_BUILD_H := $(patsubst $(SRC)%.c,%.o,$(shell egrep -sl 'include[[:space:]]+"build.h"' $(patsubst %.o,$(SRC)%.c,$(OBJECTS) $(CARE_OBJECTS))))
+$(USE_BUILD_H): build.h
+
+%.o: %.c
+	@mkdir -p $(dir $@)
+	$(COMPILE)
+
+.INTERMEDIATE: manual
+manual: $(VPATH)/../doc/care/manual.txt
+	$(Q)cp $< $@
+
+cli/care-manual.o: manual cli/cli.o
+	$(OBJIFY)
+
+cli/%-licenses.o: licenses cli/cli.o
+	$(OBJIFY)
+
+######################################################################
+# Build rules for the loader
+
+define build_loader
+LOADER$1_OBJECTS = loader/loader$1.o loader/assembly$1.o
+
+$(eval $(call define_from_arch.h,$1,LOADER_ARCH_CFLAGS))
+$(eval $(call define_from_arch.h,$1,LOADER_ADDRESS))
+
+LOADER_CFLAGS$1  += -fPIC -ffreestanding $(LOADER_ARCH_CFLAGS$1)
+LOADER_LDFLAGS$1 += -static -nostdlib -Wl$(BUILD_ID_NONE),-Ttext=$(LOADER_ADDRESS$1)
+
+loader/loader$1.o: loader/loader.c
+	@mkdir -p $$(dir $$@)
+	$$(COMPILE) $1 $$(LOADER_CFLAGS$1)
+
+loader/assembly$1.o: loader/assembly.S
+	@mkdir -p $$(dir $$@)
+	$$(COMPILE) $1 $$(LOADER_CFLAGS$1)
+
+loader/loader$1: $$(LOADER$1_OBJECTS)
+	$$($$(quiet)LD) $1 -o $$@ $$^ $$(LOADER_LDFLAGS$1)
+
+.INTERMEDIATE: loader$1.exe
+loader$1.exe: loader/loader$1
+	$$(Q)cp $$< $$@
+	$$(Q)$(STRIP) $$@
+
+loader/loader$1-wrapped.o: loader$1.exe cli/cli.o
+	$$(OBJIFY)
+endef
+
+$(eval $(build_loader))
+
+ifdef HAS_LOADER_32BIT
+$(eval $(call build_loader,-m32))
+endif
+
+######################################################################
+# Dependencies
+
+.DELETE_ON_ERROR:
+$(OBJECTS) $(CARE_OBJECTS) $(LOADER_OBJECTS) $(LOADER-m32_OBJECTS): $(firstword $(MAKEFILE_LIST))
+
+DEPS = $(OBJECTS:.o=.d) $(CARE_OBJECTS:.o=.d) $(LOADER_OBJECTS:.o=.d) $(LOADER-m32_OBJECTS:.o=.d) $(CHECK_OBJECTS:.o=.d)
+-include $(DEPS)
+
+######################################################################
+# PHONY targets
+
+PREFIX = /usr/local
+DESTDIR = $(PREFIX)/bin
+
+.PHONY: clean distclean install install-care uninstall
+clean distclean:
+	-$(RM) -f $(CHECK_OBJECTS) $(CHECK_PROGRAMS) $(CHECK_RESULTS) $(OBJECTS) $(CARE_OBJECTS) $(LOADER_OBJECTS) $(LOADER-m32_OBJECTS) proot care loader/loader loader/loader-m32 cli/care-manual.o $(DEPS) build.h licenses
+
+install: proot
+	$($(quiet)INSTALL) -D $< $(DESTDIR)/$<
+
+install-care: care
+	$($(quiet)INSTALL) -D $< $(DESTDIR)/$<
+
+uninstall:
+	-$(RM) -f $(DESTDIR)/proot
+
+uninstall-care:
+	-$(RM) -f $(DESTDIR)/care
diff --git a/5.1.0/.pc/applied-patches b/5.1.0/.pc/applied-patches
new file mode 100644
index 0000000..3e37338
--- /dev/null
+++ b/5.1.0/.pc/applied-patches
@@ -0,0 +1,6 @@
+Install-proot-into-DESTDIR-usr-bin.patch
+Fix-man-syntax.diff
+arm64.patch
+fix-use-of-size
+disable-seccomp-based-tracing-performanc
+0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch
diff --git a/5.1.0/.pc/arm64.patch/src/arch.h b/5.1.0/.pc/arm64.patch/src/arch.h
new file mode 100644
index 0000000..abe36d6
--- /dev/null
+++ b/5.1.0/.pc/arm64.patch/src/arch.h
@@ -0,0 +1,172 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#ifndef NO_LIBC_HEADER
+#include <sys/ptrace.h>    /* linux.git:c0a3a20b  */
+#include <linux/audit.h>   /* AUDIT_ARCH_*,  */
+#endif
+
+typedef unsigned long word_t;
+typedef unsigned char byte_t;
+
+#define SYSCALL_AVOIDER ((word_t) -2)
+#define SYSTRAP_NUM SYSARG_NUM
+
+#if !defined(ARCH_X86_64) && !defined(ARCH_ARM_EABI) && !defined(ARCH_X86) && !defined(ARCH_SH4)
+#    if defined(__x86_64__)
+#        define ARCH_X86_64 1
+#    elif defined(__ARM_EABI__)
+#        define ARCH_ARM_EABI 1
+#    elif defined(__aarch64__)
+#        define ARCH_ARM64 1
+#    elif defined(__arm__)
+#        error "Only EABI is currently supported for ARM"
+#    elif defined(__i386__)
+#        define ARCH_X86 1
+#    elif defined(__SH4__)
+#        define ARCH_SH4 1
+#    else
+#        error "Unsupported architecture"
+#    endif
+#endif
+
+/* Architecture specific definitions. */
+#if defined(ARCH_X86_64)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-x86_64.h"
+    #define SYSNUMS_HEADER2 "syscall/sysnums-i386.h"
+    #define SYSNUMS_HEADER3 "syscall/sysnums-x32.h"
+
+    #define SYSNUMS_ABI1 sysnums_x86_64
+    #define SYSNUMS_ABI2 sysnums_i386
+    #define SYSNUMS_ABI3 sysnums_x32
+
+    #undef  SYSTRAP_NUM
+    #define SYSTRAP_NUM SYSARG_RESULT
+    #define SYSTRAP_SIZE 2
+
+    #define SECCOMP_ARCHS {									\
+		{ .value = AUDIT_ARCH_X86_64, .nb_abis = 2, .abis = { ABI_DEFAULT, ABI_3 } },	\
+		{ .value = AUDIT_ARCH_I386,   .nb_abis = 1, .abis = { ABI_2 } }, 		\
+	}
+
+    #define HOST_ELF_MACHINE {62, 3, 6, 0}
+    #define RED_ZONE_SIZE 128
+    #define OFFSETOF_STAT_UID_32 24
+    #define OFFSETOF_STAT_GID_32 28
+
+    #define LOADER_ADDRESS 0x600000000000
+    #define HAS_LOADER_32BIT true
+
+    #define EXEC_PIC_ADDRESS   0x500000000000
+    #define INTERP_PIC_ADDRESS 0x6f0000000000
+    #define EXEC_PIC_ADDRESS_32   0x0f000000
+    #define INTERP_PIC_ADDRESS_32 0xaf000000
+
+#elif defined(ARCH_ARM_EABI)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-arm.h"
+    #define SYSNUMS_ABI1    sysnums_arm
+
+    #define SYSTRAP_SIZE 4
+
+    #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_ARM, .nb_abis = 1, .abis = { ABI_DEFAULT } } }
+
+    #define user_regs_struct user_regs
+    #define HOST_ELF_MACHINE {40, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+    #define EM_ARM 40
+
+    #define LOADER_ADDRESS 0x10000000
+
+    #define EXEC_PIC_ADDRESS   0x0f000000
+    #define INTERP_PIC_ADDRESS 0x1f000000
+
+    /* The syscall number has to be valid on ARM, so use tuxcall(2) as
+     * the "void" syscall since it has no side effects.  */
+    #undef SYSCALL_AVOIDER
+    #define SYSCALL_AVOIDER ((word_t) 222)
+
+#elif defined(ARCH_ARM64)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-arm64.h"
+    #define SYSNUMS_ABI1    sysnums_arm64
+
+    #define SYSTRAP_SIZE 4
+
+    #define SECCOMP_ARCHS { }
+
+    #define HOST_ELF_MACHINE {183, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+
+#elif defined(ARCH_X86)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-i386.h"
+    #define SYSNUMS_ABI1    sysnums_i386
+
+    #undef  SYSTRAP_NUM
+    #define SYSTRAP_NUM SYSARG_RESULT
+    #define SYSTRAP_SIZE 2
+
+    #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_I386, .nb_abis = 1, .abis = { ABI_DEFAULT } } }
+
+    #define HOST_ELF_MACHINE {3, 6, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+
+    #define LOADER_ADDRESS 0xa0000000
+    #define LOADER_ARCH_CFLAGS -mregparm=3
+
+    #define EXEC_PIC_ADDRESS   0x0f000000
+    #define INTERP_PIC_ADDRESS 0xaf000000
+
+#elif defined(ARCH_SH4)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-sh4.h"
+    #define SYSNUMS_ABI1    sysnums_sh4
+
+    #define SYSTRAP_SIZE 2
+
+    #define SECCOMP_ARCHS { }
+
+    #define user_regs_struct pt_regs
+    #define HOST_ELF_MACHINE {42, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+    #define NO_MISALIGNED_ACCESS 1
+
+#else
+
+    #error "Unsupported architecture"
+
+#endif
+
+#endif /* ARCH_H */
diff --git a/5.1.0/.pc/arm64.patch/src/loader/assembly-arm64.h b/5.1.0/.pc/arm64.patch/src/loader/assembly-arm64.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/5.1.0/.pc/arm64.patch/src/loader/assembly-arm64.h
diff --git a/5.1.0/.pc/arm64.patch/src/loader/loader.c b/5.1.0/.pc/arm64.patch/src/loader/loader.c
new file mode 100644
index 0000000..c639122
--- /dev/null
+++ b/5.1.0/.pc/arm64.patch/src/loader/loader.c
@@ -0,0 +1,257 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdbool.h>     /* bool, true, false,  */
+
+#define NO_LIBC_HEADER
+#include "loader/script.h"
+#include "compat.h"
+#include "arch.h"
+
+#define GCC_VERSION (__GNUC__ * 10000			\
+			+ __GNUC_MINOR__ * 100		\
+			+ __GNUC_PATCHLEVEL__)
+
+#if GCC_VERSION < 40500
+#define __builtin_unreachable()
+#endif
+
+#if defined(ARCH_X86_64)
+#    include "loader/assembly-x86_64.h"
+#elif defined(ARCH_ARM_EABI)
+#    include "loader/assembly-arm.h"
+#elif defined(ARCH_X86)
+#    include "loader/assembly-x86.h"
+#else
+#    error "Unsupported architecture"
+#endif
+
+#if !defined(MMAP_OFFSET_SHIFT)
+#    define MMAP_OFFSET_SHIFT 0
+#endif
+
+#define FATAL() do {						\
+		SYSCALL(EXIT, 1, 182);				\
+		__builtin_unreachable();			\
+	} while (0)
+
+#define unlikely(expr) __builtin_expect(!!(expr), 0)
+
+/**
+ * Clear the memory from @start (inclusive) to @end (exclusive).
+ */
+static inline void clear(word_t start, word_t end)
+{
+	byte_t *start_misaligned;
+	byte_t *end_misaligned;
+
+	word_t *start_aligned;
+	word_t *end_aligned;
+
+	/* Compute the number of mis-aligned bytes.  */
+	word_t start_bytes = start % sizeof(word_t);
+	word_t end_bytes   = end % sizeof(word_t);
+
+	/* Compute aligned addresses.  */
+	start_aligned = (word_t *) (start_bytes ? start + sizeof(word_t) - start_bytes : start);
+	end_aligned   = (word_t *) (end - end_bytes);
+
+	/* Clear leading mis-aligned bytes.  */
+	start_misaligned = (byte_t *) start;
+	while (start_misaligned < (byte_t *) start_aligned)
+		*start_misaligned++ = 0;
+
+	/* Clear aligned bytes.  */
+	while (start_aligned < end_aligned)
+		*start_aligned++ = 0;
+
+	/* Clear trailing mis-aligned bytes.  */
+	end_misaligned = (byte_t *) end_aligned;
+	while (end_misaligned < (byte_t *) end)
+		*end_misaligned++ = 0;
+}
+
+/**
+ * Return the address of the last path component of @string_.  Note
+ * that @string_ is not modified.
+ */
+static inline word_t basename(word_t string_)
+{
+	byte_t *string = (byte_t *) string_;
+	byte_t *cursor;
+
+	for (cursor = string; *cursor != 0; cursor++)
+		;
+
+	for (; *cursor != (byte_t) '/' && cursor > string; cursor--)
+		;
+
+	if (cursor != string)
+		cursor++;
+
+	return (word_t) cursor;
+}
+
+/**
+ * Interpret the load script pointed to by @cursor.
+ */
+void _start(void *cursor)
+{
+	bool traced = false;
+	bool reset_at_base = true;
+	word_t at_base = 0;
+
+	word_t fd = -1;
+	word_t status;
+
+	while(1) {
+		LoadStatement *stmt = cursor;
+
+		switch (stmt->action) {
+		case LOAD_ACTION_OPEN_NEXT:
+			status = SYSCALL(CLOSE, 1, fd);
+			if (unlikely((int) status < 0))
+				FATAL();
+			/* Fall through.  */
+
+		case LOAD_ACTION_OPEN:
+			fd = SYSCALL(OPEN, 3, stmt->open.string_address, O_RDONLY, 0);
+			if (unlikely((int) fd < 0))
+				FATAL();
+
+			reset_at_base = true;
+
+			cursor += LOAD_STATEMENT_SIZE(*stmt, open);
+			break;
+
+		case LOAD_ACTION_MMAP_FILE:
+			status = SYSCALL(MMAP, 6, stmt->mmap.addr, stmt->mmap.length,
+					stmt->mmap.prot, MAP_PRIVATE | MAP_FIXED, fd,
+					stmt->mmap.offset >> MMAP_OFFSET_SHIFT);
+			if (unlikely(status != stmt->mmap.addr))
+				FATAL();
+
+			if (stmt->mmap.clear_length != 0)
+				clear(stmt->mmap.addr + stmt->mmap.length - stmt->mmap.clear_length,
+					stmt->mmap.addr + stmt->mmap.length);
+
+			if (reset_at_base) {
+				at_base = stmt->mmap.addr;
+				reset_at_base = false;
+			}
+
+			cursor += LOAD_STATEMENT_SIZE(*stmt, mmap);
+			break;
+
+		case LOAD_ACTION_MMAP_ANON:
+			status = SYSCALL(MMAP, 6, stmt->mmap.addr, stmt->mmap.length,
+					stmt->mmap.prot, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+			if (unlikely(status != stmt->mmap.addr))
+				FATAL();
+
+			cursor += LOAD_STATEMENT_SIZE(*stmt, mmap);
+			break;
+
+		case LOAD_ACTION_START_TRACED:
+			traced = true;
+			/* Fall through.  */
+
+		case LOAD_ACTION_START: {
+			word_t *cursor2 = (word_t *) stmt->start.stack_pointer;
+			const word_t argc = cursor2[0];
+			const word_t at_execfn = cursor2[1];
+			word_t name;
+
+			status = SYSCALL(CLOSE, 1, fd);
+			if (unlikely((int) status < 0))
+				FATAL();
+
+			/* Right after execve, the stack content is as follow:
+			 *
+			 *   +------+--------+--------+--------+
+			 *   | argc | argv[] | envp[] | auxv[] |
+			 *   +------+--------+--------+--------+
+			 */
+
+			/* Skip argv[].  */
+			cursor2 += argc + 1;
+
+			/* Skip envp[].  */
+			do cursor2++; while (cursor2[0] != 0);
+			cursor2++;
+
+			/* Adjust auxv[].  */
+			do {
+				switch (cursor2[0]) {
+				case AT_PHDR:
+					cursor2[1] = stmt->start.at_phdr;
+					break;
+
+				case AT_PHENT:
+					cursor2[1] = stmt->start.at_phent;
+					break;
+
+				case AT_PHNUM:
+					cursor2[1] = stmt->start.at_phnum;
+					break;
+
+				case AT_ENTRY:
+					cursor2[1] = stmt->start.at_entry;
+					break;
+
+				case AT_BASE:
+					cursor2[1] = at_base;
+					break;
+
+				case AT_EXECFN:
+					/* stmt->start.at_execfn can't be used for now since it is
+					 * currently stored in a location that will be scratched
+					 * by the process (below the final stack pointer).  */
+					cursor2[1] = at_execfn;
+					break;
+
+				default:
+					break;
+				}
+				cursor2 += 2;
+			} while (cursor2[0] != AT_NULL);
+
+			/* Note that only 2 arguments are actually necessary... */
+			name = basename(stmt->start.at_execfn);
+			SYSCALL(PRCTL, 3, PR_SET_NAME, name, 0);
+
+			if (unlikely(traced))
+				SYSCALL(EXECVE, 6, 1,
+					stmt->start.stack_pointer,
+					stmt->start.entry_point, 2, 3, 4);
+			else
+				BRANCH(stmt->start.stack_pointer, stmt->start.entry_point);
+			FATAL();
+		}
+
+		default:
+			FATAL();
+		}
+	}
+
+	FATAL();
+}
diff --git a/5.1.0/.pc/disable-seccomp-based-tracing-performanc/src/GNUmakefile b/5.1.0/.pc/disable-seccomp-based-tracing-performanc/src/GNUmakefile
new file mode 100644
index 0000000..e230a18
--- /dev/null
+++ b/5.1.0/.pc/disable-seccomp-based-tracing-performanc/src/GNUmakefile
@@ -0,0 +1,242 @@
+# If you want to build outside of the source tree, use the -f option:
+#     make -f ${SOMEWHERE}/proot/src/GNUmakefile
+
+# the VPATH variable must point to the actual makefile directory
+VPATH := $(dir $(lastword $(MAKEFILE_LIST)))
+SRC    = $(dir $(firstword $(MAKEFILE_LIST)))
+
+GIT      = git
+RM       = rm
+INSTALL  = install
+CC       = $(CROSS_COMPILE)gcc
+LD       = $(CC)
+STRIP    = $(CROSS_COMPILE)strip
+OBJCOPY  = $(CROSS_COMPILE)objcopy
+OBJDUMP  = $(CROSS_COMPILE)objdump
+
+CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I. -I$(VPATH)
+CFLAGS   += -Wall -Wextra -O2
+LDFLAGS  += -ltalloc
+
+CARE_LDFLAGS = -larchive
+
+OBJECTS += \
+	cli/cli.o		\
+	cli/proot.o		\
+	cli/note.o		\
+	execve/enter.o		\
+	execve/exit.o		\
+	execve/shebang.o	\
+	execve/elf.o		\
+	execve/ldso.o		\
+	execve/auxv.o		\
+	execve/aoxp.o		\
+	path/binding.o		\
+	path/glue.o		\
+	path/canon.o		\
+	path/path.o		\
+	path/proc.o		\
+	path/temp.o		\
+	syscall/seccomp.o	\
+	syscall/syscall.o	\
+	syscall/chain.o		\
+	syscall/enter.o		\
+	syscall/exit.o		\
+	syscall/sysnum.o	\
+	syscall/socket.o	\
+	syscall/heap.o		\
+	tracee/tracee.o		\
+	tracee/mem.o		\
+	tracee/reg.o		\
+	tracee/event.o		\
+	ptrace/ptrace.o		\
+	ptrace/user.o		\
+	ptrace/wait.o		\
+	extension/extension.o	\
+	extension/kompat/kompat.o \
+	extension/fake_id0/fake_id0.o \
+	loader/loader-wrapped.o
+
+define define_from_arch.h
+$2$1 := $(shell $(CC) $1 -E -dM -DNO_LIBC_HEADER $(SRC)/arch.h | grep -w $2 | cut -f 3 -d ' ')
+endef
+
+$(eval $(call define_from_arch.h,,HAS_LOADER_32BIT))
+
+ifdef HAS_LOADER_32BIT
+  OBJECTS += loader/loader-m32-wrapped.o
+endif
+
+CARE_OBJECTS = 				\
+	cli/care.o			\
+	cli/care-manual.o		\
+	extension/care/care.o		\
+	extension/care/final.o		\
+	extension/care/extract.o	\
+	extension/care/archive.o
+
+.DEFAULT_GOAL = proot
+all: proot
+
+######################################################################
+# Beautified output
+
+quiet_GEN = @echo "  GEN	$@"; $(GEN)
+quiet_CC  = @echo "  CC	$@"; $(CC)
+quiet_LD  = @echo "  LD	$@"; $(LD)
+quiet_INSTALL = @echo "  INSTALL	$?"; $(INSTALL)
+
+V = 0
+ifeq ($(V), 0)
+    quiet = quiet_
+    Q     = @
+    silently = >/dev/null 2>&1
+else
+    quiet = 
+    Q     = 
+    silently = 
+endif
+
+######################################################################
+# Auto-configuration
+
+CHECK_VERSION = VERSION=$$($(GIT) describe --tags --dirty --abbrev=8 --always 2>/dev/null); \
+		if [ ! -z "$${VERSION}" ]; \
+		then /bin/echo -e "\#undef VERSION\n\#define VERSION \"$${VERSION}\""; \
+		fi;
+
+CHECK_FEATURES = process_vm seccomp_filter
+CHECK_PROGRAMS = $(foreach feature,$(CHECK_FEATURES),.check_$(feature))
+CHECK_OBJECTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).o)
+CHECK_RESULTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).res)
+
+.SILENT .IGNORE .INTERMEDIATE: $(CHECK_OBJECTS) $(CHECK_PROGRAMS)
+
+.check_%.o: .check_%.c
+	-$(COMPILE:echo=false) $(silently)
+
+.check_%: .check_%.o
+	-$(LINK:echo=false) $(silently)
+
+.check_%.res: .check_%
+	$(Q)if [ -e $< ]; then echo "#define HAVE_$(shell echo $* | tr a-z A-Z)" > $@; else echo "" > $@; fi
+
+build.h: $(CHECK_RESULTS)
+	$($(quiet)GEN)
+	$(Q)echo "/* This file is auto-generated, edit at your own risk.  */" > $@
+	$(Q)echo "#ifndef BUILD_H"      >> $@
+	$(Q)echo "#define BUILD_H"      >> $@
+	$(Q)sh -c '$(CHECK_VERSION)'    >> $@
+	$(Q)cat $^                      >> $@
+	$(Q)echo "#endif /* BUILD_H */" >> $@
+
+BUILD_ID_NONE := $(shell if ld --build-id=none --version >/dev/null 2>&1; then echo ',--build-id=none'; fi)
+
+######################################################################
+# Build rules
+
+COMPILE = $($(quiet)CC) $(CPPFLAGS) $(CFLAGS) -MD -c $(SRC)$< -o $@
+LINK    = $($(quiet)LD) -o $@ $^ $(LDFLAGS)
+
+OBJIFY = $($(quiet)GEN)									\
+	$(OBJCOPY)									\
+		--input binary								\
+		--output `env LANG=C $(OBJDUMP) -f cli/cli.o |				\
+			grep 'file format' | awk '{print $$4}'`				\
+		--binary-architecture `env LANG=C $(OBJDUMP) -f cli/cli.o |		\
+				grep architecture | cut -f 1 -d , | awk '{print $$2}'`	\
+		$< $@
+
+proot: $(OBJECTS)
+	$(LINK)
+
+care: $(OBJECTS) $(CARE_OBJECTS)
+	$(LINK) $(CARE_LDFLAGS)
+
+# Special case to compute which files depend on the auto-generated
+# file "build.h".
+USE_BUILD_H := $(patsubst $(SRC)%.c,%.o,$(shell egrep -sl 'include[[:space:]]+"build.h"' $(patsubst %.o,$(SRC)%.c,$(OBJECTS) $(CARE_OBJECTS))))
+$(USE_BUILD_H): build.h
+
+%.o: %.c
+	@mkdir -p $(dir $@)
+	$(COMPILE)
+
+.INTERMEDIATE: manual
+manual: $(VPATH)/../doc/care/manual.txt
+	$(Q)cp $< $@
+
+cli/care-manual.o: manual cli/cli.o
+	$(OBJIFY)
+
+cli/%-licenses.o: licenses cli/cli.o
+	$(OBJIFY)
+
+######################################################################
+# Build rules for the loader
+
+define build_loader
+LOADER$1_OBJECTS = loader/loader$1.o loader/assembly$1.o
+
+$(eval $(call define_from_arch.h,$1,LOADER_ARCH_CFLAGS))
+$(eval $(call define_from_arch.h,$1,LOADER_ADDRESS))
+
+LOADER_CFLAGS$1  += -fPIC -ffreestanding $(LOADER_ARCH_CFLAGS$1)
+LOADER_LDFLAGS$1 += -static -nostdlib -Wl$(BUILD_ID_NONE),-Ttext=$(LOADER_ADDRESS$1)
+
+loader/loader$1.o: loader/loader.c
+	@mkdir -p $$(dir $$@)
+	$$(COMPILE) $1 $$(LOADER_CFLAGS$1)
+
+loader/assembly$1.o: loader/assembly.S
+	@mkdir -p $$(dir $$@)
+	$$(COMPILE) $1 $$(LOADER_CFLAGS$1)
+
+loader/loader$1: $$(LOADER$1_OBJECTS)
+	$$($$(quiet)LD) $1 -o $$@ $$^ $$(LOADER_LDFLAGS$1)
+
+.INTERMEDIATE: loader$1.exe
+loader$1.exe: loader/loader$1
+	$$(Q)cp $$< $$@
+	$$(Q)$(STRIP) $$@
+
+loader/loader$1-wrapped.o: loader$1.exe cli/cli.o
+	$$(OBJIFY)
+endef
+
+$(eval $(build_loader))
+
+ifdef HAS_LOADER_32BIT
+$(eval $(call build_loader,-m32))
+endif
+
+######################################################################
+# Dependencies
+
+.DELETE_ON_ERROR:
+$(OBJECTS) $(CARE_OBJECTS) $(LOADER_OBJECTS) $(LOADER-m32_OBJECTS): $(firstword $(MAKEFILE_LIST))
+
+DEPS = $(OBJECTS:.o=.d) $(CARE_OBJECTS:.o=.d) $(LOADER_OBJECTS:.o=.d) $(LOADER-m32_OBJECTS:.o=.d) $(CHECK_OBJECTS:.o=.d)
+-include $(DEPS)
+
+######################################################################
+# PHONY targets
+
+PREFIX = /usr/local
+DESTDIR = $(PREFIX)/bin
+
+.PHONY: clean distclean install install-care uninstall
+clean distclean:
+	-$(RM) -f $(CHECK_OBJECTS) $(CHECK_PROGRAMS) $(CHECK_RESULTS) $(OBJECTS) $(CARE_OBJECTS) $(LOADER_OBJECTS) $(LOADER-m32_OBJECTS) proot care loader/loader loader/loader-m32 cli/care-manual.o $(DEPS) build.h licenses
+
+install: proot
+	$($(quiet)INSTALL) -D $< $(DESTDIR)/usr/bin/$<
+
+install-care: care
+	$($(quiet)INSTALL) -D $< $(DESTDIR)/$<
+
+uninstall:
+	-$(RM) -f $(DESTDIR)/usr/bin/proot
+
+uninstall-care:
+	-$(RM) -f $(DESTDIR)/care
diff --git a/5.1.0/.pc/fix-use-of-size/src/execve/enter.c b/5.1.0/.pc/fix-use-of-size/src/execve/enter.c
new file mode 100644
index 0000000..8f22d9c
--- /dev/null
+++ b/5.1.0/.pc/fix-use-of-size/src/execve/enter.c
@@ -0,0 +1,667 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>  /* lstat(2), lseek(2), */
+#include <sys/stat.h>   /* lstat(2), lseek(2), fchmod(2), */
+#include <unistd.h>     /* access(2), lstat(2), close(2), read(2), */
+#include <errno.h>      /* E*, */
+#include <assert.h>     /* assert(3), */
+#include <talloc.h>     /* talloc*, */
+#include <sys/mman.h>   /* PROT_*, */
+#include <string.h>     /* strlen(3), strcpy(3), */
+#include <stdlib.h>     /* getenv(3), */
+#include <stdio.h>      /* fwrite(3), */
+#include <assert.h>     /* assert(3), */
+
+#include "execve/execve.h"
+#include "execve/shebang.h"
+#include "execve/aoxp.h"
+#include "execve/ldso.h"
+#include "execve/elf.h"
+#include "path/path.h"
+#include "path/temp.h"
+#include "tracee/tracee.h"
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "arch.h"
+#include "cli/note.h"
+
+#define P(a) PROGRAM_FIELD(load_info->elf_header, *program_header, a)
+
+/**
+ * Add @program_header (type PT_LOAD) to @load_info->mappings.  This
+ * function returns -errno if an error occured, otherwise it returns
+ * 0.
+ */
+static int add_mapping(const Tracee *tracee UNUSED, LoadInfo *load_info,
+		const ProgramHeader *program_header)
+{
+	size_t index;
+	word_t start_address;
+	word_t end_address;
+	static word_t page_size = 0;
+	static word_t page_mask = 0;
+
+	if (page_size == 0) {
+		page_size = sysconf(_SC_PAGE_SIZE);
+		if ((int) page_size <= 0)
+			page_size = 0x1000;
+		page_mask = ~(page_size - 1);
+	}
+
+	if (load_info->mappings == NULL)
+		index = 0;
+	else
+		index = talloc_array_length(load_info->mappings);
+
+	load_info->mappings = talloc_realloc(load_info, load_info->mappings, Mapping, index + 1);
+	if (load_info->mappings == NULL)
+		return -ENOMEM;
+
+	start_address = P(vaddr) & page_mask;
+	end_address   = (P(vaddr) + P(filesz) + page_size) & page_mask;
+
+	load_info->mappings[index].fd     = -1; /* Unknown yet.  */
+	load_info->mappings[index].offset = P(offset) & page_mask;
+	load_info->mappings[index].addr   = start_address;
+	load_info->mappings[index].length = end_address - start_address;
+	load_info->mappings[index].flags  = MAP_PRIVATE | MAP_FIXED;
+	load_info->mappings[index].prot   =  ( (P(flags) & PF_R ? PROT_READ  : 0)
+					| (P(flags) & PF_W ? PROT_WRITE : 0)
+					| (P(flags) & PF_X ? PROT_EXEC  : 0));
+
+	/* "If the segment's memory size p_memsz is larger than the
+	 * file size p_filesz, the "extra" bytes are defined to hold
+	 * the value 0 and to follow the segment's initialized area."
+	 * -- man 7 elf.  */
+	if (P(memsz) > P(filesz)) {
+		/* How many extra bytes in the current page?  */
+		load_info->mappings[index].clear_length = end_address - P(vaddr) - P(filesz);
+
+		/* Create new pages for the remaining extra bytes.  */
+		start_address = end_address;
+		end_address   = (P(vaddr) + P(memsz) + page_size) & page_mask;
+		if (end_address > start_address) {
+			index++;
+			load_info->mappings = talloc_realloc(load_info, load_info->mappings,
+							Mapping, index + 1);
+			if (load_info->mappings == NULL)
+				return -ENOMEM;
+
+			load_info->mappings[index].fd     = -1;  /* Anonymous.  */
+			load_info->mappings[index].offset =  0;
+			load_info->mappings[index].addr   = start_address;
+			load_info->mappings[index].length = end_address - start_address;
+			load_info->mappings[index].clear_length = 0;
+			load_info->mappings[index].flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
+			load_info->mappings[index].prot   = load_info->mappings[index - 1].prot;
+		}
+	}
+	else
+		load_info->mappings[index].clear_length = 0;
+
+	return 0;
+}
+
+/**
+ * Translate @user_path into @host_path and check if this latter exists, is
+ * executable and is a regular file.  This function returns -errno if
+ * an error occured, 0 otherwise.
+ */
+int translate_and_check_exec(Tracee *tracee, char host_path[PATH_MAX], const char *user_path)
+{
+	struct stat statl;
+	int status;
+
+	if (user_path[0] == '\0')
+		return -ENOEXEC;
+
+	status = translate_path(tracee, host_path, AT_FDCWD, user_path, true);
+	if (status < 0)
+		return status;
+
+	status = access(host_path, F_OK);
+	if (status < 0)
+		return -ENOENT;
+
+	status = access(host_path, X_OK);
+	if (status < 0)
+		return -EACCES;
+
+	status = lstat(host_path, &statl);
+	if (status < 0)
+		return -EPERM;
+
+	return 0;
+}
+
+/**
+ * Add @program_header (type PT_INTERP) to @load_info->interp.  This
+ * function returns -errno if an error occured, otherwise it returns
+ * 0.
+ */
+static int add_interp(Tracee *tracee, int fd, LoadInfo *load_info,
+		const ProgramHeader *program_header)
+{
+	char host_path[PATH_MAX];
+	char *user_path;
+	int status;
+
+	/* Only one PT_INTERP segment is allowed.  */
+	if (load_info->interp != NULL)
+		return -EINVAL;
+
+	load_info->interp = talloc_zero(load_info, LoadInfo);
+	if (load_info->interp == NULL)
+		return -ENOMEM;
+
+	user_path = talloc_size(tracee->ctx, P(filesz) + 1);
+	if (user_path == NULL)
+		return -ENOMEM;
+
+	/* Remember pread(2) doesn't change the
+	 * current position in the file.  */
+	status = pread(fd, user_path, P(filesz), P(offset));
+	if ((size_t) status != P(filesz)) /* Unexpected size.  */
+		status = -EACCES;
+	if (status < 0)
+		return status;
+
+	user_path[P(filesz)] = '\0';
+
+	/* When a QEMU command was specified:
+	 *
+	 * - if it's a foreign binary we are reading the ELF
+	 *   interpreter of QEMU instead.
+	 *
+	 * - if it's a host binary, we are reading its ELF
+	 *   interpreter.
+	 *
+	 * In both case, it lies in "/host-rootfs" from a guest
+	 * point-of-view.  */
+	if (tracee->qemu != NULL && user_path[0] == '/') {
+		user_path = talloc_asprintf(tracee->ctx, "%s%s", HOST_ROOTFS, user_path);
+		if (user_path == NULL)
+			return -ENOMEM;
+	}
+
+	status = translate_and_check_exec(tracee, host_path, user_path);
+	if (status < 0)
+		return status;
+
+	load_info->interp->host_path = talloc_strdup(load_info->interp, host_path);
+	if (load_info->interp->host_path == NULL)
+		return -ENOMEM;
+
+	load_info->interp->user_path = talloc_strdup(load_info->interp, user_path);
+	if (load_info->interp->user_path == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+#undef P
+
+struct add_load_info_data {
+	LoadInfo *load_info;
+	Tracee *tracee;
+	int fd;
+};
+
+/**
+ * This function is a program header iterator.  It invokes
+ * add_mapping() or add_interp(), according to the type of
+ * @program_header.  This function returns -errno if an error
+ * occurred, otherwise 0.
+ */
+static int add_load_info(const ElfHeader *elf_header,
+			const ProgramHeader *program_header, void *data_)
+{
+	struct add_load_info_data *data = data_;
+	int status;
+
+	switch (PROGRAM_FIELD(*elf_header, *program_header, type)) {
+	case PT_LOAD:
+		status = add_mapping(data->tracee, data->load_info, program_header);
+		if (status < 0)
+			return status;
+		break;
+
+	case PT_INTERP:
+		status = add_interp(data->tracee, data->fd, data->load_info, program_header);
+		if (status < 0)
+			return status;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * Extract the load info from @load->host_path.  This function returns
+ * -errno if an error occured, otherwise it returns 0.
+ */
+static int extract_load_info(Tracee *tracee, LoadInfo *load_info)
+{
+	struct add_load_info_data data;
+	int fd = -1;
+	int status;
+
+	assert(load_info != NULL);
+	assert(load_info->host_path != NULL);
+
+	fd = open_elf(load_info->host_path, &load_info->elf_header);
+	if (fd < 0)
+		return fd;
+
+	/* Sanity check.  */
+	switch (ELF_FIELD(load_info->elf_header, type)) {
+	case ET_EXEC:
+	case ET_DYN:
+		break;
+
+	default:
+		status = -EINVAL;
+		goto end;
+	}
+
+	data.load_info = load_info;
+	data.tracee    = tracee;
+	data.fd        = fd;
+
+	status = iterate_program_headers(tracee, fd, &load_info->elf_header, add_load_info, &data);
+end:
+	if (fd >= 0)
+		close(fd);
+
+	return status;
+}
+
+/**
+ * Add @load_base to each adresses of @load_info.
+ */
+static void add_load_base(LoadInfo *load_info, word_t load_base)
+{
+	size_t nb_mappings;
+	size_t i;
+
+	nb_mappings = talloc_array_length(load_info->mappings);
+	for (i = 0; i < nb_mappings; i++)
+		load_info->mappings[i].addr += load_base;
+
+	if (IS_CLASS64(load_info->elf_header))
+		load_info->elf_header.class64.e_entry += load_base;
+	else
+		load_info->elf_header.class32.e_entry += load_base;
+}
+
+/**
+ * Compute the final load address for each position independant
+ * objects of @tracee.
+ *
+ * TODO: support for ASLR.
+ */
+static void compute_load_addresses(Tracee *tracee)
+{
+	if (IS_POSITION_INDENPENDANT(tracee->load_info->elf_header)
+	    && tracee->load_info->mappings[0].addr == 0) {
+#if defined(HAS_LOADER_32BIT)
+		if (IS_CLASS32(tracee->load_info->elf_header))
+			add_load_base(tracee->load_info, EXEC_PIC_ADDRESS_32);
+		else
+#endif
+		add_load_base(tracee->load_info, EXEC_PIC_ADDRESS);
+	}
+
+	/* Nothing more to do?  */
+	if (tracee->load_info->interp == NULL)
+		return;
+
+	if (IS_POSITION_INDENPENDANT(tracee->load_info->interp->elf_header)
+	    && tracee->load_info->interp->mappings[0].addr == 0) {
+#if defined(HAS_LOADER_32BIT)
+		if (IS_CLASS32(tracee->load_info->elf_header))
+			add_load_base(tracee->load_info->interp, INTERP_PIC_ADDRESS_32);
+		else
+#endif
+		add_load_base(tracee->load_info->interp, INTERP_PIC_ADDRESS);
+	}
+}
+
+/**
+ * Expand in argv[] and envp[] the runner for @user_path, if needed.
+ * This function returns -errno if an error occurred, otherwise 0.  On
+ * success, both @host_path and @user_path point to the program to
+ * execute (respectively from host and guest point-of-views), and both
+ * @tracee's argv[] (pointed to by SYSARG_2) @tracee's envp[] (pointed
+ * to by SYSARG_3) are correctly updated.
+ */
+static int expand_runner(Tracee* tracee, char host_path[PATH_MAX], char user_path[PATH_MAX])
+{
+	ArrayOfXPointers *envp;
+	char *argv0;
+	int status;
+
+	/* Execution of host programs when QEMU is in use relies on
+	 * LD_ environment variables.  */
+	status = fetch_array_of_xpointers(tracee, &envp, SYSARG_3, 0);
+	if (status < 0)
+		return status;
+
+	/* Environment variables should be compared with the "name"
+	 * part of the "name=value" string format.  */
+	envp->compare_xpointee = (compare_xpointee_t) compare_xpointee_env;
+
+	/* No need to adjust argv[] if it's a host binary (a.k.a
+	 * mixed-mode).  */
+	if (!is_host_elf(tracee, host_path)) {
+		ArrayOfXPointers *argv;
+		size_t nb_qemu_args;
+		size_t i;
+
+		status = fetch_array_of_xpointers(tracee, &argv, SYSARG_2, 0);
+		if (status < 0)
+			return status;
+
+		status = read_xpointee_as_string(argv, 0, &argv0);
+		if (status < 0)
+			return status;
+
+		/* Assuming PRoot was invoked this way:
+		 *
+		 *     proot -q 'qemu-arm -cpu cortex-a9' ...
+		 *
+		 * a call to:
+		 *
+		 *     execve("/bin/true", { "true", NULL }, ...)
+		 *
+		 * becomes:
+		 *
+		 *     execve("/usr/bin/qemu",
+		 *           { "qemu", "-cpu", "cortex-a9", "-0", "true", "/bin/true", NULL }, ...)
+		 */
+
+		nb_qemu_args = talloc_array_length(tracee->qemu) - 1;
+		status = resize_array_of_xpointers(argv, 1, nb_qemu_args + 2);
+		if (status < 0)
+			return status;
+
+		for (i = 0; i < nb_qemu_args; i++) {
+			status = write_xpointee(argv, i, tracee->qemu[i]);
+			if (status < 0)
+				return status;
+		}
+
+		status = write_xpointees(argv, i, 3, "-0", argv0, user_path);
+		if (status < 0)
+			return status;
+
+		/* Ensure LD_ features should not be applied to QEMU
+		 * iteself.  */
+		status = ldso_env_passthru(tracee, envp, argv, "-E", "-U", i);
+		if (status < 0)
+			return status;
+
+		status = push_array_of_xpointers(argv, SYSARG_2);
+		if (status < 0)
+			return status;
+
+		/* Launch the runner in lieu of the initial
+		 * program. */
+		assert(strlen(tracee->qemu[0]) + strlen(HOST_ROOTFS) < PATH_MAX);
+		assert(tracee->qemu[0][0] == '/');
+
+		strcpy(host_path, tracee->qemu[0]);
+
+		strcpy(user_path, HOST_ROOTFS);
+		strcat(user_path, host_path);
+	}
+
+	/* Provide information to the host dynamic linker to find host
+	 * libraries (remember the guest root file-system contains
+	 * libraries for the guest architecture only).  */
+	status = rebuild_host_ldso_paths(tracee, host_path, envp);
+	if (status < 0)
+		return status;
+
+	status = push_array_of_xpointers(envp, SYSARG_3);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+extern unsigned char _binary_loader_exe_start;
+extern unsigned char _binary_loader_exe_size;
+
+extern unsigned char WEAK _binary_loader_m32_exe_start;
+extern unsigned char WEAK _binary_loader_m32_exe_size;
+
+/**
+ * Extract the built-in loader.  This function returns NULL if an
+ * error occurred, otherwise it returns the path to the extracted
+ * loader.  Note: @tracee is only used for notification purpose.
+ */
+static char *extract_loader(const Tracee *tracee, bool wants_32bit_version)
+{
+	char path[PATH_MAX];
+	size_t status2;
+	void *start;
+	size_t size;
+	int status;
+	int fd;
+
+	char *loader_path = NULL;
+	FILE *file = NULL;
+
+	file = open_temp_file(NULL, "prooted");
+	if (file == NULL)
+		goto end;
+	fd = fileno(file);
+
+	if (wants_32bit_version) {
+		start = (void *) &_binary_loader_m32_exe_start;
+		size  = (size_t) &_binary_loader_m32_exe_size;
+	}
+	else {
+		start = (void *) &_binary_loader_exe_start;
+		size  = (size_t) &_binary_loader_exe_size;
+	}
+
+	status2 = write(fd, start, size);
+	if (status2 != size) {
+		note(tracee, ERROR, SYSTEM, "can't write the loader");
+		goto end;
+	}
+
+	status = fchmod(fd, S_IRUSR|S_IXUSR);
+	if (status < 0) {
+		note(tracee, ERROR, SYSTEM, "can't change loader permissions (u+rx)");
+		goto end;
+	}
+
+	status = readlink_proc_pid_fd(getpid(), fd, path);
+	if (status < 0) {
+		note(tracee, ERROR, INTERNAL, "can't retrieve loader path (/proc/self/fd/)");
+		goto end;
+	}
+
+	loader_path = talloc_strdup(talloc_autofree_context(), path);
+	if (loader_path == NULL) {
+		note(tracee, ERROR, INTERNAL, "can't allocate memory");
+		goto end;
+	}
+
+	if (tracee->verbose >= 2)
+		note(tracee, INFO, INTERNAL, "loader: %s", loader_path);
+
+end:
+	if (file != NULL) {
+		status = fclose(file);
+		if (status < 0)
+			note(tracee, WARNING, SYSTEM, "can't close loader file");
+	}
+
+	return loader_path;
+}
+
+/**
+ * Get the path to the loader for the given @tracee.  This function
+ * returns NULL if an error occurred.
+ */
+static inline const char *get_loader_path(const Tracee *tracee)
+{
+	static char *loader_path = NULL;
+
+#if defined(HAS_LOADER_32BIT)
+	static char *loader32_path = NULL;
+
+	if (IS_CLASS32(tracee->load_info->elf_header)) {
+		loader32_path = loader32_path ?: getenv("PROOT_LOADER_32") ?: extract_loader(tracee, true);
+		return loader32_path;
+	}
+	else
+#endif
+	{
+		loader_path = loader_path ?: getenv("PROOT_LOADER") ?: extract_loader(tracee, false);
+		return loader_path;
+	}
+}
+
+/**
+ * Extract all the information that will be required by
+ * translate_load_*().  This function returns -errno if an error
+ * occured, otherwise 0.
+ */
+int translate_execve_enter(Tracee *tracee)
+{
+	char user_path[PATH_MAX];
+	char host_path[PATH_MAX];
+	char new_exe[PATH_MAX];
+	char *raw_path;
+	const char *loader_path;
+	int status;
+
+	if (IS_NOTIFICATION_PTRACED_LOAD_DONE(tracee)) {
+		/* Syscalls can now be reported to its ptracer.  */
+		tracee->as_ptracee.ignore_loader_syscalls = false;
+
+		/* Cancel this spurious execve, it was only used as a
+		 * notification.  */
+		set_sysnum(tracee, PR_void);
+		return 0;
+	}
+
+	status = get_sysarg_path(tracee, user_path, SYSARG_1);
+	if (status < 0)
+		return status;
+
+	/* Remember the user path before it is overwritten by
+	 * expand_shebang().  This "raw" path is useful to fix the
+	 * value of AT_EXECFN and /proc/{@tracee->pid}/comm.  */
+	raw_path = talloc_strdup(tracee->ctx, user_path);
+	if (raw_path == NULL)
+		return -ENOMEM;
+
+	status = expand_shebang(tracee, host_path, user_path);
+	if (status < 0)
+		/* The Linux kernel actually returns -EACCES when
+		 * trying to execute a directory.  */
+		return status == -EISDIR ? -EACCES : status;
+
+	/* user_path is modified only if there's an interpreter
+	 * (ie. for a script or with qemu).  */
+	if (status == 0 && tracee->qemu == NULL)
+		TALLOC_FREE(raw_path);
+
+	/* Remember the new value for "/proc/self/exe".  It points to
+	 * a canonicalized guest path, hence detranslate_path()
+	 * instead of using user_path directly.  */
+	strcpy(new_exe, host_path);
+	status = detranslate_path(tracee, new_exe, NULL);
+	if (status >= 0) {
+		talloc_unlink(tracee, tracee->new_exe);
+		tracee->new_exe = talloc_strdup(tracee, new_exe);
+	}
+	else
+		tracee->new_exe = NULL;
+
+	if (tracee->qemu != NULL) {
+		status = expand_runner(tracee, host_path, user_path);
+		if (status < 0)
+			return status;
+	}
+
+	TALLOC_FREE(tracee->load_info);
+
+	tracee->load_info = talloc_zero(tracee, LoadInfo);
+	if (tracee->load_info == NULL)
+		return -ENOMEM;
+
+	tracee->load_info->host_path = talloc_strdup(tracee->load_info, host_path);
+	if (tracee->load_info->host_path == NULL)
+		return -ENOMEM;
+
+	tracee->load_info->user_path = talloc_strdup(tracee->load_info, user_path);
+	if (tracee->load_info->user_path == NULL)
+		return -ENOMEM;
+
+	tracee->load_info->raw_path = (raw_path != NULL
+			? talloc_reparent(tracee->ctx, tracee->load_info, raw_path)
+			: talloc_reference(tracee->load_info, tracee->load_info->user_path));
+	if (tracee->load_info->raw_path == NULL)
+		return -ENOMEM;
+
+	status = extract_load_info(tracee, tracee->load_info);
+	if (status < 0)
+		return status;
+
+	if (tracee->load_info->interp != NULL) {
+		status = extract_load_info(tracee, tracee->load_info->interp);
+		if (status < 0)
+			return status;
+
+		/* An ELF interpreter is supposed to be
+		 * standalone.  */
+		if (tracee->load_info->interp->interp != NULL)
+			return -EINVAL;
+	}
+
+	compute_load_addresses(tracee);
+
+	/* Execute the loader instead of the program.  */
+	loader_path = get_loader_path(tracee);
+	if (loader_path == NULL)
+		return -ENOENT;
+
+	status = set_sysarg_path(tracee, loader_path, SYSARG_1);
+	if (status < 0)
+		return status;
+
+	/* Mask to its ptracer syscalls performed by the loader.  */
+	tracee->as_ptracee.ignore_loader_syscalls = true;
+
+	return 0;
+}
diff --git a/5.1.0/.travis.yml b/5.1.0/.travis.yml
new file mode 100644
index 0000000..86d9639
--- /dev/null
+++ b/5.1.0/.travis.yml
@@ -0,0 +1,29 @@
+language: c
+
+compiler: gcc
+
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq libtalloc-dev uthash-dev libarchive-dev gdb strace realpath
+ - sudo pip install cpp-coveralls
+
+script: if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -C src loader.exe loader-m32.exe build.h && env CFLAGS=--coverage LDFLAGS='--coverage' make -C src proot && env PATH=/bin:/usr/bin:/sbin:/usr/sbin:$PWD/src make -C tests; fi
+
+after_success:
+  - coveralls --build-root src --exclude tests --gcov-options '\-lp'
+
+env:
+  global:
+   # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
+   # via the "travis encrypt" command using the project repo's public key
+   - secure: "G2fG/oWcEOiG+RYLCK3XOO/7ZXn4LoiIyOT4fxxJzb43gu/90lEkbwsALqVAAjh/Fn5T4rYqiECeJ0jEhxvWak1pK/jkFshfXzL34yaY8ZLNtwvnFf7+DDtsj1Hx136TEjYuyc/jasoTf/3fNlIX6Oh1BB6c0UtJfHwTfbreRbI="
+
+addons:
+  coverity_scan:
+    project:
+      name: "cedric-vincent/PRoot"
+      description: "PRoot"
+    notification_email: cedric.vincent@gmail.com
+    build_command_prepend:
+    build_command: make -C src
+    branch_pattern: coverity_scan
diff --git a/5.1.0/AUTHORS b/5.1.0/AUTHORS
new file mode 100644
index 0000000..dceedc3
--- /dev/null
+++ b/5.1.0/AUTHORS
@@ -0,0 +1,32 @@
+The copyright holder for PRoot and CARE is STMicroelectronics, these
+tools are developed in the Compilation Expertise Center by:
+
+Cédric VINCENT <cedric.vincent@st.com>
+        Original author, maintainer.
+
+Rémi DURAFFORT <remi.duraffort@st.com>
+        Improved the -0 feature, many experiments, bug reports, fixes, and articles.
+
+Christophe GUILLON <christophe.guillon@st.com>
+        Improved CARE, plugin experiments, bug reports, and fixes.
+
+Yves JANIN <yves.janin@st.com>
+        Support for the i386 architecture, many experiments and bug reports.
+
+Antoine MOYNAULT <antoine.moynault@st.com>
+        Many experiments and bug reports.
+
+Claire ROBINE <claire.robine@st.com>
+        Many bug fixes.
+
+Clément BAZIN <clement@bazin-fr.org>
+        Plugins interface, dependency tracker plugin, and bug reports.
+
+Christian BERTIN <christian.bertin@st.com>
+        Valuable support.
+
+Denis FERRANTI <denis.ferranti@st.com>
+        Valuable support.
+
+Paul GHALEB <paul.ghaleb@st.com>
+        User manual review.
diff --git a/5.1.0/COPYING b/5.1.0/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/5.1.0/COPYING
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/5.1.0/README.rst b/5.1.0/README.rst
new file mode 100644
index 0000000..7075607
--- /dev/null
+++ b/5.1.0/README.rst
@@ -0,0 +1,19 @@
+Manuals
+=======
+
+- `PRoot <doc/proot/manual.txt>`_
+
+- `CARE <doc/care/manual.txt>`_
+
+
+Build status
+============
+
+- .. image:: https://travis-ci.org/cedric-vincent/PRoot.png?branch=master
+     :target: https://travis-ci.org/cedric-vincent/PRoot
+
+- .. image:: https://coveralls.io/repos/cedric-vincent/PRoot/badge.png?branch=master
+     :target: https://coveralls.io/r/cedric-vincent/PRoot?branch=master
+
+- .. image:: https://scan.coverity.com/projects/602/badge.svg
+     :target: https://scan.coverity.com/projects/602
diff --git a/5.1.0/debian/changelog b/5.1.0/debian/changelog
new file mode 100644
index 0000000..375b5fe
--- /dev/null
+++ b/5.1.0/debian/changelog
@@ -0,0 +1,71 @@
+proot (5.1.0-1.3) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Add patch from upstream to add support for renameat2 system call (Closes:
+    #909581)
+
+ -- Johannes 'josch' Schauer <josch@debian.org>  Thu, 13 Dec 2018 06:13:02 +0100
+
+proot (5.1.0-1.2) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Add patch from upstream to fix simple invocation like "proot ls"
+    (Closes: #847292)
+  * Disable the seccomp-based tracing optimization, which just segfaults
+    with recent kernels (4.8.4+, according to upstream bug #160)
+
+ -- Simon McVittie <smcv@debian.org>  Sat, 14 Jan 2017 15:58:21 +0000
+
+proot (5.1.0-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Fix FTBFS on arm64, patch by Sebastian Ramacher (Closes: #788113).
+
+ -- Andrey Rahmatullin <wrar@debian.org>  Sat, 26 Nov 2016 22:12:08 +0500
+
+proot (5.1.0-1) unstable; urgency=low
+  * Upgrade to latest PRoot version
+    - PRoot is now embedding is own ELF interpreter
+
+ -- Rémi Duraffort <ivoire@videolan.org>  Tue, 27 Jan 2015 14:28:42 +0200
+
+proot (4.0.2-1) unstable; urgency=low
+  * Upgrade to latest PRoot version
+    - Experimental port of PRoot for AArch64
+  * Silent one wrong litian warning
+    - proot binary: spelling-error-in-binary usr/bin/proot tEH the
+
+ -- Rémi Duraffort <ivoire@videolan.org>  Fri, 12 Sep 2014 09:59:21 +0200
+
+proot (4.0.1-1) unstable; urgency=low
+  * Upgrade to latest PRoot version
+    - Fix issue with CWD (Closes: #756935)
+  * debian/patches/Fix-man-syntax.diff: correct typographic mistakes in the
+    manpage
+
+ -- Rémi Duraffort <ivoire@videolan.org>  Wed, 06 Aug 2014 13:02:57 +0200
+
+proot (4.0.0-1) unstable; urgency=low
+  * Upgrade to latest PRoot version
+
+ -- Rémi Duraffort <ivoire@videolan.org>  Tue, 08 Jul 2014 15:18:03 +0200
+
+proot (3.2.2-1) unstable; urgency=low
+
+  * Upgrade to latest PRoot version (Closes: #730363)
+  * Only build for supported architectures (Closes: #733247)
+  * Silent one wrong lintian warning
+  * Upgrade Standards Version to 3.9.5
+  * Use DEP-3 format for patches
+  * Fix copyright holders
+  * Build with hardening
+  * Print the full command line while building
+  * Add a watch file
+
+ -- Rémi Duraffort <ivoire@videolan.org>  Wed, 29 Jan 2014 13:15:20 +0200
+
+proot (3.0.2-1) unstable; urgency=low
+
+  * Initial release (Closes: #701894)
+
+ -- Rémi Duraffort <ivoire@videolan.org>  Wed, 03 Jul 2013 11:13:33 +0200
diff --git a/5.1.0/debian/compat b/5.1.0/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/5.1.0/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/5.1.0/debian/control b/5.1.0/debian/control
new file mode 100644
index 0000000..bbd699e
--- /dev/null
+++ b/5.1.0/debian/control
@@ -0,0 +1,27 @@
+Source: proot
+Section: utils
+Priority: optional
+Maintainer: Rémi Duraffort <ivoire@videolan.org>
+Build-Depends: debhelper (>= 9.0.0), libtalloc-dev
+Standards-Version: 3.9.5
+Homepage: http://proot.me
+Vcs-Git: git://github.com/ivoire/PRoot-debian
+Vcs-Browser: https://github.com/ivoire/proot-debian
+
+Package: proot
+Architecture: amd64 arm64 armel armhf i386 sh4 x32
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: emulate chroot, bind mount and binfmt_misc for non-root users
+ PRoot is a user-space implementation of chroot, mount --bind,
+ and binfmt_misc.
+ .
+ This means that users don't need any privileges or setup to do things like
+ using an arbitrary directory as the new root filesystem, making files
+ accessible somewhere else in the filesystem hierarchy, or executing programs
+ built for another CPU architecture transparently through QEMU user-mode.
+ .
+ Also, developers can add their own features or use PRoot as a Linux process
+ instrumentation engine thanks to its extension mechanism.
+ .
+ Technically PRoot relies on ptrace, an unprivileged system-call available in
+ every Linux kernel.
diff --git a/5.1.0/debian/copyright b/5.1.0/debian/copyright
new file mode 100644
index 0000000..3f1e383
--- /dev/null
+++ b/5.1.0/debian/copyright
@@ -0,0 +1,28 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: proot
+Source: http://proot.me
+
+Files: *
+Copyright: 2013, STMicroelectronics
+License: GPL-2+
+
+Files: debian/*
+Copyright: 2013, Rémi Duraffort <ivoire@videolan.org>
+License: GPL-2+
+
+License: GPL-2+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
diff --git a/5.1.0/debian/docs b/5.1.0/debian/docs
new file mode 100644
index 0000000..496ece0
--- /dev/null
+++ b/5.1.0/debian/docs
@@ -0,0 +1 @@
+doc/proot/manual.txt
diff --git a/5.1.0/debian/patches/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch b/5.1.0/debian/patches/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch
new file mode 100644
index 0000000..af38669
--- /dev/null
+++ b/5.1.0/debian/patches/0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch
@@ -0,0 +1,202 @@
+From fd417981bea00250128274a4f2d196ee1c10c6ea Mon Sep 17 00:00:00 2001
+From: Kimon Hoffmann <Kimon.Hoffmann@lawo.com>
+Date: Wed, 10 Oct 2018 13:10:07 +0200
+Subject: [PATCH] Properly filter the renameat2 syscall introduced in Linux
+ v3.15.
+
+Handle the renameat2 syscall analogous to renameat, as their only
+difference is an additional flags attribute, which isn't relevant to
+the path based adjustments performed by proot.
+
+Removed erroneous syscall entry from arm64 table.
+---
+ src/extension/kompat/kompat.c | 19 +++++++++++++++++++
+ src/syscall/enter.c           |  1 +
+ src/syscall/exit.c            |  3 ++-
+ src/syscall/seccomp.c         |  1 +
+ src/syscall/sysnums-arm.h     |  5 +++++
+ src/syscall/sysnums-arm64.h   |  5 ++++-
+ src/syscall/sysnums-i386.h    |  4 ++++
+ src/syscall/sysnums-sh4.h     |  5 +++++
+ src/syscall/sysnums-x32.h     |  4 ++++
+ src/syscall/sysnums-x86_64.h  |  4 ++++
+ src/syscall/sysnums.list      |  5 ++++-
+ 11 files changed, 53 insertions(+), 3 deletions(-)
+
+--- a/src/extension/kompat/kompat.c
++++ b/src/extension/kompat/kompat.c
+@@ -509,6 +509,24 @@ static int handle_sysenter_end(Tracee *t
+ 		return 0;
+ 	}
+ 
++	case PR_renameat2: {
++		Modif modif = {
++			.expected_release = KERNEL_VERSION(3,15,0),
++			.new_sysarg_num   = PR_rename,
++			.shifts = { [0] = {
++					.sysarg  = SYSARG_2,
++					.nb_args = 1,
++					.offset  =-1 },
++				    [1] = {
++					    .sysarg  = SYSARG_4,
++					    .nb_args = 1,
++					    .offset  = -2 }
++			}
++		};
++		modify_syscall(tracee, config, &modif);
++		return 0;
++	}
++
+ 	case PR_signalfd4: {
+ 		bool modified;
+ 		Modif modif = {
+@@ -968,6 +986,7 @@ static FilteredSysnum filtered_sysnums[]
+ 	{ PR_pselect6, 		0 },
+ 	{ PR_readlinkat, 	0 },
+ 	{ PR_renameat, 		0 },
++	{ PR_renameat2,		0 },
+ 	{ PR_setdomainname,	FILTER_SYSEXIT },
+ 	{ PR_sethostname,	FILTER_SYSEXIT },
+ 	{ PR_signalfd4, 	FILTER_SYSEXIT },
+--- a/src/syscall/enter.c
++++ b/src/syscall/enter.c
+@@ -532,6 +532,7 @@ int translate_syscall_enter(Tracee *trac
+ 		break;
+ 
+ 	case PR_renameat:
++	case PR_renameat2:
+ 		olddirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+ 		newdirfd = peek_reg(tracee, CURRENT, SYSARG_3);
+ 
+--- a/src/syscall/exit.c
++++ b/src/syscall/exit.c
+@@ -231,7 +231,8 @@ void translate_syscall_exit(Tracee *trac
+ 		break;
+ 
+ 	case PR_rename:
+-	case PR_renameat: {
++	case PR_renameat:
++	case PR_renameat2: {
+ 		char old_path[PATH_MAX];
+ 		char new_path[PATH_MAX];
+ 		ssize_t old_length;
+--- a/src/syscall/seccomp.c
++++ b/src/syscall/seccomp.c
+@@ -383,6 +383,7 @@ static FilteredSysnum proot_sysnums[] =
+ 	{ PR_removexattr,	0 },
+ 	{ PR_rename,		FILTER_SYSEXIT },
+ 	{ PR_renameat,		FILTER_SYSEXIT },
++	{ PR_renameat2,		FILTER_SYSEXIT },
+ 	{ PR_rmdir,		0 },
+ 	{ PR_setxattr,		0 },
+ 	{ PR_socketcall,	FILTER_SYSEXIT },
+--- a/src/syscall/sysnums-arm.h
++++ b/src/syscall/sysnums-arm.h
+@@ -335,4 +335,9 @@ static const Sysnum sysnums_arm[] = {
+ 	[ 375 ] = PR_setns,
+ 	[ 376 ] = PR_process_vm_readv,
+ 	[ 377 ] = PR_process_vm_writev,
++	[ 378 ] = PR_kcmp,
++	[ 379 ] = PR_finit_module,
++	[ 380 ] = PR_sched_setattr,
++	[ 381 ] = PR_sched_getattr,
++	[ 382 ] = PR_renameat2,
+ };
+--- a/src/syscall/sysnums-arm64.h
++++ b/src/syscall/sysnums-arm64.h
+@@ -259,5 +259,8 @@ static const Sysnum sysnums_arm64[] = {
+ 	[ 270 ] = PR_process_vm_readv,
+ 	[ 271 ] = PR_process_vm_writev,
+ 	[ 272 ] = PR_kcmp,
+-	[ 273 ] = PR_syscalls,
++	[ 273 ] = PR_finit_module,
++	[ 274 ] = PR_sched_setattr,
++	[ 275 ] = PR_sched_getattr,
++	[ 276 ] = PR_renameat2,
+ };
+--- a/src/syscall/sysnums-i386.h
++++ b/src/syscall/sysnums-i386.h
+@@ -347,4 +347,8 @@ static const Sysnum sysnums_i386[] = {
+ 	[ 347 ] = PR_process_vm_readv,
+ 	[ 348 ] = PR_process_vm_writev,
+ 	[ 349 ] = PR_kcmp,
++	[ 350 ] = PR_finit_module,
++	[ 351 ] = PR_sched_setattr,
++	[ 352 ] = PR_sched_getattr,
++	[ 353 ] = PR_renameat2,
+ };
+--- a/src/syscall/sysnums-sh4.h
++++ b/src/syscall/sysnums-sh4.h
+@@ -339,4 +339,9 @@ static const Sysnum sysnums_sh4[] = {
+ 	[ 364 ] = PR_setns,
+ 	[ 365 ] = PR_process_vm_readv,
+ 	[ 366 ] = PR_process_vm_writev,
++	[ 367 ] = PR_kcmp,
++	[ 368 ] = PR_finit_module,
++	[ 369 ] = PR_sched_setattr,
++	[ 370 ] = PR_sched_getattr,
++	[ 371 ] = PR_renameat2,
+ };
+--- a/src/syscall/sysnums-x32.h
++++ b/src/syscall/sysnums-x32.h
+@@ -272,6 +272,10 @@ static const Sysnum sysnums_x32[] = {
+ 	[ 308 ] = PR_setns,
+ 	[ 309 ] = PR_getcpu,
+ 	[ 312 ] = PR_kcmp,
++	[ 313 ] = PR_finit_module,
++	[ 314 ] = PR_sched_setattr,
++	[ 315 ] = PR_sched_getattr,
++	[ 316 ] = PR_renameat2,
+ 	[ 512 ] = PR_rt_sigaction,
+ 	[ 513 ] = PR_rt_sigreturn,
+ 	[ 514 ] = PR_ioctl,
+--- a/src/syscall/sysnums-x86_64.h
++++ b/src/syscall/sysnums-x86_64.h
+@@ -314,4 +314,8 @@ static const Sysnum sysnums_x86_64[] = {
+ 	[ 310 ] = PR_process_vm_readv,
+ 	[ 311 ] = PR_process_vm_writev,
+ 	[ 312 ] = PR_kcmp,
++	[ 313 ] = PR_finit_module,
++	[ 314 ] = PR_sched_setattr,
++	[ 315 ] = PR_sched_getattr,
++	[ 316 ] = PR_renameat2,
+ };
+--- a/src/syscall/sysnums.list
++++ b/src/syscall/sysnums.list
+@@ -74,6 +74,7 @@ SYSNUM(fcntl)
+ SYSNUM(fcntl64)
+ SYSNUM(fdatasync)
+ SYSNUM(fgetxattr)
++SYSNUM(finit_module)
+ SYSNUM(flistxattr)
+ SYSNUM(flock)
+ SYSNUM(fork)
+@@ -251,6 +252,7 @@ SYSNUM(remap_file_pages)
+ SYSNUM(removexattr)
+ SYSNUM(rename)
+ SYSNUM(renameat)
++SYSNUM(renameat2)
+ SYSNUM(request_key)
+ SYSNUM(restart_syscall)
+ SYSNUM(rmdir)
+@@ -265,10 +267,12 @@ SYSNUM(rt_tgsigqueueinfo)
+ SYSNUM(sched_get_priority_max)
+ SYSNUM(sched_get_priority_min)
+ SYSNUM(sched_getaffinity)
++SYSNUM(sched_getattr)
+ SYSNUM(sched_getparam)
+ SYSNUM(sched_getscheduler)
+ SYSNUM(sched_rr_get_interval)
+ SYSNUM(sched_setaffinity)
++SYSNUM(sched_setattr)
+ SYSNUM(sched_setparam)
+ SYSNUM(sched_setscheduler)
+ SYSNUM(sched_yield)
+@@ -351,7 +355,6 @@ SYSNUM(sync)
+ SYSNUM(sync_file_range)
+ SYSNUM(sync_file_range2)
+ SYSNUM(syncfs)
+-SYSNUM(syscalls)
+ SYSNUM(sysfs)
+ SYSNUM(sysinfo)
+ SYSNUM(syslog)
diff --git a/5.1.0/debian/patches/Fix-man-syntax.diff b/5.1.0/debian/patches/Fix-man-syntax.diff
new file mode 100644
index 0000000..a01273e
--- /dev/null
+++ b/5.1.0/debian/patches/Fix-man-syntax.diff
@@ -0,0 +1,18 @@
+Author: Rémi Duraffort <ivoire@videolan.org>
+Description: Correct typographic mistakes in the manpage
+Forwarded: yes
+Last-Update: 2015-01-27
+
+Index: proot-5.1.0/doc/proot/man.1
+===================================================================
+--- proot-5.1.0.orig/doc/proot/man.1
++++ proot-5.1.0/doc/proot/man.1
+@@ -2,7 +2,7 @@
+ .
+ .TH PROOT 1 "2014-12-12" "5.1.0" ""
+ .SH NAME
+-PRoot \- chroot, mount --bind, and binfmt_misc without privilege/setup
++PRoot \- chroot, mount \-\-bind, and binfmt_misc without privilege/setup
+ .
+ .nr rst2man-indent-level 0
+ .
diff --git a/5.1.0/debian/patches/Install-proot-into-DESTDIR-usr-bin.patch b/5.1.0/debian/patches/Install-proot-into-DESTDIR-usr-bin.patch
new file mode 100644
index 0000000..99a8d2c
--- /dev/null
+++ b/5.1.0/debian/patches/Install-proot-into-DESTDIR-usr-bin.patch
@@ -0,0 +1,23 @@
+Author: Rémi Duraffort <ivoire@videolan.org>
+Description: Install proot into $(DESTDIR)/usr/bin/
+Forwarded: not-needed
+Last-Update: 2015-01-27
+
+--- a/src/GNUmakefile
++++ b/src/GNUmakefile
+@@ -230,13 +230,13 @@
+ 	-$(RM) -f $(CHECK_OBJECTS) $(CHECK_PROGRAMS) $(CHECK_RESULTS) $(OBJECTS) $(CARE_OBJECTS) $(LOADER_OBJECTS) $(LOADER-m32_OBJECTS) proot care loader/loader loader/loader-m32 cli/care-manual.o $(DEPS) build.h licenses
+ 
+ install: proot
+-	$($(quiet)INSTALL) -D $< $(DESTDIR)/$<
++	$($(quiet)INSTALL) -D $< $(DESTDIR)/usr/bin/$<
+ 
+ install-care: care
+ 	$($(quiet)INSTALL) -D $< $(DESTDIR)/$<
+ 
+ uninstall:
+-	-$(RM) -f $(DESTDIR)/proot
++	-$(RM) -f $(DESTDIR)/usr/bin/proot
+ 
+ uninstall-care:
+ 	-$(RM) -f $(DESTDIR)/care
diff --git a/5.1.0/debian/patches/arm64.patch b/5.1.0/debian/patches/arm64.patch
new file mode 100644
index 0000000..7ca3695
--- /dev/null
+++ b/5.1.0/debian/patches/arm64.patch
@@ -0,0 +1,134 @@
+diff -ru proot-5.1.0.orig/src/arch.h proot-5.1.0/src/arch.h
+--- proot-5.1.0.orig/src/arch.h
++++ proot-5.1.0/src/arch.h
+@@ -125,6 +125,9 @@
+     #define OFFSETOF_STAT_UID_32 0
+     #define OFFSETOF_STAT_GID_32 0
+ 
++    #define EXEC_PIC_ADDRESS   0x500000000000
++    #define INTERP_PIC_ADDRESS 0x6f0000000000
++
+ #elif defined(ARCH_X86)
+ 
+     #define SYSNUMS_HEADER1 "syscall/sysnums-i386.h"
+diff -ru proot-5.1.0.orig/src/loader/assembly-arm64.h proot-5.1.0/src/loader/assembly-arm64.h
+--- /dev/null
++++ proot-5.1.0/src/loader/assembly-arm64.h
+@@ -0,0 +1,93 @@
++/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
++ *
++ * This file is part of PRoot.
++ *
++ * Copyright (C) 2014 STMicroelectronics
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301 USA.
++ */
++
++#define BRANCH(stack_pointer, destination) do {			\
++	asm volatile (						\
++		"// Restore initial stack pointer.	\n\t"	\
++		"mov sp, %0				\n\t"	\
++		"					\n\t"	\
++		"// Clear rtld_fini.			\n\t"	\
++		"mov x0, #0				\n\t"	\
++		"					\n\t"	\
++		"// Start the program.			\n\t"	\
++		"br %1					\n"	\
++		: /* no output */				\
++		: "r" (stack_pointer), "r" (destination)	\
++		: "memory", "sp", "x0");			\
++	__builtin_unreachable();				\
++	} while (0)
++
++#define PREPARE_ARGS_1(arg1_)				\
++	register word_t arg1 asm("x0") = arg1_;		\
++
++#define PREPARE_ARGS_3(arg1_, arg2_, arg3_)		\
++	PREPARE_ARGS_1(arg1_)				\
++	register word_t arg2 asm("x1") = arg2_;		\
++	register word_t arg3 asm("x2") = arg3_;		\
++
++#define PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_)	\
++	PREPARE_ARGS_3(arg1_, arg2_, arg3_)		\
++	register word_t arg4 asm("x3") = arg4_;
++
++#define PREPARE_ARGS_6(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_)	\
++	PREPARE_ARGS_3(arg1_, arg2_, arg3_)				\
++	register word_t arg4 asm("x3") = arg4_;				\
++	register word_t arg5 asm("x4") = arg5_;				\
++	register word_t arg6 asm("x5") = arg6_;
++
++#define OUTPUT_CONTRAINTS_1			\
++	"r" (arg1)
++
++#define OUTPUT_CONTRAINTS_3			\
++	OUTPUT_CONTRAINTS_1,			\
++	"r" (arg2), "r" (arg3)
++
++#define OUTPUT_CONTRAINTS_4			\
++	OUTPUT_CONTRAINTS_3,			\
++	"r" (arg4)
++
++#define OUTPUT_CONTRAINTS_6				\
++	OUTPUT_CONTRAINTS_3,				\
++	"r" (arg4), "r" (arg5), "r" (arg6)
++
++#define SYSCALL(number_, nb_args, args...)			\
++	({							\
++		register word_t number asm("w8") = number_;	\
++		register word_t result asm("x0");		\
++		PREPARE_ARGS_##nb_args(args)			\
++			asm volatile (				\
++				"svc #0x00000000	\n\t"	\
++				: "=r" (result)			\
++				: "r" (number),			\
++				OUTPUT_CONTRAINTS_##nb_args	\
++				: "memory");			\
++			result;					\
++	})
++
++#define OPENAT	56
++#define CLOSE	57
++#define MMAP	222
++#define MMAP_OFFSET_SHIFT 0
++#define EXECVE	221
++#define EXIT	93
++#define PRCTL	167
++
+diff -ru proot-5.1.0.orig/src/loader/loader.c proot-5.1.0/src/loader/loader.c
+--- proot-5.1.0.orig/src/loader/loader.c
++++ proot-5.1.0/src/loader/loader.c
+@@ -39,6 +39,8 @@
+ #    include "loader/assembly-x86_64.h"
+ #elif defined(ARCH_ARM_EABI)
+ #    include "loader/assembly-arm.h"
++#elif defined(ARCH_ARM64)
++#    include "loader/assembly-arm64.h"
+ #elif defined(ARCH_X86)
+ #    include "loader/assembly-x86.h"
+ #else
+@@ -134,7 +136,11 @@
+ 			/* Fall through.  */
+ 
+ 		case LOAD_ACTION_OPEN:
++#ifdef OPENAT
++			fd = SYSCALL(OPENAT, 4, AT_FDCWD, stmt->open.string_address, O_RDONLY, 0);
++#else
+ 			fd = SYSCALL(OPEN, 3, stmt->open.string_address, O_RDONLY, 0);
++#endif
+ 			if (unlikely((int) fd < 0))
+ 				FATAL();
+ 
diff --git a/5.1.0/debian/patches/disable-seccomp-based-tracing-performanc b/5.1.0/debian/patches/disable-seccomp-based-tracing-performanc
new file mode 100644
index 0000000..c340de6
--- /dev/null
+++ b/5.1.0/debian/patches/disable-seccomp-based-tracing-performanc
@@ -0,0 +1,24 @@
+From: Simon McVittie <smcv@debian.org>
+Date: Sat, 14 Jan 2017 15:52:13 +0000
+X-Dgit-Generated: 5.1.0-1.2 dcc5f0999759be03aed5b62a8683e0b965d0219d
+Subject: Disable seccomp-based tracing performance improvement
+
+It is faster (according to upstream documentation), but on current
+(4.8.4+) kernels it just segfaults. Software that works slowly seems
+better than software that doesn't work at all.
+
+Bug: https://github.com/proot-me/PRoot/issues/106
+
+---
+
+--- proot-5.1.0.orig/src/GNUmakefile
++++ proot-5.1.0/src/GNUmakefile
+@@ -105,7 +105,7 @@ CHECK_VERSION = VERSION=$$($(GIT) descri
+ 		then /bin/echo -e "\#undef VERSION\n\#define VERSION \"$${VERSION}\""; \
+ 		fi;
+ 
+-CHECK_FEATURES = process_vm seccomp_filter
++CHECK_FEATURES = process_vm
+ CHECK_PROGRAMS = $(foreach feature,$(CHECK_FEATURES),.check_$(feature))
+ CHECK_OBJECTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).o)
+ CHECK_RESULTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).res)
diff --git a/5.1.0/debian/patches/fix-use-of-size b/5.1.0/debian/patches/fix-use-of-size
new file mode 100644
index 0000000..53d001b
--- /dev/null
+++ b/5.1.0/debian/patches/fix-use-of-size
@@ -0,0 +1,40 @@
+From: Nicolas Cornu <ncornu@aldebaran.com>
+Date: Wed, 29 Jul 2015 14:52:57 +0200
+X-Dgit-Generated: 5.1.0-1.2 37bdc8d26bc0fd1af13142dd34dc11ae2ac2564a
+Subject: Fix use of size
+
+Applied-upstream: 5.1.1, commit:d649854ddb66779950954aac99d960379c631a71
+Bug: https://github.com/proot-me/PRoot/pull/108
+Bug-Debian: https://bugs.debian.org/847292
+
+---
+
+--- proot-5.1.0.orig/src/execve/enter.c
++++ proot-5.1.0/src/execve/enter.c
+@@ -454,10 +454,10 @@ static int expand_runner(Tracee* tracee,
+ }
+ 
+ extern unsigned char _binary_loader_exe_start;
+-extern unsigned char _binary_loader_exe_size;
++extern unsigned char _binary_loader_exe_end;
+ 
+ extern unsigned char WEAK _binary_loader_m32_exe_start;
+-extern unsigned char WEAK _binary_loader_m32_exe_size;
++extern unsigned char WEAK _binary_loader_m32_exe_end;
+ 
+ /**
+  * Extract the built-in loader.  This function returns NULL if an
+@@ -483,11 +483,11 @@ static char *extract_loader(const Tracee
+ 
+ 	if (wants_32bit_version) {
+ 		start = (void *) &_binary_loader_m32_exe_start;
+-		size  = (size_t) &_binary_loader_m32_exe_size;
++		size  = (size_t)(&_binary_loader_m32_exe_end-&_binary_loader_m32_exe_start);
+ 	}
+ 	else {
+ 		start = (void *) &_binary_loader_exe_start;
+-		size  = (size_t) &_binary_loader_exe_size;
++		size  = (size_t) (&_binary_loader_exe_end-&_binary_loader_exe_start);
+ 	}
+ 
+ 	status2 = write(fd, start, size);
diff --git a/5.1.0/debian/patches/series b/5.1.0/debian/patches/series
new file mode 100644
index 0000000..3e37338
--- /dev/null
+++ b/5.1.0/debian/patches/series
@@ -0,0 +1,6 @@
+Install-proot-into-DESTDIR-usr-bin.patch
+Fix-man-syntax.diff
+arm64.patch
+fix-use-of-size
+disable-seccomp-based-tracing-performanc
+0001-Properly-filter-the-renameat2-syscall-introduced-in-.patch
diff --git a/5.1.0/debian/proot.manpages b/5.1.0/debian/proot.manpages
new file mode 100644
index 0000000..5d35424
--- /dev/null
+++ b/5.1.0/debian/proot.manpages
@@ -0,0 +1 @@
+doc/proot/proot.1
diff --git a/5.1.0/debian/rules b/5.1.0/debian/rules
new file mode 100755
index 0000000..9fc0160
--- /dev/null
+++ b/5.1.0/debian/rules
@@ -0,0 +1,14 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+%:
+	dh $@ --sourcedirectory=src
+
+# Force make to print the commands
+# By default V=0
+override_dh_auto_build:
+	dh_auto_build -- V=1
+
+override_dh_installman:
+	mv doc/proot/man.1 doc/proot/proot.1
+	dh_installman
+	mv doc/proot/proot.1 doc/proot/man.1
diff --git a/5.1.0/debian/source/format b/5.1.0/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/5.1.0/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/5.1.0/debian/watch b/5.1.0/debian/watch
new file mode 100644
index 0000000..10b7474
--- /dev/null
+++ b/5.1.0/debian/watch
@@ -0,0 +1,2 @@
+version=3
+opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/PRoot-$1.tar.gz/ https://github.com/cedric-vincent/PRoot/releases .*/v?(\d\S*)\.tar\.gz
diff --git a/5.1.0/doc/GNUmakefile b/5.1.0/doc/GNUmakefile
new file mode 100644
index 0000000..b290017
--- /dev/null
+++ b/5.1.0/doc/GNUmakefile
@@ -0,0 +1,29 @@
+OUTPUTS = proot/man.1 proot.h proot/rpm-spec proot/index.html care.h care/index.html
+all: $(OUTPUTS)
+
+%/man.1: %/manual.txt
+	rst2man $< $@
+
+%.xml: %.txt
+	rst2xml --no-doctype $< $@
+
+%.html: %.txt
+	rst2html $< $@
+
+# Workaround to avoid unescaped C character.
+%/manual-quoted.txt: %/manual.txt
+	sed 's/"/\\\\"/g' $^ > $@
+
+%.h: %/stylesheets/cli.xsl %/manual-quoted.xml
+	xsltproc --output $@ $^
+
+%/rpm-spec:  %/stylesheets/rpm-spec.xsl %/manual.xml # %/changelog.txt
+	xsltproc --output $@ $^
+	echo "* $(shell date +'%a %b %d %Y') Cédric VINCENT <cedric.vincent@st.com>" >> $@
+	cat $*/changelog.txt >> $@
+
+%/index.html: stylesheets/website.xsl %/stylesheets/website.xsl %/manual.xml
+	xsltproc --output $@ $*/stylesheets/website.xsl $*/manual.xml
+
+clean:
+	rm -f *.xml $(OUTPUTS) *-quoted.*
diff --git a/5.1.0/doc/articles/extending_qemu-fig1.svg b/5.1.0/doc/articles/extending_qemu-fig1.svg
new file mode 100644
index 0000000..33cd2d1
--- /dev/null
+++ b/5.1.0/doc/articles/extending_qemu-fig1.svg
@@ -0,0 +1,1001 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="655.53192"
+   height="158.86346"
+   id="svg3593"
+   version="1.1"
+   inkscape:version="0.48.1 r9760"
+   sodipodi:docname="article-proot+qemu-fig2.svg">
+  <defs
+     id="defs3595">
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3615"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3617"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3619"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3621"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3623"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3625"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3627"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3629"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3631"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3633"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3635"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3637"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3639"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3641"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3643"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3645"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9-6"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3-1"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-5"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4-5"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3-6"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-56"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4-9"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9-74"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3-5"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-2"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4-54"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9-4"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3-4"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4-0"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9-8"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3-68"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-8"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4-4"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4078"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4080"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4082"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4084"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4086"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4088"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4090"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4092"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3-61"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-59"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4-49"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4212"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4214"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4216"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4218"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4220"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4222"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4224"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4226"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-9-81"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4780-3-2"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-9"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4-3"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4324"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4326"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4328"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4330"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4332"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4334"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4336"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4338"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.6"
+     inkscape:cx="540.32222"
+     inkscape:cy="44.525493"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="748"
+     inkscape:window-x="0"
+     inkscape:window-y="30"
+     inkscape:window-maximized="1"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:snap-global="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3912"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata3598">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(42.406933,-519.46875)">
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:none"
+       id="rect4419"
+       width="90.000015"
+       height="20"
+       x="392.8588"
+       y="549.73834" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3878"
+       width="90.000015"
+       height="40"
+       x="392.8588"
+       y="529.73834"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="397.8588"
+       y="544.73834"
+       id="text3880"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3882"
+         x="397.8588"
+         y="544.73834"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans">process 1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="412.8588"
+       y="564.73834"
+       id="text3903"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans"
+         sodipodi:role="line"
+         id="tspan3905"
+         x="412.8588"
+         y="564.73834">QEMU</tspan></text>
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3878-5"
+       width="60.000015"
+       height="20"
+       x="467.8588"
+       y="584.73834" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4748"
+       y="599.73834"
+       x="472.8588"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       xml:space="preserve"><tspan
+         y="599.73834"
+         x="472.8588"
+         id="tspan4750"
+         sodipodi:role="line">PRoot</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text4748-3"
+       y="614.41302"
+       x="-477.38126"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       xml:space="preserve"
+       transform="scale(-1,1)"><tspan
+         y="614.41302"
+         x="-477.38126"
+         id="tspan4750-7"
+         sodipodi:role="line" /></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="372.15564"
+       y="503.67035"
+       id="text5416"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5418"
+         x="372.15564"
+         y="503.67035" /></text>
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3878-5-4"
+       width="100.00002"
+       height="20"
+       x="447.8588"
+       y="619.73834" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="452.8588"
+       y="634.73834"
+       id="text5420"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5422"
+         x="452.8588"
+         y="634.73834">host kernel</tspan></text>
+    <g
+       transform="translate(322.95256,547.05085)"
+       id="g4554-8" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="489.8588"
+       y="549.73834"
+       id="text6457"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan6459"
+         x="489.8588"
+         y="549.73834">...</tspan></text>
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:none"
+       id="rect4419-0"
+       width="89.999985"
+       height="20"
+       x="512.85883"
+       y="549.73834" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3878-9"
+       width="89.999985"
+       height="40"
+       x="512.85883"
+       y="529.73834"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="517.85883"
+       y="544.73834"
+       id="text3880-3"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3882-6"
+         x="517.85883"
+         y="544.73834"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans">process <tspan
+   style="font-style:italic;-inkscape-font-specification:Sans Italic"
+   id="tspan3359">N</tspan></tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="532.85883"
+       y="564.73834"
+       id="text3903-0"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans"
+         sodipodi:role="line"
+         id="tspan3905-6"
+         x="532.85883"
+         y="564.73834">QEMU</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow2Lstart-9);marker-end:url(#Arrow2Lend-2);display:inline"
+       d="m 497.85881,604.73834 0,15"
+       id="path8719-4-3"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow2Lstart-9);marker-end:url(#Arrow2Lend-2);display:inline"
+       d="m 457.85881,569.73834 40,15"
+       id="path8719-4-3-7"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow2Lstart-9);marker-end:url(#Arrow2Lend-2);display:inline"
+       d="m 497.85881,584.73834 39.61431,-15.05459"
+       id="path8719-4-3-7-7"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       sodipodi:nodetypes="cc" />
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:none"
+       id="rect4419-09"
+       width="90.000015"
+       height="20"
+       x="242.85881"
+       y="549.73834" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3878-1"
+       width="90.000015"
+       height="40"
+       x="242.85881"
+       y="529.73834"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="247.85881"
+       y="544.73834"
+       id="text3880-7"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3882-7"
+         x="247.85881"
+         y="544.73834"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans">process 1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="262.8588"
+       y="564.73834"
+       id="text3903-1"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans"
+         sodipodi:role="line"
+         id="tspan3905-1"
+         x="262.8588"
+         y="564.73834">QEMU</tspan></text>
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3878-5-4-67"
+       width="100.00002"
+       height="20"
+       x="237.8588"
+       y="619.73834" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="242.8588"
+       y="634.73834"
+       id="text5420-3"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5422-6"
+         x="242.8588"
+         y="634.73834">host kernel</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow2Lstart-9);marker-end:url(#Arrow2Lend-2);display:inline"
+       d="m 287.59307,570.00409 0,50"
+       id="path8719-4-3-3"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       sodipodi:nodetypes="cc" />
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:none"
+       id="rect4419-9"
+       width="220"
+       height="75"
+       x="-32.406933"
+       y="530.00409" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3878-5-4-8"
+       width="100.00002"
+       height="20"
+       x="27.858812"
+       y="619.73834" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="32.85881"
+       y="634.73834"
+       id="text5420-5"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5422-61"
+         x="32.85881"
+         y="634.73834">host kernel</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="69.858795"
+       y="549.73834"
+       id="text6457-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan6459-5"
+         x="69.858795"
+         y="549.73834">...</tspan></text>
+    <rect
+       style="fill:#cccccc;fill-opacity:1;stroke:none"
+       id="rect4419-0-9"
+       width="89.999985"
+       height="20"
+       x="92.858826"
+       y="549.73834" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="127.59306"
+       y="600.00409"
+       id="text3903-0-0"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans"
+         sodipodi:role="line"
+         id="tspan3905-6-3"
+         x="127.59306"
+         y="600.00409">QEMU</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow2Lstart-9);marker-end:url(#Arrow2Lend-2);display:inline"
+       d="m 77.858825,604.73834 0,15"
+       id="path8719-4-3-0"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow2Lstart-9);marker-end:url(#Arrow2Lend-2);display:inline"
+       d="m 37.593066,555.00409 25,25"
+       id="path8719-4-3-7-4"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.53149605;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow2Lstart-9);marker-end:url(#Arrow2Lend-2);display:inline"
+       d="m 67.593066,580.00409 50.000004,-25"
+       id="path8719-4-3-7-7-4"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       sodipodi:nodetypes="cc" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.53100002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.59300005, 1.59300005;stroke-dashoffset:0"
+       id="rect5446"
+       width="90"
+       height="20"
+       x="-27.406933"
+       y="535.00409" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="-22.406933"
+       y="550.00409"
+       id="text3880-8"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3882-8"
+         x="-22.406933"
+         y="550.00409"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans">process 1</tspan></text>
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.53100002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.59300005, 1.59300005;stroke-dashoffset:0"
+       id="rect5446-7"
+       width="115"
+       height="20"
+       x="-22.406933"
+       y="580.00409" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="-17.406933"
+       y="595.00409"
+       id="text3880-8-4"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3882-8-4"
+         x="-17.406933"
+         y="595.00409"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans">guest kernel</tspan></text>
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.53100002;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.59300005, 1.59300005;stroke-dashoffset:0"
+       id="rect5446-6"
+       width="90"
+       height="20"
+       x="92.593063"
+       y="535.00409" />
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="97.593063"
+       y="550.00409"
+       id="text3880-3-4"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3882-6-8"
+         x="97.593063"
+         y="550.00409"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans">process <tspan
+   style="font-style:italic;-inkscape-font-specification:Sans Italic"
+   id="tspan3359-1">N</tspan></tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="82.678574"
+       y="127.67435"
+       id="text5476"
+       sodipodi:linespacing="125%"
+       transform="translate(-37.406934,519.47259)"><tspan
+         sodipodi:role="line"
+         id="tspan5478"
+         x="82.678574"
+         y="127.67435" /></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="12.593066"
+       y="665.00409"
+       id="text5480"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5482"
+         x="12.593066"
+         y="665.00409"
+         style="font-style:italic;-inkscape-font-specification:Sans Italic">(a) system-mode</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="232.59306"
+       y="665.00409"
+       id="text5484"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5486"
+         x="232.59306"
+         y="665.00409"
+         style="font-style:italic;-inkscape-font-specification:Sans Italic">(b) user-mode</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="407.59308"
+       y="665.00409"
+       id="text5488"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5490"
+         x="407.59308"
+         y="665.00409">(<tspan
+   style="font-style:italic;-inkscape-font-specification:Sans Italic"
+   id="tspan5492">c) user-mode + PRoot</tspan></tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="Layer"
+     transform="translate(5.0000028,0.00384)" />
+</svg>
diff --git a/5.1.0/doc/articles/extending_qemu-fig2.svg b/5.1.0/doc/articles/extending_qemu-fig2.svg
new file mode 100644
index 0000000..d98e5eb
--- /dev/null
+++ b/5.1.0/doc/articles/extending_qemu-fig2.svg
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="635.27875"
+   height="109.59689"
+   id="svg3024"
+   version="1.1"
+   inkscape:version="0.48.1 r9760"
+   sodipodi:docname="article-proot+qemu-fig1.svg">
+  <defs
+     id="defs3026">
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4783-4"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="277.09991"
+     inkscape:cy="-24.886332"
+     inkscape:document-units="px"
+     showgrid="true"
+     inkscape:window-width="1280"
+     inkscape:window-height="748"
+     inkscape:window-x="0"
+     inkscape:window-y="30"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg3024"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:snap-global="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3196"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata3029">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <text
+     xml:space="preserve"
+     style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+     x="9.1015625"
+     y="22.15625"
+     id="text3903"
+     sodipodi:linespacing="125%"><tspan
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans"
+       sodipodi:role="line"
+       id="tspan3905"
+       x="9.1015625"
+       y="22.15625">QEMU:</tspan></text>
+  <text
+     sodipodi:linespacing="125%"
+     id="text4748"
+     y="52.15625"
+     x="9.1015625"
+     style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+     xml:space="preserve"><tspan
+       y="52.15625"
+       x="9.1015625"
+       id="tspan4750"
+       sodipodi:role="line">PRoot:</tspan></text>
+  <text
+     sodipodi:linespacing="125%"
+     id="text4748-3"
+     y="52.5625"
+     x="-151.7334"
+     style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+     xml:space="preserve"
+     transform="scale(-1,1)"><tspan
+       y="52.5625"
+       x="-151.7334"
+       id="tspan4750-7"
+       sodipodi:role="line" /></text>
+  <text
+     xml:space="preserve"
+     style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+     x="46.507782"
+     y="-58.180161"
+     id="text5416"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5418"
+       x="46.507782"
+       y="-58.180161" /></text>
+  <text
+     xml:space="preserve"
+     style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+     x="9.1015625"
+     y="82.15625"
+     id="text5420"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5422"
+       x="9.1015625"
+       y="82.15625">host kernel:</tspan></text>
+  <g
+     transform="translate(-2.695314,-14.799687)"
+     id="g4554-8" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:2.02413559;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend-2)"
+     d="m 69.101562,28.58482 89.999998,0 L 170,99.596893 l 9.10156,-41.012072 90,0 10,40.000002 170,0 10,-40.000003 10,0 10,40.000003 10.83358,-60 132.65567,-0.487288"
+     id="path3181"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cccccccccccc" />
+  <text
+     sodipodi:linespacing="125%"
+     id="text4748-6"
+     y="52.15625"
+     x="179.10156"
+     style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
+     xml:space="preserve"><tspan
+       y="52.15625"
+       x="179.10156"
+       id="tspan4750-1"
+       sodipodi:role="line"
+       style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans Italic">translation</tspan></text>
+  <text
+     sodipodi:linespacing="125%"
+     id="text4748-6-9"
+     y="92.15625"
+     x="299.10156"
+     style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
+     xml:space="preserve"><tspan
+       y="92.15625"
+       x="299.10156"
+       id="tspan4750-1-2"
+       sodipodi:role="line"
+       style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans Italic">kernel operation</tspan><tspan
+       y="112.15625"
+       x="299.10156"
+       sodipodi:role="line"
+       id="tspan3324" /></text>
+  <text
+     sodipodi:linespacing="125%"
+     id="text4748-6-9-0"
+     y="22.15625"
+     x="69.101562"
+     style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
+     xml:space="preserve"><tspan
+       y="22.15625"
+       x="69.101562"
+       id="tspan4750-1-2-2"
+       sodipodi:role="line"
+       style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans Italic">system call</tspan><tspan
+       y="42.15625"
+       x="69.101562"
+       sodipodi:role="line"
+       id="tspan3324-3" /></text>
+  <text
+     sodipodi:linespacing="125%"
+     id="text4748-6-9-0-9"
+     y="32.15625"
+     x="489.10156"
+     style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
+     xml:space="preserve"><tspan
+       y="32.15625"
+       x="489.10156"
+       id="tspan4750-1-2-2-2"
+       sodipodi:role="line"
+       style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans Italic">result &amp; errno</tspan><tspan
+       y="52.15625"
+       x="489.10156"
+       sodipodi:role="line"
+       id="tspan3324-3-2" /></text>
+  <text
+     sodipodi:linespacing="125%"
+     id="text4748-6-9-0-9-9"
+     y="59.596893"
+     x="610"
+     style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
+     xml:space="preserve"><tspan
+       y="59.596893"
+       x="610"
+       id="tspan4750-1-2-2-2-2"
+       sodipodi:role="line"
+       style="font-size:16px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;font-family:Sans;-inkscape-font-specification:Sans Italic">t</tspan><tspan
+       y="79.596893"
+       x="610"
+       sodipodi:role="line"
+       id="tspan3324-3-2-0" /></text>
+</svg>
diff --git a/5.1.0/doc/articles/extending_qemu.txt b/5.1.0/doc/articles/extending_qemu.txt
new file mode 100644
index 0000000..e36f12d
--- /dev/null
+++ b/5.1.0/doc/articles/extending_qemu.txt
@@ -0,0 +1,220 @@
+.. include:: stylesheets/article-html.txt
+
+================================================
+Extending QEMU User-Mode with PRoot: Why and How
+================================================
+
+:Original Title:  PRoot: a Step Forward for QEMU User-Mode
+:Published at:    1st International QEMU Users' Forum
+:Authors:         Cédric Vincent & Yves Janin
+:PRoot Version:   0.5
+
+:Abstract:
+
+    This paper introduces PRoot, a new tool specifically designed to
+    extend QEMU user-mode.  We detail our motivations, compare with
+    other similar solutions and give first results.
+
+Extending QEMU User-Mode
+========================
+
+QEMU [C1]_ is an open-source hardware emulator with two main usages:
+in *system-mode* a whole guest machine is emulated to run a full
+operating system.  It can benefit from virtualization support like KVM
+to avoid the emulation of most CPU operations.  By contrast, QEMU
+*user-mode* only emulates the CPU to run one guest process at a time,
+and communications with the host kernel are converted by a thin layer.
+
+Our initial motivation was to use QEMU to ease the development of
+embedded Linux applications by emulating their build system and
+test-suites directly on developers' workstations.  During our
+experiments we found out that the system-mode was not fast enough and
+we decided to focus on the user-mode.  Unfortunately this latter
+cannot execute a tree of guest processes within a guest Linux
+distribution for reasons we detail in the next section.  To get the
+best of these two modes we developed PRoot, a tool fully compatible
+with QEMU that can be seen as an *extension* of the user-mode.
+
+
+Overcoming QEMU user-mode limitations with PRoot
+------------------------------------------------
+
+As illustrated by Figure 1 (a) and (b), QEMU should run faster for a
+given process in user-mode than in system-mode since it does not
+emulate the peripherals nor the guest kernel.  However the boundary
+between the guest environment and the host becomes *thinner*, and the
+host kernel now has to support some of the operations that were
+devoted to the guest kernel.  We can define three requirements that
+will guide us throughout the rest of this paper:
+
+R1
+    an efficient and correct path translation mechanism between the
+    guest and the host.  This feature is typically required to
+    emulate programs that perform absolute accesses to architecture
+    specific files such as the dynamic linker ``/lib/ld-linux.so``.
+    Note that a correct translation scheme must support relative paths
+    and symbolic links too.
+
+R2
+    the ability to spawn a new process and keep emulation running for
+    this new process.
+
+R3
+    the ability to run a host process program.  Strictly speaking R3
+    is not mandatory, but using *un-emulated* cross-compilers and
+    interpreters is particularly useful to speed-up build process and
+    test-suites.
+
+QEMU user-mode status for R1 and R2 is currently not satisfying.  For
+R1, QEMU user-mode has the ability to redirect file operations made by
+the guest process but it can take several minutes at each process
+creation to scan the guest Linux distribution.  Moreover there is no
+support for relative paths and symbolic links.
+
+Let us now consider R2.  From the point-of-view of the host kernel, an
+emulated process image P1 is actually an image of QEMU |Q1P1|.  When
+|Q1P1| executes a new program, the resultant process P2 is totally out
+of the control of QEMU.  As a conclusion R2 is not supported either.
+
+.. |Q1P1| replace:: Q1\ :sub:`P1`
+
+.. figure:: extending_qemu-fig1.svg
+
+   Figure 1: Guest process[es] running under QEMU, arrows are system calls flow
+
+The ambition of PRoot is to fulfill R1, R2 and later on R3, while
+keeping design, implementation and use as simple as possible.  Since
+PRoot is also used for validation purpose, it has to reproduce kernel
+results and errors as if the emulated applications were run in a
+native environment.
+
+PRoot is based on ``ptrace``, a Linux system call [C2]_ that is mainly
+used by debuggers or system call tracers such as ``strace`` and the
+GNU Debugger ``gdb``.  However since it provides unique facility to
+monitor and control processes, it can also be applied to a much wider
+range of applications bringing kernel-like features in user-space
+[C3]_ [C4]_.  With ``ptrace``, PRoot is able to catch every system
+call emitted by a QEMUlated process and dynamically redirect them as
+shown in Figure 2.  One of the main task in PRoot is the path
+canonicalization that translates paths from the guest world to the
+host world and vice versa (R1).  Additionally, when PRoot detects a
+new process about to be created, it can change the initial request and
+get a new instance of QEMU running the new process (R2) as shown in
+Figure 1 (c).
+
+.. figure:: extending_qemu-fig2.svg
+
+   Figure 2: Control flow of a syscall done by a guest process under QEMU+PRoot
+
+
+Results
+=======
+
+Experiments presented in this section were performed on a Pentium-4
+2.4GHz workstation with 1GiB of RAM running Slackware-13.1.
+Concerning the guest system, we used ARMedSlack-12.2 with QEMU-0.12.5
+configured to provide 256MiB of RAM when used in system-mode.
+
+
+Functional Comparison With Similar Tools
+----------------------------------------
+
+Table 1 exemplifies two Linux packages that are representative of the
+complexity of an embedded Linux distribution; Perl-5 requires a guest
+environment for its bootstrap whereas the Coreutils test-suite
+exhibits numerous limit configurations that can help to find
+unexpected behaviors or bugs.
+
+Many path translation tools already exist but few pass these tests
+(R1).  Fakechroot-2.14 and Fakeroot-Ng-0.17 fail.  Plash is a modified
+GNU C library and was therefore not considered, and we did not
+consider ``chroot`` either since it requires administration
+privileges.  Generally speaking, all these tools were not designed to
+support the execution of processes through an emulator (R2).
+
+Only PRoot and ScratchBox2 [C5]_ proved complete enough to configure,
+build and validate the two complex Linux packages.  Table 1 gives the
+results of their test-suites run with PRoot and ScratchBox2, it also
+gives system-mode results as a reference.
+
+.. table:: Table 1: Results of the packages' test-suites
+
+    ====================  ===============  ==========  ===========
+    Package                ScratchBox-2.2   PRoot-0.5  system-mode
+    ====================  ===============  ==========  ===========
+    Perl-5.10.0                     99.6%       99.6%        99.8%
+    GNU Coreutils-6.12              94.9%       97.3%        96.7%
+    ====================  ===============  ==========  ===========
+
+ScratchBox2 and PRoot have similar path canonicalization algorithms
+but differ in their design [#]_ and usage.  Unlike ScratchBox2, PRoot
+does not need any configuration and does not assume anything about the
+guest and host environments.  By contrast, ScratchBox2 is a highly
+flexible tool with scripting facility.  A complete technical
+comparison between ScratchBox2 and PRoot is beyond the scope of this
+paper, but we can safely conclude that both are functional enough to
+be already used in an industrial environment.  Choosing one instead
+another one depends on your expectations: simplicity with PRoot vs
+powerful customization with ScratchBox2.
+
+.. [#] ScratchBox2 relies on the dynamic linker to override system
+       call wrappers in the C library.
+
+
+Performance Comparison With QEMU System-Mode
+--------------------------------------------
+
+Table 2 compares performance of QEMU-0.12.5, first in user-mode with
+PRoot-0.5 and then in system-mode.  Timings were measured with the
+command ``time`` and we checked that the system-mode results were
+coherent with the host clock.
+
+.. table:: Table 2: Performance of PRoot+QEMU user-mode vs QEMU system-mode
+
+    ==================  ===============  ===============
+    stage                   Perl-5.10.0   Coreutils-6.12
+    ==================  ===============  ===============
+    archive extraction      3.6x faster      2.7x faster
+    configuration           2.0x faster      4.0x faster
+    build                   2.9x faster      3.5x faster
+    validation              4.1x faster      3.6x faster
+    ==================  ===============  ===============
+
+The speed-up with QEMU user-mode is quite impressive and comes from
+the fact that the guest kernel and the hardware are not emulated.  We
+think that all these results will be further improved when PRoot
+handles *un-emulated* cross-compilers and interpreters (R3).  This
+feature is still under development and looks promising.
+
+
+Conclusion
+==========
+
+The simple fact that PRoot requires no privilege or setup is a great
+advantage that should ease the usage of this *extended* user-mode.  It
+is worth mentioning that PRoot should work with any version of QEMU
+user-mode since no patch is needed, and in any Linux environment as
+well.  Finally, the current version of PRoot is mature enough to be
+already used in an industrial environment.
+
+
+References
+==========
+
+.. [C1] Bellard, F.: QEMU, a Fast and Portable Dynamic Translator.
+        USENIX Annual Technical Conference, FREENIX Track (2005)
+        41--46
+
+.. [C2] Kerrisk, M.: The Linux Programming Interface.  No Starch Press
+        (2010) 23, 43--46, 367--370
+
+.. [C3] Spillane, R. P., Wright, C. P., Sivathanu, G., Zadok, E.: Rapid
+        File System Development Using ptrace.  Proceedings of the 2007
+        Workshop on Experimental Computer Science (ExpCS'07), 22. ACM
+        (2007)
+
+.. [C4] Dike, J.: User-mode Linux.  Proceedings of the 5th Annual Linux
+        Showcase & Conference - Volume 5 (ALS'01). USENIX Association
+        (2001)
+
+.. [C5] ScratchBox2. http://www.freedesktop.org/wiki/Software/sbox2
diff --git a/5.1.0/doc/articles/howto_debian_rootfs.txt b/5.1.0/doc/articles/howto_debian_rootfs.txt
new file mode 100644
index 0000000..06bfdd7
--- /dev/null
+++ b/5.1.0/doc/articles/howto_debian_rootfs.txt
@@ -0,0 +1,209 @@
+.. include:: stylesheets/article-html.txt
+
+=======================================
+How to Set Up a Debian RootFS for PRoot
+=======================================
+
+:Original Title:  PRoot sorcery
+:URL:             http://ivoire.dinauz.org/blog/post/2012/04/16/PRoot-sorcery
+:Part of:         http://ivoire.dinauz.org/blog/tag/PRoot
+:Author:          Rémi Duraffort
+:PRoot Version:   1.8.3
+
+:Abstract:
+
+    A good practice for software developer is to provide a test suite
+    while developing a software. When developing for Linux, it's also
+    a good practice to compile the software and run the test suite on
+    many distributions like Debian, Ubuntu, Fedora, ArchLinux, Centos,
+    Slackware and for both i386 and x86_64.
+
+    Usually, softwares are compiled and tested on only one
+    distribution because setting up the right environment is long and
+    painful. Most of the time root privileges are also required to
+    setup such environment.
+
+    In this article and the following one, I will show that using
+    PRoot_, such testing is quite handy and can be done by any users.
+
+.. _PRoot: http://proot.me
+
+Getting PRoot up and running
+============================
+
+In order to test PRoot, you can download the latest version on the
+`official website`_ and compile it. You can also grab a package for
+your distribution on the `Open Build Service`_.
+
+.. _official website: http://proot.me
+.. _Open Build Service: http://software.opensuse.org/download.html?project=home:cedric-vincent&amp;package=proot
+
+If you choose to compile PRoot, that's just a matter of::
+
+    #!/bin/sh
+    git clone git://github.com/cedric-vincent/PRoot.git
+    cd PRoot/src
+    make
+    [...]
+    ./proot
+
+
+Grabbing a RootFS
+=================
+
+The second step to test VLC media player in different distributions is
+to get a root file system for every distribution we want to try.
+
+The first and easy way to have a working root file system is to
+download it from `OpenVZ repository`_ or `OpenVZ contribs`_.
+
+.. _OpenVZ repository: http://download.openvz.org/template/precreated/
+.. _OpenVZ contribs: http://download.openvz.org/template/precreated/contrib/
+
+It's also possible, under Debian and Ubuntu, to create a root file
+system using debootstrap, but let's take the easy way for today::
+
+    #!/bin/sh
+    % mkdir debian-6.0-x86_64
+    % cd debian-6.0-x86_64
+    % wget http://download.openvz.org/template/precreated/debian-6.0-x86_64.tar.gz
+    [...]
+    % tar xf debian-6.0-x86_64.tar.gz
+    % cd ..
+
+As we will see later, you can safely ignore the warnings printed by
+tar when extracting the file system. Let us note that everything is
+run as a normal user.
+
+Now you can "jump" into this new root file system using PRoot::
+
+    #!/bin/sh
+    % cat /etc/debian_version
+    wheezy/sid
+    % proot debian-6.0-x86_64
+    ~ cat /etc/debian_version
+    6.0.4
+
+For now on, the root file system is the one you just downloaded. For
+instance::
+
+     #!/bin/sh
+     ~ gcc --version
+     gcc (Debian 4.4.5-8) 4.4.5
+     ~ logout
+     % gcc --version
+     gcc (Debian 4.6.3-1) 4.6.3
+
+You just tested the first feature provided by PRoot:
+
+* Changing the root file system of a process
+
+As you may have noticed, I used ``%`` for the host file system shell
+prompt (a Debian Sid) and ``~`` for the PRooted one (a Debian
+Squeeze).
+
+
+Setting up the new RootFS
+=========================
+
+We now have a basic and working root file systems but some
+configuration has to be done before any real usages:
+
+* Adding the right users and groups to /etc/passwd and /etc/group
+* Configuring DNS resolution
+* Binding some special directories
+* Updating the system
+
+Normally, all this tasks can only be done by root as they will
+modifies files owned by root. As we extracted the archive as a normal
+user, the current user can modify any files in the root file system
+though making root privileges pointless.
+
+Adding some user and groups
+---------------------------
+
+In order to keep the same user inside the PRooted file system, you
+just have to copy the right lines from ``/etc/passwd`` to the
+corresponding file in the PRooted file system. You can do the same
+thing for groups in ``/etc/group``.
+
+Configuring DNS resolution
+--------------------------
+
+Just copy ``/etc/resolv.conf`` from the host root file system to the
+PRooted one. This way the same mechanism will be used in the host
+system and in the PRooted one.
+
+Another solution is to ask PRoot to do the job for you: binding
+/etc/resolv.conf to the same file in the PRooted file system. Adding
+``-b /etc/resolv.conf`` to the PRoot command line will do the trick::
+
+    #!/bin/sh
+    % proot debian-6.0-x86_66
+    ~ cat /etc/resolv.conf
+    cat: /etc/resolv.conf: No such file or directory
+    ~ logout
+    % proot -b /etc/resolv.conf debian-6.0-x86_64
+    ~ cat /etc/resolv.conf
+    [...]same file as /etc/resolv.conf on the host[...]
+
+You just tested the second feature provided by PRoot:
+
+* Binding some files to another location in the file system.
+
+In this case you bound /etc/resolv.conf to the same location inside
+the PRooted environment. It's also possible to bind it somewhere else
+with: ``-b /etc/resolv.conf:/Somewere_else_in_the_PRooted_FS``.
+
+Binding some special directories
+--------------------------------
+
+For the moment, the ``/dev`` and ``/proc`` directories are
+empty. However some programs need it in order to work correctly. For
+example ssh-keygen will refuse to work without ``/dev/random``.
+
+We should bind the real /dev and /proc in the new root file
+system. Adding ``-b /dev -b /proc`` to the PRoot command line will
+solve this issue.
+
+Updating the system
+-------------------
+
+We already noticed that the current user can modify any file on the
+PRooted file system because it was extracted by this user.
+
+However most tools like dpkg required the current user id to be root
+in order to work. For this reason, PRoot can be launched with the
+``-0`` (zero) option which fake some syscalls and makes the programs
+think the current user is root::
+
+    #!/bin/sh
+    % proot -b /etc/resolv.conf -0 debian-6.0-x86_64
+    ~ id -a
+    uid=0(root) gid=0(root) groupes=0(root)
+    ~ cat /etc/apt/source.list
+    deb http://ftp.debian.org/debian squeeze main contrib non-free
+    deb http://security.debian.org squeeze/updates main contrib non-free
+    ~ apt-get update
+    Hit http://ftp.debian.org squeeze Release.gpg
+    Ign http://ftp.debian.org/debian/ squeeze/contrib Translation-en
+    [...]
+    Reading package lists... Done
+    ~ apt-get upgrade
+    [...]
+
+You can manage this root file system like a classical one. Pay
+attention that some services that really required root privileges to
+work (like apache or some daemons) could not run correctly under PRoot
+as we only fake root privileges.
+
+Future work
+===========
+
+This article is beginning to be really long so I will finish here for
+today.
+
+We saw a simple way to get a working Debian root file systems that we
+can manage without real root privileges. This work will be useful for
+the next article which will cover the compilation and testing of VLC
+media player in this new root file system.
diff --git a/5.1.0/doc/articles/howto_migrate_from_scratchbox2.txt b/5.1.0/doc/articles/howto_migrate_from_scratchbox2.txt
new file mode 100644
index 0000000..80cbb93
--- /dev/null
+++ b/5.1.0/doc/articles/howto_migrate_from_scratchbox2.txt
@@ -0,0 +1,115 @@
+.. include:: stylesheets/article-html.txt
+
+========================================
+How to migrate from Scratchbox2 to PRoot
+========================================
+
+:Author:         Cédric Vincent
+:PRoot Version:  3.1
+
+:Abstract:
+
+    PRoot is designed with simplicity and consistency in mind, that's
+    why most of the Scratchbox2's concepts can be simulated in PRoot
+    with bindings and a wrapper only.  Obviously the comparison
+    between Scratchbox2 and PRoot is biased as I'm the maintainer of
+    PRoot.
+
+
+Target
+======
+
+In Scratchbox2, "target" is a name for a configuration that specifies
+the path to the guest rootfs and the path to the cross-compiler.
+
+PRoot doesn't consider a cross-compiler like a special tool, thus the
+user is free to execute it just like any other host programs, either
+through the /host-rootfs binding (default when using QEMU):
+
+    proot -q qemu-arm -r rootfs [...]
+    $ /host-rootfs/opt/cross-tools/arm-linux-gcc [...]
+
+or through a user-specified binding:
+
+     proot -b /opt/cross-tools/arm-linux-gcc:/usr/bin/gcc -q qemu-arm -r rootfs [...]
+     $ /usr/bin/gcc
+
+Also, PRoot has no configuration support on purpose, this lets the
+user free to forge the command-line with any programming languages
+(shell, Perl, Python, ...).  To me, this is more powerful than any
+configuration syntax.
+
+
+Execution Policy
+================
+
+In Scratchbox2, the view of the virtual file-system is automatically
+altered according to the executed program.  Here is a quote from
+"Scratchbox2: Internals and Architecture":
+
+    For example, /usr/lib/perl must be mapped to the target root when
+    target's perl is running, but to the corresponding place in the
+    tools directory [ed: where host tools are] when the other perl is
+    running.
+
+In PRoot, all processes see exactly the same virtual file-system,
+there's *no exception* at all.  For example, to use the host Perl the
+user can to adjust PERL5LIB explicitly or bind the host instance over
+the guest one:
+
+    proot -b /usr/bin/perl $bind_perl_modules [...]
+
+where $bind_perl_modules is the output of the following command:
+
+    perl -e 'print map { "-b $_ " } grep { m#^/# } @INC'
+
+
+Modes
+=====
+
+Scratchbox2 comes with 3 predefined mapping rule sets ("emulate",
+"simple" and "accel") that define how programs are executed (emulated
+or natively) and what are the default bindings.
+
+PRoot has 2 predefined binding sets: "none" ("-r" option) or
+"recommended" ("-R" option).  Regarding how a program is executed
+(emulated or natively), PRoot detects automatically if the binary is
+made for the host architecture or not, wherever it lies on the virtual
+file-system.
+
+
+Sessions
+========
+
+In Scratchbox2, a "session" is a "target" instance where the rules
+from a given "mode" (a.k.a mapping rule sets) are applied.  Also, the
+/tmp directory is "private" to each session.
+
+About the "target" and "mode" support in PRoot, please refer to the
+sections above.  About "private" directories, the user can simulate
+this feature by binding dedicated directories or files over "private"
+ones::
+
+    proot -b ~/tmp-session-01:/tmp [...]
+
+
+Network Namespace
+=================
+
+Scratchbox2 can translate network addresses.  This feature doesn't
+exist in PRoot but can be implemented easily, as an extension for
+instance.
+
+
+Permission Namespace
+====================
+
+Scratchbox2 (v2.4) has a permission engine that allows one to fake
+privileged operations, this engine is even more powerful than
+fakeroot's one.
+
+PRoot has a permission engine ("-0" option) that I want to keep as
+small as possible, its only purpose is to cheat package managers that
+does some [useless] sanity checks.  Note that fakeroot can also be
+used under PRoot.
+
diff --git a/5.1.0/doc/articles/stylesheets/article-html.txt b/5.1.0/doc/articles/stylesheets/article-html.txt
new file mode 100644
index 0000000..efef946
--- /dev/null
+++ b/5.1.0/doc/articles/stylesheets/article-html.txt
@@ -0,0 +1,11 @@
+.. raw:: html
+
+   <style>
+   body {
+       max-width: 45em;
+       min-width: 25em;
+       margin-left: auto;
+       margin-right: auto;
+       text-align: justify;
+   }
+   </style>
diff --git a/5.1.0/doc/care/changelog.txt b/5.1.0/doc/care/changelog.txt
new file mode 100644
index 0000000..1226bba
--- /dev/null
+++ b/5.1.0/doc/care/changelog.txt
@@ -0,0 +1,104 @@
+CARE v2.2
+=========
+
++ Special characters in environment variables are now correctly quoted
+  in the generated "re-execute.sh" script.  For instance, the value of
+  "COMP_WORDBREAKS" environment variable on Ubuntu used to make CARE
+  generate broken "re-execute.sh" scripts.
+
++ It is now possible to deliver CARE as a dynamically linked binary.
+  In this case, the self-extracting format is not supported since one
+  can't assume the re-execution environment contains all the
+  pre-requisites (libtalloc, libarchive, proot).  Thus, CARE and PRoot
+  should be deployed independently on the re-execution environment.
+
++ Syscall are now emulated only if it is really needed.
+
+This release is based on PRoot v4.0.3, so it contains all the
+following generic fixes too:
+
+  https://github.com/cedric-vincent/PRoot/releases/tag/v4.0.0
+  https://github.com/cedric-vincent/PRoot/releases/tag/v4.0.1
+  https://github.com/cedric-vincent/PRoot/releases/tag/v4.0.2
+  https://github.com/cedric-vincent/PRoot/releases/tag/v4.0.3
+
+
+CARE v2.1
+=========
+
+This release contains all the fixes from PRoot v3.2.2 [1] and the
+following new features:
+
++ CARE now supports three new archive formats:
+
+  - a self-extracting format, this has become the default behavior.
+    Here's an example::
+
+      somewhere$ care echo OK
+      [...]
+      OK
+      [...]
+      care info:   - run `./care-140115135934.bin` to extract the output archive.
+
+      elsewhere$ ./care-140115135934.bin
+       info: archive found: offset = 195816, size = 3035122
+       info: extracted: care-140115135934/rootfs/usr
+       info: extracted: care-140115135934/rootfs/usr/local
+       [...]
+       info: extracted: care-140115135934/re-execute.sh
+       info: extracted: care-140115135934/README.txt
+       info: extracted: care-140115135934/proot
+
+   - the GNU tar format, this is the most commonly used archive
+     format.  It can be combined with all the compression formats
+     supported by CARE: ".tar.gz" or ".tar.lzo".
+
+   - a "copy" format where the content is copied directly into a
+     directory instead of being archived in a file.  For instance::
+
+       $ care -o foo/ echo OK
+       [...]
+       $ ls foo
+       README.txt  proot  re-execute.sh  rootfs/
+
++ It is recommended to use the new "-x/--extract" option to extract
+  archives created by CARE, since most extracting tools -- that are
+  not based on libarchive -- are too limited to extract them
+  correctly.
+
++ CARE now returns the exit code from the re-executed command.  For
+  instance, with the previous version:
+
+    $ care-v2.0 -o test.cpio sh -c 'exit 1'
+    [...]
+    $ echo $?
+    1
+    [...]
+    $ test/re-execute.sh
+    $ echo $?
+    0
+    $ test/re-execute.sh sh -c 'exit 2'
+    $ echo $?
+    0
+
+  And with this new version:
+
+    $ care-v2.1 -o test.cpio sh -c 'exit 1'
+    [...]
+    $ echo $?
+    1
+    [...]
+    $ test/re-execute.sh
+    $ echo $?
+    1
+    $ test/re-execute.sh sh -c 'exit 2'
+    $ echo $?
+    2
+
++ Applications that rely on DBUS and/or on KDE cache are now
+  supported.
+
+Thanks to Antoine Moynault, Christophe Guillon, and Rémi Duraffort for
+their help.
+
+[1] https://github.com/cedric-vincent/PRoot/blob/v3.2.2/doc/changelog.txt
diff --git a/5.1.0/doc/care/manual.txt b/5.1.0/doc/care/manual.txt
new file mode 100644
index 0000000..25e4bed
--- /dev/null
+++ b/5.1.0/doc/care/manual.txt
@@ -0,0 +1,462 @@
+======
+ CARE
+======
+
+-------------------------------------------------
+Comprehensive Archiver for Reproducible Execution
+-------------------------------------------------
+
+:Date: 2014-09-15
+:Version: 2.2
+:Manual section: 1
+
+
+Synopsis
+========
+
+**care** [*option*] ... *command*
+
+
+Description
+===========
+
+CARE monitors the execution of the specified command to create an
+*archive* that contains all the material required to *re-execute* it
+in the same context.  That way, the command will be reproducible
+everywhere, even on Linux systems that are supposed to be not
+compatible with the original Linux system.  CARE is typically useful
+to get reliable bug reports, demonstrations, `artifact evaluation`_,
+tutorials, portable applications, minimal rootfs, file-system
+coverage, ...
+
+By design, CARE does not record events at all.  Instead, it archives
+environment variables and accessed file-system components -- before
+modification -- during the so-called *initial* execution.  Then, to
+reproduce this execution, the ``re-execute.sh`` script embedded into
+the archive restores the environment variables and relaunches the
+command confined into the saved file-system.  That way, both *initial*
+and *reproduced* executions should produce the same results as they
+use the same context, assuming they do not rely on external events --
+like key strokes or network packets -- or that these external events
+are replayed manually or automatically, using umockdev_ for instance.
+That means it is possible to alter explicitly the reproduced
+executions by changing content of the saved file-system, or by
+replaying different external events.
+
+.. _umockdev: https://github.com/martinpitt/umockdev/
+
+.. _artifact evaluation: http://www.artifact-eval.org/
+
+Privacy
+-------
+
+To ensure that no sensitive file can possibly leak into the archive,
+CARE *conceals* recursively the content of ``$HOME`` and ``/tmp``,
+that is, they appear empty during the original execution.  Although,
+for consistency reasons, the content of ``$PWD`` is *revealed* even if
+it is nested into the two previous paths.
+
+As a consequence, a program executed under CARE may behave
+unexpectedly because a required path is not accessible anymore.  In
+this case, such a path has to be revealed explicitly.  For details,
+see the options ``--concealed-path`` and ``--revealed-path``, and the
+file ``concealed-accesses.txt`` as well.
+
+It is advised to inspect the archived content before sharing it.
+
+
+Options
+=======
+
+The command-line interface is composed of two parts: first CARE's
+options, then the command to launch.  This section describes the
+options supported by CARE, that is, the first part of its command-line
+interface.
+
+-o path, --output=path
+    Archive in *path*, its suffix specifies the format.
+
+    The suffix of *path* is used to select the archive format, it can
+    be one of the following:
+
+    =========  ========================================================
+    suffix     comment
+    =========  ========================================================
+    /          don't archive, copy into the specified directory instead
+    .tar       most common archive format
+    .cpio      most portable archive format, it can archive sockets too
+    ?.gz       most common compression format, but slow
+    ?.lzo      fast compression format, but uncommon
+    ?.bin      see ``Self-extracting format`` section
+    ?.?.bin    see ``Self-extracting format`` section
+    .bin       see ``Self-extracting format`` section
+    .raw       recommended archive format, use `care -x` to extract
+    =========  ========================================================
+
+    where "?" means the suffix must be combined with another one.  For
+    examples: ".tar.lzo", ".cpio.gz", ".tar.bin", ".cpio.lzo.bin", ...
+    If this option is not specified, the default output path is
+    ``care-<DATE>.bin`` or ``care-<DATE>.raw``, depending on whether
+    CARE was built with self-extracting format support or not.
+
+-c path, --concealed-path=path
+    Make *path* content appear empty during the original execution.
+
+    Some paths may contain sensitive data that should never be
+    archived.  This is typically the case for most of the files in:
+
+    * $HOME
+    * /tmp
+
+    That's why these directories are recursively *concealed* from the
+    original execution, unless the ``-d`` option is specified.
+    Concealed paths appear empty during the original execution, as a
+    consequence their original content can't be accessed nor archived.
+
+-r path, --revealed-path=path
+    Make *path* content accessible when nested in a concealed path.
+
+    Concealed paths might make the original execution with CARE behave
+    differently from an execution without CARE.  For example, a lot of
+    ``No such file or directory`` errors might appear.  The solution
+    is to *reveal* recursively any required paths that would be nested
+    into a *concealed* path.  Note that ``$PWD`` is *revealed*, unless
+    the ``-d`` option is specified.
+
+-p path, --volatile-path=path
+    Don't archive *path* content, reuse actual *path* instead.
+
+    Some paths contain only communication means with programs that
+    can't be monitored by CARE, like the kernel or a remote server.
+    Such paths are said *volatile*; they shouldn't be archived,
+    instead they must be accessed from the *actual* rootfs during the
+    re-execution.  This is typically the case for the following pseudo
+    file-systems, sockets, and authority files:
+
+    * /dev
+    * /proc
+    * /sys
+    * /run/shm
+    * /tmp/.X11-unix
+    * /tmp/.ICE-unix
+    * $XAUTHORITY
+    * $ICEAUTHORITY
+    * /var/run/dbus/system_bus_socket
+    * /var/tmp/kdecache-$LOGNAME
+
+    This is also typically the case for any other fifos or sockets.
+    These paths are considered *volatile*, unless the ``-d`` option is
+    specified.
+
+-e name, --volatile-env=name
+    Don't archive *name* env. variable, reuse actual value instead.
+
+    Some environment variables are used to communicate with programs
+    that can't be monitored by CARE, like remote servers.  Such
+    environment variables are said *volatile*; they shouldn't be
+    archived, instead they must be accessed from the *actual*
+    environment during the re-execution.  This is typically the case
+    for the following ones:
+
+    * DISPLAY
+    * http_proxy
+    * https_proxy
+    * ftp_proxy
+    * all_proxy
+    * HTTP_PROXY
+    * HTTPS_PROXY
+    * FTP_PROXY
+    * ALL_PROXY
+    * DBUS_SESSION_BUS_ADDRESS
+    * SESSION_MANAGER
+    * XDG_SESSION_COOKIE
+
+    These environment variables are considered *volatile*, unless the
+    ``-d`` option is specified.
+
+-m value, --max-archivable-size=value
+    Set the maximum size of archivable files to *value* megabytes.
+
+    To keep the CPU time and the disk space used by the archiver
+    reasonable, files whose size exceeds *value* megabytes are
+    truncated down to 0 bytes.  The default is 1GB, unless the ``-d``
+    option is specified.  A negative *value* means no limit.
+
+-d, --ignore-default-config
+    Don't use the default options.
+
+-x file, --extract=file
+    Extract content of the archive *file*, then exit.
+
+    It is recommended to use this option to extract archives created
+    by CARE because most extracting tools -- that are not based on
+    libarchive -- are too limited to extract them correctly.
+
+-v value, --verbose=value
+    Set the level of debug information to *value*.
+
+    The higher the integer *value* is, the more detailed debug
+    information is printed to the standard error stream.  A negative
+    *value* makes CARE quiet except on fatal errors.
+
+-V, --version, --about
+    Print version, copyright, license and contact, then exit.
+
+-h, --help, --usage
+    Print the user manual, then exit.
+
+
+Exit Status
+===========
+
+If an internal error occurs, ``care`` returns a non-zero exit status,
+otherwise it returns the exit status of the last terminated program.
+When an error has occurred, the only way to know if it comes from the
+last terminated program or from ``care`` itself is to have a look at
+the error message.
+
+
+Files
+=====
+
+The output archive contains the following files:
+
+``re-execute.sh``
+    start the re-execution of the initial command as originally
+    specified.  It is also possible to specify an alternate command.
+    For example, assuming ``gcc`` was archived, it can be re-invoked
+    differently:
+
+        $ ./re-execute.sh gcc --version
+        gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
+
+        $ echo 'int main(void) { return puts(\"OK\"); }' > rootfs/foo.c
+        $ ./re-execute.sh gcc -Wall /foo.c
+        $ foo.c: In function "main":
+        $ foo.c:1:1: warning: implicit declaration of function "puts"
+
+``rootfs/``
+    directory where all the files used during the original execution
+    were archived, they will be required for the reproduced execution.
+
+``proot``
+    virtualization tool invoked by re-execute.sh to confine the
+    reproduced execution into the rootfs.  It also emulates the
+    missing kernel features if needed.
+
+``concealed-accesses.txt``
+    list of accessed paths that were concealed during the original
+    execution.  Its main purpose is to know what are the paths that
+    should be revealed if the the original execution didn't go as
+    expected.  It is absolutely useless for the reproduced execution.
+
+
+Limitations
+===========
+
+It's not possible to use GDB, strace, or any programs based on
+*ptrace* under CARE yet.  This latter is also based on this syscall,
+but the Linux kernel allows only one *ptracer* per process.  This will
+be fixed in a future version of CARE thanks to a ptrace emulator.
+
+
+Example
+=======
+
+In this example, Alice wants to report to Bob that the compilation of
+PRoot v2.4 raises an unexpected warning::
+
+    alice$ make -C PRoot-2.4/src/
+    
+    make: Entering directory `PRoot-2.4/src'
+    [...]
+    CC    path/proc.o
+    ./path/proc.c: In function 'readlink_proc':
+    ./path/proc.c:132:3: warning: ignoring return value of 'strtol'
+    [...]
+
+Technically, Alice uses Ubuntu 11.04 for x86, whereas Bob uses
+Slackware 13.37 on x86_64.  Both distros are supposed to be shipped
+with GCC 4.5.2, however Bob is not able to reproduce this issue on his
+system::
+
+    bob$ make -C PRoot-2.4/src/
+    
+    make: Entering directory `PRoot-2.4/src'
+    [...]
+    CC    path/proc.o
+    [...]
+
+Since they don't have much time to investigate this issue by iterating
+between each other, they decide to use CARE.  First, Alice prepends
+``care`` to her command::
+
+    alice$ care make -C PRoot-2.4/src/
+    
+    care info: concealed path: $HOME
+    care info: concealed path: /tmp
+    care info: revealed path: $PWD
+    care info: ----------------------------------------------------------------------
+    make: Entering directory `PRoot-2.4/src'
+    [...]
+    CC    path/proc.o
+    ./path/proc.c: In function 'readlink_proc':
+    ./path/proc.c:132:3: warning: ignoring return value of 'strtol'
+    [...]
+    care info: ----------------------------------------------------------------------
+    care info: Hints:
+    care info:   - search for "conceal" in `care -h` if the execution didn't go as expected.
+    care info:   - use `./care-130213072430.bin` to extract the output archive.
+
+Then she sends the ``care-130213072430.bin`` file to Bob.  Now, he
+should be able to reproduce her issue on his system::
+
+    bob$ ./care-130213072430.bin
+    [...]
+    bob$ ./care-130213072430/re-execute.sh
+
+    make: Entering directory `PRoot-2.4/src'
+    [...]
+    CC    path/proc.o
+    ./path/proc.c: In function 'readlink_proc':
+    ./path/proc.c:132:3: warning: ignoring return value of 'strtol'
+    [...]
+
+So far so good!  This compiler warning doesn't make sense to Bob since
+``strtol`` is used there to check a string format; the return value is
+useless, only the ``errno`` value matters.  Further investigations are
+required, so Bob re-execute Alice's GCC differently to get more
+details::
+
+    bob$ ./care-130213072430/re-execute.sh gcc --version
+    
+    gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
+    Copyright (C) 2010 Free Software Foundation, Inc.
+    This is free software; see the source for copying conditions.  There is NO
+    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+The same invocation on his system returns something slightly
+different::
+
+    bob$ gcc --version
+    
+    gcc (GCC) 4.5.2
+    Copyright (C) 2010 Free Software Foundation, Inc.
+    This is free software; see the source for copying conditions.  There is NO
+    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+This confirms that both GCC versions are the same, however Alice's one
+seems to have been modified by Ubuntu.  Although, according to the web
+page related to this Ubuntu package [#]_, no changes regarding
+``strtol`` were made.  So Bob decides to search into the files coming
+from Alice's system, that is, the ``rootfs`` directory in the
+archive::
+
+    bob$ grep -wIrl strtol ./care-130213072430/rootfs
+    
+    care-130213072430/rootfs/usr/include/inttypes.h
+    care-130213072430/rootfs/usr/include/stdlib.h
+    [...]
+
+Here, the file ``usr/include/stdlib.h`` contains a declaration of
+``strtol`` with the "warn unused result" attribute.  On Ubuntu, this
+file belongs to the EGLIBC package, and its related web page [#]_
+shows that this attribute was actually wrongly introduced by the
+official EGLIBC developers.  Ultimately Bob should notify them in this
+regard.
+
+Thanks to CARE, Bob was able to reproduce the issue reported by Alice
+without effort.  For investigations purpose, he was able to re-execute
+programs differently and to search into the relevant files.
+
+.. [#] https://launchpad.net/ubuntu/oneiric/+source/gcc-4.5/4.5.2-8ubuntu4
+.. [#] https://launchpad.net/ubuntu/+source/eglibc/2.13-0ubuntu13.2
+
+
+Self-extracting format
+======================
+
+The self-extracting format used by CARE starts with an extracting
+program, followed by a regular archive, and it ends with a special
+footer.  This latter contains the signature "I_LOVE_PIZZA" followed by
+the size of the embedded archive::
+
+    +------------------------+
+    |   extracting program   |
+    +------------------------+
+    |                        |
+    |    embedded archive    |
+    |                        |
+    +------------------------+
+    | uint8_t  signature[13] |
+    | uint64_t archive_size  |  # big-endian
+    +------------------------+
+
+The command ``care -x`` can be used against a self-extracting archive,
+even if they were not build for the same architecture.  For instance,
+a self-extracting archive produced for ARM can be extracted with a
+``care`` program built for x86_64, and vice versa.  It is also
+possible to use external tools to extract the embedded archive, for
+example::
+
+    $ care -o foo.tar.gz.bin /usr/bin/echo OK
+    [...]
+    OK
+    [...]
+
+    $ hexdump -C foo.tar.gz.bin | tail -3
+    0015b5b0  00 b0 2e 00 49 5f 4c 4f  56 45 5f 50 49 5a 5a 41  |....I_LOVE_PIZZA|
+    0015b5c0  00 00 00 00 00 00 12 b4  13                       |.........|
+    0015b5c9
+
+    $ file_size=`stat -c %s foo.tar.gz.bin`
+    $ archive_size=$((16#12b413))
+    $ footer_size=21
+    $ skip=$(($file_size - $archive_size - $footer_size))
+
+    $ dd if=foo.tar.gz.bin of=foo.tar.gz bs=1 skip=$skip count=$archive_size
+    1225747+0 records in
+    1225747+0 records out
+    1225747 bytes (1.2 MB) copied, 2.99546 s, 409 kB/s
+
+    $ file foo.tar.gz
+    foo.tar.gz: gzip compressed data, from Unix
+
+    $ tar -tzf foo.tar.gz
+    foo/rootfs/usr/
+    [...]
+    foo/re-execute.sh
+    foo/README.txt
+    foo/proot
+
+
+Downloads
+=========
+
+CARE is heavily based on PRoot_, that's why they are both hosted in
+the same repository: http://github.proot.me.  Since CARE is supposed
+to work on any Linux systems, it is recommended to use following
+highly compatible static binaries:
+
+* for x86_64: http://static.reproducible.io/care-x86_64
+
+* for x86: http://static.reproducible.io/care-x86
+
+* for ARM: http://static.reproducible.io/care-arm
+
+* other architectures: on demand.
+
+.. _PRoot: http://proot.me
+
+Colophon
+========
+
+Visit http://reproducible.io for help, bug reports, suggestions, patches, ...
+Copyright (C) 2014 STMicroelectronics, licensed under GPL v2 or later.
+
+::
+
+        _____ ____ _____ ____
+       /   __/ __ |  __ \  __|
+      /   /_/     |     /  __|
+      \_____|__|__|__|__\____|
diff --git a/5.1.0/doc/care/roadmap.txt b/5.1.0/doc/care/roadmap.txt
new file mode 100644
index 0000000..b639835
--- /dev/null
+++ b/5.1.0/doc/care/roadmap.txt
@@ -0,0 +1,42 @@
+=========
+ Roadmap
+=========
+
+CARE v2.2
+=========
+
+* Based on PRoot v3.3.
+
+* Use PRoot "fake id" option ("-i").
+
+* Make "re-execute.sh" print a useful message when -h/--help is
+  specified.
+
+* Add an option to archive specified path, no matter whether it is
+  used or not.
+
+* In concealed-accesses.txt, print the name of the program that tried
+  to access a concealed path too.
+
+* Fake the full utsname structure.
+
+
+CARE v2.3
+=========
+
+* Add an option to augment an existing archive with content used from
+  a new monitored execution.
+
+
+Not yet scheduled
+=================
+
+Fixes
+-----
+
+* Accept *care as valid CLI name
+
+* Bug: an archive for "wine notepad.exe" created on Ubuntu 12.04
+  x86_64 can't be re-executed on RHEL5 x86_64.
+
+* Warn when an unemulated feature is used (ppoll, getcpu, flags, ...)
diff --git a/5.1.0/doc/care/stylesheets/cli.xsl b/5.1.0/doc/care/stylesheets/cli.xsl
new file mode 100644
index 0000000..a31d2d6
--- /dev/null
+++ b/5.1.0/doc/care/stylesheets/cli.xsl
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:output method="text" />
+
+  <xsl:template match="/">
+    <xsl:text>/* This file is automatically generated from the documentation. EDIT AT YOUR OWN RISK. */
+
+#ifndef CARE_CLI_H
+#define CARE_CLI_H
+
+#include "cli/cli.h"
+
+#ifndef VERSION
+#define VERSION "</xsl:text><xsl:value-of select="//version" /><xsl:text>"
+#endif
+
+#define CARE_MAX_SIZE 1024
+
+</xsl:text>
+
+<xsl:apply-templates select="//option_string[.='-c']" />
+<xsl:apply-templates select="//option_string[.='-r']" />
+<xsl:apply-templates select="//option_string[.='-p']" />
+<xsl:apply-templates select="//option_string[.='-e']" />
+
+    <xsl:apply-templates select="//option_group" mode="handlers" />
+    <xsl:text>
+static int pre_initialize_bindings(Tracee *, const Cli *, size_t, char *const *, size_t);
+static int post_initialize_bindings(Tracee *, const Cli *, size_t, char *const *, size_t);
+</xsl:text>
+    <xsl:text>
+static Cli care_cli = {
+	.version  = VERSION,
+	.name     = "care",
+</xsl:text>
+    <xsl:apply-templates select="//subtitle"/>
+    <xsl:apply-templates select="//section[@names='synopsis']" />
+    <xsl:apply-templates select="//section[@names='colophon']" />
+    <xsl:apply-templates select="//section[@names='logo']" />
+    <xsl:text>
+	.pre_initialize_bindings  = pre_initialize_bindings,
+	.post_initialize_bindings = post_initialize_bindings,
+
+	.options = {
+</xsl:text>
+    <xsl:apply-templates select="//option_group" mode="options" />
+  <xsl:text>	END_OF_OPTIONS,
+	},
+};
+
+#endif /* CARE_CLI_H */
+</xsl:text>
+  </xsl:template>
+
+  <!-- Constant string definitions -->
+
+  <xsl:template match="subtitle">
+    <xsl:text>	.subtitle = "</xsl:text>
+    <xsl:value-of select="." />
+    <xsl:text>",
+</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="section[@names='synopsis']">
+    <xsl:text>	.synopsis = "</xsl:text>
+    <xsl:value-of select="./paragraph" />
+    <xsl:text>",
+</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="section[@names='colophon']">
+    <xsl:text>	.colophon = "</xsl:text>
+    <xsl:value-of select="./paragraph" />
+    <xsl:text>",
+</xsl:text>
+    <xsl:text>	.logo = "\
+</xsl:text>
+    <xsl:value-of select="./literal_block" />
+    <xsl:text>",
+</xsl:text>
+  </xsl:template>
+
+  <!-- Recommanded options declarations -->
+
+  <xsl:template match="option_string[.='-c']">
+    <xsl:text>static char const *default_concealed_paths[] = {
+</xsl:text>
+    <xsl:apply-templates select="ancestor-or-self::option_list_item//list_item" />
+    <xsl:text>	NULL,
+};
+
+</xsl:text>
+
+  </xsl:template>
+
+  <xsl:template match="option_string[.='-r']">
+    <xsl:text>static char const *default_revealed_paths[] = {
+</xsl:text>
+    <xsl:apply-templates select="ancestor-or-self::option_list_item//list_item" />
+    <xsl:text>	NULL,
+};
+
+</xsl:text>
+
+  </xsl:template>
+
+  <xsl:template match="option_string[.='-p']">
+    <xsl:text>static char const *default_volatile_paths[] = {
+</xsl:text>
+    <xsl:apply-templates select="ancestor-or-self::option_list_item//list_item" />
+    <xsl:text>	NULL,
+};
+
+</xsl:text>
+
+  </xsl:template>
+
+  <xsl:template match="option_string[.='-e']">
+    <xsl:text>static char const *default_volatile_envars[] = {
+</xsl:text>
+    <xsl:apply-templates select="ancestor-or-self::option_list_item//list_item" />
+    <xsl:text>	NULL,
+};
+
+</xsl:text>
+  </xsl:template>
+
+  <!-- Option declarations -->
+
+  <xsl:template match="option_group" mode="options">
+    <xsl:text>	{ .class = "</xsl:text>
+    <xsl:value-of select="ancestor-or-self::section[1]/title" />
+    <xsl:text>",
+</xsl:text>
+    <xsl:text>	  .arguments = {
+</xsl:text>
+    <xsl:apply-templates select="option" mode="options" />
+    <xsl:text>		{ .name = NULL, .separator = '\0', .value = NULL } },
+</xsl:text>
+    <xsl:text>	  .handler = handle_option_</xsl:text>
+    <xsl:value-of select="substring(option[1]/option_string, 2, 1)" />
+    <xsl:text>,
+</xsl:text>
+    <xsl:text>	  .description = "</xsl:text>
+    <xsl:apply-templates select="../description/paragraph[1]" mode="options" />
+    <xsl:text>",
+</xsl:text>
+    <xsl:text>	  .detail = NULL,
+	},
+</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="emphasis" mode="options">
+    <xsl:text>*</xsl:text>
+    <xsl:value-of select="." />
+    <xsl:text>*</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="paragraph">
+      <xsl:apply-templates/>
+    <xsl:text>
+
+</xsl:text>
+  </xsl:template>
+
+  <!-- Option aliases declarations -->
+
+  <xsl:template match="option" mode="options">
+    <xsl:text>		{ </xsl:text>
+    <xsl:text>.name = "</xsl:text>
+    <xsl:value-of select="option_string" />
+    <xsl:text>", .separator = '</xsl:text>
+    <xsl:choose>
+      <xsl:when test="option_argument">
+	<xsl:value-of select="option_argument/@delimiter" />
+	<xsl:text>', .value = "</xsl:text>
+	<xsl:value-of select="option_argument" />
+	<xsl:text>"</xsl:text>
+      </xsl:when>
+      <xsl:otherwise>
+	<xsl:text>\0', .value = NULL</xsl:text>
+      </xsl:otherwise>
+    </xsl:choose>
+    <xsl:text> },
+</xsl:text>
+  </xsl:template>
+
+  <!-- Handler declarations -->
+
+  <xsl:template match="option_group" mode="handlers">
+    <xsl:text>static int handle_option_</xsl:text>
+    <xsl:value-of select="substring(option[1]/option_string, 2, 1)" />
+    <xsl:text>(Tracee *tracee, const Cli *cli, const char *value);
+</xsl:text>
+  </xsl:template>
+
+</xsl:transform>
diff --git a/5.1.0/doc/care/stylesheets/website.css b/5.1.0/doc/care/stylesheets/website.css
new file mode 100644
index 0000000..cfe9317
--- /dev/null
+++ b/5.1.0/doc/care/stylesheets/website.css
@@ -0,0 +1,13 @@
+@import url("website.css");
+
+h1 {
+    color: SkyBlue;
+}
+
+#contents a:hover {
+    border-bottom: 2px solid SkyBlue;
+}
+
+a {
+    border-bottom: 1px solid SkyBlue;
+}
diff --git a/5.1.0/doc/care/stylesheets/website.xsl b/5.1.0/doc/care/stylesheets/website.xsl
new file mode 100644
index 0000000..c601514
--- /dev/null
+++ b/5.1.0/doc/care/stylesheets/website.xsl
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:import href = "../../stylesheets/website.xsl" />
+
+  <xsl:template match="/">
+    <html xmlns="http://www.w3.org/1999/xhtml" itemscope="" itemtype="http://schema.org/Product" xml:lang="en" lang="en">
+
+      <head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>
+	  <xsl:value-of select="document/title" /> — <xsl:value-of select="document/subtitle" />
+	</title>
+	<link rel="stylesheet" href="care-website.css" type="text/css" />
+	<meta itemprop="name" content="CARE" />
+	<meta itemprop="description">
+	  <xsl:attribute name="content">
+	    <xsl:value-of select="//section[@names='description']/paragraph[1]" />
+	  </xsl:attribute>
+	</meta>
+	<script type="text/javascript">
+	  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+	  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+	  ga('create', 'UA-46144158-1', 'reproducible.io');
+	  ga('send', 'pageview');
+	</script>
+      </head>
+
+      <body>
+
+	<div id="title">
+	  <h1>CARE</h1>
+	  <xsl:text> </xsl:text>
+	  <div class="g-plusone" data-size="small">
+	    <xsl:comment>By default XSLTproc converts tags with no
+	    content to self-closing tags</xsl:comment>
+	  </div>
+	</div>
+
+	  <div id="contents">
+	    <ul>
+	      <li><a href="#description">Description</a></li>
+	      <li><a href="#example">Example</a></li>
+	      <li><a href="#downloads">Downloads</a></li>
+	      <li><a href="#support">Support</a></li>
+	      <li><a href="https://plus.google.com/107771643881342199474/posts">News+</a></li>
+	    </ul>
+	  </div>
+
+	  <xsl:apply-templates select="//section[@names='description']" />
+	  <xsl:apply-templates select="//section[@names='example']" />
+	  <xsl:apply-templates select="//section[@names='downloads']" />
+
+	  <div class="section" id="support">
+	    <h2>Support</h2>
+	    <p>Feel free to send your questions, bug reports,
+	    suggestions, and patchs to <a
+	    href="mailto:reproducible@googlegroups.com">the
+	    mailing-list</a> or to <a
+	    href="https://groups.google.com/forum/?fromgroups#!forum/reproducible">the
+	    forum</a>, but please be sure that your answer isn't in
+	    the <a
+	    href="https://raw.github.com/cedric-vincent/PRoot/next/doc/care/manual.txt">user
+	    manual</a> first.
+	    </p>
+	  </div>
+
+	  <script type="text/javascript">
+	    (function() {
+	    var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
+	    po.src = 'https://apis.google.com/js/plusone.js';
+	    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
+	    })();
+	  </script>
+
+      </body>
+    </html>
+
+  </xsl:template>
+</xsl:transform>
diff --git a/5.1.0/doc/ecosystem/care-ecosystem.graphml b/5.1.0/doc/ecosystem/care-ecosystem.graphml
new file mode 100644
index 0000000..1c9058f
--- /dev/null
+++ b/5.1.0/doc/ecosystem/care-ecosystem.graphml
@@ -0,0 +1,435 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+  <!--Created by yEd 3.13-->
+  <key for="graphml" id="d0" yfiles.type="resources"/>
+  <key for="port" id="d1" yfiles.type="portgraphics"/>
+  <key for="port" id="d2" yfiles.type="portgeometry"/>
+  <key for="port" id="d3" yfiles.type="portuserdata"/>
+  <key attr.name="url" attr.type="string" for="node" id="d4"/>
+  <key attr.name="description" attr.type="string" for="node" id="d5"/>
+  <key for="node" id="d6" yfiles.type="nodegraphics"/>
+  <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+  <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+  <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+  <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+  <graph edgedefault="directed" id="G">
+    <data key="d7"/>
+    <node id="n0">
+      <data key="d4"><![CDATA[http://reproducible.io]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="49.53125" x="-24.765625" y="-15.0"/>
+          <y:Fill color="#FF9900" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="39.53125" x="5.0" y="6.015625">CARE<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n1">
+      <data key="d5"><![CDATA[Gogo uses CARE to reproduce -- bit accurately -- the build of an embedded Linux distribution.]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="48.927734375" x="176.33882507911434" y="-301.66754050376784"/>
+          <y:Fill color="#99FFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="38.927734375" x="5.0" y="6.015625">Gogo<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n2">
+      <data key="d4"/>
+      <data key="d5"><![CDATA[Copyright holder and unique sponsor of CARE.
+]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="142.47265625" x="261.29259233244335" y="-124.19943708374738"/>
+          <y:Fill color="#99FFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="132.47265625" x="5.0" y="6.015625">STMicroelectronics<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n3">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="82.4375" x="84.6175322138738" y="-96.64086034940046"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="72.4375" x="5.0" y="6.015625">is used by<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n4">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="116.380859375" x="-163.15515147836032" y="-122.15599460304256"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="106.380859375" x="5.0" y="6.015625">is presented at<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n5">
+      <data key="d4"/>
+      <data key="d5"><![CDATA[Linaro LAVA uses CARE to boot some ST boards and to archives failures during validation]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="96.248046875" x="-158.01053765500095" y="317.3025037418872"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="86.248046875" x="5.0" y="6.015625">Linaro LAVA<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n6">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="99.97460937500001" x="52.4701522039035" y="94.55578271979161"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="89.974609375" x="5.000000000000007" y="6.015625">is shipped in<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n7">
+      <data key="d4"><![CDATA[https://aur.archlinux.org/packages/care/]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="85.625" x="271.1124520413913" y="139.7615084115239"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="75.625" x="5.0" y="6.015625">Arch Linux<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n8">
+      <data key="d4"><![CDATA[http://packages.gentoo.org/package/sys-apps/proot]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="62.755859375" x="92.19422537680252" y="312.45980286557915"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="52.755859375" x="5.0" y="6.015625">Gentoo<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n9">
+      <data key="d4"><![CDATA[http://www.slideshare.net/linaroorg/lcu14-211-lava-use-cases-sw-testing-reproducing-a-lava-failures-locally-using-care]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="153.44140625" x="-68.06034313332424" y="-364.8928381159217"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="143.44140625" x="5.0" y="6.015625">Linaro Connect 2014<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n10">
+      <data key="d4"><![CDATA[http://ctuning.org/cm/wiki/index.php?title=Events:TRUST2014]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="95.57421875" x="-231.06930207249655" y="-313.17383828900506"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="85.57421875" x="5.0" y="6.015625">TRUST 2014<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n11">
+      <data key="d4"><![CDATA[http://www.openmole.org/documentation/tutorials/embed-r-scilab/]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="81.91015625" x="-323.3281381408953" y="191.79810196725595"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="71.91015625" x="5.0" y="6.015625">OpenMole<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n12">
+      <data key="d4"><![CDATA[https://archive.fosdem.org/2014/schedule/event/syscall/]]></data>
+      <data key="d5"><![CDATA[Lightning talk]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="104.392578125" x="-357.324279106177" y="-186.4552702366005"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="94.392578125" x="5.0" y="6.015625">Fosdem 2012<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n13">
+      <data key="d4"/>
+      <data key="d5"><![CDATA[About 100 domains references http://reproducible.io according to Google]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="127.6953125" x="-413.5669895377619" y="-0.9861523926047937"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="117.6953125" x="5.0" y="6.015625">many web pages<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n14">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="78.681640625" x="-126.413006754006" y="107.14104284922254"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="68.681640625" x="5.0" y="6.015625">is used in<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <edge id="e0" source="n0" target="n6">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e1" source="n0" target="n3">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e2" source="n0" target="n4">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e3" source="n4" target="n9">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e4" source="n4" target="n10">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e5" source="n4" target="n12">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e6" source="n4" target="n13">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e7" source="n6" target="n8">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e8" source="n6" target="n7">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e9" source="n3" target="n2">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e10" source="n3" target="n1">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e11" source="n14" target="n11">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e12" source="n0" target="n14">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e13" source="n14" target="n5">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+  </graph>
+  <data key="d0">
+    <y:Resources/>
+  </data>
+</graphml>
diff --git a/5.1.0/doc/ecosystem/care-ecosystem.svg b/5.1.0/doc/ecosystem/care-ecosystem.svg
new file mode 100644
index 0000000..f3fb034
--- /dev/null
+++ b/5.1.0/doc/ecosystem/care-ecosystem.svg
@@ -0,0 +1,410 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill-opacity="1" color-rendering="auto" color-interpolation="auto" stroke="black" text-rendering="auto" stroke-linecap="square" width="848" stroke-miterlimit="10" stroke-opacity="1" shape-rendering="auto" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" height="743" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12" stroke-dashoffset="0" image-rendering="auto">
+  <!--Generated by ySVG 2.5-->
+  <defs id="genericDefs"/>
+  <g>
+    <defs id="defs1">
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath1">
+        <path d="M0 0 L848 0 L848 743 L0 743 L0 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath2">
+        <path d="M-429 -380 L419 -380 L419 363 L-429 363 L-429 -380 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath3">
+        <path d="M0 0 L0 17 L590 17 L590 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4">
+        <path d="M0 0 L0 17 L297 17 L297 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath5">
+        <path d="M0 0 L0 17 L564 17 L564 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath6">
+        <path d="M0 0 L0 17 L92 17 L92 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath7">
+        <path d="M0 0 L0 17 L469 17 L469 0 Z"/>
+      </clipPath>
+      <script type="text/ecmascript"><![CDATA[      var SVGDocument = null;
+      var SVGRoot = null;
+      var TrueCoords = null;
+      var lastElement = null;
+      var initialized = null;
+      var tipGroup;
+      function Init(evt)
+      {
+         SVGDocument = evt.target.ownerDocument;
+         SVGRoot = SVGDocument.documentElement;
+         TrueCoords = SVGRoot.createSVGPoint();
+         initialized = evt;
+      };
+      function GetTrueCoords(evt)
+      {
+         var newScale = SVGRoot.currentScale;
+         var translation = SVGRoot.currentTranslate;
+         TrueCoords.x = (evt.clientX - translation.x)/newScale;
+         TrueCoords.y = (evt.clientY - translation.y)/newScale;
+      };
+      function HideTooltip( evt )
+      {
+         if(initialized == null) {
+           Init(evt);
+         }
+         if(tipGroup != null) {
+           tipGroup.setAttributeNS(null, 'visibility', 'hidden');
+         }
+      };
+      function ShowTooltip( evt )
+      {
+         if(initialized == null) {
+           Init(evt);
+         }
+         GetTrueCoords( evt );
+         var tipScale = 1/SVGRoot.currentScale;
+         var targetElement = evt.currentTarget;
+         if ( lastElement != targetElement )
+         {
+            var targetId = targetElement.getAttributeNS(null, 'id');
+            var tipId = 'tooltip.' + targetId;
+            tipGroup = SVGDocument.getElementById(tipId);
+            var xPos = TrueCoords.x + (10 * tipScale);
+            var yPos = TrueCoords.y + (10 * tipScale);
+            tipGroup.setAttributeNS(null, 'transform', 'translate(' + xPos + ',' + yPos + ') scale(' + tipScale + ')');
+            tipGroup.setAttributeNS(null, 'visibility', 'visible');
+         }
+      };
+]]></script>
+    </defs>
+    <g fill="white" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="translate(429,380)" stroke="white">
+      <rect x="-429" width="848" height="743" y="-380" clip-path="url(#clipPath2)" stroke="none"/>
+    </g>
+    <g id="y.node.0">
+      <a xlink:href="http://reproducible.io">
+        <g fill="rgb(255,153,0)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(255,153,0)">
+          <ellipse rx="24.7656" ry="15" cx="0" cy="0" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-17.7656" xml:space="preserve" y="4.1543" stroke="none">CARE</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+          <ellipse rx="24.7656" fill="none" ry="15" cx="0" cy="0"/>
+        </g>
+      </a>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.1" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(153,255,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(153,255,255)">
+        <ellipse rx="24.4639" ry="15" cx="200.8027" cy="-286.6675" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="183.3388" xml:space="preserve" y="-282.5132" stroke="none">Gogo</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <ellipse rx="24.4639" fill="none" ry="15" cx="200.8027" cy="-286.6675"/>
+      </g>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.2" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(153,255,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(153,255,255)">
+        <ellipse rx="71.2363" ry="15" cx="332.5289" cy="-109.1994" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="268.2926" xml:space="preserve" y="-105.0451" stroke="none">STMicroelectronics</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <ellipse rx="71.2363" fill="none" ry="15" cx="332.5289" cy="-109.1994"/>
+      </g>
+    </g>
+    <g id="y.node.3">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="91.6175" xml:space="preserve" y="-77.4866" stroke="none">is used by</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <rect fill="none" x="84.6175" width="82.4375" height="30" y="-96.6409"/>
+      </g>
+    </g>
+    <g id="y.node.4">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-156.1552" xml:space="preserve" y="-103.0017" stroke="none">is presented at</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <rect fill="none" x="-163.1552" width="116.3809" height="30" y="-122.156"/>
+      </g>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.5" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(204,255,204)">
+        <ellipse rx="48.124" ry="15" cx="-109.8865" cy="332.3025" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-151.0105" xml:space="preserve" y="336.4568" stroke="none">Linaro LAVA</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <ellipse rx="48.124" fill="none" ry="15" cx="-109.8865" cy="332.3025"/>
+      </g>
+    </g>
+    <g id="y.node.6">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="59.4702" xml:space="preserve" y="113.7101" stroke="none">is shipped in</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <rect fill="none" x="52.4702" width="99.9746" height="30" y="94.5558"/>
+      </g>
+    </g>
+    <g id="y.node.7">
+      <a xlink:href="https://aur.archlinux.org/packages/care/">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(204,204,255)">
+          <ellipse rx="42.8125" ry="15" cx="313.925" cy="154.7615" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="278.1125" xml:space="preserve" y="158.9158" stroke="none">Arch Linux</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+          <ellipse rx="42.8125" fill="none" ry="15" cx="313.925" cy="154.7615"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.8">
+      <a xlink:href="http://packages.gentoo.org/package/sys-apps/proot">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(204,204,255)">
+          <ellipse rx="31.3779" ry="15" cx="123.5722" cy="327.4598" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="99.1942" xml:space="preserve" y="331.6141" stroke="none">Gentoo</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+          <ellipse rx="31.3779" fill="none" ry="15" cx="123.5722" cy="327.4598"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.9">
+      <a xlink:href="http://www.slideshare.net/linaroorg/lcu14-211-lava-use-cases-sw-testing-reproducing-a-lava-failures-locally-using-care">
+        <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(255,255,153)">
+          <ellipse rx="76.7207" ry="15" cx="8.6604" cy="-349.8928" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-61.0603" xml:space="preserve" y="-345.7386" stroke="none">Linaro Connect 2014</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+          <ellipse rx="76.7207" fill="none" ry="15" cx="8.6604" cy="-349.8928"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.10">
+      <a xlink:href="http://ctuning.org/cm/wiki/index.php?title=Events:TRUST2014">
+        <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(255,255,153)">
+          <ellipse rx="47.7871" ry="15" cx="-183.2822" cy="-298.1738" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-224.0693" xml:space="preserve" y="-294.0195" stroke="none">TRUST 2014</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+          <ellipse rx="47.7871" fill="none" ry="15" cx="-183.2822" cy="-298.1738"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.11">
+      <a xlink:href="http://www.openmole.org/documentation/tutorials/embed-r-scilab/">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(204,255,204)">
+          <ellipse rx="40.9551" ry="15" cx="-282.3731" cy="206.7981" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-316.3281" xml:space="preserve" y="210.9524" stroke="none">OpenMole</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+          <ellipse rx="40.9551" fill="none" ry="15" cx="-282.3731" cy="206.7981"/>
+        </g>
+      </a>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.12" onmousemove="ShowTooltip(evt)">
+      <a xlink:href="https://archive.fosdem.org/2014/schedule/event/syscall/">
+        <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(255,255,153)">
+          <ellipse rx="52.1963" ry="15" cx="-305.128" cy="-171.4553" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-350.3243" xml:space="preserve" y="-167.301" stroke="none">Fosdem 2012</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+          <ellipse rx="52.1963" fill="none" ry="15" cx="-305.128" cy="-171.4553"/>
+        </g>
+      </a>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.13" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke="rgb(255,255,153)">
+        <ellipse rx="63.8477" ry="15" cx="-349.7193" cy="14.0138" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-406.567" xml:space="preserve" y="18.1681" stroke="none">many web pages</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <ellipse rx="63.8477" fill="none" ry="15" cx="-349.7193" cy="14.0138"/>
+      </g>
+    </g>
+    <g id="y.node.14">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,429,380)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-119.413" xml:space="preserve" y="126.2953" stroke="none">is used in</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <rect fill="none" x="-126.413" width="78.6816" height="30" y="107.141"/>
+      </g>
+    </g>
+    <g id="y.edge.1">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M16.9002 -10.9646 L96.0049 -62.2867"/>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path d="M102.7162 -66.6409 L89.9279 -64.3041 L95.166 -61.7424 L95.3707 -55.915 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.9">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M167.055 -87.1366 L264.4137 -100.1176"/>
+        <path d="M272.3435 -101.1749 L259.788 -104.5451 L263.4225 -99.9854 L261.1096 -94.6328 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.10">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M131.3209 -96.6409 L192.7037 -264.5174"/>
+        <path d="M195.4509 -272.0309 L186.6341 -262.4776 L192.3602 -263.5782 L196.026 -259.0436 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.2">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-12.6366 -12.9004 L-84.6733 -86.441"/>
+        <path d="M-90.2715 -92.156 L-85.4462 -80.0847 L-83.9736 -85.7266 L-78.3024 -87.0823 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.0">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M12.206 13.0516 L82.9649 88.7128"/>
+        <path d="M88.4293 94.5558 L83.8846 82.3761 L82.2819 87.9824 L76.5809 89.2066 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.8">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M152.4448 120.2416 L269.5548 145.2764"/>
+        <path d="M277.378 146.9488 L266.6884 139.5507 L268.5769 145.0674 L264.5979 149.3298 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.7">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M103.9109 124.5558 L121.3486 304.5132"/>
+        <path d="M122.1202 312.4759 L125.9396 300.0496 L121.2522 303.5178 L115.9862 301.014 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.3">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-97.9432 -122.156 L-1.7235 -327.7098"/>
+        <path d="M1.6681 -334.9553 L-7.9478 -326.2068 L-2.1475 -326.8041 L1.1091 -321.9673 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.4">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-111.1147 -122.156 L-174.1477 -275.8945"/>
+        <path d="M-177.1825 -283.2965 L-177.2565 -270.2968 L-173.7683 -274.9693 L-168.004 -274.0903 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.5">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-151.6596 -122.156 L-262.71 -157.8292"/>
+        <path d="M-270.3267 -160.2759 L-260.4309 -151.8454 L-261.7579 -157.5233 L-257.3725 -161.3662 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.6">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-135.2637 -92.156 L-315.1767 -3.0871"/>
+        <path d="M-322.3462 0.4623 L-309.3736 -0.3808 L-314.2805 -3.5307 L-313.8103 -9.3427 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.12">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-9.8172 13.7711 L-71.7351 100.6269"/>
+        <path d="M-76.379 107.141 L-65.3418 100.2722 L-71.1546 99.8126 L-73.4845 94.4674 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.11">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-121.6767 137.141 L-248.6006 192.1587"/>
+        <path d="M-255.9406 195.3404 L-242.9419 195.1554 L-247.683 191.761 L-246.9191 185.9803 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.13">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,429,380)" stroke-linecap="butt">
+        <path fill="none" d="M-88.7005 137.141 L-107.3957 309.3578"/>
+        <path d="M-108.2591 317.3111 L-101.9932 305.9208 L-107.2878 308.3636 L-111.9348 304.8416 Z" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.1" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="590" height="17" y="0" clip-path="url(#clipPath3)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath3)" stroke="none">Gogo uses CARE to reproduce -- bit accurately -- the build of an embedded Linux distribution.</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L590 0 L590 17 L0 17 L0 0 ZM1 1 L589 1 L589 16 L1 16 L1 1 Z" clip-path="url(#clipPath3)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.2" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="297" height="17" y="0" clip-path="url(#clipPath4)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath4)" stroke="none">Copyright holder and unique sponsor of CARE.</text>
+        <text fill="black" x="293" xml:space="preserve" y="13" clip-path="url(#clipPath4)" stroke="none"> </text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L297 0 L297 17 L0 17 L0 0 ZM1 1 L296 1 L296 16 L1 16 L1 1 Z" clip-path="url(#clipPath4)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.5" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="564" height="17" y="0" clip-path="url(#clipPath5)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath5)" stroke="none">Linaro LAVA uses CARE to boot some ST boards and to archives failures during validation</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L564 0 L564 17 L0 17 L0 0 ZM1 1 L563 1 L563 16 L1 16 L1 1 Z" clip-path="url(#clipPath5)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.12" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="92" height="17" y="0" clip-path="url(#clipPath6)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath6)" stroke="none">Lightning talk</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L92 0 L92 17 L0 17 L0 0 ZM1 1 L91 1 L91 16 L1 16 L1 1 Z" clip-path="url(#clipPath6)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.13" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="469" height="17" y="0" clip-path="url(#clipPath7)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath7)" stroke="none">About 100 domains references http://reproducible.io according to Google</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L469 0 L469 17 L0 17 L0 0 ZM1 1 L468 1 L468 16 L1 16 L1 1 Z" clip-path="url(#clipPath7)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/5.1.0/doc/ecosystem/proot-ecosystem.graphml b/5.1.0/doc/ecosystem/proot-ecosystem.graphml
new file mode 100644
index 0000000..1d4d6ae
--- /dev/null
+++ b/5.1.0/doc/ecosystem/proot-ecosystem.graphml
@@ -0,0 +1,881 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+  <!--Created by yEd 3.13-->
+  <key for="graphml" id="d0" yfiles.type="resources"/>
+  <key for="port" id="d1" yfiles.type="portgraphics"/>
+  <key for="port" id="d2" yfiles.type="portgeometry"/>
+  <key for="port" id="d3" yfiles.type="portuserdata"/>
+  <key attr.name="url" attr.type="string" for="node" id="d4"/>
+  <key attr.name="description" attr.type="string" for="node" id="d5"/>
+  <key for="node" id="d6" yfiles.type="nodegraphics"/>
+  <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+  <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+  <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+  <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+  <graph edgedefault="directed" id="G">
+    <data key="d7"/>
+    <node id="n0">
+      <data key="d4"><![CDATA[http://proot.me]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="54.259765625" x="-27.1298828125" y="-15.0"/>
+          <y:Fill color="#FF9900" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="44.259765625" x="5.0" y="6.015625">PRoot<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n1">
+      <data key="d4"><![CDATA[https://github.com/ev3dev/brickstrap]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="85.255859375" x="8.689222029961527" y="406.8904477937454"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="75.255859375" x="5.0" y="6.015625">BrickStrap<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n2">
+      <data key="d4"><![CDATA[https://packages.debian.org/sid/proot]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="61.443359375" x="354.68058384338565" y="-194.13708511994318"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="51.443359375" x="5.0" y="6.015625">Debian<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n3">
+      <data key="d4"><![CDATA[https://github.com/squeaky-pl/portable-pypy]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="108.83984375" x="107.00967476271475" y="378.1481722320285"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="98.83984375" x="5.0" y="6.015625">Portable Pypy<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n4">
+      <data key="d4"><![CDATA[https://play.google.com/store/apps/details?id=champion.gnuroot]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="75.1015625" x="-450.90609758795875" y="83.8047693947313"/>
+          <y:Fill color="#FFCCCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="65.1015625" x="5.0" y="6.015625">GNURoot<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n5">
+      <data key="d4"><![CDATA[https://play.google.com/store/apps/details?id=com.cuntubuntu]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="110.55078125" x="-480.1559338693215" y="-25.075910500312432"/>
+          <y:Fill color="#FFCCCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="100.55078125" x="5.0" y="6.015625">Debian noroot<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n6">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="82.408203125" x="-213.7405317385705" y="14.26055813032196"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="72.408203125" x="5.0" y="6.015625">is core for<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n7">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="78.681640625" x="103.59273131298826" y="85.97029176804374"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="68.681640625" x="5.0" y="6.015625">is used in<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n8">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="99.974609375" x="54.241210084416" y="-155.5753061829868"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="89.974609375" x="5.0" y="6.015625">is shipped in<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n9">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="116.380859375" x="-167.6934869707976" y="-151.50670476431128"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="106.380859375" x="5.0" y="6.015625">is presented at<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n10">
+      <data key="d4"/>
+      <data key="d5"><![CDATA[Copyright holder and unique sponsor of PRoot.
+]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="142.47265625" x="-350.5031410359237" y="305.36705075050264"/>
+          <y:Fill color="#99FFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="132.47265625" x="5.0" y="6.015625">STMicroelectronics<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n11">
+      <data key="d4"><![CDATA[https://archive.fosdem.org/2014/schedule/event/syscall/]]></data>
+      <data key="d5"><![CDATA[Lightning talk]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="104.392578125" x="-93.55920604191515" y="-437.9823980958948"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="94.392578125" x="5.0" y="6.015625">Fosdem 2012<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n12">
+      <data key="d4"><![CDATA[http://reproducible.io]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="49.53125" x="-411.72348342029915" y="160.7515741231802"/>
+          <y:Fill color="#FFCCCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="39.53125" x="5.0" y="6.015625">CARE<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n13">
+      <data key="d4"><![CDATA[http://packages.gentoo.org/package/sys-apps/proot]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="62.755859375" x="243.83124041283997" y="-338.8594026621462"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="52.755859375" x="5.0" y="6.015625">Gentoo<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n14">
+      <data key="d4"><![CDATA[https://aur.archlinux.org/packages/proot/]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="85.625" x="295.50543185367104" y="-272.2274810090376"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="75.625" x="5.0" y="6.015625">Arch Linux<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n15">
+      <data key="d4"><![CDATA[https://launchpad.net/ubuntu/+source/proot]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="63.69921875" x="28.591460019473068" y="-435.6802552182031"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="53.69921875" x="5.0" y="6.015625">Ubuntu<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n16">
+      <data key="d4"><![CDATA[http://gfxmonk.net/dist/0install/proot.xml]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="64.208984375" x="108.30506081770423" y="-416.13608342416507"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="54.208984375" x="5.0" y="6.015625">0install<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n17">
+      <data key="d4"><![CDATA[https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/system/proot]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="54.740234375" x="184.28565441143212" y="-383.54692285903116"/>
+          <y:Fill color="#CCCCFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="44.740234375" x="5.0" y="6.015625">NixOS<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n18">
+      <data key="d4"><![CDATA[https://nixos.org/wiki/How_to_install_nix_in_home_%28on_another_distribution%29]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="54.740234375" x="384.14171534680975" y="-121.22152175644175"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="44.740234375" x="5.0" y="6.015625">NixOS<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n19">
+      <data key="d4"><![CDATA[https://aur.archlinux.org/packages/xampp/]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="91.970703125" x="216.49045883118833" y="319.2625449525815"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="81.970703125" x="5.0" y="6.015625">xampp AUR<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n20">
+      <data key="d4"><![CDATA[https://aur.archlinux.org/packages/hammerwatch/]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="142.73046875" x="281.7140094424758" y="221.55876137923843"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="132.73046875" x="5.0" y="6.015625">hammerwatch AUR<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n21">
+      <data key="d5"><![CDATA[Enea uses PRoot in an internal tool (host environment for API testing of target software) at a customer.]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="46.9765625" x="-209.1070661324986" y="367.32272584656107"/>
+          <y:Fill color="#99FFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="36.9765625" x="5.0" y="6.015625">Enea<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n22">
+      <data key="d4"><![CDATA[https://forge.ocamlcore.org/projects/opam2debian]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="110.017578125" x="356.2343185721427" y="92.25719753471871"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="100.017578125" x="5.0" y="6.015625">OPAM2Debian<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n23">
+      <data key="d4"><![CDATA[http://sioworkers.readthedocs.org/en/latest/]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="98.064453125" x="375.7878196465929" y="-27.36641980947448"/>
+          <y:Fill color="#CCFFCC" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="88.064453125" x="5.0" y="6.015625">SIO Workers<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n24">
+      <data key="d4"><![CDATA[http://adt.cs.upb.de/quf/]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="161.5859375" x="-265.6290019615982" y="-397.7017648595326"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="151.5859375" x="5.0" y="6.015625">QEMU workshop 2011<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n25">
+      <data key="d4"><![CDATA[http://www.slideshare.net/linaroorg/lcu14-211-lava-use-cases-sw-testing-reproducing-a-lava-failures-locally-using-care]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="153.44140625" x="-398.40020428209834" y="-292.7540252369358"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="143.44140625" x="5.0" y="6.015625">Linaro Connect 2014<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n26">
+      <data key="d4"/>
+      <data key="d5"><![CDATA[About 175 domains references http://proot.me according to Google]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="127.6953125" x="-464.13839253711944" y="-157.8017032206403"/>
+          <y:Fill color="#FFFF99" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="117.6953125" x="5.0" y="6.015625">many web pages<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n27">
+      <data key="d5"><![CDATA[Sony has an internal wiki page about CE Linux that references http://proot.me]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="47.251953125" x="-377.11120095137943" y="220.95168178833467"/>
+          <y:Fill color="#99FFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="37.251953125" x="5.0" y="6.015625">Sony<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n28">
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="82.4375" x="-129.84723893150272" y="135.89728609129622"/>
+          <y:Fill hasColor="false" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="72.4375" x="5.0" y="6.015625">is used by<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="rectangle"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n29">
+      <data key="d5"><![CDATA[Cisco has an internal wiki page that references http://proot.me]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="49.419921875" x="-146.35284463093" y="392.21985320800195"/>
+          <y:Fill color="#99FFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="39.419921875" x="5.0" y="6.015625">Cisco
+<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <node id="n30">
+      <data key="d5"><![CDATA[Ericsson has an internal Bugzilla ticket that references http://proot.me]]></data>
+      <data key="d6">
+        <y:ShapeNode>
+          <y:Geometry height="30.0" width="70.4140625" x="-79.37080412941125" y="407.69913788066305"/>
+          <y:Fill color="#99FFFF" transparent="false"/>
+          <y:BorderStyle color="#000000" type="line" width="1.0"/>
+          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="DejaVu Sans" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="17.96875" modelName="custom" textColor="#000000" visible="true" width="60.4140625" x="5.0" y="6.015625">Ericsson<y:LabelModel>
+              <y:SmartNodeLabelModel distance="4.0"/>
+            </y:LabelModel>
+            <y:ModelParameter>
+              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+            </y:ModelParameter>
+          </y:NodeLabel>
+          <y:Shape type="ellipse"/>
+        </y:ShapeNode>
+      </data>
+    </node>
+    <edge id="e0" source="n0" target="n7">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e1" source="n0" target="n8">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e2" source="n0" target="n9">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e3" source="n0" target="n6">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e4" source="n8" target="n2">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e5" source="n8" target="n14">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e6" source="n8" target="n13">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e7" source="n8" target="n17">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e8" source="n8" target="n16">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e9" source="n8" target="n15">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e10" source="n9" target="n11">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e11" source="n9" target="n24">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e12" source="n9" target="n25">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e13" source="n9" target="n26">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e14" source="n6" target="n5">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e15" source="n6" target="n4">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e16" source="n6" target="n12">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e17" source="n7" target="n1">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e18" source="n7" target="n3">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e19" source="n7" target="n19">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e20" source="n7" target="n20">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e21" source="n7" target="n22">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e22" source="n7" target="n23">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e23" source="n7" target="n18">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e24" source="n0" target="n28">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e25" source="n28" target="n27">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e26" source="n28" target="n10">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e27" source="n28" target="n21">
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e28" source="n28" target="n29">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+    <edge id="e29" source="n28" target="n30">
+      <data key="d9"/>
+      <data key="d10">
+        <y:PolyLineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="line" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+          <y:BendStyle smoothed="false"/>
+        </y:PolyLineEdge>
+      </data>
+    </edge>
+  </graph>
+  <data key="d0">
+    <y:Resources/>
+  </data>
+</graphml>
diff --git a/5.1.0/doc/ecosystem/proot-ecosystem.svg b/5.1.0/doc/ecosystem/proot-ecosystem.svg
new file mode 100644
index 0000000..25bf298
--- /dev/null
+++ b/5.1.0/doc/ecosystem/proot-ecosystem.svg
@@ -0,0 +1,761 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill-opacity="1" color-rendering="auto" color-interpolation="auto" stroke="black" text-rendering="auto" stroke-linecap="square" width="985" stroke-miterlimit="10" stroke-opacity="1" shape-rendering="auto" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" height="906" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12" stroke-dashoffset="0" image-rendering="auto">
+  <!--Generated by ySVG 2.5-->
+  <defs id="genericDefs"/>
+  <g>
+    <defs id="defs1">
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath1">
+        <path d="M0 0 L985 0 L985 906 L0 906 L0 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath2">
+        <path d="M-496 -453 L489 -453 L489 453 L-496 453 L-496 -453 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath3">
+        <path d="M0 0 L0 17 L302 17 L302 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4">
+        <path d="M0 0 L0 17 L92 17 L92 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath5">
+        <path d="M0 0 L0 17 L659 17 L659 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath6">
+        <path d="M0 0 L0 17 L432 17 L432 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath7">
+        <path d="M0 0 L0 17 L496 17 L496 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath8">
+        <path d="M0 0 L0 17 L403 17 L403 0 Z"/>
+      </clipPath>
+      <clipPath clipPathUnits="userSpaceOnUse" id="clipPath9">
+        <path d="M0 0 L0 17 L450 17 L450 0 Z"/>
+      </clipPath>
+      <script type="text/ecmascript"><![CDATA[      var SVGDocument = null;
+      var SVGRoot = null;
+      var TrueCoords = null;
+      var lastElement = null;
+      var initialized = null;
+      var tipGroup;
+      function Init(evt)
+      {
+         SVGDocument = evt.target.ownerDocument;
+         SVGRoot = SVGDocument.documentElement;
+         TrueCoords = SVGRoot.createSVGPoint();
+         initialized = evt;
+      };
+      function GetTrueCoords(evt)
+      {
+         var newScale = SVGRoot.currentScale;
+         var translation = SVGRoot.currentTranslate;
+         TrueCoords.x = (evt.clientX - translation.x)/newScale;
+         TrueCoords.y = (evt.clientY - translation.y)/newScale;
+      };
+      function HideTooltip( evt )
+      {
+         if(initialized == null) {
+           Init(evt);
+         }
+         if(tipGroup != null) {
+           tipGroup.setAttributeNS(null, 'visibility', 'hidden');
+         }
+      };
+      function ShowTooltip( evt )
+      {
+         if(initialized == null) {
+           Init(evt);
+         }
+         GetTrueCoords( evt );
+         var tipScale = 1/SVGRoot.currentScale;
+         var targetElement = evt.currentTarget;
+         if ( lastElement != targetElement )
+         {
+            var targetId = targetElement.getAttributeNS(null, 'id');
+            var tipId = 'tooltip.' + targetId;
+            tipGroup = SVGDocument.getElementById(tipId);
+            var xPos = TrueCoords.x + (10 * tipScale);
+            var yPos = TrueCoords.y + (10 * tipScale);
+            tipGroup.setAttributeNS(null, 'transform', 'translate(' + xPos + ',' + yPos + ') scale(' + tipScale + ')');
+            tipGroup.setAttributeNS(null, 'visibility', 'visible');
+         }
+      };
+]]></script>
+    </defs>
+    <g fill="white" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="translate(496,453)" stroke="white">
+      <rect x="-496" width="985" height="906" y="-453" clip-path="url(#clipPath2)" stroke="none"/>
+    </g>
+    <g id="y.node.0">
+      <a target="_blank" xlink:type="simple" xlink:href="http://proot.me" xlink:show="new">
+        <g fill="rgb(255,153,0)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,153,0)">
+          <ellipse rx="27.1299" ry="15" cx="0" cy="0" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-20.1299" xml:space="preserve" y="4.1543" stroke="none">PRoot</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="27.1299" fill="none" ry="15" cx="0" cy="0"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.1">
+      <a target="_blank" xlink:type="simple" xlink:href="https://github.com/ev3dev/brickstrap" xlink:show="new">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,255,204)">
+          <ellipse rx="42.6279" ry="15" cx="51.3172" cy="421.8904" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="15.6892" xml:space="preserve" y="426.0447" stroke="none">BrickStrap</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="42.6279" fill="none" ry="15" cx="51.3172" cy="421.8904"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.2">
+      <a target="_blank" xlink:type="simple" xlink:href="https://packages.debian.org/sid/proot" xlink:show="new">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,204,255)">
+          <ellipse rx="30.7217" ry="15" cx="385.4023" cy="-179.1371" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="361.6806" xml:space="preserve" y="-174.9828" stroke="none">Debian</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="30.7217" fill="none" ry="15" cx="385.4023" cy="-179.1371"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.3">
+      <a target="_blank" xlink:type="simple" xlink:href="https://github.com/squeaky-pl/portable-pypy" xlink:show="new">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,255,204)">
+          <ellipse rx="54.4199" ry="15" cx="161.4296" cy="393.1482" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="114.0097" xml:space="preserve" y="397.3025" stroke="none">Portable Pypy</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="54.4199" fill="none" ry="15" cx="161.4296" cy="393.1482"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.4">
+      <a target="_blank" xlink:type="simple" xlink:href="https://play.google.com/store/apps/details?id=champion.gnuroot" xlink:show="new">
+        <g fill="rgb(255,204,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,204,204)">
+          <ellipse rx="37.5508" ry="15" cx="-413.3553" cy="98.8048" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-443.9061" xml:space="preserve" y="102.9591" stroke="none">GNURoot</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="37.5508" fill="none" ry="15" cx="-413.3553" cy="98.8048"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.5">
+      <a target="_blank" xlink:type="simple" xlink:href="https://play.google.com/store/apps/details?id=com.cuntubuntu" xlink:show="new">
+        <g fill="rgb(255,204,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,204,204)">
+          <ellipse rx="55.2754" ry="15" cx="-424.8805" cy="-10.0759" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-473.1559" xml:space="preserve" y="-5.9216" stroke="none">Debian noroot</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="55.2754" fill="none" ry="15" cx="-424.8805" cy="-10.0759"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.6">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-206.7405" xml:space="preserve" y="33.4149" stroke="none">is core for</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <rect fill="none" x="-213.7405" width="82.4082" height="30" y="14.2606"/>
+      </g>
+    </g>
+    <g id="y.node.7">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="110.5927" xml:space="preserve" y="105.1246" stroke="none">is used in</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <rect fill="none" x="103.5927" width="78.6816" height="30" y="85.9703"/>
+      </g>
+    </g>
+    <g id="y.node.8">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="61.2412" xml:space="preserve" y="-136.421" stroke="none">is shipped in</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <rect fill="none" x="54.2412" width="99.9746" height="30" y="-155.5753"/>
+      </g>
+    </g>
+    <g id="y.node.9">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-160.6935" xml:space="preserve" y="-132.3524" stroke="none">is presented at</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <rect fill="none" x="-167.6935" width="116.3809" height="30" y="-151.5067"/>
+      </g>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.10" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(153,255,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(153,255,255)">
+        <ellipse rx="71.2363" ry="15" cx="-279.2668" cy="320.3671" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-343.5031" xml:space="preserve" y="324.5214" stroke="none">STMicroelectronics</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <ellipse rx="71.2363" fill="none" ry="15" cx="-279.2668" cy="320.3671"/>
+      </g>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.11" onmousemove="ShowTooltip(evt)">
+      <a target="_blank" xlink:type="simple" xlink:href="https://archive.fosdem.org/2014/schedule/event/syscall/" xlink:show="new">
+        <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,255,153)">
+          <ellipse rx="52.1963" ry="15" cx="-41.3629" cy="-422.9824" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-86.5592" xml:space="preserve" y="-418.8281" stroke="none">Fosdem 2012</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="52.1963" fill="none" ry="15" cx="-41.3629" cy="-422.9824"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.12">
+      <a target="_blank" xlink:type="simple" xlink:href="http://reproducible.io" xlink:show="new">
+        <g fill="rgb(255,204,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,204,204)">
+          <ellipse rx="24.7656" ry="15" cx="-386.9579" cy="175.7516" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-404.7235" xml:space="preserve" y="179.9059" stroke="none">CARE</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="24.7656" fill="none" ry="15" cx="-386.9579" cy="175.7516"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.13">
+      <a target="_blank" xlink:type="simple" xlink:href="http://packages.gentoo.org/package/sys-apps/proot" xlink:show="new">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,204,255)">
+          <ellipse rx="31.3779" ry="15" cx="275.2092" cy="-323.8594" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="250.8312" xml:space="preserve" y="-319.7051" stroke="none">Gentoo</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="31.3779" fill="none" ry="15" cx="275.2092" cy="-323.8594"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.14">
+      <a target="_blank" xlink:type="simple" xlink:href="https://aur.archlinux.org/packages/proot/" xlink:show="new">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,204,255)">
+          <ellipse rx="42.8125" ry="15" cx="338.3179" cy="-257.2275" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="302.5054" xml:space="preserve" y="-253.0732" stroke="none">Arch Linux</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="42.8125" fill="none" ry="15" cx="338.3179" cy="-257.2275"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.15">
+      <a target="_blank" xlink:type="simple" xlink:href="https://launchpad.net/ubuntu/+source/proot" xlink:show="new">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,204,255)">
+          <ellipse rx="31.8496" ry="15" cx="60.4411" cy="-420.6803" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="35.5915" xml:space="preserve" y="-416.526" stroke="none">Ubuntu</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="31.8496" fill="none" ry="15" cx="60.4411" cy="-420.6803"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.16">
+      <a target="_blank" xlink:type="simple" xlink:href="http://gfxmonk.net/dist/0install/proot.xml" xlink:show="new">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,204,255)">
+          <ellipse rx="32.1045" ry="15" cx="140.4096" cy="-401.1361" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="115.3051" xml:space="preserve" y="-396.9818" stroke="none">0install</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="32.1045" fill="none" ry="15" cx="140.4096" cy="-401.1361"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.17">
+      <a target="_blank" xlink:type="simple" xlink:href="https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/system/proot" xlink:show="new">
+        <g fill="rgb(204,204,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,204,255)">
+          <ellipse rx="27.3701" ry="15" cx="211.6558" cy="-368.5469" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="191.2857" xml:space="preserve" y="-364.3926" stroke="none">NixOS</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="27.3701" fill="none" ry="15" cx="211.6558" cy="-368.5469"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.18">
+      <a target="_blank" xlink:type="simple" xlink:href="https://nixos.org/wiki/How_to_install_nix_in_home_%28on_another_distribution%29" xlink:show="new">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,255,204)">
+          <ellipse rx="27.3701" ry="15" cx="411.5118" cy="-106.2215" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="391.1417" xml:space="preserve" y="-102.0672" stroke="none">NixOS</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="27.3701" fill="none" ry="15" cx="411.5118" cy="-106.2215"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.19">
+      <a target="_blank" xlink:type="simple" xlink:href="https://aur.archlinux.org/packages/xampp/" xlink:show="new">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,255,204)">
+          <ellipse rx="45.9854" ry="15" cx="262.4758" cy="334.2625" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="223.4905" xml:space="preserve" y="338.4168" stroke="none">xampp AUR</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="45.9854" fill="none" ry="15" cx="262.4758" cy="334.2625"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.20">
+      <a target="_blank" xlink:type="simple" xlink:href="https://aur.archlinux.org/packages/hammerwatch/" xlink:show="new">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,255,204)">
+          <ellipse rx="71.3652" ry="15" cx="353.0792" cy="236.5588" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="288.714" xml:space="preserve" y="240.7131" stroke="none">hammerwatch AUR</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="71.3652" fill="none" ry="15" cx="353.0792" cy="236.5588"/>
+        </g>
+      </a>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.21" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(153,255,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(153,255,255)">
+        <ellipse rx="23.4883" ry="15" cx="-185.6188" cy="382.3227" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-202.1071" xml:space="preserve" y="386.477" stroke="none">Enea</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <ellipse rx="23.4883" fill="none" ry="15" cx="-185.6188" cy="382.3227"/>
+      </g>
+    </g>
+    <g id="y.node.22">
+      <a target="_blank" xlink:type="simple" xlink:href="https://forge.ocamlcore.org/projects/opam2debian" xlink:show="new">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,255,204)">
+          <ellipse rx="55.0088" ry="15" cx="411.2431" cy="107.2572" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="363.2343" xml:space="preserve" y="111.4115" stroke="none">OPAM2Debian</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="55.0088" fill="none" ry="15" cx="411.2431" cy="107.2572"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.23">
+      <a target="_blank" xlink:type="simple" xlink:href="http://sioworkers.readthedocs.org/en/latest/" xlink:show="new">
+        <g fill="rgb(204,255,204)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(204,255,204)">
+          <ellipse rx="49.0322" ry="15" cx="424.82" cy="-12.3664" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="382.7878" xml:space="preserve" y="-8.2121" stroke="none">SIO Workers</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="49.0322" fill="none" ry="15" cx="424.82" cy="-12.3664"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.24">
+      <a target="_blank" xlink:type="simple" xlink:href="http://adt.cs.upb.de/quf/" xlink:show="new">
+        <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,255,153)">
+          <ellipse rx="80.793" ry="15" cx="-184.836" cy="-382.7018" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-258.629" xml:space="preserve" y="-378.5475" stroke="none">QEMU workshop 2011</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="80.793" fill="none" ry="15" cx="-184.836" cy="-382.7018"/>
+        </g>
+      </a>
+    </g>
+    <g id="y.node.25">
+      <a target="_blank" xlink:type="simple" xlink:href="http://www.slideshare.net/linaroorg/lcu14-211-lava-use-cases-sw-testing-reproducing-a-lava-failures-locally-using-care" xlink:show="new">
+        <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,255,153)">
+          <ellipse rx="76.7207" ry="15" cx="-321.6795" cy="-277.754" stroke="none"/>
+        </g>
+        <g>
+          <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+            <text x="-391.4002" xml:space="preserve" y="-273.5997" stroke="none">Linaro Connect 2014</text>
+          </g>
+        </g>
+        <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+          <ellipse rx="76.7207" fill="none" ry="15" cx="-321.6795" cy="-277.754"/>
+        </g>
+      </a>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.26" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(255,255,153)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(255,255,153)">
+        <ellipse rx="63.8477" ry="15" cx="-400.2907" cy="-142.8017" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-457.1384" xml:space="preserve" y="-138.6474" stroke="none">many web pages</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <ellipse rx="63.8477" fill="none" ry="15" cx="-400.2907" cy="-142.8017"/>
+      </g>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.27" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(153,255,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(153,255,255)">
+        <ellipse rx="23.626" ry="15" cx="-353.4852" cy="235.9517" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-370.1112" xml:space="preserve" y="240.106" stroke="none">Sony</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <ellipse rx="23.626" fill="none" ry="15" cx="-353.4852" cy="235.9517"/>
+      </g>
+    </g>
+    <g id="y.node.28">
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-122.8472" xml:space="preserve" y="155.0516" stroke="none">is used by</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <rect fill="none" x="-129.8472" width="82.4375" height="30" y="135.8973"/>
+      </g>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.29" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(153,255,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(153,255,255)">
+        <ellipse rx="24.71" ry="15" cx="-121.6429" cy="407.2199" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-139.3528" xml:space="preserve" y="411.3741" stroke="none">Cisco</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <ellipse rx="24.71" fill="none" ry="15" cx="-121.6429" cy="407.2199"/>
+      </g>
+    </g>
+    <g onmouseout="HideTooltip(evt)" id="y.node.30" onmousemove="ShowTooltip(evt)">
+      <g fill="rgb(153,255,255)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke="rgb(153,255,255)">
+        <ellipse rx="35.207" ry="15" cx="-44.1638" cy="422.6991" stroke="none"/>
+      </g>
+      <g>
+        <g stroke-linecap="butt" transform="matrix(1,0,0,1,496,453)" text-rendering="geometricPrecision" font-family="'DejaVu Sans'" shape-rendering="geometricPrecision" font-weight="bold" stroke-miterlimit="1.45">
+          <text x="-72.3708" xml:space="preserve" y="426.8534" stroke="none">Ericsson</text>
+        </g>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <ellipse rx="35.207" fill="none" ry="15" cx="-44.1638" cy="422.6991"/>
+      </g>
+    </g>
+    <g id="y.edge.3">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-25.9372 4.3987 L-123.4449 20.9351"/>
+      </g>
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path d="M-131.3323 22.2727 L-118.6652 25.1959 L-122.459 20.7679 L-120.3373 15.3367 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.14">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-213.7405 22.8375 L-369.0458 -1.3722"/>
+        <path d="M-376.9503 -2.6043 L-365.8636 4.1843 L-368.0577 -1.2181 L-364.3234 -5.6964 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.15">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-213.7405 41.1596 L-375.238 87.7972"/>
+        <path d="M-382.924 90.0167 L-370.0078 91.4911 L-374.2773 87.5197 L-372.7823 81.8837 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.0">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M16.7213 11.8122 L115.1654 81.3545"/>
+        <path d="M121.6996 85.9703 L114.7833 74.9628 L114.3487 80.7775 L109.0135 83.1304 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.17">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M138.6514 115.9703 L57.774 399.2729"/>
+        <path d="M55.5779 406.9655 L63.68 396.7991 L58.0485 398.3113 L54.0641 394.054 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.18">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M143.8831 115.9703 L159.9748 370.1664"/>
+        <path d="M160.4802 378.1505 L164.7121 365.8586 L159.9116 369.1684 L154.732 366.4903 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.1">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M10.2905 -13.8791 L88.3421 -119.149"/>
+        <path d="M93.1069 -125.5753 L81.9433 -118.9138 L87.7466 -118.3457 L89.9762 -112.9579 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.4">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M154.2158 -147.4308 L347.8994 -173.9937"/>
+        <path d="M355.8252 -175.0807 L343.2571 -178.4039 L346.9087 -173.8578 L344.6159 -168.4966 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.2">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-10.9994 -13.7119 L-92.4645 -115.2664"/>
+        <path d="M-97.4703 -121.5067 L-93.8618 -109.0176 L-91.8388 -114.4864 L-86.0614 -115.2749 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.10">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-105.9352 -151.5067 L-46.7737 -400.2344"/>
+        <path d="M-44.9225 -408.0173 L-52.5636 -397.5 L-47.0051 -399.2616 L-42.835 -395.186 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.16">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-194.4922 44.2606 L-363.9232 160.0145"/>
+        <path d="M-370.5288 164.5274 L-357.7998 161.8865 L-363.0975 159.4504 L-363.4409 153.6295 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.6">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M118.2216 -155.5753 L256.9722 -304.3101"/>
+        <path d="M262.4293 -310.1599 L250.5875 -304.7959 L256.2901 -303.5789 L257.8998 -297.9745 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.5">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M134.3295 -155.5753 L306.5338 -241.3887"/>
+        <path d="M313.6941 -244.9568 L300.7237 -244.0798 L305.6388 -240.9427 L305.1838 -235.1295 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.9">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M101.8836 -155.5753 L64.0152 -397.8167"/>
+        <path d="M62.7796 -405.7207 L59.693 -393.0925 L64.1697 -396.8287 L69.573 -394.637 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.8">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M106.3114 -155.5753 L137.2307 -378.2436"/>
+        <path d="M138.3311 -386.1676 L131.7281 -374.9693 L137.0932 -377.2531 L141.6331 -373.5939 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.7">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M111.297 -155.5753 L201.4017 -346.7867"/>
+        <path d="M204.8119 -354.0234 L195.1736 -345.2997 L200.9754 -345.8821 L204.2196 -341.0369 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.23">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M162.3777 85.9703 L389.3263 -89.1067"/>
+        <path d="M395.6605 -93.9932 L383.1051 -90.6224 L388.5345 -88.4959 L389.2132 -82.7046 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.19">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M150.6198 115.9703 L251.2465 312.3481"/>
+        <path d="M254.8948 319.4678 L253.8722 306.5081 L250.7905 311.4581 L244.9726 311.0684 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.20">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M166.1817 115.9703 L324.2522 217.9592"/>
+        <path d="M330.9744 222.2964 L323.6018 211.5892 L323.4119 217.417 L318.1803 219.992 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.21">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M182.2744 101.8921 L348.4385 105.7856"/>
+        <path d="M356.4363 105.973 L344.5567 100.6933 L347.4388 105.7622 L344.3224 110.6905 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.22">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M180.241 85.9703 L387.7073 2.5553"/>
+        <path d="M395.1298 -0.429 L382.1308 -0.5916 L386.7795 2.9284 L385.8613 8.6866 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.11">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-114.0929 -151.5067 L-177.9128 -360.076"/>
+        <path d="M-180.2536 -367.7259 L-181.5236 -354.7881 L-177.6202 -359.1198 L-171.9612 -357.7141 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.12">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-132.0355 -151.5067 L-293.4008 -258.9287"/>
+        <path d="M-300.0602 -263.3619 L-292.8419 -252.55 L-292.5684 -258.3746 L-287.3004 -260.8742 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.13">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-167.6935 -137.7664 L-328.7143 -141.2522"/>
+        <path d="M-336.7124 -141.4254 L-324.8235 -136.1668 L-327.7145 -141.2306 L-324.607 -146.1645 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.24">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-8.3794 14.2666 L-75.7668 128.9991"/>
+        <path d="M-79.8183 135.8973 L-69.4296 128.0823 L-75.2603 128.1369 L-78.0523 123.0178 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.25">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-129.8472 164.134 L-324.7858 226.7353"/>
+        <path d="M-332.4027 229.1814 L-319.4486 230.2729 L-323.8337 226.4296 L-322.5062 220.7518 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.26">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-105.5021 165.8973 L-256.8684 300.4558"/>
+        <path d="M-262.8475 305.7709 L-250.5569 301.5351 L-256.121 299.7914 L-257.2009 294.0613 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.27">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-94.915 165.8973 L-176.4538 360.4545"/>
+        <path d="M-179.546 367.8327 L-170.2963 358.698 L-176.0673 359.5322 L-179.5191 354.8328 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.28">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-90.5605 165.8973 L-118.6948 384.331"/>
+        <path d="M-119.7168 392.2655 L-113.2248 381.0025 L-118.5671 383.3392 L-123.1429 379.7251 Z" stroke="none"/>
+      </g>
+    </g>
+    <g id="y.edge.29">
+      <g text-rendering="geometricPrecision" stroke-miterlimit="1.45" shape-rendering="geometricPrecision" transform="matrix(1,0,0,1,496,453)" stroke-linecap="butt">
+        <path fill="none" d="M-86.1746 165.8973 L-47.9033 399.8404"/>
+        <path d="M-46.6117 407.7354 L-43.6147 395.0856 L-48.0647 398.8535 L-53.4835 396.7001 Z" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.10" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="302" height="17" y="0" clip-path="url(#clipPath3)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath3)" stroke="none">Copyright holder and unique sponsor of PRoot.</text>
+        <text fill="black" x="298" xml:space="preserve" y="13" clip-path="url(#clipPath3)" stroke="none"> </text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L302 0 L302 17 L0 17 L0 0 ZM1 1 L301 1 L301 16 L1 16 L1 1 Z" clip-path="url(#clipPath3)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.11" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="92" height="17" y="0" clip-path="url(#clipPath4)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath4)" stroke="none">Lightning talk</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L92 0 L92 17 L0 17 L0 0 ZM1 1 L91 1 L91 16 L1 16 L1 1 Z" clip-path="url(#clipPath4)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.21" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="659" height="17" y="0" clip-path="url(#clipPath5)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath5)" stroke="none">Enea uses PRoot in an internal tool (host environment for API testing of target software) at a customer.</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L659 0 L659 17 L0 17 L0 0 ZM1 1 L658 1 L658 16 L1 16 L1 1 Z" clip-path="url(#clipPath5)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.26" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="432" height="17" y="0" clip-path="url(#clipPath6)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath6)" stroke="none">About 175 domains references http://proot.me according to Google</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L432 0 L432 17 L0 17 L0 0 ZM1 1 L431 1 L431 16 L1 16 L1 1 Z" clip-path="url(#clipPath6)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.27" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="496" height="17" y="0" clip-path="url(#clipPath7)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath7)" stroke="none">Sony has an internal wiki page about CE Linux that references http://proot.me</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L496 0 L496 17 L0 17 L0 0 ZM1 1 L495 1 L495 16 L1 16 L1 1 Z" clip-path="url(#clipPath7)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.29" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="403" height="17" y="0" clip-path="url(#clipPath8)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath8)" stroke="none">Cisco has an internal wiki page that references http://proot.me</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L403 0 L403 17 L0 17 L0 0 ZM1 1 L402 1 L402 16 L1 16 L1 1 Z" clip-path="url(#clipPath8)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+    <g visibility="hidden" id="tooltip.y.node.30" pointer-events="none">
+      <g fill="rgb(195,212,232)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(195,212,232)">
+        <rect x="0" width="450" height="17" y="0" clip-path="url(#clipPath9)" stroke="none"/>
+        <text fill="black" x="4" xml:space="preserve" y="13" clip-path="url(#clipPath9)" stroke="none">Ericsson has an internal Bugzilla ticket that references http://proot.me</text>
+      </g>
+      <g fill="rgb(49,106,196)" text-rendering="geometricPrecision" shape-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(49,106,196)">
+        <path d="M0 0 L450 0 L450 17 L0 17 L0 0 ZM1 1 L449 1 L449 16 L1 16 L1 1 Z" clip-path="url(#clipPath9)" fill-rule="evenodd" stroke="none"/>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/5.1.0/doc/howto-release.txt b/5.1.0/doc/howto-release.txt
new file mode 100644
index 0000000..59bb724
--- /dev/null
+++ b/5.1.0/doc/howto-release.txt
@@ -0,0 +1,45 @@
+How to make a release of PRoot?
+===============================
+
+This document summarizes checks that must be performed before
+releasing PRoot or CARE.
+
+Checks
+------
+
++ Sanity checks:
+  * on ARM and *all* OBS distros (x86 and x86_64): `make -C test`
+  * on x86_64, with *and* without seccomp:
+    - `make -C tests` on *all* OBS distros
+    - `make -C tests memcheck`
+    - `CFLAGS=-fsanitize=address LDFLAGS=-lasan`
+    - `make -C tests V=1 2>&1 | grep talloc`
+
++ Fonctional checks: no regressions must appear with respect to
+  tests/validation.mk and to the configurations tested in the previous
+  release (`git show tags/...`).
+
++ Performance checks: the following command must not suffer from
+  unexpected performance regression::
+
+    time proot -R / perl -e 'system("/usr/bin/true") for (1..10000)'
+
+  where "/usr/bin/true" is a symlink to "/bin/true".
+
++ Static analysis: Coverity Scan and Clang Scan Build must not report
+  new issues.
+
+
+Documentation Update
+--------------------
+
+0. update "doc/changelog.txt"
+
+1. update the release number in "doc/proot/manual.txt"
+
+2. regenerate the documentation: `make -C doc`
+
+3. regenerate the command-line interface: `cp doc/*.h
+   src/cli/; $EDITOR src/cli/{proot,care}.h`
+
+4. upload the generated RPM .spec file to OBS
diff --git a/5.1.0/doc/proot/changelog.txt b/5.1.0/doc/proot/changelog.txt
new file mode 100644
index 0000000..cb86311
--- /dev/null
+++ b/5.1.0/doc/proot/changelog.txt
@@ -0,0 +1,1171 @@
+Release v5.1.0
+==============
+
+New features
+------------
+
++ Processes under PRoot now appear with their real names, that is,
+  they are not renamed "ld-linux.so" or "prooted-..." anymore:
+
+  before:
+
+      $ proot-v4.0.3 ps
+        PID TTY          TIME CMD
+       7885 pts/11   00:00:00 bash
+       8131 pts/11   00:00:00 proot-v4.0.3
+       8132 pts/11   00:00:00 ld-2.17.so
+
+      $ proot-v5.0.0 ps
+        PID TTY          TIME CMD
+       7885 pts/11   00:00:00 bash
+       7916 pts/11   00:00:00 proot-v5.0.0
+       7917 pts/11   00:00:00 prooted-7916-Jb
+
+  now:
+
+      $ proot-v5.1.0 ps
+        PID TTY          TIME CMD
+       7885 pts/11   00:00:00 bash
+       8585 pts/11   00:00:00 proot-v5.1.0
+       8586 pts/11   00:00:00 ps
+
+Fixes
+-----
+
++ It is now possible to use GDB against multi-threaded programs under
+  PRoot x86_64 and x86.
+
++ It is possible to execute x86_64 programs from x86 programs again.
+
++ It is possible to use x86 ptrace-based programs (strace, gdb, ...)
+  under PRoot x86_64 again.
+
++ The loader is now built with the "build-id" linker option explicitly
+  disabled.  This special section might interfere with loaded
+  programs.
+
++ The loader can now load relocatable objects that have a predefined
+  base address.
+
+Acknowledgements
+----------------
+
+Thanks to Erwan Gouriou, Sébastien Gandon, Christian milkylainen,
+Henrik Wallin, and Frank Teo for their bug reports and tests.
+
+Thanks to Jérôme Audu, Yann Droneaud, and Christophe Monat for their
+precious help.
+
+
+Release v5.0.0
+==============
+
+Highlight
+---------
+
+PRoot used to rely on the ELF loader embedded in the ELF interpreter
+from the GNU libc.  Sadly this latter suffers from many issues:
+
++ programs that use constructors or destructors might crash: a typical
+  example is C++ programs.
+
++ programs that rely on the "rpath" mechanism and that are invoked
+  through a symlink might not start: a typical example is the JVM on
+  Debian.
+
++ programs that read processes command-line migth be confused because
+  initial argv[0] is replaced: typical examples are ps and top.
+
+Moreover not all ELF interpreters provide this feature.  For instance,
+ELF interpreters shipped with Bionic (Android) and some versions of
+the uClibC can't be used as ELF loaders.  As a consequence it was not
+possible to proot into a rootfs that uses such C library.
+
+Now PRoot has its own loader, that means all the limitations above
+doesn't exist anymore.
+
+Fixes
+-----
+
++ Most bugs related to shebang support -- ie. "#!" at the beginning of
+  a program -- were fixed.
+
+Command-line interface changes
+------------------------------
+
++ PRoot now starts a login shell when no command is specified; this
+  makes the shell read profile files from the guest rootfs, as
+  expected by some guest programs.  To get the old behavior, launch
+  "/bin/sh" explicitly:
+
+      proot -r whatever /bin/sh
+
++ The -R option now binds "/run" and "/var/run/dbus/system_bus_socket"
+  too.  This is useful for guest programs that need to communicate
+  with host services.
+
+
+Release v4.0.3
+==============
+
++ Heap emulation is disabled when a "suspicious" call to brk(2) is
+  actually legit, as it might be the case when launching the very
+  first program.
+
++ The "-0" and "-S" options ("root" identity emulation) now fake
+  success of mknodat(2), as it was the case for mknod(2) previously.
+  This missing feature was revealed by the AArch64 port.
+
++ The "-k" option (kernel compatibility emulation) now works on
+  Linux/AArch64.
+
+Thanks to Rémi Duraffort for the bug reports and for his LAVA testing
+platform!
+
+
+Release v4.0.2
+==============
+
++ Fix how the very first program is launched by PRoot.  Previously,
+  argv[0] was not preserved when the very first program was launched
+  through a symbolic link.  This old behavior used to bug programs
+  like Busybox and python-exec.  Thanks to "hhm", Ivailo "fluxer"
+  Monev, and Joakim Tjernlund for the bug reports.
+
++ Fix renameat(2) sysexit support.  There was a bug in PRoot that was
+  exposed by the Aarch64 (a.k.a arm64) port only but that might affect
+  other architectures.
+
++ Fix build for AArch64.  Thanks to Rémi Duraffort for the patches and
+  for the Debian/arm64 testing platform.
+
++ Fix support for "long" socket paths.  These can only be 108 bytes
+  long; this limit might be easily reached with PRoot since the path
+  to the rootfs is always prepended.  The solution was to
+  automatically bind this long path to a shorter path.  This bug was
+  exposed by LibreOffice and Yocto's pseudo.  Thanks to Christophe
+  Guillon for the bug report.
+
+
+Release v4.0.1
+==============
+
++ Fix a couple of portability issues in the testsuite.  Thanks to Rémi
+  Duraffort for all the tests he made on his instance of Linaro LAVA.
+
++ Set $PWD to the value specified by the -w option, otherwise Bash pwd
+  builtin might be confused under some specific circumstances.  Thanks
+  to Jérémy Bobbio for the bug report.
+
++ Fix support for accessat and fchmodat syscalls: they have only three
+  parameters, not four.  This bug was exposed by Gentoo's sandbox:
+
+      proot -S gentoo-amd64-hardened+nomultilib-rootfs emerge util-linux
+
+
+Release v4.0.0
+==============
+
+Highlights
+----------
+
++ It is now possible to use GDB, Strace, or any other program based on
+  "ptrace" under PRoot.  This was not the case previously because it
+  is not possible to stack ptracers on Linux, so an emulation layer
+  was developed in order to bypass this limitation.  This has required
+  a lot of changes in PRoot, hence the major number version bumping.
+  It was mostly tested on x86_64, and partially tested on x86 and ARM.
+  This ptrace emulation support is still experimental, and there are a
+  couple of known issues, but feel free to report unexpected behaviors
+  if you need a fix.
+
++ A new command-line option is available: "-S".  It is similar to the
+  "-R" option expect it enables the "-0" option and binds only a
+  minimal set of paths that are known to not be updated by package
+  installations, to avoid unexpected changes on host files.  This
+  option is useful to safely create and install packages into the
+  guest rootfs.  For example:
+
+      $ proot -S ubuntu-14.04-rootfs/ apt-get install samba
+
+  or:
+
+      $ proot -S ubuntu-14.04-rootfs/
+      # apt-get install samba
+
+  If "-0 -R" is used instead of "-S", the same command fails since it
+  tries to update "/etc/group", which is bound to the host system and
+  is not writable (assuming PRoot is ran without privileges):
+
+      $ proot -0 -R ubuntu-14.04-rootfs/
+      # apt-get install samba
+      [...]
+      Adding group `sambashare' (GID 105) ...
+      Permission denied
+
++ The fake_id0 extension can now fake any user and group identifiers.
+  That means, when "-0" is specified, PRoot-ed processes can change
+  their real, effective and saved identifiers, with respect to the
+  rules described in setuid, setfsuid, setreuid, setresuid, and
+  setfsuid manuals.  Also, the new command-line option "-i" was added
+  to change explicitly the identifiers to the specified values.  This
+  option will be used by CARE to re-execute with the same initial
+  identifiers, but it could also be useful to threaten your teammates
+  ;).  Note that the "-0" option is actually the same as "-i 0:0".
+
++ The old command-line interface is not supported anymore.  That means
+  it is now impossible to specify the path to the guest rootfs without
+  using -r or -R.  Also, -Q and -B options are definitively gone,
+  instead the -R option must be specified, respectively with and
+  without -q.  See PRoot v3.1 release notes for details.
+
+Fixes
+-----
+
++ getcwd(2) and chdir(2) now return the correct error code when,
+  respectively, the current directory does not exist anymore and the
+  target directory doesn't have the "search" permission.
+
++ Named file descriptors (ie. links in /proc/<pid>/fd/*) are not
+  dereferenced anymore since they may point to special objects like
+  pipes, sockets, inodes, ...  Such objects do not exist on the
+  file-system name-space, so dereferencing them used to cause
+  unexpected errors.
+
++ Extensions now see every component of canonicalized paths.  An
+  optimization in the canonicalization loop used to skip the first
+  part of a path if it was known to be already canonicalized, sadly
+  this short-cut may confuse some extensions, like -0.
+
++ Temporary files and directories created by PRoot for its own purpose
+  are now automatically deleted when PRoot exits.
+
+
+Miscellaneous
+-------------
+
++ PRoot does not rely on GCC C extensions anymore, like nested
+  functions.  That means its stack does not have to be executable
+  (this is required for hardened Linux systems), and it can now be
+  compiled with Clang.
+
++ The ASLR (Address Space Layout Randomization) is not disabled
+  anymore, and the heap is now emulated on all architectures.
+
+
+Internal changes
+----------------
+
+This section is dedicated to developers.
+
++ PRoot now remembers the parent of all tracees, it is similar to a
+  traced process tree.  This was required for the ptrace emulation
+  support, but this could be useful to some extensions.
+
++ It is now possible to restart a tracee with any ptrace restart mode:
+  single-step, single-block, ...
+
++ Functions {peek,poke}_mem were replaced with functions
+  {peek,poke}_{,u}int{8,16,32,64}.  These new functions performs type
+  conversion and fetch only the necessary amount of data in target
+  tracee's memory to avoid invalid accesses.
+
++ There is a new interface to handle ELF auxiliary vectors.  See
+  ptrace emulation, kompat and fake_id0 extensions for usage examples.
+
++ There is a new interface to create temporary files and directories
+  that are automatically deleted on exit.  See CARE extension, glue
+  and auxv support for usage examples.
+
++ When built with GCC function instrumentation support, PRoot prints
+  the currently called function on standard error stream (stderr).
+
+Thanks
+------
+
+Thanks go to Stephen McCamant, Oren Tirosh, Jérôme Audu, and Carlos
+Hernan Prada Rojas for their bug reports and tests; and to Rémi
+Duraffort for his contributions.
+
+
+Release v3.2.2
+==============
+
++ Remove a useless memory layout constraint on x86_64 that bugs some
+  programs like java and or qemu.
+
++ It is now possible to launch the initial program from a relative
+  path without specifying the "./" prefix, for example:
+
+    $ proot path/to/program
+
++ Don't discard fcntl(F_DUPFD_CLOEXEC) systematically when the kompat
+  extension is enabled (-k option).
+
++ Don't use syscalls that require Linux >= 2.6.16 anymore.
+
+
+Release v3.2.1
+==============
+
++ Make ptrace/seccomp even more portable on Ubuntu.
+
+Thanks to Maxence Dalmais for the bug report and tests.
+
+
+Release v3.2
+============
+
+This release was mostly driven by the requirements of "CARE", a new
+project based on PRoot that will be released publicly soon on
+http://reproducible.io.  For information, "CARE" is the short for
+"Comprehensive Archiver for Reproducible Execution".
+
+Highlights
+----------
+
++ Many bugs exposed by a couple of static code analyzers (Coverity,
+  Clang, ...) and some test-suites (Linux Test Project, libuv, ...)
+  are now fixed.
+
++ The "kompat" extension ("-k" option) can now emulate most of the
+  kernel features that would be required by the guest system but that
+  are not available on the host kernel.  For example, it can now make
+  programs from Ubuntu 13.04 64-bit run on RedHat 5 64-bit without any
+  further tweaks:
+
+     rh5-64$ proot -k 3.8 -R ubuntu-13.04-64bit/ ...
+
++ On ARM and x86_64, the heap segment is now emulated with a regular
+  memory mapping to ensure this former always exists.  This was
+  required because some kernels might put a non-fixed memory mapping
+  right after the regular heap when using some GNU ELF interpreters
+  (ld.so) as loaders.  Without the heap segment emulation, some
+  programs like Bash would crash because the heap can't grow anymore:
+
+      bash: xmalloc: locale.c:73: cannot allocate 2 bytes (0 bytes allocated)
+
+Miscellaneous
+-------------
+
++ When using the "-R" option, the path to the guest rootfs is now
+  bound into the guest rootfs itself.  This is required to run
+  programs that search for their DSOs in /proc/self/maps, like VLC for
+  instance.
+
++ When using the "-v" option with a level greater than 2, syscalls are
+  now printed as strings instead of numbers, à la strace:
+
+    $ proot -v 3 true
+    [...]
+    proot info: pid 29847: sysenter start: mmap(0x0, 0x2d141, 0x1, 0x2, 0x3, 0x0) [...]
+    [...]
+
++ The article about the migration from ScratchBox2 is now publicly
+  available:
+
+    https://github.com/cedric-vincent/PRoot/blob/v3.2/doc/articles/howto_migrate_from_scratchbox2.txt
+
+Internal changes
+----------------
+
++ Tools based on PRoot (CARE, DepsTracker, ATOS, ...) can now easily
+  replace the original command-line interface with their own
+  command-line interface.
+
++ It is now possible to chain forged syscalls to a regular syscall.
+  Search for "register_chained_syscall" in the sources for details.
+
++ A couple of new helpers are now visible from the extensions.
+
+Thanks
+------
+
++ Bug reports and tests: Corbin Champion, Maxence Dalmais, and Nicolas
+  Cornu.
+
++ Static code analysis: Antoine Moynault and Christophe Guillon.
+
++ Patches: Rémi Duraffort.
+
++ Unexpected hint: Christophe Monat :)
+
+
+Release v3.1
+============
+
+Command-line interface changes
+------------------------------
+
++ The initial command is not search in "." anymore, unless the "./"
+  prefix is specified or unless "." is in $PATH, as expected.
+
++ The "-B" and "-Q" options are obsoleted by the new "-R" option.
+  This latter is equivalent to "-B -r", as there was actually no point
+  at using the "-B" option without "-r".
+
++ A warning is now emitted when the rootfs is specified à la
+  chroot(1), that is, without using "-r" or "-R".
+
+The old command-line interface is not documented anymore, but it will
+be still supported for a couple of releases.  Although, users are
+strongly encouraged to switch to the new one:
+
+        ======================   =================
+        old CLI                  new CLI
+        ======================   =================
+        proot rootfs             proot -r rootfs
+        proot -B rootfs          proot -R rootfs
+        proot -B -r rootfs       proot -R rootfs
+        proot -Q qemu rootfs     proot -R rootfs -q qemu
+        proot -Q qemu -r rootfs  proot -R rootfs -q qemu
+        =======================  =======================
+
+Extensions
+----------
+
++ The "kompat" extension ("-k" option) has been greatly enhanced.  For
+  example, it can now make programs from Ubuntu 13.04 32-bit run on
+  RedHat 5 64-bit:
+
+     rh5-64$ proot -k 3.8 -R ubuntu-13.04-32bit/ ...
+
++ The "fake id0" extension ("-0" option) handles more syscalls:
+  mknod(2), capset(2), setxattr(2), setresuid(2), setresgid(2),
+  getresuid(2), and getresgid(2).
+
+Miscellaneous
+-------------
+
++ PRoot is now compiled with large file-system support (LFS), this
+  make it works with 64-bit file-systems (eg. CIFS) on 32-bit
+  platforms.
+
++ The special symbolic link "/proc/self/root" now points to the guest
+  rootfs, that is, to the path specified by "-r" or "-R".  Just like
+  with chroot(2), this symlink may be broken as the referenced host
+  path likely does not exist in the guest rootfs.  Although, this
+  symlink is typically used to know if a process is under a chroot-ed
+  environment.
+
++ Under QEMU, LD_LIBRARY_PATH is not clobbered anymore when a guest
+  program is launched by a host program.
+
++ When seccomp-filter is enabled, this release is about 8% faster than
+  the previous one.
+
++ A couple of bugs reported by Scan Coverity are fixed.
+
+Thanks
+------
+
+Special thanks to Stephan Hadamik, Jérôme Audu, and Rémi Duraffort for
+their valuable help.
+
+
+Release v3.0.2
+==============
+
++ Fix the search of the initial command: when the initial command is a
+  symbolic link, PRoot has to dereference it in guest namespace, not
+  in the host one.
+
++ Return error code EACCESS instead of EISDIR when trying to execute a
+  directory.  Some programs, such as "env", behave differently with
+  respect to this error code.  For example:
+
+      ### setup
+      $ mkdir -p /tmp/foo/python
+      $ export PATH=/tmp/foo:$PATH
+
+      ### before (PRoot v2.3 ... v3.0.1)
+      before$ proot env python
+      env: python: Is a directory
+
+      ### now (PRoot v3.0.2 ...)
+      $ proot env python
+      Python 2.7.5 (default, May 29 2013, 02:28:51)
+      [GCC 4.8.0] on linux2
+      Type "help", "copyright", "credits" or "license" for more information.
+      >>>
+
+
+Release v3.0.1
+==============
+
+Fix support for bindings where the guest path is explicitly not
+dereferenced.  Be careful, the syntax has changed:
+
+        before$ proot -b /bin/bash:!/bin/sh
+
+        now$ proot -b /bin/bash:/bin/sh!
+
+
+Release v3.0
+============
+
+New features
+------------
+
++ PRoot can now use the kernel feature named "seccomp-filter", a.k.a
+  "seccomp mode 2", to improve its own performance significantly.  For
+  examples on my workstation, the tables below show the time overhead
+  induced by PRoot compared to a native execution:
+
+  - when generating the Perl 5.16.1 package:
+
+    ===============  ===========  ==========
+    command          seccomp off  seccomp on
+    ===============  ===========  ==========
+    ./configure.gnu          75%         25%
+    make -j4                 70%         45%
+    make -j4 check           25%          9%
+    ===============  ===========  ==========
+
+  - when generating the Coreutils 8.19 package:
+
+    ===============  ===========  ==========
+    command          seccomp off  seccomp on
+    ===============  ===========  ==========
+    ./configure              80%         33%
+    make -j4                 75%         33%
+    make -j4 check           80%          8%
+    ===============  ===========  ==========
+
++ It is now possible to explicitly not dereference the guest location
+  of a binding by specifying ``!`` as the first character.  For
+  instance::
+
+      proot -b /bin/bash:!/bin/sh
+
+  will not overlay ``/bin/dash`` when this latter is pointed to by
+  ``/bin/sh`` (it's typically the case on Ubuntu and Debian).
+
+Fix
+---
+
++ The initial command is not search in $PATH anymore when it starts
+  with ``/`` or ``./``, and it doesn't exist.  For instance::
+
+      $ rm test
+      $ proot ./test
+      proot warning: './test not found (root = /, cwd = /usr/local/cedric/git/proot)
+      proot error: see `proot --help` or `man proot`.
+
+Thanks
+------
+
+Many thanks to Will Drewry and Indan Zupancic, who made possible to
+accelerate PTRACE_SYSCALL with seccomp-filter.  Also, thanks to Paul
+Moore for his valuable set of seccomp tools.
+
+Notes
+-----
+
++ Unlike what I said, this release is not shipped with a ptrace
+  emulator.  It's planned for the next one, though.
+
++ Seccomp-filter was first introduced in Linux 3.5 a year ago, it was
+  also officially back-ported to Ubuntu 12.04 (Linux 3.2).  To know if
+  PRoot is actually using this accelerator on your system, check the
+  verbose output.  For instance::
+
+    $ proot -v 1 true
+    ...
+    proot info: ptrace acceleration (seccomp mode 2) enabled
+    ...
+
+  But first, be sure it was built with this support::
+
+    $ proot -V
+    ...
+    built-in accelerators: process_vm = yes, seccomp_filter = yes
+    ...
+
+
+Release v2.4.1
+==============
+
+Fixes
+-----
+
++ Fix all warnings reported by GCC-4.8 "-Wall -Wextra" and Coverity
+  Prevent 4.5.
+
++ Fix Unix sockets path translation for some x86_64 systems.
+
++ Make the "kompat" extension (-k option) work again.
+
++ Fix spurious "can't delete /tmp/proot-$PID-XXXXX" messages.
+
+
+
+Release v2.4
+============
+
+New architectures
+-----------------
+
++ PRoot now works natively on Linux ARM64 systems (a.k.a AArch64).
+  Note that PRoot/AArch64 doesn't support 32-bit binaries yet.
+
++ PRoot/x86_64 now supports x32 binaries/rootfs.
+
+Fixes
+-----
+
++ Paths from Unix domain sockets are now translated.  For example, it
+  wasn't possible previously to use "tmux" in the guest rootfs if
+  another instance were running in the host rootfs.
+
++ When a host path is bound to a nonexistent guest path, PRoot tries
+  to create this latter in the guest rootfs, for some technical
+  reasons.  Previously, this "dummy" guest path was created with RWX
+  permissions but this might cause troubles when re-using the rootfs
+  for other purpose.  Now, this "dummy" guest path is created with
+  minimal permissions, and it is also possible to avoid its creation
+  by defining the PROOT_DONT_POLLUTE_ROOTFS environment variable.
+
+Command-line interface changes
+------------------------------
+
++ The directory "/run" is removed from the list of recommended
+  bindings (-B option) because this creates to much conflicts with
+  programs that write in the "/run/var" directory.
+
++ The -0 option now makes user's files appear as if they were actually
+  owned by root, and it also fakes the success of any mode changes
+  (chmod* syscalls).  This is typically useful to create packages
+  where the files belong to the root user (it's almost always the
+  case).
+
+Internal changes
+----------------
+
++ PRoot should be even more portable now.  For instance, there's no
+  need to worry about syscallee-saved registers anymore.
+
+Thanks
+------
+
+This release was made possible thanks to, in no special order: Yvan
+Roux, Jerôme Audu, Heehooman, Yann Droneaud, and James Le Cuirot.  See
+"git log" for details.
+
+
+Release v2.3.1
+==============
+
+New feature
+-----------
+
++ The "fake id0" feature was improved by Rémi Duraffort in order to
+  support privileged write operations in read-only files/directories.
+  Some package managers (Fedora, Debian, ...) relies on this special
+  behavior::
+
+      # ls -ld /usr/lib
+      dr-xr-xr-x 22 root root 40960 Jan  2 11:19 /usr/lib/
+      # install -v something.so /usr/lib/
+      removed ‘/usr/lib/something.so‘
+      ‘something.so‘ -> ‘/usr/lib/something.so‘
+
+Fixes
+-----
+
++ Fix bindings to a guest path that contains a symbolic link.  For
+  example when the given guest path ``/var/run/dbus`` is a symbolic
+  link to ``/run/dbus``.
+
++ Fix a memory corruption when accessing files in "/proc/self/"
+
+Special thanks to Rémi Duraffort for the improved "fake id0" feature
+and for the bug reports.
+
+
+Release v2.3
+============
+
+This release is intended more specifically to developers and advanced
+users, it was mostly driven by the requirements of an internal
+STMicroelectronics project named "Auto-Tuning Optimization Service".
+
+New features
+------------
+
++ There's now an extension mechanism in PRoot that allows developers
+  to add their own features and/or to use PRoot as a Linux process
+  instrumentation engine.  The two following old features were moved
+  to this new extension interface: "-k *string*" and "-0"
+  (respectively: set the kernel release and compatibility level to
+  *string*"; and force some syscalls to behave as if executed by
+  "root").
+
++ It is now possible to execute PRoot under PRoot, well somewhat.
+  Actually the initial instance of PRoot detects that it is being
+  called again and recomputes the configuration for the new process
+  tree.  This feature is still experimental and was way harder to
+  implement than expected, however it was worth the effort since it
+  enforced the consistency in PRoot.  Just one example among many, in
+  PRoot the "chroot" feature is now really equivalent to the
+  "mount/bind" one, that is, ``chroot path/to/rootfs`` is similar to
+  ``mount --bind path/to/rootfs /``.
+
++ The "current working directory" (chdir(2), getcwd(2), ...) is now
+  fully emulated by PRoot.  Sadly a minor regression was introduced:
+  even if the current working directory has been removed, getcwd(2)
+  returns a "correct" value.  This should be fixed in the next
+  release.
+
+Command-line interface changes
+------------------------------
+
++ The message "proot info: started/exited" isn't printed by default
+  anymore since it might introduce noise when PRoot is used inside a
+  test-suite that compares outputs.  This message was initially added
+  to know whether the guest program has exited immediately.
+
++ The "-u" and "-W" options have disappeared.  The former wasn't
+  really useful and the latter was definitely useless since the
+  default "current working directory" is "." since v2.1, that means
+  the three examples below are equivalent ("-W" was just an alias to
+  "-b . -w .")::
+
+      proot -b . [...]
+      proot -b . -w . [...]
+      proot -W [...]
+
+Fixes
+-----
+
++ The option ``-w .`` is now really equivalent to ``-w $PWD``.
+
++ A bug almost impossible to describe here has been fixed, it appeared
+  only when specifying relative bindings, for instance: ``-b .``.
+
+Internal changes
+----------------
+
++ PRoot now relies on Talloc: a hierarchical, reference counted memory
+  pool system with destructors.  It is the core memory allocator used
+  in Samba: http://talloc.samba.org.  This is definitely a worthwhile
+  dependency for the sake of development scalability and
+  debuggability.  For example, PRoot now has an explicit garbage
+  collector (c.f. ``tracee->ctx``), and the full dynamic memory
+  hierarchy can be printed by sending the USR1 signal to PRoot::
+
+      native-shell$ proot --mount=$HOME --mount=/proc --rootfs=./slackware-14/
+      prooted-shell$ kill -s USR1 $(grep Tracer /proc/self/status | cut -f 2)
+
+      Tracee           0x6150c0  768 bytes  0 ref'    (pid = 22495)
+          talloc_new: ./tracee/tracee.c:97 0x615420  0 bytes  0 ref'
+          $exe             0x61bef0  10 bytes  0 ref'     ("/bin/bash")
+          @cmdline         0x61bf60  16 bytes  0 ref'     ("/bin/sh", )
+              /bin/sh          0x61bfd0  8 bytes  0 ref'
+          $glue            0x61bae0  24 bytes  0 ref'     ("/tmp/proot-22494-UfGAPh")
+          FileSystemNameSpace 0x615480  32 bytes  0 ref'
+              $cwd             0x61b880  13 bytes  0 ref'     ("/home/cedric")
+              Bindings         0x61b970  16 bytes  0 ref'     (host)
+                  Binding          0x615570  8280 bytes  1 ref'   (/home/cedric:/home/cedric)
+                  Binding          0x6176a0  8280 bytes  1 ref'   (/proc:/proc)
+                  Binding          0x6197d0  8280 bytes  1 ref'   (/usr/local/proot/slackware-14:/)
+              Bindings         0x61b900  16 bytes  0 ref'     (guest)
+                  Binding          -> 0x6176a0
+                  Binding          -> 0x615570
+                  Binding          -> 0x6197d0
+
+
+Release v2.2
+============
+
++ This release brings some critical fixes so an upgrade is highly
+  recommended, especially on x86_64 and Ubuntu.
+
++ PRoot is now a lot faster: the speed-up can be up to 50% depending
+  on the kind of application.
+
++ PRoot can now mount/bind files anywhere in the guest rootfs, even if
+  the mount point has no parent directory (and/or can't be created).
+  With previous versions of PRoot, that would created kinda black hole
+  in the filesystem hierarchy that might bug some programs like "cpio"
+  or "rpm".
+
+  For example, with the previous version of PRoot::
+
+       $ proot -b /etc/motd:/black/holes/and/revelations
+       proot warning: can't create the guest path (binding) ...
+       proot info: started
+
+       $ find /black
+       find: `/black: No such file or directory
+
+       $ cat /black/holes/and/revelations
+       Time has come to make things right -- Matthew Bellamy
+
+  And now::
+
+       $ proot -b /etc/motd:/black/holes/and/revelations
+       proot info: started
+
+       $ find /black
+       /black
+       /black/holes
+       /black/holes/and
+       /black/holes/and/revelations
+
+       $ cat /black/holes/and/revelations
+       Time has come to make things right -- Matthew Bellamy
+
++ "/run" was added to the list of recommended bindings (-B/-Q).
+
++ SH4 and ARM architectures are now officially supported.
+
+Thanks
+------
+
+Huge thanks to Rémi DURAFFORT for all the tests, bug reports, fixes,
+and for hosting http://proot.me.
+
+Thanks to Thomas P. HIGDON for the advanced investigation on a really
+tricky bug (red zone corruption).
+
+
+Release v2.1
+============
+
+New features
+------------
+
++ PRoot can now emulate some of the syscalls that are available in the
+  kernel release specified by -k but that are missing in the host
+  kernel.  This allows the execution of guest programs expecting a
+  kernel newer than the actual one, if you encountered the famous
+  "FATAL: kernel too old" or "qemu: Unsupported syscall" messages.
+
++ The current working directory isn't changed anymore if it is still
+  accessible in the guest environment (binding).
+
+Fixes
+-----
+
++ Added support for architectures with no misalignment support (SH4).
+
++ Fix support for: link(2), linkat(2), symlink(2), and symlinkat(2).
+
+
+Release v2.0.1
+==============
+
++ Fix a compatibility issue with QEMU v1.1
+
++ Fix the initialization of bindings that point to "/proc/self".
+
+These problems were reported by Alkino:
+
+    https://github.com/cedric-vincent/PRoot/issues/3
+
+
+Release v2.0
+============
+
+New features
+------------
+
++ There's now a specific support to handle special symlinks in /proc.
+  As of now, only the following ones are correctly handled:
+
+      * /proc/self, it was already supported previously but now this
+        is done consistently (i.e. not a hack);
+
+      * /proc/<PID>/exe, for any <PID> monitored by PRoot; and
+
+      * /proc/<PID>/fd/<FD>.
+
++ The list of supported syscalls was updated, as of Linux 3.4.1.
+
+Command-line interface changes
+------------------------------
+
++ The path to the guest rootfs can now be specified by the new
+  -r/--rootfs option.  This permits the use of shell aliases, for
+  example:
+
+      $ alias armedslack='proot -Q qemu-arm -r /path/to/armedslack'
+      $ armedslack -v 1 -b ~/arm_cpuinfo:/proc/cpuinfo
+
+  That wasn't possible previously because the path to the guest rootfs
+  had to be the last option.
+
++ The -v/--verbose option now takes a parameter, and a negative
+  integer makes PRoot quiet except on fatal errors.
+
++ The -h/--help option now prints a detailed message.
+
++ The -V/--version and -h/--help options now exit with success.
+
+Fix
+---
+
++ Return correct errno if a non-final path component isn't a directory
+  nor a symlink.
+
++ Fix the insertion of an item in the list of host/guest bindings.
+
+
+Internal changes
+----------------
+
+This section is dedicated to PRoot developers.
+
++ File-system information is now inherited from a traced process to
+  its children.  This permits the emulation of symlinks in /proc/self:
+  cmdline, exe, cwd, root, ...
+
++ The execution of QEMU is now fully confined to the virtual rootfs
+  namespace: it now relies on the "mixed-execution" feature, just like
+  a regular host program.
+
+
+Release v1.9
+============
+
+Fixes
+-----
+
++ Be as transparent as possible with respect to SIGSTOP and SIGTRAP
+  signals.  For instance, the Open POSIX Test Suite now reports the
+  same level of success whether it is run under PRoot or not (it
+  depends on the kernel version though).
+
++ Ignore terminating signals and kill all tracees on abnormal
+  termination signals (^\, segmentation fault, divide by zero, ...).
+  This ensures no tracee will stay alive without being monitored
+  anymore.
+
++ Force utsname.machine to "i686" -- instead of "i386" -- for 32-bit
+  programs running on x86_64 systems.  This improves the compatibility
+  with package managers that deduce the current architecture from
+  `uname -m`.
+
++ Fix x86_64 support for linkat() and fchownat().
+
++ Fix mixed-execution support, LD_LIBRARY_PATH was defined twice for
+  host programs.
+
+
+Release v1.8.4
+==============
+
+New feature
+-----------
+
++ The -0 option now fakes success on ``chroot("/")``.  This feature is
+  required by some guest package managers, like ``pacman`` -- the Arch
+  Linux Package Manager.
+
+Fix
+---
+
++ Nested bindings are now correctly supported.  For example with these
+  bindings -- nested from the host point-of-view::
+
+      host$ proot -b /:/host-rootfs -b /tmp ...
+      guest$ ln -s /tmp/bar /tmp/foo
+      # ... points to "/tmp/bar" instead of "/host-rootfs/tmp/bar"
+
+  and with these bindings -- nested from the guest point-of-view::
+
+      host$ proot -b /bin -b /usr/bin/find:/bin/find ...
+      guest$ /bin/find
+      # ... works instead of "no such file or directory"
+
+Internal changes
+----------------
+
+This section is dedicated to PRoot developers.
+
++ Functions to compare two pathes (equal, prefix, not comparable, ...)
+  are now available, at last.
+
++ The "ignore ELF interpreter" option can be (dis|en)able with the
+  ``PROOT_IGNORE_ELF_INTERPRETER`` environment variable and/or with
+  the ``config.ignore_elf_interpreter`` internal variable.
+
+
+Release v1.8.3
+==============
+
+New features
+------------
+
++ The -0 option now fakes success on ownership changes.  This improves
+  the compatibility with package managers that abort if ``chown(2)``
+  fails.  Note that this is quite limited compared to ``fakeroot``.
+
++ Force utsname.machine to "i386" for 32-bit programs running on
+  x86_64 systems.  This improves the compatibility with package
+  managers that deduce the current architecture from `uname -m`.
+
+Fixes
+-----
+
++ Fix a regression regarding the concatenation of the ``..`` with a
+  path ending with ``.``.  For intance you can now do ``ls foo`` where
+  ``foo`` is a symbolic link to ``/bar/.``.
+
++ Don't return an error if the specified size for ``getcwd(2)`` and
+  ``readlink(2)`` is greater than PATH_MAX.  Technically the result
+  may likely be shorter than this limit.
+
+
+Release v1.8.2
+==============
+
++ This is the first public release of PRoot, it's time to increase its
+  maturity artificially ...  Actually it's an homage to Blink 182 ;)
+
++ User manual finally published.
+
++ PRoot can now *mix* the execution of host programs and the execution
+  of guest programs emulated by QEMU.  This is useful to use programs
+  that aren't available initially in the guest environment and to
+  speed up build-time by using cross-compilation tools or any CPU
+  independent program, like interpreters.
+
++ Absolute symlinks from bound directories that point to any bound
+  directory are kept consistent: for example, given the host symlink
+  ``/bin/sh -> /bin/bash``, and given the command-line option ``-b
+  /bin:/foo``, the symlink will appeared as ``/foo/sh -> /foo/bash``.
+
++ Three command-line options are gone:
+
+  * ``-p`` (don't block the ptrace syscall) wasn't really useful.
+
+  * ``-e`` (don't use the ELF interpreter) isn't required anymore.
+
+  * ``-a`` (disable the ASLR mechanism) is now the default.
+
++ Don't complain anymore when parent directories of a *recommended
+  binding* (as enabled by ``-B``, ``-M`` and ``-Q`` options) can't be
+  created.
+
++ Support job control under ptrace as introduced in Linux 3.0+.
+
++ ``LD_`` environment variables are now passed to the QEMUlated
+  program, not to QEMU itself.  It means ``ldd`` works (there's a bug
+  in QEMU/ARM though).
+
++ Many fixes and improved compatibility thanks to the Open Build
+  Service instantiated at http://build.opensuse.com
+
++ Note: v0.7.1 was an experimental release.
+
+
+Release v0.7.0
+==============
+
++ Search the guest program in $PATH relatively to the guest rootfs,
+  for instance you can now just write::
+
+      proot /path/to/guest/rootfs/  perl
+
+  instead of::
+
+      proot /path/to/guest/rootfs/  /usr/bin/perl
+
++ The command-line interface was re-written from scratch, the only
+  incompatible change is that QEMU options are now separated by
+  spaces::
+
+     proot -Q "qemu-arm -g 1234" ...
+
+  instead of::
+
+     proot -Q qemu-arm,-g,1234 ...
+
++ New option "-0": force syscalls "get*id" to report identity 0, aka
+  "root".
+
++ Many fixes, code refactoring, new testing framework, ...
+
+Special thanks to Claire ROBINE for her contribution.
+
+
+Release v0.6.2
+==============
+
++ Change the default command from $SHELL to "/bin/sh".  The previous
+  behaviour led to an unexpected error -- from user's point-of-view --
+  when $SHELL didn't exit in the new root file-system.
+
++ Fix *partially* support for readlink(2) when mirror pathes are in
+  use.  Prior this patch, any symbolic link -- that points to an
+  absolute path which prefix is equal to the host-side of any mirror
+  path -- was bugged.  For instance, the command "proot -m /bin:/host
+  $ROOTFS /usr/bin/readlink /usr/bin/ps" returned "/host" instead of
+  "/bin/ps".
+
++ Add the option "-V" to print the version then exit.
+
++ Be more explicit when a wrong command-line argument is used.
+
++ Remove the SIGSEGV help message: it was too confusing to the user.
+
++ Use a new shining build-system (again :D).
+
+Special thanks go to those contributors: Yves JANIN, Remi Duraffort
+and Christophe GUILLON.
+
+
+Release v0.6.1
+==============
+
++ Add `/tmp` to the list of mirrored paths when using -M.
+
++ Fix the ELF interpreter extraction.
+
++ Rewrite the build system.
+
+
+Release v0.6
+============
+
+New features
+------------
+
++ Added support for "asymmetric" path mirrors.
+
+    The command-line option for mirrors was extended to support the
+    syntax "-m <p1>:<p2>" where <p1> is the location of the mirror
+    within the alternate rootfs and <p2> is the path to the real
+    directory/file.  For instance you can now mirror the whole host
+    rootfs in the directory "/hostfs" within the alternate rootfs that
+    way::
+
+        proot -m /:/hostfs ...
+
++ Added an option to disable ASLR (Address Space Layout
+  Randomization).
+
+    RHEL4 and Ubuntu 10.04 use an ASLR mechanism that creates
+    conflicts between the layout of QEMU and the layout of the target
+    program.  This new option is automatically set when QEMU is used.
+
++ Added "/etc/resolv.conf" and $HOME to the list of mirrored paths
+  when using the option -M or -Q.
+
+Fixes
+-----
+
++ Fixed the detranslation of getcwd(2) and readlink(2).
+
++ Improved the build compatibility on old/broken distro.
+
++ Added support for pthread cancellation when QEMU is used.
+
++ Set QEMU's fake argv[0] to the program actually launched, not to the
+  initial script name.
+
++ Create the path up to the mirror location to cheat "walking"
+  programs.
+
diff --git a/5.1.0/doc/proot/man.1 b/5.1.0/doc/proot/man.1
new file mode 100644
index 0000000..f810410
--- /dev/null
+++ b/5.1.0/doc/proot/man.1
@@ -0,0 +1,727 @@
+.\" Man page generated from reStructuredText.
+.
+.TH PROOT 1 "2014-12-12" "5.1.0" ""
+.SH NAME
+PRoot \- chroot, mount \-\-bind, and binfmt_misc without privilege/setup
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH SYNOPSIS
+.sp
+\fBproot\fP [\fIoption\fP] ... [\fIcommand\fP]
+.SH DESCRIPTION
+.sp
+PRoot is a user\-space implementation of \fBchroot\fP, \fBmount \-\-bind\fP,
+and \fBbinfmt_misc\fP\&.  This means that users don\(aqt need any privileges
+or setup to do things like using an arbitrary directory as the new
+root filesystem, making files accessible somewhere else in the
+filesystem hierarchy, or executing programs built for another CPU
+architecture transparently through QEMU user\-mode.  Also, developers
+can use PRoot as a generic Linux process instrumentation engine thanks
+to its extension mechanism, see \fI\%CARE\fP for an example.  Technically
+PRoot relies on \fBptrace\fP, an unprivileged system\-call available in
+every Linux kernel.
+.sp
+The new root file\-system, a.k.a \fIguest rootfs\fP, typically contains a
+Linux distribution.  By default PRoot confines the execution of
+programs to the guest rootfs only, however users can use the built\-in
+\fImount/bind\fP mechanism to access files and directories from the actual
+root file\-system, a.k.a \fIhost rootfs\fP, just as if they were part of
+the guest rootfs.
+.sp
+When the guest Linux distribution is made for a CPU architecture
+incompatible with the host one, PRoot uses the CPU emulator QEMU
+user\-mode to execute transparently guest programs.  It\(aqs a convenient
+way to develop, to build, and to validate any guest Linux packages
+seamlessly on users\(aq computer, just as if they were in a \fInative\fP
+guest environment.  That way all of the cross\-compilation issues are
+avoided.
+.sp
+PRoot can also \fImix\fP the execution of host programs and the execution
+of guest programs emulated by QEMU user\-mode.  This is useful to use
+host equivalents of programs that are missing from the guest rootfs
+and to speed up build\-time by using cross\-compilation tools or
+CPU\-independent programs, like interpreters.
+.sp
+It is worth noting that the guest kernel is never involved, regardless
+of whether QEMU user\-mode is used or not.  Technically, when guest
+programs perform access to system resources, PRoot translates their
+requests before sending them to the host kernel.  This means that
+guest programs can use host resources (devices, network, ...) just as
+if they were "normal" host programs.
+.SH OPTIONS
+.sp
+The command\-line interface is composed of two parts: first PRoot\(aqs
+options (optional), then the command to launch (\fB/bin/sh\fP if not
+specified).  This section describes the options supported by PRoot,
+that is, the first part of its command\-line interface.
+.SS Regular options
+.INDENT 0.0
+.TP
+.BI \-r \ path\fP,\fB \ \-\-rootfs\fB= path
+Use \fIpath\fP as the new guest root file\-system, default is \fB/\fP\&.
+.sp
+The specified \fIpath\fP typically contains a Linux distribution where
+all new programs will be confined.  The default rootfs is \fB/\fP
+when none is specified, this makes sense when the bind mechanism
+is used to relocate host files and directories, see the \fB\-b\fP
+option and the \fBExamples\fP section for details.
+.sp
+It is recommended to use the \fB\-R\fP or \fB\-S\fP options instead.
+.TP
+.BI \-b \ path\fP,\fB \ \-\-bind\fB= path\fP,\fB \ \-m \ path\fP,\fB \ \-\-mount\fB= path
+Make the content of \fIpath\fP accessible in the guest rootfs.
+.sp
+This option makes any file or directory of the host rootfs
+accessible in the confined environment just as if it were part of
+the guest rootfs.  By default the host path is bound to the same
+path in the guest rootfs but users can specify any other location
+with the syntax: \fB\-b *host_path*:*guest_location*\fP\&.  If the
+guest location is a symbolic link, it is dereferenced to ensure
+the new content is accessible through all the symbolic links that
+point to the overlaid content.  In most cases this default
+behavior shouldn\(aqt be a problem, although it is possible to
+explicitly not dereference the guest location by appending it the
+\fB!\fP character: \fB\-b *host_path*:*guest_location!*\fP\&.
+.TP
+.BI \-q \ command\fP,\fB \ \-\-qemu\fB= command
+Execute guest programs through QEMU as specified by \fIcommand\fP\&.
+.sp
+Each time a guest program is going to be executed, PRoot inserts
+the QEMU user\-mode \fIcommand\fP in front of the initial request.
+That way, guest programs actually run on a virtual guest CPU
+emulated by QEMU user\-mode.  The native execution of host programs
+is still effective and the whole host rootfs is bound to
+\fB/host\-rootfs\fP in the guest environment.
+.TP
+.BI \-w \ path\fP,\fB \ \-\-pwd\fB= path\fP,\fB \ \-\-cwd\fB= path
+Set the initial working directory to \fIpath\fP\&.
+.sp
+Some programs expect to be launched from a given directory but do
+not perform any \fBchdir\fP by themselves.  This option avoids the
+need for running a shell and then entering the directory manually.
+.TP
+.BI \-v \ value\fP,\fB \ \-\-verbose\fB= value
+Set the level of debug information to \fIvalue\fP\&.
+.sp
+The higher the integer \fIvalue\fP is, the more detailed debug
+information is printed to the standard error stream.  A negative
+\fIvalue\fP makes PRoot quiet except on fatal errors.
+.TP
+.B \-V\fP,\fB  \-\-version\fP,\fB  \-\-about
+Print version, copyright, license and contact, then exit.
+.TP
+.B \-h\fP,\fB  \-\-help\fP,\fB  \-\-usage
+Print the version and the command\-line usage, then exit.
+.UNINDENT
+.SS Extension options
+.sp
+The following options enable built\-in extensions.  Technically
+developers can add their own features to PRoot or use it as a Linux
+process instrumentation engine thanks to its extension mechanism, see
+the sources for further details.
+.INDENT 0.0
+.TP
+.BI \-k \ string\fP,\fB \ \-\-kernel\-release\fB= string
+Make current kernel appear as kernel release \fIstring\fP\&.
+.sp
+If a program is run on a kernel older than the one expected by its
+GNU C library, the following error is reported: "FATAL: kernel too
+old".  To be able to run such programs, PRoot can emulate some of
+the features that are available in the kernel release specified by
+\fIstring\fP but that are missing in the current kernel.
+.TP
+.B \-0\fP,\fB  \-\-root\-id
+Make current user appear as "root" and fake its privileges.
+.sp
+Some programs will refuse to work if they are not run with "root"
+privileges, even if there is no technical reason for that.  This
+is typically the case with package managers.  This option allows
+users to bypass this kind of limitation by faking the user/group
+identity, and by faking the success of some operations like
+changing the ownership of files, changing the root directory to
+\fB/\fP, ...  Note that this option is quite limited compared to
+\fBfakeroot\fP\&.
+.TP
+.BI \-i \ string\fP,\fB \ \-\-change\-id\fB= string
+Make current user and group appear as \fIstring\fP "uid:gid".
+.sp
+This option makes the current user and group appear as \fIuid\fP and
+\fIgid\fP\&.  Likewise, files actually owned by the current user and
+group appear as if they were owned by \fIuid\fP and \fIgid\fP instead.
+Note that the \fB\-0\fP option is the same as \fB\-i 0:0\fP\&.
+.UNINDENT
+.SS Alias options
+.sp
+The following options are aliases for handy sets of options.
+.INDENT 0.0
+.TP
+.BI \-R \ path
+Alias: \fB\-r *path*\fP + a couple of recommended \fB\-b\fP\&.
+.sp
+Programs isolated in \fIpath\fP, a guest rootfs, might still need to
+access information about the host system, as it is illustrated in
+the \fBExamples\fP section of the manual.  These host information
+are typically: user/group definition, network setup, run\-time
+information, users\(aq files, ...  On all Linux distributions, they
+all lie in a couple of host files and directories that are
+automatically bound by this option:
+.INDENT 7.0
+.IP \(bu 2
+/etc/host.conf
+.IP \(bu 2
+/etc/hosts
+.IP \(bu 2
+/etc/hosts.equiv
+.IP \(bu 2
+/etc/mtab
+.IP \(bu 2
+/etc/netgroup
+.IP \(bu 2
+/etc/networks
+.IP \(bu 2
+/etc/passwd
+.IP \(bu 2
+/etc/group
+.IP \(bu 2
+/etc/nsswitch.conf
+.IP \(bu 2
+/etc/resolv.conf
+.IP \(bu 2
+/etc/localtime
+.IP \(bu 2
+/dev/
+.IP \(bu 2
+/sys/
+.IP \(bu 2
+/proc/
+.IP \(bu 2
+/tmp/
+.IP \(bu 2
+/run/
+.IP \(bu 2
+/var/run/dbus/system_bus_socket
+.IP \(bu 2
+$HOME
+.IP \(bu 2
+\fIpath\fP
+.UNINDENT
+.TP
+.BI \-S \ path
+Alias: \fB\-0 \-r *path*\fP + a couple of recommended \fB\-b\fP\&.
+.sp
+This option is useful to safely create and install packages into
+the guest rootfs.  It is similar to the \fB\-R\fP option expect it
+enables the \fB\-0\fP option and binds only the following minimal set
+of paths to avoid unexpected changes on host files:
+.INDENT 7.0
+.IP \(bu 2
+/etc/host.conf
+.IP \(bu 2
+/etc/hosts
+.IP \(bu 2
+/etc/nsswitch.conf
+.IP \(bu 2
+/etc/resolv.conf
+.IP \(bu 2
+/dev/
+.IP \(bu 2
+/sys/
+.IP \(bu 2
+/proc/
+.IP \(bu 2
+/tmp/
+.IP \(bu 2
+/run/shm
+.IP \(bu 2
+$HOME
+.IP \(bu 2
+\fIpath\fP
+.UNINDENT
+.UNINDENT
+.SH EXIT STATUS
+.sp
+If an internal error occurs, \fBproot\fP returns a non\-zero exit status,
+otherwise it returns the exit status of the last terminated
+program. When an error has occurred, the only way to know if it comes
+from the last terminated program or from \fBproot\fP itself is to have a
+look at the error message.
+.SH FILES
+.sp
+PRoot reads links in \fB/proc/<pid>/fd/\fP to support \fIopenat(2)\fP\-like
+syscalls made by the guest programs.
+.SH EXAMPLES
+.sp
+In the following examples the directories \fB/mnt/slackware\-8.0\fP and
+\fB/mnt/armslack\-12.2/\fP contain a Linux distribution respectively made
+for x86 CPUs and ARM CPUs.
+.SS \fBchroot\fP equivalent
+.sp
+To execute a command inside a given Linux distribution, just give
+\fBproot\fP the path to the guest rootfs followed by the desired
+command.  The example below executes the program \fBcat\fP to print the
+content of a file:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/ cat /etc/motd
+
+Welcome to Slackware Linux 8.0
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+The default command is \fB/bin/sh\fP when none is specified. Thus the
+shortest way to confine an interactive shell and all its sub\-programs
+is:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/
+
+$ cat /etc/motd
+Welcome to Slackware Linux 8.0
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBmount \-\-bind\fP equivalent
+.sp
+The bind mechanism enables one to relocate files and directories.  This is
+typically useful to trick programs that perform access to hard\-coded
+locations, like some installation scripts:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b /tmp/alternate_opt:/opt
+
+$ cd to/sources
+$ make install
+[...]
+install \-m 755 prog "/opt/bin"
+[...] # prog is installed in "/tmp/alternate_opt/bin" actually
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+As shown in this example, it is possible to bind over files not even
+owned by the user.  This can be used to \fIoverlay\fP system configuration
+files, for instance the DNS setting:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+ls \-l /etc/hosts
+\-rw\-r\-\-r\-\- 1 root root 675 Mar  4  2011 /etc/hosts
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b ~/alternate_hosts:/etc/hosts
+
+$ echo \(aq1.2.3.4 google.com\(aq > /etc/hosts
+$ resolveip google.com
+IP address of google.com is 1.2.3.4
+$ echo \(aq5.6.7.8 google.com\(aq > /etc/hosts
+$ resolveip google.com
+IP address of google.com is 5.6.7.8
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Another example: on most Linux distributions \fB/bin/sh\fP is a symbolic
+link to \fB/bin/bash\fP, whereas it points to \fB/bin/dash\fP on Debian
+and Ubuntu.  As a consequence a \fB#!/bin/sh\fP script tested with Bash
+might not work with Dash.  In this case, the binding mechanism of
+PRoot can be used to set non\-disruptively \fB/bin/bash\fP as the default
+\fB/bin/sh\fP on these two Linux distributions:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b /bin/bash:/bin/sh [...]
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Because \fB/bin/sh\fP is initially a symbolic link to \fB/bin/dash\fP, the
+content of \fB/bin/bash\fP is actually bound over this latter:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b /bin/bash:/bin/sh
+
+$ md5sum /bin/sh
+089ed56cd74e63f461bef0fdfc2d159a  /bin/sh
+$ md5sum /bin/bash
+089ed56cd74e63f461bef0fdfc2d159a  /bin/bash
+$ md5sum /bin/dash
+089ed56cd74e63f461bef0fdfc2d159a  /bin/dash
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+In most cases this shouldn\(aqt be a problem, but it is still possible to
+strictly bind \fB/bin/bash\fP over \fB/bin/sh\fP \-\- without dereferencing
+it \-\- by specifying the \fB!\fP character at the end:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-b \(aq/bin/bash:/bin/sh!\(aq
+
+$ md5sum /bin/sh
+089ed56cd74e63f461bef0fdfc2d159a  /bin/sh
+$ md5sum /bin/bash
+089ed56cd74e63f461bef0fdfc2d159a  /bin/bash
+$ md5sum /bin/dash
+c229085928dc19e8d9bd29fe88268504  /bin/dash
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBchroot\fP + \fBmount \-\-bind\fP equivalent
+.sp
+The two features above can be combined to make any file from the host
+rootfs accessible in the confined environment just as if it were
+initially part of the guest rootfs.  It is sometimes required to run
+programs that rely on some specific files:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/
+
+$ ps \-o tty,command
+Error, do this: mount \-t proc none /proc
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+works better with:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/ \-b /proc
+
+$ ps \-o tty,command
+TT       COMMAND
+?        \-bash
+?        proot \-b /proc /mnt/slackware\-8.0/
+?        \-
+?        ps \-o tty,command
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Actually there\(aqs a bunch of such specific files, that\(aqs why PRoot
+provides the option \fB\-R\fP to bind automatically a pre\-defined list of
+recommended paths:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/slackware\-8.0/
+
+$ ps \-o tty,command
+TT       COMMAND
+pts/6    \-bash
+pts/6    proot \-R /mnt/slackware\-8.0/
+pts/6    \-
+pts/6    ps \-o tty,command
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBchroot\fP + \fBmount \-\-bind\fP + \fBsu\fP equivalent
+.sp
+Some programs will not work correctly if they are not run by the
+"root" user, this is typically the case with package managers.  PRoot
+can fake the root identity and its privileges when the \fB\-0\fP (zero)
+option is specified:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-r /mnt/slackware\-8.0/ \-0
+
+# id
+uid=0(root) gid=0(root) [...]
+
+# mkdir /tmp/foo
+# chmod a\-rwx /tmp/foo
+# echo \(aqI bypass file\-system permissions.\(aq > /tmp/foo/bar
+# cat /tmp/foo/bar
+I bypass file\-system permissions.
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+This option is typically required to create or install packages into
+the guest rootfs.  Note it is \fInot\fP recommended to use the \fB\-R\fP
+option when installing packages since they may try to update bound
+system files, like \fB/etc/group\fP\&.  Instead, it is recommended to use
+the \fB\-S\fP option.  This latter enables the \fB\-0\fP option and binds
+only paths that are known to not be updated by packages:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-S /mnt/slackware\-8.0/
+
+# installpkg perl.tgz
+Installing package perl...
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS \fBchroot\fP + \fBmount \-\-bind\fP + \fBbinfmt_misc\fP equivalent
+.sp
+PRoot uses QEMU user\-mode to execute programs built for a CPU
+architecture incompatible with the host one.  From users\(aq
+point\-of\-view, guest programs handled by QEMU user\-mode are executed
+transparently, that is, just like host programs.  To enable this
+feature users just have to specify which instance of QEMU user\-mode
+they want to use with the option \fB\-q\fP:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm
+
+$ cat /etc/motd
+Welcome to ARMedSlack Linux 12.2
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+The parameter of the \fB\-q\fP option is actually a whole QEMU user\-mode
+command, for instance to enable its GDB server on port 1234:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q "qemu\-arm \-g 1234" emacs
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+PRoot allows one to mix transparently the emulated execution of guest
+programs and the native execution of host programs in the same
+file\-system namespace.  It\(aqs typically useful to extend the list of
+available programs and to speed up build\-time significantly.  This
+mixed\-execution feature is enabled by default when using QEMU
+user\-mode, and the content of the host rootfs is made accessible
+through \fB/host\-rootfs\fP:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm
+
+$ file /bin/echo
+[...] ELF 32\-bit LSB executable, ARM [...]
+$ /bin/echo \(aqHello world!\(aq
+Hello world!
+
+$ file /host\-rootfs/bin/echo
+[...] ELF 64\-bit LSB executable, x86\-64 [...]
+$ /host\-rootfs/bin/echo \(aqHello mixed world!\(aq
+Hello mixed world!
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Since both host and guest programs use the guest rootfs as \fB/\fP,
+users may want to deactivate explicitly cross\-filesystem support found
+in most GNU cross\-compilation tools.  For example with GCC configured
+to cross\-compile to the ARM target:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm
+
+$ export CC=/host\-rootfs/opt/cross\-tools/arm\-linux/bin/gcc
+$ export CFLAGS="\-\-sysroot=/"   # could be optional indeed
+$ ./configure; make
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+As with regular files, a host instance of a program can be bound over
+its guest instance.  Here is an example where the guest binary of
+\fBmake\fP is overlaid by the host one:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+proot \-R /mnt/armslack\-12.2/ \-q qemu\-arm \-b /usr/bin/make
+
+$ which make
+/usr/bin/make
+$ make \-\-version # overlaid
+GNU Make 3.82
+Built for x86_64\-slackware\-linux\-gnu
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+It\(aqs worth mentioning that even when mixing the native execution of
+host programs and the emulated execution of guest programs, they still
+believe they are running in a native guest environment.  As a
+demonstration, here is a partial output of a typical \fB\&./configure\fP
+script:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+checking whether the C compiler is a cross\-compiler... no
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SH DOWNLOADS
+.SS PRoot
+.sp
+The latest release of PRoot is packaged on \fI\%http://packages.proot.me\fP
+and sources are hosted on \fI\%http://github.proot.me\fP\&.  It is also
+available as highly compatible static binaries:
+.INDENT 0.0
+.IP \(bu 2
+for x86_64: \fI\%http://static.proot.me/proot\-x86_64\fP
+.IP \(bu 2
+for x86: \fI\%http://static.proot.me/proot\-x86\fP
+.IP \(bu 2
+for ARM: \fI\%http://static.proot.me/proot\-arm\fP
+.IP \(bu 2
+other architectures: on demand.
+.UNINDENT
+.SS Rootfs
+.sp
+Here follows a couple of URLs where some rootfs archives can be freely
+downloaded.  Note that \fBmknod\fP errors reported by \fBtar\fP when
+extracting these archives can be safely ignored since special files
+are typically bound (see \fB\-R\fP option for details).
+.INDENT 0.0
+.IP \(bu 2
+\fI\%http://download.openvz.org/template/precreated/\fP
+.IP \(bu 2
+\fI\%https://images.linuxcontainers.org/images/\fP
+.IP \(bu 2
+\fI\%http://distfiles.gentoo.org/releases/\fP
+.IP \(bu 2
+\fI\%http://cdimage.ubuntu.com/ubuntu\-core/releases/\fP
+.IP \(bu 2
+\fI\%http://archlinuxarm.org/developers/downloads\fP
+.UNINDENT
+.sp
+Technically such rootfs archive can be created by running the
+following command on the expected Linux distribution:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+tar \-\-one\-file\-system \-\-create \-\-gzip \-\-file my_rootfs.tar.gz /
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SS QEMU user\-mode
+.sp
+QEMU user\-mode is required only if the guest rootfs was made for a CPU
+architecture incompatible with the host one, for instance when using a
+ARM rootfs on a x86_64 computer.  This package can be installed either
+from \fI\%http://qemu.proot.me\fP or from the host package manager under the
+name of "qemu\-user" on most Linux distro.  In case one would like to
+build QEMU user\-mode from sources, the \fB\-\-enable\-linux\-user\fP option
+has to be specified to the \fB\&./configure\fP script.
+.SH SEE ALSO
+.sp
+chroot(1), mount(8), binfmt_misc, ptrace(2), qemu(1), sb2(1),
+bindfs(1), fakeroot(1), fakechroot(1)
+.SH COLOPHON
+.sp
+Visit \fI\%http://proot.me\fP for help, bug reports, suggestions, patches, ...
+Copyright (C) 2014 STMicroelectronics, licensed under GPL v2 or later.
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+ _____ _____              ___
+|  __ \e  __ \e_____  _____|   |_
+|   __/     /  _  \e/  _  \e    _|
+|__|  |__|__\e_____/\e_____/\e____|
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.\" Generated by docutils manpage writer.
+.
diff --git a/5.1.0/doc/proot/manual.txt b/5.1.0/doc/proot/manual.txt
new file mode 100644
index 0000000..53938c5
--- /dev/null
+++ b/5.1.0/doc/proot/manual.txt
@@ -0,0 +1,560 @@
+=======
+ PRoot
+=======
+
+-------------------------------------------------------------------------
+``chroot``, ``mount --bind``, and ``binfmt_misc`` without privilege/setup
+-------------------------------------------------------------------------
+
+:Date: 2014-12-12
+:Version: 5.1.0
+:Manual section: 1
+
+
+Synopsis
+========
+
+**proot** [*option*] ... [*command*]
+
+
+Description
+===========
+
+PRoot is a user-space implementation of ``chroot``, ``mount --bind``,
+and ``binfmt_misc``.  This means that users don't need any privileges
+or setup to do things like using an arbitrary directory as the new
+root filesystem, making files accessible somewhere else in the
+filesystem hierarchy, or executing programs built for another CPU
+architecture transparently through QEMU user-mode.  Also, developers
+can use PRoot as a generic Linux process instrumentation engine thanks
+to its extension mechanism, see CARE_ for an example.  Technically
+PRoot relies on ``ptrace``, an unprivileged system-call available in
+every Linux kernel.
+
+The new root file-system, a.k.a *guest rootfs*, typically contains a
+Linux distribution.  By default PRoot confines the execution of
+programs to the guest rootfs only, however users can use the built-in
+*mount/bind* mechanism to access files and directories from the actual
+root file-system, a.k.a *host rootfs*, just as if they were part of
+the guest rootfs.
+
+When the guest Linux distribution is made for a CPU architecture
+incompatible with the host one, PRoot uses the CPU emulator QEMU
+user-mode to execute transparently guest programs.  It's a convenient
+way to develop, to build, and to validate any guest Linux packages
+seamlessly on users' computer, just as if they were in a *native*
+guest environment.  That way all of the cross-compilation issues are
+avoided.
+
+PRoot can also *mix* the execution of host programs and the execution
+of guest programs emulated by QEMU user-mode.  This is useful to use
+host equivalents of programs that are missing from the guest rootfs
+and to speed up build-time by using cross-compilation tools or
+CPU-independent programs, like interpreters.
+
+It is worth noting that the guest kernel is never involved, regardless
+of whether QEMU user-mode is used or not.  Technically, when guest
+programs perform access to system resources, PRoot translates their
+requests before sending them to the host kernel.  This means that
+guest programs can use host resources (devices, network, ...) just as
+if they were "normal" host programs.
+
+.. _CARE: http://reproducible.io
+
+
+Options
+=======
+
+The command-line interface is composed of two parts: first PRoot's
+options (optional), then the command to launch (``/bin/sh`` if not
+specified).  This section describes the options supported by PRoot,
+that is, the first part of its command-line interface.
+
+
+Regular options
+---------------
+
+-r path, --rootfs=path
+    Use *path* as the new guest root file-system, default is ``/``.
+
+    The specified *path* typically contains a Linux distribution where
+    all new programs will be confined.  The default rootfs is ``/``
+    when none is specified, this makes sense when the bind mechanism
+    is used to relocate host files and directories, see the ``-b``
+    option and the ``Examples`` section for details.
+
+    It is recommended to use the ``-R`` or ``-S`` options instead.
+
+-b path, --bind=path, -m path, --mount=path
+    Make the content of *path* accessible in the guest rootfs.
+
+    This option makes any file or directory of the host rootfs
+    accessible in the confined environment just as if it were part of
+    the guest rootfs.  By default the host path is bound to the same
+    path in the guest rootfs but users can specify any other location
+    with the syntax: ``-b *host_path*:*guest_location*``.  If the
+    guest location is a symbolic link, it is dereferenced to ensure
+    the new content is accessible through all the symbolic links that
+    point to the overlaid content.  In most cases this default
+    behavior shouldn't be a problem, although it is possible to
+    explicitly not dereference the guest location by appending it the
+    ``!`` character: ``-b *host_path*:*guest_location!*``.
+
+-q command, --qemu=command
+    Execute guest programs through QEMU as specified by *command*.
+
+    Each time a guest program is going to be executed, PRoot inserts
+    the QEMU user-mode *command* in front of the initial request.
+    That way, guest programs actually run on a virtual guest CPU
+    emulated by QEMU user-mode.  The native execution of host programs
+    is still effective and the whole host rootfs is bound to
+    ``/host-rootfs`` in the guest environment.
+
+-w path, --pwd=path, --cwd=path
+    Set the initial working directory to *path*.
+
+    Some programs expect to be launched from a given directory but do
+    not perform any ``chdir`` by themselves.  This option avoids the
+    need for running a shell and then entering the directory manually.
+
+-v value, --verbose=value
+    Set the level of debug information to *value*.
+
+    The higher the integer *value* is, the more detailed debug
+    information is printed to the standard error stream.  A negative
+    *value* makes PRoot quiet except on fatal errors.
+
+-V, --version, --about
+    Print version, copyright, license and contact, then exit.
+
+-h, --help, --usage
+    Print the version and the command-line usage, then exit.
+
+
+Extension options
+-----------------
+
+The following options enable built-in extensions.  Technically
+developers can add their own features to PRoot or use it as a Linux
+process instrumentation engine thanks to its extension mechanism, see
+the sources for further details.
+
+-k string, --kernel-release=string
+    Make current kernel appear as kernel release *string*.
+
+    If a program is run on a kernel older than the one expected by its
+    GNU C library, the following error is reported: "FATAL: kernel too
+    old".  To be able to run such programs, PRoot can emulate some of
+    the features that are available in the kernel release specified by
+    *string* but that are missing in the current kernel.
+
+-0, --root-id
+    Make current user appear as "root" and fake its privileges.
+
+    Some programs will refuse to work if they are not run with "root"
+    privileges, even if there is no technical reason for that.  This
+    is typically the case with package managers.  This option allows
+    users to bypass this kind of limitation by faking the user/group
+    identity, and by faking the success of some operations like
+    changing the ownership of files, changing the root directory to
+    ``/``, ...  Note that this option is quite limited compared to
+    ``fakeroot``.
+
+-i string, --change-id=string
+    Make current user and group appear as *string* "uid:gid".
+
+    This option makes the current user and group appear as *uid* and
+    *gid*.  Likewise, files actually owned by the current user and
+    group appear as if they were owned by *uid* and *gid* instead.
+    Note that the ``-0`` option is the same as ``-i 0:0``.
+
+
+Alias options
+-------------
+
+The following options are aliases for handy sets of options.
+
+-R path
+    Alias: ``-r *path*`` + a couple of recommended ``-b``.
+
+    Programs isolated in *path*, a guest rootfs, might still need to
+    access information about the host system, as it is illustrated in
+    the ``Examples`` section of the manual.  These host information
+    are typically: user/group definition, network setup, run-time
+    information, users' files, ...  On all Linux distributions, they
+    all lie in a couple of host files and directories that are
+    automatically bound by this option:
+
+    * /etc/host.conf
+    * /etc/hosts
+    * /etc/hosts.equiv
+    * /etc/mtab
+    * /etc/netgroup
+    * /etc/networks
+    * /etc/passwd
+    * /etc/group
+    * /etc/nsswitch.conf
+    * /etc/resolv.conf
+    * /etc/localtime
+    * /dev/
+    * /sys/
+    * /proc/
+    * /tmp/
+    * /run/
+    * /var/run/dbus/system_bus_socket
+    * $HOME
+    * *path*
+
+-S path
+    Alias: ``-0 -r *path*`` + a couple of recommended ``-b``.
+
+    This option is useful to safely create and install packages into
+    the guest rootfs.  It is similar to the ``-R`` option expect it
+    enables the ``-0`` option and binds only the following minimal set
+    of paths to avoid unexpected changes on host files:
+
+    * /etc/host.conf
+    * /etc/hosts
+    * /etc/nsswitch.conf
+    * /etc/resolv.conf
+    * /dev/
+    * /sys/
+    * /proc/
+    * /tmp/
+    * /run/shm
+    * $HOME
+    * *path*
+
+
+Exit Status
+===========
+
+If an internal error occurs, ``proot`` returns a non-zero exit status,
+otherwise it returns the exit status of the last terminated
+program. When an error has occurred, the only way to know if it comes
+from the last terminated program or from ``proot`` itself is to have a
+look at the error message.
+
+
+Files
+=====
+
+PRoot reads links in ``/proc/<pid>/fd/`` to support `openat(2)`-like
+syscalls made by the guest programs.
+
+
+Examples
+========
+
+In the following examples the directories ``/mnt/slackware-8.0`` and
+``/mnt/armslack-12.2/`` contain a Linux distribution respectively made
+for x86 CPUs and ARM CPUs.
+
+
+``chroot`` equivalent
+---------------------
+
+To execute a command inside a given Linux distribution, just give
+``proot`` the path to the guest rootfs followed by the desired
+command.  The example below executes the program ``cat`` to print the
+content of a file::
+
+    proot -r /mnt/slackware-8.0/ cat /etc/motd
+    
+    Welcome to Slackware Linux 8.0
+
+The default command is ``/bin/sh`` when none is specified. Thus the
+shortest way to confine an interactive shell and all its sub-programs
+is::
+
+    proot -r /mnt/slackware-8.0/
+    
+    $ cat /etc/motd
+    Welcome to Slackware Linux 8.0
+
+
+``mount --bind`` equivalent
+---------------------------
+
+The bind mechanism enables one to relocate files and directories.  This is
+typically useful to trick programs that perform access to hard-coded
+locations, like some installation scripts::
+
+    proot -b /tmp/alternate_opt:/opt
+    
+    $ cd to/sources
+    $ make install
+    [...]
+    install -m 755 prog "/opt/bin"
+    [...] # prog is installed in "/tmp/alternate_opt/bin" actually
+
+As shown in this example, it is possible to bind over files not even
+owned by the user.  This can be used to *overlay* system configuration
+files, for instance the DNS setting::
+
+    ls -l /etc/hosts
+    -rw-r--r-- 1 root root 675 Mar  4  2011 /etc/hosts
+
+::
+
+    proot -b ~/alternate_hosts:/etc/hosts
+    
+    $ echo '1.2.3.4 google.com' > /etc/hosts
+    $ resolveip google.com
+    IP address of google.com is 1.2.3.4
+    $ echo '5.6.7.8 google.com' > /etc/hosts
+    $ resolveip google.com
+    IP address of google.com is 5.6.7.8
+
+Another example: on most Linux distributions ``/bin/sh`` is a symbolic
+link to ``/bin/bash``, whereas it points to ``/bin/dash`` on Debian
+and Ubuntu.  As a consequence a ``#!/bin/sh`` script tested with Bash
+might not work with Dash.  In this case, the binding mechanism of
+PRoot can be used to set non-disruptively ``/bin/bash`` as the default
+``/bin/sh`` on these two Linux distributions::
+
+    proot -b /bin/bash:/bin/sh [...]
+
+Because ``/bin/sh`` is initially a symbolic link to ``/bin/dash``, the
+content of ``/bin/bash`` is actually bound over this latter::
+
+    proot -b /bin/bash:/bin/sh
+    
+    $ md5sum /bin/sh
+    089ed56cd74e63f461bef0fdfc2d159a  /bin/sh
+    $ md5sum /bin/bash
+    089ed56cd74e63f461bef0fdfc2d159a  /bin/bash
+    $ md5sum /bin/dash
+    089ed56cd74e63f461bef0fdfc2d159a  /bin/dash
+
+In most cases this shouldn't be a problem, but it is still possible to
+strictly bind ``/bin/bash`` over ``/bin/sh`` -- without dereferencing
+it -- by specifying the ``!`` character at the end::
+
+    proot -b '/bin/bash:/bin/sh!'
+    
+    $ md5sum /bin/sh
+    089ed56cd74e63f461bef0fdfc2d159a  /bin/sh
+    $ md5sum /bin/bash
+    089ed56cd74e63f461bef0fdfc2d159a  /bin/bash
+    $ md5sum /bin/dash
+    c229085928dc19e8d9bd29fe88268504  /bin/dash
+
+
+``chroot`` + ``mount --bind`` equivalent
+----------------------------------------
+
+The two features above can be combined to make any file from the host
+rootfs accessible in the confined environment just as if it were
+initially part of the guest rootfs.  It is sometimes required to run
+programs that rely on some specific files::
+
+    proot -r /mnt/slackware-8.0/
+    
+    $ ps -o tty,command
+    Error, do this: mount -t proc none /proc
+
+works better with::
+
+    proot -r /mnt/slackware-8.0/ -b /proc
+    
+    $ ps -o tty,command
+    TT       COMMAND
+    ?        bash
+    ?        proot -b /proc /mnt/slackware-8.0/
+    ?        sh
+    ?        ps -o tty,command
+
+Actually there's a bunch of such specific files, that's why PRoot
+provides the option ``-R`` to bind automatically a pre-defined list of
+recommended paths::
+
+    proot -R /mnt/slackware-8.0/
+    
+    $ ps -o tty,command
+    TT       COMMAND
+    pts/6    bash
+    pts/6    proot -R /mnt/slackware-8.0/
+    pts/6    sh
+    pts/6    ps -o tty,command
+
+
+``chroot`` + ``mount --bind`` + ``su`` equivalent
+-------------------------------------------------
+
+Some programs will not work correctly if they are not run by the
+"root" user, this is typically the case with package managers.  PRoot
+can fake the root identity and its privileges when the ``-0`` (zero)
+option is specified::
+
+    proot -r /mnt/slackware-8.0/ -0
+    
+    # id
+    uid=0(root) gid=0(root) [...]
+    
+    # mkdir /tmp/foo
+    # chmod a-rwx /tmp/foo
+    # echo 'I bypass file-system permissions.' > /tmp/foo/bar
+    # cat /tmp/foo/bar
+    I bypass file-system permissions.
+
+This option is typically required to create or install packages into
+the guest rootfs.  Note it is *not* recommended to use the ``-R``
+option when installing packages since they may try to update bound
+system files, like ``/etc/group``.  Instead, it is recommended to use
+the ``-S`` option.  This latter enables the ``-0`` option and binds
+only paths that are known to not be updated by packages::
+
+    proot -S /mnt/slackware-8.0/
+    
+    # installpkg perl.tgz
+    Installing package perl...
+
+
+``chroot`` + ``mount --bind`` + ``binfmt_misc`` equivalent
+----------------------------------------------------------
+
+PRoot uses QEMU user-mode to execute programs built for a CPU
+architecture incompatible with the host one.  From users'
+point-of-view, guest programs handled by QEMU user-mode are executed
+transparently, that is, just like host programs.  To enable this
+feature users just have to specify which instance of QEMU user-mode
+they want to use with the option ``-q``::
+
+    proot -R /mnt/armslack-12.2/ -q qemu-arm
+    
+    $ cat /etc/motd
+    Welcome to ARMedSlack Linux 12.2
+
+The parameter of the ``-q`` option is actually a whole QEMU user-mode
+command, for instance to enable its GDB server on port 1234::
+
+    proot -R /mnt/armslack-12.2/ -q "qemu-arm -g 1234" emacs
+
+PRoot allows one to mix transparently the emulated execution of guest
+programs and the native execution of host programs in the same
+file-system namespace.  It's typically useful to extend the list of
+available programs and to speed up build-time significantly.  This
+mixed-execution feature is enabled by default when using QEMU
+user-mode, and the content of the host rootfs is made accessible
+through ``/host-rootfs``::
+
+    proot -R /mnt/armslack-12.2/ -q qemu-arm
+    
+    $ file /bin/echo
+    [...] ELF 32-bit LSB executable, ARM [...]
+    $ /bin/echo 'Hello world!'
+    Hello world!
+
+    $ file /host-rootfs/bin/echo
+    [...] ELF 64-bit LSB executable, x86-64 [...]
+    $ /host-rootfs/bin/echo 'Hello mixed world!'
+    Hello mixed world!
+
+Since both host and guest programs use the guest rootfs as ``/``,
+users may want to deactivate explicitly cross-filesystem support found
+in most GNU cross-compilation tools.  For example with GCC configured
+to cross-compile to the ARM target::
+
+    proot -R /mnt/armslack-12.2/ -q qemu-arm
+    
+    $ export CC=/host-rootfs/opt/cross-tools/arm-linux/bin/gcc
+    $ export CFLAGS="--sysroot=/"   # could be optional indeed
+    $ ./configure; make
+
+As with regular files, a host instance of a program can be bound over
+its guest instance.  Here is an example where the guest binary of
+``make`` is overlaid by the host one::
+
+   proot -R /mnt/armslack-12.2/ -q qemu-arm -b /usr/bin/make
+   
+   $ which make
+   /usr/bin/make
+   $ make --version # overlaid
+   GNU Make 3.82
+   Built for x86_64-slackware-linux-gnu
+
+It's worth mentioning that even when mixing the native execution of
+host programs and the emulated execution of guest programs, they still
+believe they are running in a native guest environment.  As a
+demonstration, here is a partial output of a typical ``./configure``
+script::
+
+    checking whether the C compiler is a cross-compiler... no
+
+
+Downloads
+=========
+
+PRoot
+-----
+
+The latest release of PRoot is packaged on http://packages.proot.me
+and sources are hosted on http://github.proot.me.  It is also
+available as highly compatible static binaries:
+
+* for x86_64: http://static.proot.me/proot-x86_64
+
+* for x86: http://static.proot.me/proot-x86
+
+* for ARM: http://static.proot.me/proot-arm
+
+* other architectures: on demand.
+
+
+Rootfs
+------
+
+Here follows a couple of URLs where some rootfs archives can be freely
+downloaded.  Note that ``mknod`` errors reported by ``tar`` when
+extracting these archives can be safely ignored since special files
+are typically bound (see ``-R`` option for details).
+
+* http://download.openvz.org/template/precreated/
+
+* https://images.linuxcontainers.org/images/
+
+* http://distfiles.gentoo.org/releases/
+
+* http://cdimage.ubuntu.com/ubuntu-core/releases/
+
+* http://archlinuxarm.org/developers/downloads
+
+Technically such rootfs archive can be created by running the
+following command on the expected Linux distribution::
+
+    tar --one-file-system --create --gzip --file my_rootfs.tar.gz /
+
+
+QEMU user-mode
+--------------
+
+QEMU user-mode is required only if the guest rootfs was made for a CPU
+architecture incompatible with the host one, for instance when using a
+ARM rootfs on a x86_64 computer.  This package can be installed either
+from http://qemu.proot.me or from the host package manager under the
+name of "qemu-user" on most Linux distro.  In case one would like to
+build QEMU user-mode from sources, the ``--enable-linux-user`` option
+has to be specified to the ``./configure`` script.
+
+
+See Also
+========
+
+chroot(1), mount(8), binfmt_misc, ptrace(2), qemu(1), sb2(1),
+bindfs(1), fakeroot(1), fakechroot(1)
+
+
+Colophon
+========
+
+Visit http://proot.me for help, bug reports, suggestions, patches, ...
+Copyright (C) 2014 STMicroelectronics, licensed under GPL v2 or later.
+
+::
+
+     _____ _____              ___
+    |  __ \  __ \_____  _____|   |_
+    |   __/     /  _  \/  _  \    _|
+    |__|  |__|__\_____/\_____/\____|
+
diff --git a/5.1.0/doc/proot/roadmap.txt b/5.1.0/doc/proot/roadmap.txt
new file mode 100644
index 0000000..d2dd1f1
--- /dev/null
+++ b/5.1.0/doc/proot/roadmap.txt
@@ -0,0 +1,195 @@
+=========
+ Roadmap
+=========
+
+PRoot v5.1.1
+============
+
+* Fix ptrace emulation: on ARM.
+
+* Fix ``proot-x86_64 -k ... -r rootfs-i686 uname -m``
+
+* Fix TODO in test-517e1d6a
+
+* Understand why loader-wrapped.o is so big on x86_64?
+
+
+PRoot v5.2: leveraging on the loader
+====================================
+
+Highlight
+---------
+
+* Position-independent programs are loaded to predefined addresses,
+  even if ASLR is enabled.  This might results in conflicts with
+  mappings created implicitly by the kernel ("[vdso]", "[stack]",
+  ...).  A reliable solution is to let the kernel choose the position
+  of position-independent programs.
+
+* The loader is loaded to a predefined address, si it might conflicts
+  with programs that are loaded to the same address.  A solution is to
+  detect such situation and to make the loader relocate itself.
+
+* The loader stays in memory, even once it is not used anymore.  This
+  might create useless address-space pressure for programs that need
+  large memory mappings (ex. JVM).
+
+* Some programs assumes the heap segment is right after the data
+  segment (cf. issue 52 on Github).
+
+Misc.
+-----
+
+* Write a loader for a.out programs, to be able to execute programs
+  from very old Linux distros :)
+
+
+PRoot v6.0: VFS
+===============
+
+Highlight
+---------
+
+One core feature of PRoot is the path translation.  This mechanism
+heavily relies on "stat", sadly this syscall is quite slow on some FS
+(like NFS).  The idea is to cache the results of the path translation
+mechanism to avoid the use of "stat" as much as possible in order to
+speed-up PRoot.
+
+The internal structure of this FS cache could also be used to emulate
+the "getdents" syscall in order to add or hide entries.
+
+
+Not yet scheduled
+=================
+
+Fixes
+-----
+
+* Fix ptrace emulation support on ARM.
+
+* Fix support for GDB v/fork & execve catchpoints.
+
+* Add support for unimplemented ptrace requests.
+
+* Add new hidden option "PROOT_MIN_HEAP_SIZE".
+
+* Fix ``mkdir foo; cd foo; rmdir ../foo; readlink /proc/self/cwd``.
+
+* Forbid rename/unlink on a mount point:
+
+    $ mv mount_point elsewhere
+    mv: cannot move "mount_point" to "elsewhere": Device or resource busy
+
+* Add support for the string $ORIGIN (or equivalently ${ORIGIN}) in an rpath specification
+
+* Add support for /etc/ld.so.preload and /etc/ld.so.conf[.d] in mixed-mode.
+
+* Fix ``proot -k 1.2.3 proot -k 2.4.6 -k 3.4.5 uname -r | grep 3.4.5``.
+
+* Don't use the same prefix for glued path::
+
+      $ proot -b /etc/fstab -b /bin/readdir:/bin/readdir -r /tmp/empty-rootfs
+      [...]
+      proot info: binding = /tmp/proot-6738-CMr1hE:/bin
+      proot info: binding = /tmp/proot-6738-CMr1hE:/etc
+      [...]
+      $ readdir /bin
+      DT_DIR  ..
+      DT_DIR  .
+      DT_REG  readdir
+      DT_REG  fstab
+      $ readdir /etc
+      DT_DIR  ..
+      DT_DIR  .
+      DT_REG  readdir
+      DT_REG  fstab
+
+
+Features
+--------
+
+* Use PTRACE_O_EXITKILL if possible.
+
+* Do not seccomp-trace any syscalls when there are no bindings.  This
+  should improve performance of ATOS extensions a alot.
+
+* Add a mechanism to add new [fake] entries in /proc, for instance
+  ``/proc/proot/config``.
+
+* Add a way to get the reverse translation of a path::
+
+      proot [bindings] -x /usr/local/bin
+
+  or maybe something like that::
+
+      proot [bindings] readlink /proc/proot/detranslate/usr/local/bin
+
+* Make ``mount --bind`` change the tracee's configuration dynamically.
+
+* Make ``chroot`` change the tracee's configuration dynamically (not
+  only of ``/``).
+
+* Add support for a special environment variable to add paths
+  dynamically to the host LD_LIBRARY_PATH
+  ("EXTRA_HOST_LD_LIBRARY_PATH").
+
+* Add a "blind" mode where:
+
+  * unreadable executable can be executed::
+
+      proot mount: OK (rwsr-xr-x)
+      proot ping: failed (rws--x--x)
+
+  * unreadable directory can be accessed
+
+* Add command-line interface to set environment variables.
+
+    Rename push_env() in change_env() and enhance it to support the
+    "unset" feature.
+
+* Add support for coalesced options, for instance ``proot -eM``
+
+* Allow a per-module verbose level
+
+* Emulate chown, chmod, and mknod when -0 (fake_id0) is enabled.
+
+
+Documentation
+-------------
+
+* Mention "container" in the documentation.
+
+* Explain bindings aren't exclusive, i.e. "-b /tmp:/foo" doesn't invalidate "-b /tmp:/bar".
+
+* Explain why PRoot does not work with setuid programs
+
+
+Misc.
+-----
+
+* Replace "readlink(XXX, path, PATH_MAX)" with "readlink(XXX, path, PATH_MAX - 1)"
+
+* read_string should return -ENAMETOOLONG when length(XXX) >= max_size
+
+* Check (in ld.so sources) if more than one RPATH/RUNPATH entry is allowed.
+
+* Ensure tracees' clone flags has CLONE_PTRACE & ~CLONE_UNTRACED.
+
+* Add a stealth mode where over-the-stack content is restored.
+
+* Try Trinity/Scrashme (syscall fuzzers) against PRoot
+
+
+Performance
+-----------
+
+* prefetch_mem(): cache write-through memory access (read_string, fetch_args).
+
+* Fallback to /proc/<pid>/mem when process_vm_readv() isn't available.
+
+* Add a "multi-process" mode where there's one fork of PRoot per monitored process.
+
+    Each time a new_tracee structure is created, PRoot forks itself.
+    Be sure that the tracer of this new process really is the new
+    forked PRoot! (Thanks Yves for this comment)
diff --git a/5.1.0/doc/proot/rpm-spec b/5.1.0/doc/proot/rpm-spec
new file mode 100644
index 0000000..87738a5
--- /dev/null
+++ b/5.1.0/doc/proot/rpm-spec
@@ -0,0 +1,1232 @@
+%define version v5.1.0
+
+Summary   : chroot, mount --bind, and binfmt_misc without privilege/setup
+Version   : %{version}
+Release   : 1
+License   : GPL2+
+Group     : Applications/System
+Source    : proot-%{version}.tar.gz
+Buildroot : %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
+Prefix    : /usr
+Name      : proot
+
+BuildRequires: libtalloc-devel
+
+%if 0%{?suse_version} >= 1210 || 0%{?fedora_version} >= 15
+BuildRequires: glibc-static
+%endif
+
+%if !0%{?suse_version} != 0
+BuildRequires: which
+%endif
+
+%description
+PRoot is a user-space implementation of chroot, mount --bind,
+and binfmt_misc.  This means that users don't need any privileges
+or setup to do things like using an arbitrary directory as the new
+root filesystem, making files accessible somewhere else in the
+filesystem hierarchy, or executing programs built for another CPU
+architecture transparently through QEMU user-mode.  Also, developers
+can use PRoot as a generic Linux process instrumentation engine thanks
+to its extension mechanism, see CARE for an example.  Technically
+PRoot relies on ptrace, an unprivileged system-call available in
+every Linux kernel.
+
+%prep
+%setup -n proot-%{version}
+
+%build
+make -C src
+
+%install
+make -C src install PREFIX=%{buildroot}/%{prefix}
+install -D doc/proot/man.1 %{buildroot}/%{_mandir}/man1/proot.1
+
+%check
+env LD_SHOW_AUXV=1 true
+cat /proc/cpuinfo
+./src/proot -V
+./src/proot -v 1 true
+make -C tests
+
+%clean
+rm -rf %{buildroot}
+
+%files
+%defattr(-,root,root)
+%{prefix}/bin/proot
+%doc %{_mandir}/man1/proot.1*
+%doc COPYING
+%doc doc/*
+
+%changelog
+* Thu Dec 11 2014 Cédric VINCENT <cedric.vincent@st.com>
+Release v5.1.0
+==============
+
+New features
+------------
+
++ Processes under PRoot now appear with their real names, that is,
+  they are not renamed "ld-linux.so" or "prooted-..." anymore:
+
+  before:
+
+      $ proot-v4.0.3 ps
+        PID TTY          TIME CMD
+       7885 pts/11   00:00:00 bash
+       8131 pts/11   00:00:00 proot-v4.0.3
+       8132 pts/11   00:00:00 ld-2.17.so
+
+      $ proot-v5.0.0 ps
+        PID TTY          TIME CMD
+       7885 pts/11   00:00:00 bash
+       7916 pts/11   00:00:00 proot-v5.0.0
+       7917 pts/11   00:00:00 prooted-7916-Jb
+
+  now:
+
+      $ proot-v5.1.0
+        PID TTY          TIME CMD
+       7885 pts/11   00:00:00 bash
+       8585 pts/11   00:00:00 proot-v5.1.0
+       8586 pts/11   00:00:00 ps
+
+Fixes
+-----
+
++ It is now possible to use GDB against multi-threaded programs under
+  PRoot.
+
++ It is possible to execute 32-bit programs from 64-bit programs
+  again.
+
++ It is possible to use 32-bit ptrace-based programs (strace, gdb,
+  ...) under PRoot 64-bit again.
+
++ The loader is now built with the "build-id" linker option explicitly
+  disabled.  This special section might interfere with loaded
+  programs.
+
+Thanks
+------
+
+Thanks to Erwan Gouriou, Sébastien Gandon, Christian "milkylainen",
+and Henrik Wallin for their bug reports and tests.
+
+Thanks to Jérôme Audu, Yann Droneaud and Christophe Monat for their
+precious help to fix bugs.
+
+
+Release v5.0.0
+==============
+
+Highlight
+---------
+
+PRoot used to rely on the ELF loader embedded in the ELF interpreter
+from the GNU libc.  Sadly this latter suffers from many issues:
+
++ programs that use constructors or destructors might crash: a typical
+  example is C++ programs.
+
++ programs that rely on the "rpath" mechanism and that are invoked
+  through a symlink might not start: a typical example is the JVM on
+  Debian.
+
++ programs that read processes command-line migth be confused because
+  initial argv[0] is replaced: typical examples are ps and top.
+
+Moreover not all ELF interpreters provide this feature.  For instance,
+ELF interpreters shipped with Bionic (Android) and some versions of
+the uClibC can't be used as ELF loaders.  As a consequence it was not
+possible to proot into a rootfs that uses such C library.
+
+Now PRoot has its own loader, that means all the limitations above
+doesn't exist anymore.
+
+Fixes
+-----
+
++ Most bugs related to shebang support -- ie. "#!" at the beginning of
+  a program -- were fixed.
+
+Command-line interface changes
+------------------------------
+
++ PRoot now starts a login shell when no command is specified; this
+  makes the shell read profile files from the guest rootfs, as
+  expected by some guest programs.  To get the old behavior, launch
+  "/bin/sh" explicitly:
+
+      proot -r whatever /bin/sh
+
++ The -R option now binds "/run" and "/var/run/dbus/system_bus_socket"
+  too.  This is useful for guest programs that need to communicate
+  with host services.
+
+
+Release v4.0.3
+==============
+
++ Heap emulation is disabled when a "suspicious" call to brk(2) is
+  actually legit, as it might be the case when launching the very
+  first program.
+
++ The "-0" and "-S" options ("root" identity emulation) now fake
+  success of mknodat(2), as it was the case for mknod(2) previously.
+  This missing feature was revealed by the AArch64 port.
+
++ The "-k" option (kernel compatibility emulation) now works on
+  Linux/AArch64.
+
+Thanks to Rémi Duraffort for the bug reports and for his LAVA testing
+platform!
+
+
+Release v4.0.2
+==============
+
++ Fix how the very first program is launched by PRoot.  Previously,
+  argv[0] was not preserved when the very first program was launched
+  through a symbolic link.  This old behavior used to bug programs
+  like Busybox and python-exec.  Thanks to "hhm", Ivailo "fluxer"
+  Monev, and Joakim Tjernlund for the bug reports.
+
++ Fix renameat(2) sysexit support.  There was a bug in PRoot that was
+  exposed by the Aarch64 (a.k.a arm64) port only but that might affect
+  other architectures.
+
++ Fix build for AArch64.  Thanks to Rémi Duraffort for the patches and
+  for the Debian/arm64 testing platform.
+
++ Fix support for "long" socket paths.  These can only be 108 bytes
+  long; this limit might be easily reached with PRoot since the path
+  to the rootfs is always prepended.  The solution was to
+  automatically bind this long path to a shorter path.  This bug was
+  exposed by LibreOffice and Yocto's pseudo.  Thanks to Christophe
+  Guillon for the bug report.
+
+
+Release v4.0.1
+==============
+
++ Fix a couple of portability issues in the testsuite.  Thanks to Rémi
+  Duraffort for all the tests he made on his instance of Linaro LAVA.
+
++ Set $PWD to the value specified by the -w option, otherwise Bash pwd
+  builtin might be confused under some specific circumstances.  Thanks
+  to Jérémy Bobbio for the bug report.
+
++ Fix support for accessat and fchmodat syscalls: they have only three
+  parameters, not four.  This bug was exposed by Gentoo's sandbox:
+
+      proot -S gentoo-amd64-hardened+nomultilib-rootfs emerge util-linux
+
+
+Release v4.0.0
+==============
+
+Highlights
+----------
+
++ It is now possible to use GDB, Strace, or any other program based on
+  "ptrace" under PRoot.  This was not the case previously because it
+  is not possible to stack ptracers on Linux, so an emulation layer
+  was developed in order to bypass this limitation.  This has required
+  a lot of changes in PRoot, hence the major number version bumping.
+  It was mostly tested on x86_64, and partially tested on x86 and ARM.
+  This ptrace emulation support is still experimental, and there are a
+  couple of known issues, but feel free to report unexpected behaviors
+  if you need a fix.
+
++ A new command-line option is available: "-S".  It is similar to the
+  "-R" option expect it enables the "-0" option and binds only a
+  minimal set of paths that are known to not be updated by package
+  installations, to avoid unexpected changes on host files.  This
+  option is useful to safely create and install packages into the
+  guest rootfs.  For example:
+
+      $ proot -S ubuntu-14.04-rootfs/ apt-get install samba
+
+  or:
+
+      $ proot -S ubuntu-14.04-rootfs/
+      # apt-get install samba
+
+  If "-0 -R" is used instead of "-S", the same command fails since it
+  tries to update "/etc/group", which is bound to the host system and
+  is not writable (assuming PRoot is ran without privileges):
+
+      $ proot -0 -R ubuntu-14.04-rootfs/
+      # apt-get install samba
+      [...]
+      Adding group `sambashare' (GID 105) ...
+      Permission denied
+
++ The fake_id0 extension can now fake any user and group identifiers.
+  That means, when "-0" is specified, PRoot-ed processes can change
+  their real, effective and saved identifiers, with respect to the
+  rules described in setuid, setfsuid, setreuid, setresuid, and
+  setfsuid manuals.  Also, the new command-line option "-i" was added
+  to change explicitly the identifiers to the specified values.  This
+  option will be used by CARE to re-execute with the same initial
+  identifiers, but it could also be useful to threaten your teammates
+  ;).  Note that the "-0" option is actually the same as "-i 0:0".
+
++ The old command-line interface is not supported anymore.  That means
+  it is now impossible to specify the path to the guest rootfs without
+  using -r or -R.  Also, -Q and -B options are definitively gone,
+  instead the -R option must be specified, respectively with and
+  without -q.  See PRoot v3.1 release notes for details.
+
+Fixes
+-----
+
++ getcwd(2) and chdir(2) now return the correct error code when,
+  respectively, the current directory does not exist anymore and the
+  target directory doesn't have the "search" permission.
+
++ Named file descriptors (ie. links in /proc/<pid>/fd/*) are not
+  dereferenced anymore since they may point to special objects like
+  pipes, sockets, inodes, ...  Such objects do not exist on the
+  file-system name-space, so dereferencing them used to cause
+  unexpected errors.
+
++ Extensions now see every component of canonicalized paths.  An
+  optimization in the canonicalization loop used to skip the first
+  part of a path if it was known to be already canonicalized, sadly
+  this short-cut may confuse some extensions, like -0.
+
++ Temporary files and directories created by PRoot for its own purpose
+  are now automatically deleted when PRoot exits.
+
+
+Miscellaneous
+-------------
+
++ PRoot does not rely on GCC C extensions anymore, like nested
+  functions.  That means its stack does not have to be executable
+  (this is required for hardened Linux systems), and it can now be
+  compiled with Clang.
+
++ The ASLR (Address Space Layout Randomization) is not disabled
+  anymore, and the heap is now emulated on all architectures.
+
+
+Internal changes
+----------------
+
+This section is dedicated to developers.
+
++ PRoot now remembers the parent of all tracees, it is similar to a
+  traced process tree.  This was required for the ptrace emulation
+  support, but this could be useful to some extensions.
+
++ It is now possible to restart a tracee with any ptrace restart mode:
+  single-step, single-block, ...
+
++ Functions {peek,poke}_mem were replaced with functions
+  {peek,poke}_{,u}int{8,16,32,64}.  These new functions performs type
+  conversion and fetch only the necessary amount of data in target
+  tracee's memory to avoid invalid accesses.
+
++ There is a new interface to handle ELF auxiliary vectors.  See
+  ptrace emulation, kompat and fake_id0 extensions for usage examples.
+
++ There is a new interface to create temporary files and directories
+  that are automatically deleted on exit.  See CARE extension, glue
+  and auxv support for usage examples.
+
++ When built with GCC function instrumentation support, PRoot prints
+  the currently called function on standard error stream (stderr).
+
+Thanks
+------
+
+Thanks go to Stephen McCamant, Oren Tirosh, Jérôme Audu, and Carlos
+Hernan Prada Rojas for their bug reports and tests; and to Rémi
+Duraffort for his contributions.
+
+
+Release v3.2.2
+==============
+
++ Remove a useless memory layout constraint on x86_64 that bugs some
+  programs like java and or qemu.
+
++ It is now possible to launch the initial program from a relative
+  path without specifying the "./" prefix, for example:
+
+    $ proot path/to/program
+
++ Don't discard fcntl(F_DUPFD_CLOEXEC) systematically when the kompat
+  extension is enabled (-k option).
+
++ Don't use syscalls that require Linux >= 2.6.16 anymore.
+
+
+Release v3.2.1
+==============
+
++ Make ptrace/seccomp even more portable on Ubuntu.
+
+Thanks to Maxence Dalmais for the bug report and tests.
+
+
+Release v3.2
+============
+
+This release was mostly driven by the requirements of "CARE", a new
+project based on PRoot that will be released publicly soon on
+http://reproducible.io.  For information, "CARE" is the short for
+"Comprehensive Archiver for Reproducible Execution".
+
+Highlights
+----------
+
++ Many bugs exposed by a couple of static code analyzers (Coverity,
+  Clang, ...) and some test-suites (Linux Test Project, libuv, ...)
+  are now fixed.
+
++ The "kompat" extension ("-k" option) can now emulate most of the
+  kernel features that would be required by the guest system but that
+  are not available on the host kernel.  For example, it can now make
+  programs from Ubuntu 13.04 64-bit run on RedHat 5 64-bit without any
+  further tweaks:
+
+     rh5-64$ proot -k 3.8 -R ubuntu-13.04-64bit/ ...
+
++ On ARM and x86_64, the heap segment is now emulated with a regular
+  memory mapping to ensure this former always exists.  This was
+  required because some kernels might put a non-fixed memory mapping
+  right after the regular heap when using some GNU ELF interpreters
+  (ld.so) as loaders.  Without the heap segment emulation, some
+  programs like Bash would crash because the heap can't grow anymore:
+
+      bash: xmalloc: locale.c:73: cannot allocate 2 bytes (0 bytes allocated)
+
+Miscellaneous
+-------------
+
++ When using the "-R" option, the path to the guest rootfs is now
+  bound into the guest rootfs itself.  This is required to run
+  programs that search for their DSOs in /proc/self/maps, like VLC for
+  instance.
+
++ When using the "-v" option with a level greater than 2, syscalls are
+  now printed as strings instead of numbers, à la strace:
+
+    $ proot -v 3 true
+    [...]
+    proot info: pid 29847: sysenter start: mmap(0x0, 0x2d141, 0x1, 0x2, 0x3, 0x0) [...]
+    [...]
+
++ The article about the migration from ScratchBox2 is now publicly
+  available:
+
+    https://github.com/cedric-vincent/PRoot/blob/v3.2/doc/articles/howto_migrate_from_scratchbox2.txt
+
+Internal changes
+----------------
+
++ Tools based on PRoot (CARE, DepsTracker, ATOS, ...) can now easily
+  replace the original command-line interface with their own
+  command-line interface.
+
++ It is now possible to chain forged syscalls to a regular syscall.
+  Search for "register_chained_syscall" in the sources for details.
+
++ A couple of new helpers are now visible from the extensions.
+
+Thanks
+------
+
++ Bug reports and tests: Corbin Champion, Maxence Dalmais, and Nicolas
+  Cornu.
+
++ Static code analysis: Antoine Moynault and Christophe Guillon.
+
++ Patches: Rémi Duraffort.
+
++ Unexpected hint: Christophe Monat :)
+
+
+Release v3.1
+============
+
+Command-line interface changes
+------------------------------
+
++ The initial command is not search in "." anymore, unless the "./"
+  prefix is specified or unless "." is in $PATH, as expected.
+
++ The "-B" and "-Q" options are obsoleted by the new "-R" option.
+  This latter is equivalent to "-B -r", as there was actually no point
+  at using the "-B" option without "-r".
+
++ A warning is now emitted when the rootfs is specified à la
+  chroot(1), that is, without using "-r" or "-R".
+
+The old command-line interface is not documented anymore, but it will
+be still supported for a couple of releases.  Although, users are
+strongly encouraged to switch to the new one:
+
+        ======================   =================
+        old CLI                  new CLI
+        ======================   =================
+        proot rootfs             proot -r rootfs
+        proot -B rootfs          proot -R rootfs
+        proot -B -r rootfs       proot -R rootfs
+        proot -Q qemu rootfs     proot -R rootfs -q qemu
+        proot -Q qemu -r rootfs  proot -R rootfs -q qemu
+        =======================  =======================
+
+Extensions
+----------
+
++ The "kompat" extension ("-k" option) has been greatly enhanced.  For
+  example, it can now make programs from Ubuntu 13.04 32-bit run on
+  RedHat 5 64-bit:
+
+     rh5-64$ proot -k 3.8 -R ubuntu-13.04-32bit/ ...
+
++ The "fake id0" extension ("-0" option) handles more syscalls:
+  mknod(2), capset(2), setxattr(2), setresuid(2), setresgid(2),
+  getresuid(2), and getresgid(2).
+
+Miscellaneous
+-------------
+
++ PRoot is now compiled with large file-system support (LFS), this
+  make it works with 64-bit file-systems (eg. CIFS) on 32-bit
+  platforms.
+
++ The special symbolic link "/proc/self/root" now points to the guest
+  rootfs, that is, to the path specified by "-r" or "-R".  Just like
+  with chroot(2), this symlink may be broken as the referenced host
+  path likely does not exist in the guest rootfs.  Although, this
+  symlink is typically used to know if a process is under a chroot-ed
+  environment.
+
++ Under QEMU, LD_LIBRARY_PATH is not clobbered anymore when a guest
+  program is launched by a host program.
+
++ When seccomp-filter is enabled, this release is about 8% faster than
+  the previous one.
+
++ A couple of bugs reported by Scan Coverity are fixed.
+
+Thanks
+------
+
+Special thanks to Stephan Hadamik, Jérôme Audu, and Rémi Duraffort for
+their valuable help.
+
+
+Release v3.0.2
+==============
+
++ Fix the search of the initial command: when the initial command is a
+  symbolic link, PRoot has to dereference it in guest namespace, not
+  in the host one.
+
++ Return error code EACCESS instead of EISDIR when trying to execute a
+  directory.  Some programs, such as "env", behave differently with
+  respect to this error code.  For example:
+
+      ### setup
+      $ mkdir -p /tmp/foo/python
+      $ export PATH=/tmp/foo:$PATH
+
+      ### before (PRoot v2.3 ... v3.0.1)
+      before$ proot env python
+      env: python: Is a directory
+
+      ### now (PRoot v3.0.2 ...)
+      $ proot env python
+      Python 2.7.5 (default, May 29 2013, 02:28:51)
+      [GCC 4.8.0] on linux2
+      Type "help", "copyright", "credits" or "license" for more information.
+      >>>
+
+
+Release v3.0.1
+==============
+
+Fix support for bindings where the guest path is explicitly not
+dereferenced.  Be careful, the syntax has changed:
+
+        before$ proot -b /bin/bash:!/bin/sh
+
+        now$ proot -b /bin/bash:/bin/sh!
+
+
+Release v3.0
+============
+
+New features
+------------
+
++ PRoot can now use the kernel feature named "seccomp-filter", a.k.a
+  "seccomp mode 2", to improve its own performance significantly.  For
+  examples on my workstation, the tables below show the time overhead
+  induced by PRoot compared to a native execution:
+
+  - when generating the Perl 5.16.1 package:
+
+    ===============  ===========  ==========
+    command          seccomp off  seccomp on
+    ===============  ===========  ==========
+    ./configure.gnu          75%         25%
+    make -j4                 70%         45%
+    make -j4 check           25%          9%
+    ===============  ===========  ==========
+
+  - when generating the Coreutils 8.19 package:
+
+    ===============  ===========  ==========
+    command          seccomp off  seccomp on
+    ===============  ===========  ==========
+    ./configure              80%         33%
+    make -j4                 75%         33%
+    make -j4 check           80%          8%
+    ===============  ===========  ==========
+
++ It is now possible to explicitly not dereference the guest location
+  of a binding by specifying ``!`` as the first character.  For
+  instance::
+
+      proot -b /bin/bash:!/bin/sh
+
+  will not overlay ``/bin/dash`` when this latter is pointed to by
+  ``/bin/sh`` (it's typically the case on Ubuntu and Debian).
+
+Fix
+---
+
++ The initial command is not search in $PATH anymore when it starts
+  with ``/`` or ``./``, and it doesn't exist.  For instance::
+
+      $ rm test
+      $ proot ./test
+      proot warning: './test not found (root = /, cwd = /usr/local/cedric/git/proot)
+      proot error: see `proot --help` or `man proot`.
+
+Thanks
+------
+
+Many thanks to Will Drewry and Indan Zupancic, who made possible to
+accelerate PTRACE_SYSCALL with seccomp-filter.  Also, thanks to Paul
+Moore for his valuable set of seccomp tools.
+
+Notes
+-----
+
++ Unlike what I said, this release is not shipped with a ptrace
+  emulator.  It's planned for the next one, though.
+
++ Seccomp-filter was first introduced in Linux 3.5 a year ago, it was
+  also officially back-ported to Ubuntu 12.04 (Linux 3.2).  To know if
+  PRoot is actually using this accelerator on your system, check the
+  verbose output.  For instance::
+
+    $ proot -v 1 true
+    ...
+    proot info: ptrace acceleration (seccomp mode 2) enabled
+    ...
+
+  But first, be sure it was built with this support::
+
+    $ proot -V
+    ...
+    built-in accelerators: process_vm = yes, seccomp_filter = yes
+    ...
+
+
+Release v2.4.1
+==============
+
+Fixes
+-----
+
++ Fix all warnings reported by GCC-4.8 "-Wall -Wextra" and Coverity
+  Prevent 4.5.
+
++ Fix Unix sockets path translation for some x86_64 systems.
+
++ Make the "kompat" extension (-k option) work again.
+
++ Fix spurious "can't delete /tmp/proot-$PID-XXXXX" messages.
+
+
+
+Release v2.4
+============
+
+New architectures
+-----------------
+
++ PRoot now works natively on Linux ARM64 systems (a.k.a AArch64).
+  Note that PRoot/AArch64 doesn't support 32-bit binaries yet.
+
++ PRoot/x86_64 now supports x32 binaries/rootfs.
+
+Fixes
+-----
+
++ Paths from Unix domain sockets are now translated.  For example, it
+  wasn't possible previously to use "tmux" in the guest rootfs if
+  another instance were running in the host rootfs.
+
++ When a host path is bound to a nonexistent guest path, PRoot tries
+  to create this latter in the guest rootfs, for some technical
+  reasons.  Previously, this "dummy" guest path was created with RWX
+  permissions but this might cause troubles when re-using the rootfs
+  for other purpose.  Now, this "dummy" guest path is created with
+  minimal permissions, and it is also possible to avoid its creation
+  by defining the PROOT_DONT_POLLUTE_ROOTFS environment variable.
+
+Command-line interface changes
+------------------------------
+
++ The directory "/run" is removed from the list of recommended
+  bindings (-B option) because this creates to much conflicts with
+  programs that write in the "/run/var" directory.
+
++ The -0 option now makes user's files appear as if they were actually
+  owned by root, and it also fakes the success of any mode changes
+  (chmod* syscalls).  This is typically useful to create packages
+  where the files belong to the root user (it's almost always the
+  case).
+
+Internal changes
+----------------
+
++ PRoot should be even more portable now.  For instance, there's no
+  need to worry about syscallee-saved registers anymore.
+
+Thanks
+------
+
+This release was made possible thanks to, in no special order: Yvan
+Roux, Jerôme Audu, Heehooman, Yann Droneaud, and James Le Cuirot.  See
+"git log" for details.
+
+
+Release v2.3.1
+==============
+
+New feature
+-----------
+
++ The "fake id0" feature was improved by Rémi Duraffort in order to
+  support privileged write operations in read-only files/directories.
+  Some package managers (Fedora, Debian, ...) relies on this special
+  behavior::
+
+      # ls -ld /usr/lib
+      dr-xr-xr-x 22 root root 40960 Jan  2 11:19 /usr/lib/
+      # install -v something.so /usr/lib/
+      removed ‘/usr/lib/something.so‘
+      ‘something.so‘ -> ‘/usr/lib/something.so‘
+
+Fixes
+-----
+
++ Fix bindings to a guest path that contains a symbolic link.  For
+  example when the given guest path ``/var/run/dbus`` is a symbolic
+  link to ``/run/dbus``.
+
++ Fix a memory corruption when accessing files in "/proc/self/"
+
+Special thanks to Rémi Duraffort for the improved "fake id0" feature
+and for the bug reports.
+
+
+Release v2.3
+============
+
+This release is intended more specifically to developers and advanced
+users, it was mostly driven by the requirements of an internal
+STMicroelectronics project named "Auto-Tuning Optimization Service".
+
+New features
+------------
+
++ There's now an extension mechanism in PRoot that allows developers
+  to add their own features and/or to use PRoot as a Linux process
+  instrumentation engine.  The two following old features were moved
+  to this new extension interface: "-k *string*" and "-0"
+  (respectively: set the kernel release and compatibility level to
+  *string*"; and force some syscalls to behave as if executed by
+  "root").
+
++ It is now possible to execute PRoot under PRoot, well somewhat.
+  Actually the initial instance of PRoot detects that it is being
+  called again and recomputes the configuration for the new process
+  tree.  This feature is still experimental and was way harder to
+  implement than expected, however it was worth the effort since it
+  enforced the consistency in PRoot.  Just one example among many, in
+  PRoot the "chroot" feature is now really equivalent to the
+  "mount/bind" one, that is, ``chroot path/to/rootfs`` is similar to
+  ``mount --bind path/to/rootfs /``.
+
++ The "current working directory" (chdir(2), getcwd(2), ...) is now
+  fully emulated by PRoot.  Sadly a minor regression was introduced:
+  even if the current working directory has been removed, getcwd(2)
+  returns a "correct" value.  This should be fixed in the next
+  release.
+
+Command-line interface changes
+------------------------------
+
++ The message "proot info: started/exited" isn't printed by default
+  anymore since it might introduce noise when PRoot is used inside a
+  test-suite that compares outputs.  This message was initially added
+  to know whether the guest program has exited immediately.
+
++ The "-u" and "-W" options have disappeared.  The former wasn't
+  really useful and the latter was definitely useless since the
+  default "current working directory" is "." since v2.1, that means
+  the three examples below are equivalent ("-W" was just an alias to
+  "-b . -w .")::
+
+      proot -b . [...]
+      proot -b . -w . [...]
+      proot -W [...]
+
+Fixes
+-----
+
++ The option ``-w .`` is now really equivalent to ``-w $PWD``.
+
++ A bug almost impossible to describe here has been fixed, it appeared
+  only when specifying relative bindings, for instance: ``-b .``.
+
+Internal changes
+----------------
+
++ PRoot now relies on Talloc: a hierarchical, reference counted memory
+  pool system with destructors.  It is the core memory allocator used
+  in Samba: http://talloc.samba.org.  This is definitely a worthwhile
+  dependency for the sake of development scalability and
+  debuggability.  For example, PRoot now has an explicit garbage
+  collector (c.f. ``tracee->ctx``), and the full dynamic memory
+  hierarchy can be printed by sending the USR1 signal to PRoot::
+
+      native-shell$ proot --mount=$HOME --mount=/proc --rootfs=./slackware-14/
+      prooted-shell$ kill -s USR1 $(grep Tracer /proc/self/status | cut -f 2)
+
+      Tracee           0x6150c0  768 bytes  0 ref'    (pid = 22495)
+          talloc_new: ./tracee/tracee.c:97 0x615420  0 bytes  0 ref'
+          $exe             0x61bef0  10 bytes  0 ref'     ("/bin/bash")
+          @cmdline         0x61bf60  16 bytes  0 ref'     ("/bin/sh", )
+              /bin/sh          0x61bfd0  8 bytes  0 ref'
+          $glue            0x61bae0  24 bytes  0 ref'     ("/tmp/proot-22494-UfGAPh")
+          FileSystemNameSpace 0x615480  32 bytes  0 ref'
+              $cwd             0x61b880  13 bytes  0 ref'     ("/home/cedric")
+              Bindings         0x61b970  16 bytes  0 ref'     (host)
+                  Binding          0x615570  8280 bytes  1 ref'   (/home/cedric:/home/cedric)
+                  Binding          0x6176a0  8280 bytes  1 ref'   (/proc:/proc)
+                  Binding          0x6197d0  8280 bytes  1 ref'   (/usr/local/proot/slackware-14:/)
+              Bindings         0x61b900  16 bytes  0 ref'     (guest)
+                  Binding          -> 0x6176a0
+                  Binding          -> 0x615570
+                  Binding          -> 0x6197d0
+
+
+Release v2.2
+============
+
++ This release brings some critical fixes so an upgrade is highly
+  recommended, especially on x86_64 and Ubuntu.
+
++ PRoot is now a lot faster: the speed-up can be up to 50% depending
+  on the kind of application.
+
++ PRoot can now mount/bind files anywhere in the guest rootfs, even if
+  the mount point has no parent directory (and/or can't be created).
+  With previous versions of PRoot, that would created kinda black hole
+  in the filesystem hierarchy that might bug some programs like "cpio"
+  or "rpm".
+
+  For example, with the previous version of PRoot::
+
+       $ proot -b /etc/motd:/black/holes/and/revelations
+       proot warning: can't create the guest path (binding) ...
+       proot info: started
+
+       $ find /black
+       find: `/black: No such file or directory
+
+       $ cat /black/holes/and/revelations
+       Time has come to make things right -- Matthew Bellamy
+
+  And now::
+
+       $ proot -b /etc/motd:/black/holes/and/revelations
+       proot info: started
+
+       $ find /black
+       /black
+       /black/holes
+       /black/holes/and
+       /black/holes/and/revelations
+
+       $ cat /black/holes/and/revelations
+       Time has come to make things right -- Matthew Bellamy
+
++ "/run" was added to the list of recommended bindings (-B/-Q).
+
++ SH4 and ARM architectures are now officially supported.
+
+Thanks
+------
+
+Huge thanks to Rémi DURAFFORT for all the tests, bug reports, fixes,
+and for hosting http://proot.me.
+
+Thanks to Thomas P. HIGDON for the advanced investigation on a really
+tricky bug (red zone corruption).
+
+
+Release v2.1
+============
+
+New features
+------------
+
++ PRoot can now emulate some of the syscalls that are available in the
+  kernel release specified by -k but that are missing in the host
+  kernel.  This allows the execution of guest programs expecting a
+  kernel newer than the actual one, if you encountered the famous
+  "FATAL: kernel too old" or "qemu: Unsupported syscall" messages.
+
++ The current working directory isn't changed anymore if it is still
+  accessible in the guest environment (binding).
+
+Fixes
+-----
+
++ Added support for architectures with no misalignment support (SH4).
+
++ Fix support for: link(2), linkat(2), symlink(2), and symlinkat(2).
+
+
+Release v2.0.1
+==============
+
++ Fix a compatibility issue with QEMU v1.1
+
++ Fix the initialization of bindings that point to "/proc/self".
+
+These problems were reported by Alkino:
+
+    https://github.com/cedric-vincent/PRoot/issues/3
+
+
+Release v2.0
+============
+
+New features
+------------
+
++ There's now a specific support to handle special symlinks in /proc.
+  As of now, only the following ones are correctly handled:
+
+      * /proc/self, it was already supported previously but now this
+        is done consistently (i.e. not a hack);
+
+      * /proc/<PID>/exe, for any <PID> monitored by PRoot; and
+
+      * /proc/<PID>/fd/<FD>.
+
++ The list of supported syscalls was updated, as of Linux 3.4.1.
+
+Command-line interface changes
+------------------------------
+
++ The path to the guest rootfs can now be specified by the new
+  -r/--rootfs option.  This permits the use of shell aliases, for
+  example:
+
+      $ alias armedslack='proot -Q qemu-arm -r /path/to/armedslack'
+      $ armedslack -v 1 -b ~/arm_cpuinfo:/proc/cpuinfo
+
+  That wasn't possible previously because the path to the guest rootfs
+  had to be the last option.
+
++ The -v/--verbose option now takes a parameter, and a negative
+  integer makes PRoot quiet except on fatal errors.
+
++ The -h/--help option now prints a detailed message.
+
++ The -V/--version and -h/--help options now exit with success.
+
+Fix
+---
+
++ Return correct errno if a non-final path component isn't a directory
+  nor a symlink.
+
++ Fix the insertion of an item in the list of host/guest bindings.
+
+
+Internal changes
+----------------
+
+This section is dedicated to PRoot developers.
+
++ File-system information is now inherited from a traced process to
+  its children.  This permits the emulation of symlinks in /proc/self:
+  cmdline, exe, cwd, root, ...
+
++ The execution of QEMU is now fully confined to the virtual rootfs
+  namespace: it now relies on the "mixed-execution" feature, just like
+  a regular host program.
+
+
+Release v1.9
+============
+
+Fixes
+-----
+
++ Be as transparent as possible with respect to SIGSTOP and SIGTRAP
+  signals.  For instance, the Open POSIX Test Suite now reports the
+  same level of success whether it is run under PRoot or not (it
+  depends on the kernel version though).
+
++ Ignore terminating signals and kill all tracees on abnormal
+  termination signals (^\, segmentation fault, divide by zero, ...).
+  This ensures no tracee will stay alive without being monitored
+  anymore.
+
++ Force utsname.machine to "i686" -- instead of "i386" -- for 32-bit
+  programs running on x86_64 systems.  This improves the compatibility
+  with package managers that deduce the current architecture from
+  `uname -m`.
+
++ Fix x86_64 support for linkat() and fchownat().
+
++ Fix mixed-execution support, LD_LIBRARY_PATH was defined twice for
+  host programs.
+
+
+Release v1.8.4
+==============
+
+New feature
+-----------
+
++ The -0 option now fakes success on ``chroot("/")``.  This feature is
+  required by some guest package managers, like ``pacman`` -- the Arch
+  Linux Package Manager.
+
+Fix
+---
+
++ Nested bindings are now correctly supported.  For example with these
+  bindings -- nested from the host point-of-view::
+
+      host$ proot -b /:/host-rootfs -b /tmp ...
+      guest$ ln -s /tmp/bar /tmp/foo
+      # ... points to "/tmp/bar" instead of "/host-rootfs/tmp/bar"
+
+  and with these bindings -- nested from the guest point-of-view::
+
+      host$ proot -b /bin -b /usr/bin/find:/bin/find ...
+      guest$ /bin/find
+      # ... works instead of "no such file or directory"
+
+Internal changes
+----------------
+
+This section is dedicated to PRoot developers.
+
++ Functions to compare two pathes (equal, prefix, not comparable, ...)
+  are now available, at last.
+
++ The "ignore ELF interpreter" option can be (dis|en)able with the
+  ``PROOT_IGNORE_ELF_INTERPRETER`` environment variable and/or with
+  the ``config.ignore_elf_interpreter`` internal variable.
+
+
+Release v1.8.3
+==============
+
+New features
+------------
+
++ The -0 option now fakes success on ownership changes.  This improves
+  the compatibility with package managers that abort if ``chown(2)``
+  fails.  Note that this is quite limited compared to ``fakeroot``.
+
++ Force utsname.machine to "i386" for 32-bit programs running on
+  x86_64 systems.  This improves the compatibility with package
+  managers that deduce the current architecture from `uname -m`.
+
+Fixes
+-----
+
++ Fix a regression regarding the concatenation of the ``..`` with a
+  path ending with ``.``.  For intance you can now do ``ls foo`` where
+  ``foo`` is a symbolic link to ``/bar/.``.
+
++ Don't return an error if the specified size for ``getcwd(2)`` and
+  ``readlink(2)`` is greater than PATH_MAX.  Technically the result
+  may likely be shorter than this limit.
+
+
+Release v1.8.2
+==============
+
++ This is the first public release of PRoot, it's time to increase its
+  maturity artificially ...  Actually it's an homage to Blink 182 ;)
+
++ User manual finally published.
+
++ PRoot can now *mix* the execution of host programs and the execution
+  of guest programs emulated by QEMU.  This is useful to use programs
+  that aren't available initially in the guest environment and to
+  speed up build-time by using cross-compilation tools or any CPU
+  independent program, like interpreters.
+
++ Absolute symlinks from bound directories that point to any bound
+  directory are kept consistent: for example, given the host symlink
+  ``/bin/sh -> /bin/bash``, and given the command-line option ``-b
+  /bin:/foo``, the symlink will appeared as ``/foo/sh -> /foo/bash``.
+
++ Three command-line options are gone:
+
+  * ``-p`` (don't block the ptrace syscall) wasn't really useful.
+
+  * ``-e`` (don't use the ELF interpreter) isn't required anymore.
+
+  * ``-a`` (disable the ASLR mechanism) is now the default.
+
++ Don't complain anymore when parent directories of a *recommended
+  binding* (as enabled by ``-B``, ``-M`` and ``-Q`` options) can't be
+  created.
+
++ Support job control under ptrace as introduced in Linux 3.0+.
+
++ ``LD_`` environment variables are now passed to the QEMUlated
+  program, not to QEMU itself.  It means ``ldd`` works (there's a bug
+  in QEMU/ARM though).
+
++ Many fixes and improved compatibility thanks to the Open Build
+  Service instantiated at http://build.opensuse.com
+
++ Note: v0.7.1 was an experimental release.
+
+
+Release v0.7.0
+==============
+
++ Search the guest program in $PATH relatively to the guest rootfs,
+  for instance you can now just write::
+
+      proot /path/to/guest/rootfs/  perl
+
+  instead of::
+
+      proot /path/to/guest/rootfs/  /usr/bin/perl
+
++ The command-line interface was re-written from scratch, the only
+  incompatible change is that QEMU options are now separated by
+  spaces::
+
+     proot -Q "qemu-arm -g 1234" ...
+
+  instead of::
+
+     proot -Q qemu-arm,-g,1234 ...
+
++ New option "-0": force syscalls "get*id" to report identity 0, aka
+  "root".
+
++ Many fixes, code refactoring, new testing framework, ...
+
+Special thanks to Claire ROBINE for her contribution.
+
+
+Release v0.6.2
+==============
+
++ Change the default command from $SHELL to "/bin/sh".  The previous
+  behaviour led to an unexpected error -- from user's point-of-view --
+  when $SHELL didn't exit in the new root file-system.
+
++ Fix *partially* support for readlink(2) when mirror pathes are in
+  use.  Prior this patch, any symbolic link -- that points to an
+  absolute path which prefix is equal to the host-side of any mirror
+  path -- was bugged.  For instance, the command "proot -m /bin:/host
+  $ROOTFS /usr/bin/readlink /usr/bin/ps" returned "/host" instead of
+  "/bin/ps".
+
++ Add the option "-V" to print the version then exit.
+
++ Be more explicit when a wrong command-line argument is used.
+
++ Remove the SIGSEGV help message: it was too confusing to the user.
+
++ Use a new shining build-system (again :D).
+
+Special thanks go to those contributors: Yves JANIN, Remi Duraffort
+and Christophe GUILLON.
+
+
+Release v0.6.1
+==============
+
++ Add `/tmp` to the list of mirrored paths when using -M.
+
++ Fix the ELF interpreter extraction.
+
++ Rewrite the build system.
+
+
+Release v0.6
+============
+
+New features
+------------
+
++ Added support for "asymmetric" path mirrors.
+
+    The command-line option for mirrors was extended to support the
+    syntax "-m <p1>:<p2>" where <p1> is the location of the mirror
+    within the alternate rootfs and <p2> is the path to the real
+    directory/file.  For instance you can now mirror the whole host
+    rootfs in the directory "/hostfs" within the alternate rootfs that
+    way::
+
+        proot -m /:/hostfs ...
+
++ Added an option to disable ASLR (Address Space Layout
+  Randomization).
+
+    RHEL4 and Ubuntu 10.04 use an ASLR mechanism that creates
+    conflicts between the layout of QEMU and the layout of the target
+    program.  This new option is automatically set when QEMU is used.
+
++ Added "/etc/resolv.conf" and $HOME to the list of mirrored paths
+  when using the option -M or -Q.
+
+Fixes
+-----
+
++ Fixed the detranslation of getcwd(2) and readlink(2).
+
++ Improved the build compatibility on old/broken distro.
+
++ Added support for pthread cancellation when QEMU is used.
+
++ Set QEMU's fake argv[0] to the program actually launched, not to the
+  initial script name.
+
++ Create the path up to the mirror location to cheat "walking"
+  programs.
+
diff --git a/5.1.0/doc/proot/stylesheets/cli.xsl b/5.1.0/doc/proot/stylesheets/cli.xsl
new file mode 100644
index 0000000..f2cf60b
--- /dev/null
+++ b/5.1.0/doc/proot/stylesheets/cli.xsl
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:output method="text" />
+
+  <xsl:template match="/">
+    <xsl:text>/* This file is automatically generated from the documentation. EDIT AT YOUR OWN RISK. */
+
+#ifndef PROOT_CLI_H
+#define PROOT_CLI_H
+
+#include "cli/cli.h"
+
+#ifndef VERSION
+#define VERSION "</xsl:text><xsl:value-of select="//version" /><xsl:text>"
+#endif
+</xsl:text>
+
+    <xsl:text>
+</xsl:text>
+
+    <xsl:apply-templates select="//option_string[.='-R']" />
+    <xsl:apply-templates select="//option_string[.='-S']" />
+
+    <xsl:apply-templates select="//option_group" mode="handlers" />
+    <xsl:text>
+static int pre_initialize_bindings(Tracee *, const Cli *, size_t, char *const *, size_t);
+static int post_initialize_command(Tracee *, const Cli *, size_t, char *const *, size_t);
+</xsl:text>
+    <xsl:text>
+static Cli proot_cli = {
+	.version  = VERSION,
+	.name     = "proot",
+</xsl:text>
+    <xsl:apply-templates select="//subtitle"/>
+    <xsl:apply-templates select="//section[@names='synopsis']" />
+    <xsl:apply-templates select="//section[@names='colophon']" />
+    <xsl:apply-templates select="//section[@names='logo']" />
+    <xsl:text>
+	.pre_initialize_bindings = pre_initialize_bindings,
+	.post_initialize_command = post_initialize_command,
+
+	.options = {
+</xsl:text>
+    <xsl:apply-templates select="//option_group" mode="options" />
+  <xsl:text>	END_OF_OPTIONS,
+	},
+};
+
+#endif /* PROOT_CLI_H */
+</xsl:text>
+  </xsl:template>
+
+  <!-- Constant string definitions -->
+
+  <xsl:template match="subtitle">
+    <xsl:text>	.subtitle = "</xsl:text>
+    <xsl:value-of select="." />
+    <xsl:text>",
+</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="section[@names='synopsis']">
+    <xsl:text>	.synopsis = "</xsl:text>
+    <xsl:value-of select="./paragraph" />
+    <xsl:text>",
+</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="section[@names='colophon']">
+    <xsl:text>	.colophon = "</xsl:text>
+    <xsl:value-of select="./paragraph" />
+    <xsl:text>",
+</xsl:text>
+    <xsl:text>	.logo = "\
+</xsl:text>
+    <xsl:value-of select="./literal_block" />
+    <xsl:text>",
+</xsl:text>
+  </xsl:template>
+
+  <!-- Recommended bindings declarations -->
+
+  <xsl:template match="option_string[.='-R']">
+    <xsl:text>static const char *recommended_bindings[] = {
+</xsl:text>
+    <xsl:apply-templates select="ancestor-or-self::option_list_item//list_item" />
+    <xsl:text>	NULL,
+};
+
+</xsl:text>
+  </xsl:template>
+
+  <!-- Recommended "su" bindings declarations -->
+
+  <xsl:template match="option_string[.='-S']">
+    <xsl:text>static const char *recommended_su_bindings[] = {
+</xsl:text>
+    <xsl:apply-templates select="ancestor-or-self::option_list_item//list_item" />
+    <xsl:text>	NULL,
+};
+
+</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="list_item">
+    <xsl:text>	"</xsl:text>
+    <xsl:value-of select="." />
+    <xsl:text>",
+</xsl:text>
+  </xsl:template>
+
+  <!-- Option declarations -->
+
+  <xsl:template match="option_group" mode="options">
+    <xsl:text>	{ .class = "</xsl:text>
+    <xsl:value-of select="ancestor-or-self::section[1]/title" />
+    <xsl:text>",
+</xsl:text>
+    <xsl:text>	  .arguments = {
+</xsl:text>
+    <xsl:apply-templates select="option" mode="options" />
+    <xsl:text>		{ .name = NULL, .separator = '\0', .value = NULL } },
+</xsl:text>
+    <xsl:text>	  .handler = handle_option_</xsl:text>
+    <xsl:value-of select="substring(option[1]/option_string, 2, 1)" />
+    <xsl:text>,
+</xsl:text>
+    <xsl:text>	  .description = "</xsl:text>
+    <xsl:apply-templates select="../description/paragraph[1]" mode="options" />
+    <xsl:text>",
+</xsl:text>
+    <xsl:text>	  .detail = "</xsl:text>
+    <xsl:apply-templates select="../description/paragraph[position() > 1]" />
+    <xsl:text>",
+	},
+</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="emphasis" mode="options">
+    <xsl:text>*</xsl:text>
+    <xsl:value-of select="." />
+    <xsl:text>*</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="paragraph">
+      <xsl:apply-templates/>
+    <xsl:text>
+
+</xsl:text>
+  </xsl:template>
+
+  <!-- Option aliases declarations -->
+
+  <xsl:template match="option" mode="options">
+    <xsl:text>		{ </xsl:text>
+    <xsl:text>.name = "</xsl:text>
+    <xsl:value-of select="option_string" />
+    <xsl:text>", .separator = '</xsl:text>
+    <xsl:choose>
+      <xsl:when test="option_argument">
+	<xsl:value-of select="option_argument/@delimiter" />
+	<xsl:text>', .value = "</xsl:text>
+	<xsl:value-of select="option_argument" />
+	<xsl:text>"</xsl:text>
+      </xsl:when>
+      <xsl:otherwise>
+	<xsl:text>\0', .value = NULL</xsl:text>
+      </xsl:otherwise>
+    </xsl:choose>
+    <xsl:text> },
+</xsl:text>
+  </xsl:template>
+
+  <!-- Handler declarations -->
+
+  <xsl:template match="option_group" mode="handlers">
+    <xsl:text>static int handle_option_</xsl:text>
+    <xsl:value-of select="substring(option[1]/option_string, 2, 1)" />
+    <xsl:text>(Tracee *tracee, const Cli *cli, const char *value);
+</xsl:text>
+  </xsl:template>
+
+</xsl:transform>
diff --git a/5.1.0/doc/proot/stylesheets/rpm-spec.xsl b/5.1.0/doc/proot/stylesheets/rpm-spec.xsl
new file mode 100644
index 0000000..7015091
--- /dev/null
+++ b/5.1.0/doc/proot/stylesheets/rpm-spec.xsl
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:output method="text"/>
+
+  <xsl:template match="/">%define version v<xsl:value-of select="/document/docinfo/version"/>
+
+Summary   : <xsl:value-of select="/document/subtitle"/>
+Version   : %{version}
+Release   : 1
+License   : GPL2+
+Group     : Applications/System
+Source    : proot-%{version}.tar.gz
+Buildroot : %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
+Prefix    : /usr
+Name      : proot
+
+BuildRequires: libtalloc-devel
+
+%if 0%{?suse_version} >= 1210 || 0%{?fedora_version} >= 15
+BuildRequires: glibc-static
+%endif
+
+%if !0%{?suse_version} != 0
+BuildRequires: which
+%endif
+
+%description
+<xsl:value-of select="/document/section[@names='description']/paragraph[1]"/>
+
+%prep
+%setup -n proot-%{version}
+
+%build
+make -C src
+
+%install
+make -C src install PREFIX=%{buildroot}/%{prefix}
+install -D doc/proot/man.1 %{buildroot}/%{_mandir}/man1/proot.1
+
+%check
+env LD_SHOW_AUXV=1 true
+cat /proc/cpuinfo
+./src/proot -V
+./src/proot -v 1 true
+make -C tests
+
+%clean
+rm -rf %{buildroot}
+
+%files
+%defattr(-,root,root)
+%{prefix}/bin/proot
+%doc %{_mandir}/man1/proot.1*
+%doc COPYING
+%doc doc/*
+
+%changelog
+</xsl:template>
+</xsl:transform>
diff --git a/5.1.0/doc/proot/stylesheets/website.css b/5.1.0/doc/proot/stylesheets/website.css
new file mode 100644
index 0000000..63afcb8
--- /dev/null
+++ b/5.1.0/doc/proot/stylesheets/website.css
@@ -0,0 +1,13 @@
+@import url("website.css");
+
+h1 {
+    color: orange;
+}
+
+#contents a:hover {
+    border-bottom: 2px solid orange;
+}
+
+a {
+    border-bottom: 1px solid orange;
+}
diff --git a/5.1.0/doc/proot/stylesheets/website.xsl b/5.1.0/doc/proot/stylesheets/website.xsl
new file mode 100644
index 0000000..e8ecce1
--- /dev/null
+++ b/5.1.0/doc/proot/stylesheets/website.xsl
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:import href = "../../stylesheets/website.xsl" />
+
+  <xsl:template match="/">
+    <html xmlns="http://www.w3.org/1999/xhtml" itemscope="" itemtype="http://schema.org/Product" xml:lang="en" lang="en">
+
+      <head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>
+	  <xsl:value-of select="document/title" /> — <xsl:value-of select="document/subtitle" />
+	</title>
+	<link rel="stylesheet" href="proot-website.css" type="text/css" />
+	<meta itemprop="name" content="PRoot" />
+	<meta itemprop="description">
+	  <xsl:attribute name="content">
+	    <xsl:value-of select="//section[@names='description']/paragraph[1]" />
+	  </xsl:attribute>
+	</meta>
+	<script type="text/javascript">
+	  var _gaq = _gaq || [];
+	  _gaq.push(['_setAccount', 'UA-20176046-1']);
+	  _gaq.push(['_trackPageview']);
+	  (function() {
+	  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+	  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+	  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+	  })();
+	</script>
+      </head>
+
+      <body>
+
+	<div id="title">
+	  <h1>PRoot</h1>
+	  <xsl:text> </xsl:text>
+	  <div class="g-plusone" data-size="small">
+	    <xsl:comment>By default XSLTproc converts tags with no
+	    content to self-closing tags</xsl:comment>
+	  </div>
+	</div>
+
+	  <div id="contents">
+	    <ul>
+	      <li><a href="#description">Description</a></li>
+	      <li><a href="#examples">Examples</a></li>
+	      <li><a href="#downloads">Downloads</a></li>
+	      <li><a href="#support">Support</a></li>
+	      <li><a href="https://plus.google.com/107605112469213359575/posts">News+</a></li>
+	    </ul>
+	  </div>
+
+	  <xsl:apply-templates select="//section[@names='description']" />
+	  <xsl:apply-templates select="//section[@names='examples']" />
+	  <xsl:apply-templates select="//section[@names='downloads']" />
+
+	  <div class="section" id="support">
+	    <h2>Support</h2>
+	    <p>Feel free to send your questions, bug reports,
+	    suggestions, and patchs to <a
+	    href="mailto:proot_me@googlegroups.com">the
+	    mailing-list</a> or to <a
+	    href="https://groups.google.com/forum/?fromgroups#!forum/proot_me">the
+	    forum</a>, but please be sure that your answer isn't in
+	    the <a
+	    href="https://github.com/cedric-vincent/PRoot#proot">user
+	    manual</a> first.
+	    </p>
+	    <p>Also, Rémi Duraffort has written interesting articles
+	    on <a
+	    href="http://ivoire.dinauz.org/blog/post/2012/04/16/PRoot-sorcery">how
+	    to use a foreign Debian rootfs with PRoot</a> in order to
+	    <a
+	    href="http://ivoire.dinauz.org/blog/post/2012/05/04/Making-VLC-at-home">build
+	    and test VLC on this guest Linux distribution</a>.
+	    </p>
+	  </div>
+
+	  <script type="text/javascript">
+	    (function() {
+	    var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
+	    po.src = 'https://apis.google.com/js/plusone.js';
+	    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
+	    })();
+	  </script>
+
+      </body>
+    </html>
+
+  </xsl:template>
+</xsl:transform>
diff --git a/5.1.0/doc/stylesheets/website.css b/5.1.0/doc/stylesheets/website.css
new file mode 100644
index 0000000..b779b23
--- /dev/null
+++ b/5.1.0/doc/stylesheets/website.css
@@ -0,0 +1,176 @@
+* {
+    padding: 0;
+    margin: 0;
+
+    color: #333333;
+    line-height: 1.5em;
+
+    font-family: sans;
+}
+
+html {
+    background-color: #dddddd;
+}
+
+body {
+    background-color: white;
+
+    border: 1px solid #dddddd;
+    border-radius: 1em;
+    -moz-border-radius: 1em;
+
+    max-width: 50em;
+    min-width: 25em;
+
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 1.5em;
+    margin-bottom: 1.5em;
+
+    -moz-box-shadow: 0 0 1.5em 0.5em #333333;
+    -webkit-box-shadow: 0 0 1.5em 0.5em #333333;
+    box-shadow: 0 0 1.5em 0.5em #333333;
+}
+
+#title {
+    margin-left: auto;
+    margin-right: auto;
+    text-align: center;
+}
+
+h1 {
+    text-align: center;
+    text-shadow: 2px 3px 3px #333333;
+    font-size: 3em;
+    display: inline;
+}
+
+h2 {
+    margin: 1em;
+    margin-bottom: 0.5em;
+
+    border-bottom: 1px dotted gray;
+}
+
+h3 {
+    margin-left: 1em;
+    margin-top: 1em;
+}
+
+h3 tt {
+    font-style: italic;
+}
+
+#contents {
+    text-align: center;
+
+    background-color: gray;
+    border-top: 1px solid #dddddd;
+    border-bottom: 1px solid #dddddd;
+
+    margin-right: -1px;
+    border-right: 1px solid gray;
+    margin-left: -1px;
+    border-left: 1px solid gray;
+    
+    padding-top: 0.5em;
+    padding-bottom: 0.5em;
+}
+
+#contents ul {
+    margin: 0;
+}
+
+#contents li {
+    display: inline;
+
+    margin-left: 3%;
+    margin-right: 3%;
+}
+
+#contents a {
+    color: white;
+    text-decoration: none;
+    font-weight: bold;
+    border-bottom: none;
+}
+
+#contents a:hover {
+    border-bottom: 2px solid black;
+}
+
+a {
+    text-decoration: none;
+    border-bottom: 1px solid black;
+}
+
+p {
+    text-align: justify;
+
+    margin-left: 2em;
+    margin-right: 2em;
+    margin-top: 1em;
+    margin-bottom: 0.5em;
+}
+
+ol {
+    margin-left: 5em;
+    margin-right: 2em;
+    margin-top: 0.5em;
+    margin-bottom: 1em;
+}
+
+li {
+    margin-bottom: 0.5em;
+}
+
+table {
+    margin-left: 2em;
+    margin-right: 2em;
+}
+
+pre {
+    margin: 2em ;
+    margin-top: 0.5em ;
+    margin-bottom: 1em ;
+
+    padding: 0.5em;
+
+    background-color: #dddddd;
+    color: black;
+
+    font-family: monospace;
+
+    white-space: pre-wrap;
+
+    border-style: solid;
+    border-width: 1px;
+    border-color: gray;
+
+    border-radius: 0.5em;
+    -moz-border-radius: 0.5em;
+}
+
+pre:first-line
+{
+    font-style: italic;
+}
+
+tt {
+    font-family: monospace;
+}
+
+ul {
+    margin-left: 3em;
+}
+
+li p, li pre {
+    margin-left: 0;
+}
+
+@media print {
+    * {
+        background-color: transparent ! important;
+        border: none ! important;
+    }
+}
\ No newline at end of file
diff --git a/5.1.0/doc/stylesheets/website.xsl b/5.1.0/doc/stylesheets/website.xsl
new file mode 100644
index 0000000..cd04d3a
--- /dev/null
+++ b/5.1.0/doc/stylesheets/website.xsl
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+-->
+
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:template match="section">
+    <div class="section">
+      <xsl:attribute name="id"><xsl:value-of select="@names" />
+      </xsl:attribute>
+      <xsl:apply-templates/>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="section/title">
+    <h2>
+      <xsl:apply-templates/>
+    </h2>
+  </xsl:template>
+
+  <xsl:template match="section/section/title">
+    <h3>
+      <xsl:apply-templates/>
+    </h3>
+  </xsl:template>
+
+  <xsl:template match="paragraph">
+    <p>
+      <xsl:apply-templates/>
+    </p>
+  </xsl:template>
+
+  <xsl:template match="literal">
+    <tt>
+      <xsl:apply-templates/>
+    </tt>
+  </xsl:template>
+
+  <xsl:template match="emphasis">
+    <em>
+      <xsl:apply-templates/>
+    </em>
+  </xsl:template>
+
+  <xsl:template match="literal_block">
+    <pre>
+      <xsl:apply-templates/>
+    </pre>
+  </xsl:template>
+
+  <xsl:template match="strong">
+    <strong>
+      <xsl:apply-templates/>
+    </strong>
+  </xsl:template>
+
+  <xsl:template match="comment">
+  </xsl:template>
+
+  <xsl:template match="bullet_list">
+    <ul>
+      <xsl:apply-templates/>
+    </ul>
+  </xsl:template>
+
+  <xsl:template match="list_item">
+    <li>
+      <xsl:apply-templates/>
+    </li>
+  </xsl:template>
+
+  <xsl:template match="reference">
+    <a>
+      <xsl:attribute name="href"><xsl:value-of select="@refuri" />
+      </xsl:attribute>
+      <xsl:apply-templates/>
+    </a>
+  </xsl:template>
+
+  <xsl:template match="footnote_reference">
+    [<xsl:apply-templates/>]
+  </xsl:template>
+
+  <xsl:template match="footnote">
+      <p>
+	<xsl:apply-templates/>
+      </p>
+  </xsl:template>
+
+  <xsl:template match="footnote/label">
+    [<xsl:apply-templates/>] 
+  </xsl:template>
+
+  <xsl:template match="footnote/paragraph">
+    <xsl:apply-templates/>
+  </xsl:template>
+
+</xsl:transform>
diff --git a/5.1.0/src/.check_process_vm.c b/5.1.0/src/.check_process_vm.c
new file mode 100644
index 0000000..e7f6de2
--- /dev/null
+++ b/5.1.0/src/.check_process_vm.c
@@ -0,0 +1,8 @@
+#include <sys/uio.h>
+#include <stdlib.h>
+
+int main(void)
+{
+	return process_vm_readv(0, NULL, 0, NULL, 0, 0)
+	       + process_vm_writev(0, NULL, 0, NULL, 0, 0);
+}
diff --git a/5.1.0/src/.check_seccomp_filter.c b/5.1.0/src/.check_seccomp_filter.c
new file mode 100644
index 0000000..cd79ded
--- /dev/null
+++ b/5.1.0/src/.check_seccomp_filter.c
@@ -0,0 +1,31 @@
+#include <sys/prctl.h>     /* prctl(2), PR_* */
+#include <linux/seccomp.h> /* SECCOMP_MODE_FILTER, */
+#include <linux/filter.h>  /* struct sock_*, */
+#include <linux/audit.h>   /* AUDIT_ARCH_*, */
+#include <stddef.h>        /* offsetof(3), */
+
+int main(void)
+{
+	const size_t arch_offset    = offsetof(struct seccomp_data, arch);
+	const size_t syscall_offset = offsetof(struct seccomp_data, nr);
+	struct sock_fprog program;
+
+	#define ARCH_NR AUDIT_ARCH_X86_64
+
+	struct sock_filter filter[] = {
+		BPF_STMT(BPF_LD + BPF_W + BPF_ABS, arch_offset),
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, AUDIT_ARCH_X86_64, 0, 1),
+		BPF_STMT(BPF_LD + BPF_W + BPF_ABS, syscall_offset),
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1),
+		BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE)
+	};
+
+	program.filter = filter;
+	program.len = sizeof(filter) / sizeof(struct sock_filter);
+
+	(void) prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+	(void) prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &program);
+
+	return 1;
+}
+
diff --git a/5.1.0/src/GNUmakefile b/5.1.0/src/GNUmakefile
new file mode 100644
index 0000000..aed8800
--- /dev/null
+++ b/5.1.0/src/GNUmakefile
@@ -0,0 +1,242 @@
+# If you want to build outside of the source tree, use the -f option:
+#     make -f ${SOMEWHERE}/proot/src/GNUmakefile
+
+# the VPATH variable must point to the actual makefile directory
+VPATH := $(dir $(lastword $(MAKEFILE_LIST)))
+SRC    = $(dir $(firstword $(MAKEFILE_LIST)))
+
+GIT      = git
+RM       = rm
+INSTALL  = install
+CC       = $(CROSS_COMPILE)gcc
+LD       = $(CC)
+STRIP    = $(CROSS_COMPILE)strip
+OBJCOPY  = $(CROSS_COMPILE)objcopy
+OBJDUMP  = $(CROSS_COMPILE)objdump
+
+CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I. -I$(VPATH)
+CFLAGS   += -Wall -Wextra -O2
+LDFLAGS  += -ltalloc
+
+CARE_LDFLAGS = -larchive
+
+OBJECTS += \
+	cli/cli.o		\
+	cli/proot.o		\
+	cli/note.o		\
+	execve/enter.o		\
+	execve/exit.o		\
+	execve/shebang.o	\
+	execve/elf.o		\
+	execve/ldso.o		\
+	execve/auxv.o		\
+	execve/aoxp.o		\
+	path/binding.o		\
+	path/glue.o		\
+	path/canon.o		\
+	path/path.o		\
+	path/proc.o		\
+	path/temp.o		\
+	syscall/seccomp.o	\
+	syscall/syscall.o	\
+	syscall/chain.o		\
+	syscall/enter.o		\
+	syscall/exit.o		\
+	syscall/sysnum.o	\
+	syscall/socket.o	\
+	syscall/heap.o		\
+	tracee/tracee.o		\
+	tracee/mem.o		\
+	tracee/reg.o		\
+	tracee/event.o		\
+	ptrace/ptrace.o		\
+	ptrace/user.o		\
+	ptrace/wait.o		\
+	extension/extension.o	\
+	extension/kompat/kompat.o \
+	extension/fake_id0/fake_id0.o \
+	loader/loader-wrapped.o
+
+define define_from_arch.h
+$2$1 := $(shell $(CC) $1 -E -dM -DNO_LIBC_HEADER $(SRC)/arch.h | grep -w $2 | cut -f 3 -d ' ')
+endef
+
+$(eval $(call define_from_arch.h,,HAS_LOADER_32BIT))
+
+ifdef HAS_LOADER_32BIT
+  OBJECTS += loader/loader-m32-wrapped.o
+endif
+
+CARE_OBJECTS = 				\
+	cli/care.o			\
+	cli/care-manual.o		\
+	extension/care/care.o		\
+	extension/care/final.o		\
+	extension/care/extract.o	\
+	extension/care/archive.o
+
+.DEFAULT_GOAL = proot
+all: proot
+
+######################################################################
+# Beautified output
+
+quiet_GEN = @echo "  GEN	$@"; $(GEN)
+quiet_CC  = @echo "  CC	$@"; $(CC)
+quiet_LD  = @echo "  LD	$@"; $(LD)
+quiet_INSTALL = @echo "  INSTALL	$?"; $(INSTALL)
+
+V = 0
+ifeq ($(V), 0)
+    quiet = quiet_
+    Q     = @
+    silently = >/dev/null 2>&1
+else
+    quiet = 
+    Q     = 
+    silently = 
+endif
+
+######################################################################
+# Auto-configuration
+
+CHECK_VERSION = VERSION=$$($(GIT) describe --tags --dirty --abbrev=8 --always 2>/dev/null); \
+		if [ ! -z "$${VERSION}" ]; \
+		then /bin/echo -e "\#undef VERSION\n\#define VERSION \"$${VERSION}\""; \
+		fi;
+
+CHECK_FEATURES = process_vm
+CHECK_PROGRAMS = $(foreach feature,$(CHECK_FEATURES),.check_$(feature))
+CHECK_OBJECTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).o)
+CHECK_RESULTS  = $(foreach feature,$(CHECK_FEATURES),.check_$(feature).res)
+
+.SILENT .IGNORE .INTERMEDIATE: $(CHECK_OBJECTS) $(CHECK_PROGRAMS)
+
+.check_%.o: .check_%.c
+	-$(COMPILE:echo=false) $(silently)
+
+.check_%: .check_%.o
+	-$(LINK:echo=false) $(silently)
+
+.check_%.res: .check_%
+	$(Q)if [ -e $< ]; then echo "#define HAVE_$(shell echo $* | tr a-z A-Z)" > $@; else echo "" > $@; fi
+
+build.h: $(CHECK_RESULTS)
+	$($(quiet)GEN)
+	$(Q)echo "/* This file is auto-generated, edit at your own risk.  */" > $@
+	$(Q)echo "#ifndef BUILD_H"      >> $@
+	$(Q)echo "#define BUILD_H"      >> $@
+	$(Q)sh -c '$(CHECK_VERSION)'    >> $@
+	$(Q)cat $^                      >> $@
+	$(Q)echo "#endif /* BUILD_H */" >> $@
+
+BUILD_ID_NONE := $(shell if ld --build-id=none --version >/dev/null 2>&1; then echo ',--build-id=none'; fi)
+
+######################################################################
+# Build rules
+
+COMPILE = $($(quiet)CC) $(CPPFLAGS) $(CFLAGS) -MD -c $(SRC)$< -o $@
+LINK    = $($(quiet)LD) -o $@ $^ $(LDFLAGS)
+
+OBJIFY = $($(quiet)GEN)									\
+	$(OBJCOPY)									\
+		--input binary								\
+		--output `env LANG=C $(OBJDUMP) -f cli/cli.o |				\
+			grep 'file format' | awk '{print $$4}'`				\
+		--binary-architecture `env LANG=C $(OBJDUMP) -f cli/cli.o |		\
+				grep architecture | cut -f 1 -d , | awk '{print $$2}'`	\
+		$< $@
+
+proot: $(OBJECTS)
+	$(LINK)
+
+care: $(OBJECTS) $(CARE_OBJECTS)
+	$(LINK) $(CARE_LDFLAGS)
+
+# Special case to compute which files depend on the auto-generated
+# file "build.h".
+USE_BUILD_H := $(patsubst $(SRC)%.c,%.o,$(shell egrep -sl 'include[[:space:]]+"build.h"' $(patsubst %.o,$(SRC)%.c,$(OBJECTS) $(CARE_OBJECTS))))
+$(USE_BUILD_H): build.h
+
+%.o: %.c
+	@mkdir -p $(dir $@)
+	$(COMPILE)
+
+.INTERMEDIATE: manual
+manual: $(VPATH)/../doc/care/manual.txt
+	$(Q)cp $< $@
+
+cli/care-manual.o: manual cli/cli.o
+	$(OBJIFY)
+
+cli/%-licenses.o: licenses cli/cli.o
+	$(OBJIFY)
+
+######################################################################
+# Build rules for the loader
+
+define build_loader
+LOADER$1_OBJECTS = loader/loader$1.o loader/assembly$1.o
+
+$(eval $(call define_from_arch.h,$1,LOADER_ARCH_CFLAGS))
+$(eval $(call define_from_arch.h,$1,LOADER_ADDRESS))
+
+LOADER_CFLAGS$1  += -fPIC -ffreestanding $(LOADER_ARCH_CFLAGS$1)
+LOADER_LDFLAGS$1 += -static -nostdlib -Wl$(BUILD_ID_NONE),-Ttext=$(LOADER_ADDRESS$1)
+
+loader/loader$1.o: loader/loader.c
+	@mkdir -p $$(dir $$@)
+	$$(COMPILE) $1 $$(LOADER_CFLAGS$1)
+
+loader/assembly$1.o: loader/assembly.S
+	@mkdir -p $$(dir $$@)
+	$$(COMPILE) $1 $$(LOADER_CFLAGS$1)
+
+loader/loader$1: $$(LOADER$1_OBJECTS)
+	$$($$(quiet)LD) $1 -o $$@ $$^ $$(LOADER_LDFLAGS$1)
+
+.INTERMEDIATE: loader$1.exe
+loader$1.exe: loader/loader$1
+	$$(Q)cp $$< $$@
+	$$(Q)$(STRIP) $$@
+
+loader/loader$1-wrapped.o: loader$1.exe cli/cli.o
+	$$(OBJIFY)
+endef
+
+$(eval $(build_loader))
+
+ifdef HAS_LOADER_32BIT
+$(eval $(call build_loader,-m32))
+endif
+
+######################################################################
+# Dependencies
+
+.DELETE_ON_ERROR:
+$(OBJECTS) $(CARE_OBJECTS) $(LOADER_OBJECTS) $(LOADER-m32_OBJECTS): $(firstword $(MAKEFILE_LIST))
+
+DEPS = $(OBJECTS:.o=.d) $(CARE_OBJECTS:.o=.d) $(LOADER_OBJECTS:.o=.d) $(LOADER-m32_OBJECTS:.o=.d) $(CHECK_OBJECTS:.o=.d)
+-include $(DEPS)
+
+######################################################################
+# PHONY targets
+
+PREFIX = /usr/local
+DESTDIR = $(PREFIX)/bin
+
+.PHONY: clean distclean install install-care uninstall
+clean distclean:
+	-$(RM) -f $(CHECK_OBJECTS) $(CHECK_PROGRAMS) $(CHECK_RESULTS) $(OBJECTS) $(CARE_OBJECTS) $(LOADER_OBJECTS) $(LOADER-m32_OBJECTS) proot care loader/loader loader/loader-m32 cli/care-manual.o $(DEPS) build.h licenses
+
+install: proot
+	$($(quiet)INSTALL) -D $< $(DESTDIR)/usr/bin/$<
+
+install-care: care
+	$($(quiet)INSTALL) -D $< $(DESTDIR)/$<
+
+uninstall:
+	-$(RM) -f $(DESTDIR)/usr/bin/proot
+
+uninstall-care:
+	-$(RM) -f $(DESTDIR)/care
diff --git a/5.1.0/src/arch.h b/5.1.0/src/arch.h
new file mode 100644
index 0000000..d5a024b
--- /dev/null
+++ b/5.1.0/src/arch.h
@@ -0,0 +1,175 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#ifndef NO_LIBC_HEADER
+#include <sys/ptrace.h>    /* linux.git:c0a3a20b  */
+#include <linux/audit.h>   /* AUDIT_ARCH_*,  */
+#endif
+
+typedef unsigned long word_t;
+typedef unsigned char byte_t;
+
+#define SYSCALL_AVOIDER ((word_t) -2)
+#define SYSTRAP_NUM SYSARG_NUM
+
+#if !defined(ARCH_X86_64) && !defined(ARCH_ARM_EABI) && !defined(ARCH_X86) && !defined(ARCH_SH4)
+#    if defined(__x86_64__)
+#        define ARCH_X86_64 1
+#    elif defined(__ARM_EABI__)
+#        define ARCH_ARM_EABI 1
+#    elif defined(__aarch64__)
+#        define ARCH_ARM64 1
+#    elif defined(__arm__)
+#        error "Only EABI is currently supported for ARM"
+#    elif defined(__i386__)
+#        define ARCH_X86 1
+#    elif defined(__SH4__)
+#        define ARCH_SH4 1
+#    else
+#        error "Unsupported architecture"
+#    endif
+#endif
+
+/* Architecture specific definitions. */
+#if defined(ARCH_X86_64)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-x86_64.h"
+    #define SYSNUMS_HEADER2 "syscall/sysnums-i386.h"
+    #define SYSNUMS_HEADER3 "syscall/sysnums-x32.h"
+
+    #define SYSNUMS_ABI1 sysnums_x86_64
+    #define SYSNUMS_ABI2 sysnums_i386
+    #define SYSNUMS_ABI3 sysnums_x32
+
+    #undef  SYSTRAP_NUM
+    #define SYSTRAP_NUM SYSARG_RESULT
+    #define SYSTRAP_SIZE 2
+
+    #define SECCOMP_ARCHS {									\
+		{ .value = AUDIT_ARCH_X86_64, .nb_abis = 2, .abis = { ABI_DEFAULT, ABI_3 } },	\
+		{ .value = AUDIT_ARCH_I386,   .nb_abis = 1, .abis = { ABI_2 } }, 		\
+	}
+
+    #define HOST_ELF_MACHINE {62, 3, 6, 0}
+    #define RED_ZONE_SIZE 128
+    #define OFFSETOF_STAT_UID_32 24
+    #define OFFSETOF_STAT_GID_32 28
+
+    #define LOADER_ADDRESS 0x600000000000
+    #define HAS_LOADER_32BIT true
+
+    #define EXEC_PIC_ADDRESS   0x500000000000
+    #define INTERP_PIC_ADDRESS 0x6f0000000000
+    #define EXEC_PIC_ADDRESS_32   0x0f000000
+    #define INTERP_PIC_ADDRESS_32 0xaf000000
+
+#elif defined(ARCH_ARM_EABI)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-arm.h"
+    #define SYSNUMS_ABI1    sysnums_arm
+
+    #define SYSTRAP_SIZE 4
+
+    #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_ARM, .nb_abis = 1, .abis = { ABI_DEFAULT } } }
+
+    #define user_regs_struct user_regs
+    #define HOST_ELF_MACHINE {40, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+    #define EM_ARM 40
+
+    #define LOADER_ADDRESS 0x10000000
+
+    #define EXEC_PIC_ADDRESS   0x0f000000
+    #define INTERP_PIC_ADDRESS 0x1f000000
+
+    /* The syscall number has to be valid on ARM, so use tuxcall(2) as
+     * the "void" syscall since it has no side effects.  */
+    #undef SYSCALL_AVOIDER
+    #define SYSCALL_AVOIDER ((word_t) 222)
+
+#elif defined(ARCH_ARM64)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-arm64.h"
+    #define SYSNUMS_ABI1    sysnums_arm64
+
+    #define SYSTRAP_SIZE 4
+
+    #define SECCOMP_ARCHS { }
+
+    #define HOST_ELF_MACHINE {183, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+
+    #define EXEC_PIC_ADDRESS   0x500000000000
+    #define INTERP_PIC_ADDRESS 0x6f0000000000
+
+#elif defined(ARCH_X86)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-i386.h"
+    #define SYSNUMS_ABI1    sysnums_i386
+
+    #undef  SYSTRAP_NUM
+    #define SYSTRAP_NUM SYSARG_RESULT
+    #define SYSTRAP_SIZE 2
+
+    #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_I386, .nb_abis = 1, .abis = { ABI_DEFAULT } } }
+
+    #define HOST_ELF_MACHINE {3, 6, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+
+    #define LOADER_ADDRESS 0xa0000000
+    #define LOADER_ARCH_CFLAGS -mregparm=3
+
+    #define EXEC_PIC_ADDRESS   0x0f000000
+    #define INTERP_PIC_ADDRESS 0xaf000000
+
+#elif defined(ARCH_SH4)
+
+    #define SYSNUMS_HEADER1 "syscall/sysnums-sh4.h"
+    #define SYSNUMS_ABI1    sysnums_sh4
+
+    #define SYSTRAP_SIZE 2
+
+    #define SECCOMP_ARCHS { }
+
+    #define user_regs_struct pt_regs
+    #define HOST_ELF_MACHINE {42, 0};
+    #define RED_ZONE_SIZE 0
+    #define OFFSETOF_STAT_UID_32 0
+    #define OFFSETOF_STAT_GID_32 0
+    #define NO_MISALIGNED_ACCESS 1
+
+#else
+
+    #error "Unsupported architecture"
+
+#endif
+
+#endif /* ARCH_H */
diff --git a/5.1.0/src/attribute.h b/5.1.0/src/attribute.h
new file mode 100644
index 0000000..934888b
--- /dev/null
+++ b/5.1.0/src/attribute.h
@@ -0,0 +1,32 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef ATTRIBUTE_H
+#define ATTRIBUTE_H
+
+#define UNUSED __attribute__((unused))
+#define FORMAT(a, b, c) __attribute__ ((format (a, b, c)))
+#define DONT_INSTRUMENT __attribute__((no_instrument_function))
+#define PACKED __attribute__((packed))
+#define WEAK   __attribute__((weak))
+
+#endif /* ATTRIBUTE_H */
diff --git a/5.1.0/src/cli/care.c b/5.1.0/src/cli/care.c
new file mode 100644
index 0000000..8ece4bc
--- /dev/null
+++ b/5.1.0/src/cli/care.c
@@ -0,0 +1,374 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of CARE.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <string.h>    /* str*(3), */
+#include <assert.h>    /* assert(3), */
+#include <strings.h>   /* bzero(3), */
+#include <sys/queue.h> /* STAILQ_*, */
+#include <stdint.h>    /* INT_MIN, */
+#include <unistd.h>    /* getpid(2), close(2), */
+#include <stdio.h>     /* printf(3), fflush(3), */
+#include <unistd.h>    /* getcwd(2), */
+#include <errno.h>     /* errno(3), */
+
+#include "cli/cli.h"
+#include "cli/note.h"
+#include "path/binding.h"
+#include "path/temp.h"
+#include "extension/extension.h"
+#include "extension/care/care.h"
+#include "extension/care/extract.h"
+#include "attribute.h"
+
+/* These should be included last.  */
+#include "build.h"
+#include "cli/care.h"
+
+static int handle_option_o(Tracee *tracee UNUSED, const Cli *cli, const char *value)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	options->output = value;
+	return 0;
+}
+
+static int handle_option_c(Tracee *tracee UNUSED, const Cli *cli, const char *value)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	Item *item = queue_item(options, &options->concealed_paths, value);
+	return (item != NULL ? 0 : -1);
+}
+
+static int handle_option_r(Tracee *tracee UNUSED, const Cli *cli, const char *value)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	Item *item = queue_item(options, &options->revealed_paths, value);
+	return (item != NULL ? 0 : -1);
+}
+
+static int handle_option_p(Tracee *tracee UNUSED, const Cli *cli, const char *value)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	Item *item = queue_item(options, &options->volatile_paths, value);
+	return (item != NULL ? 0 : -1);
+}
+
+static int handle_option_e(Tracee *tracee UNUSED, const Cli *cli, const char *value)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	Item *item = queue_item(options, &options->volatile_envars, value);
+	return (item != NULL ? 0 : -1);
+}
+
+static int handle_option_m(Tracee *tracee, const Cli *cli, const char *value)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	return parse_integer_option(tracee, &options->max_size, value, "-m");
+}
+
+static int handle_option_d(Tracee *tracee UNUSED, const Cli *cli, const char *value UNUSED)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	options->ignore_default_config = true;
+	return 0;
+}
+
+static int handle_option_v(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	int status;
+
+	status = parse_integer_option(tracee, &tracee->verbose, value, "-v");
+	if (status < 0)
+		return status;
+
+	global_verbose_level = tracee->verbose;
+	return 0;
+}
+
+extern unsigned char WEAK _binary_licenses_start;
+extern unsigned char WEAK _binary_licenses_end;
+
+static int handle_option_V(Tracee *tracee UNUSED, const Cli *cli, const char *value UNUSED)
+{
+	size_t size;
+
+	print_version(cli);
+
+	printf("suitable for self-extracting archives (.bin): %s\n",
+#if defined(CARE_BINARY_IS_PORTABLE)
+		"yes"
+#else
+		"no"
+#endif
+	);
+
+	printf("\n%s\n", cli->colophon);
+	fflush(stdout);
+
+	size = &_binary_licenses_end - &_binary_licenses_start;
+	if (size > 0)
+		write(1, &_binary_licenses_start, size);
+
+	exit_failure = false;
+	return -1;
+}
+
+static int handle_option_x(Tracee *tracee UNUSED, const Cli *cli UNUSED, const char *value)
+{
+	int status = extract_archive_from_file(value);
+	exit_failure = (status < 0);
+	return -1;
+}
+
+extern unsigned char WEAK _binary_manual_start;
+extern unsigned char WEAK _binary_manual_end;
+
+static int handle_option_h(Tracee *tracee UNUSED, const Cli *cli UNUSED, const char *value UNUSED)
+{
+	size_t size;
+
+	size = &_binary_manual_end - &_binary_manual_start;
+	if (size != 0)
+		write(1, &_binary_manual_start, size);
+	else
+		printf("No manual found, please visit http://reproducible.io instead.\n");
+
+	exit_failure = false;
+	return -1;
+}
+
+/**
+ * Allocate a new binding for the given @tracee that will conceal the
+ * content of @path with an empty file or directory.  This function
+ * complains about missing @host path only if @must_exist is true.
+ */
+static Binding *new_concealing_binding(Tracee *tracee, const char *path, bool must_exist)
+{
+	struct stat statl;
+	Binding *binding;
+	const char *temp;
+	int status;
+
+	status = stat(path, &statl);
+	if (status < 0) {
+		if (must_exist)
+			note(tracee, WARNING, SYSTEM, "can't conceal %s", path);
+		return NULL;
+	}
+
+	if (S_ISDIR(statl.st_mode))
+		temp = create_temp_directory(NULL, tracee->tool_name);
+	else
+		temp = create_temp_file(NULL, tracee->tool_name);
+	if (temp == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't conceal %s", path);
+		return NULL;
+	}
+
+	binding = new_binding(tracee, temp, path, must_exist);
+	if (binding == NULL)
+		return NULL;
+
+	return binding;
+}
+
+/**
+ * Initialize @tracee's fields that are mandatory for PRoot/CARE but
+ * that are not specifiable on the command line.
+ */
+static int pre_initialize_bindings(Tracee *tracee, const Cli *cli,
+				size_t argc, char *const argv[], size_t cursor)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	char path[PATH_MAX];
+	Binding *binding;
+	const char *home;
+	const char *pwd;
+	Item *item;
+	size_t i;
+
+	if (cursor >= argc) {
+		note(tracee, ERROR, USER, "no command specified");
+		return -1;
+	}
+	options->command = &argv[cursor];
+
+	home = getenv("HOME");
+	pwd  = getenv("PWD");
+
+	/* Set these variables to their default values (ie. when not
+	 * set), this simplifies the binding setup to the related
+	 * files.  */
+	setenv("XAUTHORITY",   talloc_asprintf(tracee->ctx, "%s/.Xauthority", home), 0);
+	setenv("ICEAUTHORITY", talloc_asprintf(tracee->ctx, "%s/.ICEauthority", home), 0);
+
+	/* Enable default option first.  */
+	if (!options->ignore_default_config) {
+		const char *expanded;
+		Binding *binding;
+		int status;
+
+		/* Bind an empty file/directory over default concealed
+		 * paths.  */
+		for (i = 0; default_concealed_paths[i] != NULL; i++) {
+			expanded = expand_front_variable(tracee->ctx, default_concealed_paths[i]);
+			binding = new_concealing_binding(tracee, expanded, false);
+			if (binding != NULL)
+				VERBOSE(tracee, 0, "concealed path: %s %s",
+					default_concealed_paths[i],
+					default_concealed_paths[i] != expanded ? expanded : "");
+		}
+
+		/* Bind default revealed paths over concealed
+		 * paths.  */
+		for (i = 0; default_revealed_paths[i] != NULL; i++) {
+			expanded = expand_front_variable(tracee->ctx, default_revealed_paths[i]);
+			binding = new_binding(tracee, expanded, NULL, false);
+			if (binding != NULL)
+				VERBOSE(tracee, 0, "revealed path: %s %s",
+					default_revealed_paths[i],
+					default_revealed_paths[i] != expanded ? expanded : "");
+		}
+
+		/* Ensure the initial command is accessible.  */
+		status = which(NULL, NULL, path, options->command[0]);
+		if (status < 0)
+			return -1; /* This failure was already noticed by which().  */
+
+		binding = new_binding(tracee, path, NULL, false);
+		if (binding != NULL)
+			VERBOSE(tracee, 0, "revealed path: %s", path);
+
+		/* Sanity check.  Note: it is assumed $HOME and $PWD
+		 * are canonicalized.  */
+		if (home != NULL && pwd != NULL && strcmp(home, pwd) == 0)
+			note(tracee, WARNING, USER,
+				"$HOME is implicitely revealed since it is the same as $PWD, "
+				"change your current working directory to be sure "
+				"your personal data will be not archivable.");
+
+		/* Add the default volatile paths to the list of user
+		 * volatile paths.  */
+		for (i = 0; default_volatile_paths[i] != NULL; i++) {
+			Item *item;
+
+			expanded = expand_front_variable(tracee->ctx, default_volatile_paths[i]);
+			item = queue_item(tracee, &options->volatile_paths, expanded);
+
+			/* Remember the non expanded form, later used
+			 * by archive_re_execute_sh(). */
+			if (item != NULL && expanded != default_volatile_paths[i])
+				talloc_set_name_const(item, default_volatile_paths[i]);
+		}
+
+		for (i = 0; default_volatile_envars[i] != NULL; i++)
+			queue_item(tracee, &options->volatile_envars, default_volatile_envars[i]);
+
+		if (options->max_size == INT_MIN)
+			options->max_size = CARE_MAX_SIZE;
+	}
+	else
+		if (options->max_size == INT_MIN)
+			options->max_size = -1; /* Unlimited.  */
+
+	VERBOSE(tracee, 1, "max size: %d", options->max_size);
+
+	/* Bind an empty file/directory over user concealed paths.  */
+	if (options->concealed_paths != NULL) {
+		STAILQ_FOREACH(item, options->concealed_paths, link) {
+			binding = new_concealing_binding(tracee, item->load, true);
+			if (binding != NULL)
+				VERBOSE(tracee, 0, "concealed path: %s", (char *) item->load);
+		}
+	}
+
+	/* Bind user revealed paths over concealed paths.  */
+	if (options->revealed_paths != NULL) {
+		STAILQ_FOREACH(item, options->revealed_paths, link) {
+			binding = new_binding(tracee, item->load, NULL, true);
+			if (binding != NULL)
+				VERBOSE(tracee, 0, "revealed path: %s",	(char *) item->load);
+		}
+	}
+
+	/* Bind volatile paths over concealed paths.  */
+	if (options->volatile_paths != NULL) {
+		STAILQ_FOREACH(item, options->volatile_paths, link) {
+			binding = new_binding(tracee, item->load, NULL, false);
+			if (binding != NULL)
+				VERBOSE(tracee, 1, "volatile path: %s",	(char *) item->load);
+		}
+	}
+
+	VERBOSE(tracee, 0, "----------------------------------------------------------------------");
+
+	/* Initialize @tracee->fs->cwd with a path already canonicalized
+	 * as required by care.c:handle_initialization().  */
+	if (getcwd(path, PATH_MAX) == NULL) {
+		note(tracee, ERROR, SYSTEM, "can't get current working directory");
+		return -1;
+	}
+
+	tracee->fs->cwd = talloc_strdup(tracee->fs, path);
+	if (tracee->fs->cwd == NULL)
+		return -1;
+	talloc_set_name_const(tracee->fs->cwd, "$cwd");
+
+	/* Initialize @tracee's root (required by PRoot).  */
+	binding = new_binding(tracee, "/", "/", true);
+	if (binding == NULL)
+		return -1;
+
+	return cursor;
+}
+
+/**
+ * Initialize CARE extensions.
+ */
+static int post_initialize_bindings(Tracee *tracee, const Cli *cli,
+			       size_t argc UNUSED, char *const argv[] UNUSED, size_t cursor)
+{
+	Options *options = talloc_get_type_abort(cli->private, Options);
+	int status;
+
+	status = initialize_extension(tracee, care_callback, (void *) options);
+	if (status < 0) {
+		note(tracee, WARNING, INTERNAL, "can't initialize the care extension");
+		return -1;
+	}
+
+	return cursor;
+}
+
+const Cli *get_care_cli(TALLOC_CTX *context)
+{
+	Options *options;
+
+	global_tool_name = care_cli.name;
+
+	options = talloc_zero(context, Options);
+	if (options == NULL)
+		return NULL;
+	options->max_size = INT_MIN;
+
+	care_cli.private = options;
+	return &care_cli;
+}
diff --git a/5.1.0/src/cli/care.h b/5.1.0/src/cli/care.h
new file mode 100644
index 0000000..6d5b017
--- /dev/null
+++ b/5.1.0/src/cli/care.h
@@ -0,0 +1,192 @@
+/* This file is automatically generated from the documentation. EDIT AT YOUR OWN RISK. */
+
+#ifndef CARE_CLI_H
+#define CARE_CLI_H
+
+#include "cli/cli.h"
+
+#ifndef VERSION
+#define VERSION "2.2"
+#endif
+
+#define CARE_MAX_SIZE 1024
+
+static char const *default_concealed_paths[] = {
+	"$HOME",
+	"/tmp",
+	NULL,
+};
+
+static char const *default_revealed_paths[] = {
+	"$PWD",
+	NULL,
+};
+
+static char const *default_volatile_paths[] = {
+	"/dev",
+	"/proc",
+	"/sys",
+	"/run/shm",
+	"/tmp/.X11-unix",
+	"/tmp/.ICE-unix",
+	"$XAUTHORITY",
+	"$ICEAUTHORITY",
+	"/var/run/dbus/system_bus_socket",
+	"/var/tmp/kdecache-$LOGNAME",
+	NULL,
+};
+
+static char const *default_volatile_envars[] = {
+	"DISPLAY",
+	"http_proxy",
+	"https_proxy",
+	"ftp_proxy",
+	"all_proxy",
+	"HTTP_PROXY",
+	"HTTPS_PROXY",
+	"FTP_PROXY",
+	"ALL_PROXY",
+	"DBUS_SESSION_BUS_ADDRESS",
+	"SESSION_MANAGER",
+	"XDG_SESSION_COOKIE",
+	NULL,
+};
+
+static int handle_option_o(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_c(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_r(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_p(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_e(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_m(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_d(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_v(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_V(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_x(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_h(Tracee *tracee, const Cli *cli, const char *value);
+
+static int pre_initialize_bindings(Tracee *, const Cli *, size_t, char *const *, size_t);
+static int post_initialize_bindings(Tracee *, const Cli *, size_t, char *const *, size_t);
+
+static Cli care_cli = {
+	.version  = VERSION,
+	.name     = "care",
+	.subtitle = "Comprehensive Archiver for Reproducible Execution",
+	.synopsis = "care [option] ... command",
+	.colophon = "Visit http://reproducible.io for help, bug reports, suggestions, patches, ...\n\
+Copyright (C) 2014 STMicroelectronics, licensed under GPL v2 or later.",
+	.logo = "\
+  _____ ____ _____ ____\n\
+ /   __/ __ |  __ \\  __|\n\
+/   /_/     |     /  __|\n\
+\\_____|__|__|__|__\\____|",
+
+	.pre_initialize_bindings  = pre_initialize_bindings,
+	.post_initialize_bindings = post_initialize_bindings,
+
+	.options = {
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-o", .separator = ' ', .value = "path" },
+		{ .name = "--output", .separator = '=', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_o,
+	  .description = "Archive in *path*, its suffix specifies the format.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-c", .separator = ' ', .value = "path" },
+		{ .name = "--concealed-path", .separator = '=', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_c,
+	  .description = "Make *path* content appear empty during the original execution.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-r", .separator = ' ', .value = "path" },
+		{ .name = "--revealed-path", .separator = '=', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_r,
+	  .description = "Make *path* content accessible when nested in a concealed path.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-p", .separator = ' ', .value = "path" },
+		{ .name = "--volatile-path", .separator = '=', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_p,
+	  .description = "Don't archive *path* content, reuse actual *path* instead.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-e", .separator = ' ', .value = "name" },
+		{ .name = "--volatile-env", .separator = '=', .value = "name" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_e,
+	  .description = "Don't archive *name* env. variable, reuse actual value instead.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-m", .separator = ' ', .value = "value" },
+		{ .name = "--max-archivable-size", .separator = '=', .value = "value" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_m,
+	  .description = "Set the maximum size of archivable files to *value* megabytes.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-d", .separator = '\0', .value = NULL },
+		{ .name = "--ignore-default-config", .separator = '\0', .value = NULL },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_d,
+	  .description = "Don't use the default options.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-v", .separator = ' ', .value = "value" },
+		{ .name = "--verbose", .separator = '=', .value = "value" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_v,
+	  .description = "Set the level of debug information to *value*.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-V", .separator = '\0', .value = NULL },
+		{ .name = "--version", .separator = '\0', .value = NULL },
+		{ .name = "--about", .separator = '\0', .value = NULL },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_V,
+	  .description = "Print version, copyright, license and contact, then exit.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-x", .separator = ' ', .value = "file" },
+		{ .name = "--extract", .separator = '=', .value = "file" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_x,
+	  .description = "Extract content of the archive *file*, then exit.",
+	  .detail = NULL,
+	},
+	{ .class = "Options",
+	  .arguments = {
+		{ .name = "-h", .separator = '\0', .value = NULL },
+		{ .name = "--help", .separator = '\0', .value = NULL },
+		{ .name = "--usage", .separator = '\0', .value = NULL },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_h,
+	  .description = "Print the user manual, then exit.",
+	  .detail = NULL,
+	},
+	END_OF_OPTIONS,
+	},
+};
+
+#endif /* CARE_CLI_H */
diff --git a/5.1.0/src/cli/cli.c b/5.1.0/src/cli/cli.c
new file mode 100644
index 0000000..832a42c
--- /dev/null
+++ b/5.1.0/src/cli/cli.c
@@ -0,0 +1,580 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdio.h>         /* printf(3), */
+#include <stdbool.h>       /* bool, true, false,  */
+#include <linux/limits.h>  /* ARG_MAX, PATH_MAX, */
+#include <string.h>        /* str*(3), basename(3),  */
+#include <talloc.h>        /* talloc*,  */
+#include <stdlib.h>        /* exit(3), EXIT_*, strtol(3), {g,s}etenv(3), */
+#include <assert.h>        /* assert(3),  */
+#include <sys/types.h>     /* getpid(2),  */
+#include <unistd.h>        /* getpid(2),  */
+#include <errno.h>         /* errno(3), */
+#include <execinfo.h>      /* backtrace_symbols(3), */
+#include <limits.h>        /* INT_MAX, */
+
+#include "cli/cli.h"
+#include "cli/note.h"
+#include "extension/care/extract.h"
+#include "extension/extension.h"
+#include "tracee/tracee.h"
+#include "tracee/event.h"
+#include "path/binding.h"
+#include "path/canon.h"
+#include "path/path.h"
+
+#include "build.h"
+
+/**
+ * Print a (@detailed) usage of PRoot.
+ */
+void print_usage(Tracee *tracee, const Cli *cli, bool detailed)
+{
+	const char *current_class = "none";
+	const Option *options;
+	size_t i, j;
+
+#define DETAIL(a) if (detailed) a
+
+	DETAIL(printf("%s %s: %s.\n\n", cli->name, cli->version, cli->subtitle));
+	printf("Usage:\n  %s\n", cli->synopsis);
+	DETAIL(printf("\n"));
+
+	options = cli->options;
+	for (i = 0; options[i].class != NULL; i++) {
+		for (j = 0; ; j++) {
+			const Argument *argument = &(options[i].arguments[j]);
+
+			if (!argument->name || (!detailed && j != 0)) {
+				DETAIL(printf("\n"));
+				printf("\t%s\n", options[i].description);
+				if (detailed) {
+					if (options[i].detail[0] != '\0')
+						printf("\n%s\n\n", options[i].detail);
+					else
+						printf("\n");
+				}
+				break;
+			}
+
+			if (strcmp(options[i].class, current_class) != 0) {
+				current_class = options[i].class;
+				printf("\n%s:\n", current_class);
+			}
+
+			if (j == 0)
+				printf("  %s", argument->name);
+			else
+				printf(", %s", argument->name);
+
+			if (argument->separator != '\0')
+				printf("%c*%s*", argument->separator, argument->value);
+			else if (!detailed)
+				printf("\t");
+		}
+	}
+
+	notify_extensions(tracee, PRINT_USAGE, detailed, 0);
+
+	if (detailed)
+		printf("%s\n", cli->colophon);
+}
+
+/**
+ * Print the version of PRoot.
+ */
+void print_version(const Cli *cli)
+{
+	printf("%s %s\n\n", cli->logo, cli->version);
+	printf("built-in accelerators: process_vm = %s, seccomp_filter = %s\n",
+#if defined(HAVE_PROCESS_VM)
+		"yes",
+#else
+		"no",
+#endif
+#if defined(HAVE_SECCOMP_FILTER)
+		"yes"
+#else
+		"no"
+#endif
+		);
+}
+
+static void print_execve_help(const Tracee *tracee, const char *argv0, int status)
+{
+	note(tracee, ERROR, SYSTEM, "execve(\"%s\")", argv0);
+
+	/* Ubuntu kernel bug?  */
+	if (status == -EPERM && getenv("PROOT_NO_SECCOMP") == NULL) {
+		note(tracee, INFO, USER,
+"It seems your kernel contains this bug: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1202161\n"
+"To workaround it, set the env. variable PROOT_NO_SECCOMP to 1.");
+		return;
+	}
+
+	note(tracee, INFO, USER, "possible causes:\n"
+"  * the program is a script but its interpreter (eg. /bin/sh) was not found;\n"
+"  * the program is an ELF but its interpreter (eg. ld-linux.so) was not found;\n"
+"  * the program is a foreign binary but qemu was not specified;\n"
+"  * qemu does not work correctly (if specified);\n"
+"  * the loader was not found or doesn't work.");
+}
+
+static void print_error_separator(const Tracee *tracee, const Argument *argument)
+{
+	if (argument->separator == '\0')
+		note(tracee, ERROR, USER, "option '%s' expects no value.", argument->name);
+	else
+		note(tracee, ERROR, USER, "option '%s' and its value must be separated by '%c'.",
+			argument->name, argument->separator);
+}
+
+static void print_argv(const Tracee *tracee, const char *prompt, char *const argv[])
+{
+	char string[ARG_MAX] = "";
+	size_t i;
+
+	if (!argv)
+		return;
+
+#define APPEND(post)							\
+	do {								\
+		ssize_t length = sizeof(string) - (strlen(string) + strlen(post)); \
+		if (length <= 0)					\
+			return;						\
+		strncat(string, post, length);				\
+	} while (0)
+
+	APPEND(prompt);
+	APPEND(" =");
+	for (i = 0; argv[i] != NULL; i++) {
+		APPEND(" ");
+		APPEND(argv[i]);
+	}
+	string[sizeof(string) - 1] = '\0';
+
+#undef APPEND
+
+	note(tracee, INFO, USER, "%s", string);
+}
+
+static void print_config(Tracee *tracee, char *const argv[])
+{
+	assert(tracee != NULL);
+
+	if (tracee->verbose <= 0)
+		return;
+
+	if (tracee->qemu)
+		note(tracee, INFO, USER, "host rootfs = %s", HOST_ROOTFS);
+
+	if (tracee->glue)
+		note(tracee, INFO, USER, "glue rootfs = %s", tracee->glue);
+
+	note(tracee, INFO, USER, "exe = %s", tracee->exe);
+	print_argv(tracee, "argv", argv);
+	print_argv(tracee, "qemu", tracee->qemu);
+	note(tracee, INFO, USER, "initial cwd = %s", tracee->fs->cwd);
+	note(tracee, INFO, USER, "verbose level = %d", tracee->verbose);
+
+	notify_extensions(tracee, PRINT_CONFIG, 0, 0);
+}
+
+/**
+ * Initialize @tracee's current working directory.  This function
+ * returns -1 if an error occurred, otherwise 0.
+ */
+static int initialize_cwd(Tracee *tracee)
+{
+	char path2[PATH_MAX];
+	char path[PATH_MAX];
+	int status;
+
+	/* Compute the base directory.  */
+	if (tracee->fs->cwd[0] != '/') {
+		status = getcwd2(tracee->reconf.tracee, path);
+		if (status < 0) {
+			note(tracee, ERROR, INTERNAL, "getcwd: %s", strerror(-status));
+			return -1;
+		}
+	}
+	else
+		strcpy(path, "/");
+
+	/* The ending "." ensures canonicalize() will report an error
+	 * if tracee->fs->cwd does not exist or if it is not a
+	 * directory.  */
+	status = join_paths(3, path2, path, tracee->fs->cwd, ".");
+	if (status < 0) {
+		note(tracee, ERROR, INTERNAL, "getcwd: %s", strerror(-status));
+		return -1;
+	}
+
+	/* Initiale state for canonicalization.  */
+	strcpy(path, "/");
+
+	status = canonicalize(tracee, path2, true, path, 0);
+	if (status < 0) {
+		note(tracee, WARNING, USER, "can't chdir(\"%s\") in the guest rootfs: %s",
+			path2, strerror(-status));
+		note(tracee, INFO, USER, "default working directory is now \"/\"");
+		strcpy(path, "/");
+	}
+	chop_finality(path);
+
+	/* Replace with the canonicalized working directory.  */
+	TALLOC_FREE(tracee->fs->cwd);
+	tracee->fs->cwd = talloc_strdup(tracee->fs, path);
+	if (tracee->fs->cwd == NULL)
+		return -1;
+	talloc_set_name_const(tracee->fs->cwd, "$cwd");
+
+	/* Keep this special environment variable consistent.  */
+	setenv("PWD", path, 1);
+
+	return 0;
+}
+
+/**
+ * Initialize @tracee->exe from @exe, i.e. canonicalize it from a
+ * guest point-of-view.
+ */
+static int initialize_exe(Tracee *tracee, const char *exe)
+{
+	char path[PATH_MAX];
+	int status;
+
+	status = which(tracee, tracee->reconf.paths, path, exe ?: "/bin/sh");
+	if (status < 0)
+		return -1;
+
+	status = detranslate_path(tracee, path, NULL);
+	if (status < 0)
+		return -1;
+
+	tracee->exe = talloc_strdup(tracee, path);
+	if (tracee->exe == NULL)
+		return -1;
+	talloc_set_name_const(tracee->exe, "$exe");
+
+	return 0;
+}
+
+/**
+ * Configure @tracee according to the command-line arguments stored in
+ * @argv[].  This function returns the index in @argv[] of the command
+ * to launch, otherwise -1 if an error occured.
+ */
+static int parse_config(Tracee *tracee, size_t argc, char *const argv[])
+{
+	option_handler_t handler = NULL;
+	const Option *options;
+	const Cli *cli = NULL;
+	size_t argc_offset;
+	size_t i, j, k;
+	int status;
+
+	if (get_care_cli != NULL) {
+		/* Check if it's an self-extracting CARE archive.  */
+		status = extract_archive_from_file("/proc/self/exe");
+		if (status == 0) {
+			/* Yes it is, nothing more to do.  */
+			exit_failure = 0;
+			return -1;
+		}
+
+		/* Check if it's a valid CARE tool name.  */
+		if (strncasecmp(basename(argv[0]), "care", strlen("care")) == 0)
+			cli = get_care_cli(tracee->ctx);
+	}
+
+	/* Unknown tool name?  Default to PRoot.  */
+	if (cli == NULL)
+		cli = get_proot_cli(tracee->ctx);
+	tracee->tool_name = cli->name;
+
+	if (argc == 1) {
+		print_usage(tracee, cli, false);
+		return -1;
+	}
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		/* The current argument is the value of a short option.  */
+		if (handler != NULL) {
+			status = handler(tracee, cli, arg);
+			if (status < 0)
+				return -1;
+			handler = NULL;
+			continue;
+		}
+
+		if (arg[0] != '-')
+			break; /* End of PRoot options. */
+
+		options = cli->options;
+		for (j = 0; options[j].class != NULL; j++) {
+			const Option *option = &options[j];
+
+			/* A given option has several aliases.  */
+			for (k = 0; ; k++) {
+				const Argument *argument;
+				size_t length;
+
+				argument = &option->arguments[k];
+
+				/* End of aliases for this option.  */
+				if (!argument->name)
+					break;
+
+				length = strlen(argument->name);
+				if (strncmp(arg, argument->name, length) != 0)
+					continue;
+
+				/* Avoid ambiguities.  */
+				if (strlen(arg) > length
+				    && arg[length] != argument->separator) {
+					print_error_separator(tracee, argument);
+					return -1;
+				}
+
+				/* No option value.  */
+				if (!argument->value) {
+					status = option->handler(tracee, cli, NULL);
+					if (status < 0)
+						return -1;
+					goto known_option;
+				}
+
+				/* Value coalesced with to its option.  */
+				if (argument->separator == arg[length]) {
+					assert(strlen(arg) >= length);
+					status = option->handler(tracee, cli, &arg[length + 1]);
+					if (status < 0)
+						return -1;
+					goto known_option;
+				}
+
+				/* Avoid ambiguities.  */
+				if (argument->separator != ' ') {
+					print_error_separator(tracee, argument);
+					return -1;
+				}
+
+				/* Short option with a separated value.  */
+				handler = option->handler;
+				goto known_option;
+			}
+		}
+
+		note(tracee, ERROR, USER, "unknown option '%s'.", arg);
+		return -1;
+
+	known_option:
+		if (handler != NULL && i == argc - 1) {
+			note(tracee, ERROR, USER, "missing value for option '%s'.", arg);
+			return -1;
+		}
+	}
+	argc_offset = i;
+
+#define HOOK_CONFIG(callback)						\
+	do {								\
+		if (cli->callback != NULL) {				\
+			status = cli->callback(tracee, cli, argc, argv, i); \
+			if (status < 0)					\
+				return -1;				\
+			i = status;					\
+		}							\
+	} while (0)
+
+	HOOK_CONFIG(pre_initialize_bindings);
+
+	/* The guest rootfs is now known: bindings specified by the
+	 * user (tracee->bindings.user) can be canonicalized.  */
+	status = initialize_bindings(tracee);
+	if (status < 0)
+		return -1;
+
+	HOOK_CONFIG(post_initialize_bindings);
+	HOOK_CONFIG(pre_initialize_cwd);
+
+	/* Bindings are now installed (tracee->bindings.guest &
+	 * tracee->bindings.host): the current working directory can
+	 * be canonicalized.  */
+	status = initialize_cwd(tracee);
+	if (status < 0)
+		return -1;
+
+	HOOK_CONFIG(post_initialize_cwd);
+	HOOK_CONFIG(pre_initialize_exe);
+
+	/* Bindings are now installed and the current working
+	 * directory is canonicalized: resolve path to @tracee->exe
+	 * and configure @tracee->cmdline.  */
+	status = initialize_exe(tracee, argv[argc_offset]);
+	if (status < 0)
+		return -1;
+
+	HOOK_CONFIG(post_initialize_exe);
+#undef HOOK_CONFIG
+
+	print_config(tracee, &argv[argc_offset]);
+
+	return argc_offset;
+}
+
+bool exit_failure = true;
+
+int main(int argc, char *const argv[])
+{
+	Tracee *tracee;
+	int status;
+
+	/* Configure the memory allocator.  */
+	talloc_enable_leak_report();
+
+#if defined(TALLOC_VERSION_MAJOR) && TALLOC_VERSION_MAJOR >= 2
+	talloc_set_log_stderr();
+#endif
+
+	/* Pre-create the first tracee (pid == 0).  */
+	tracee = get_tracee(NULL, 0, true);
+	if (tracee == NULL)
+		goto error;
+	tracee->pid = getpid();
+
+	/* Pre-configure the first tracee.  */
+	status = parse_config(tracee, argc, argv);
+	if (status < 0)
+		goto error;
+
+	/* Start the first tracee.  */
+	status = launch_process(tracee, &argv[status]);
+	if (status < 0) {
+		print_execve_help(tracee, tracee->exe, status);
+		goto error;
+	}
+
+	/* Start tracing the first tracee and all its children.  */
+	exit(event_loop());
+
+error:
+	TALLOC_FREE(tracee);
+
+	if (exit_failure) {
+		fprintf(stderr, "fatal error: see `%s --help`.\n", basename(argv[0]));
+		exit(EXIT_FAILURE);
+	}
+	else
+		exit(EXIT_SUCCESS);
+}
+
+/**
+ * Convert @value into an integer, then put the result into
+ * *@variable.  This function prints a warning and returns -1 if a
+ * conversion error occured, otherwise it returns 0.
+ */
+int parse_integer_option(const Tracee *tracee, int *variable, const char *value, const char *option)
+{
+	char *end_ptr = NULL;
+
+	errno = 0;
+	*variable = strtol(value, &end_ptr, 10);
+	if (errno != 0 || end_ptr == value) {
+		note(tracee, ERROR, USER, "option `%s` expects an integer value.", option);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Expand the environment variable in front of @string, if any.  For
+ * example, this function can expand "$HOME" or "$HOME/.ICEauthority".
+ */
+const char *expand_front_variable(TALLOC_CTX *context, const char *string)
+{
+	const char *suffix;
+	char *expanded;
+	ptrdiff_t size;
+
+	if (string[0] != '$')
+		return string;
+
+	suffix = strchr(string, '/');
+	if (suffix == NULL)
+		return (getenv(&string[1]) ?: string);
+
+	size = suffix - string;
+	if (size <= 1)
+		return string;
+
+	expanded = talloc_strndup(context, &string[1], size - 1);
+	if (expanded == NULL)
+		return string;
+
+	expanded = getenv(expanded);
+	if (expanded == NULL)
+		return string;
+
+	expanded = talloc_asprintf(context, "%s%s", expanded, suffix);
+	if (expanded == NULL)
+		return string;
+
+	return expanded;
+}
+
+/* Here follows the support for GCC function instrumentation.  Build
+ * with CFLAGS='-finstrument-functions -O0 -g' and LDFLAGS='-rdynamic'
+ * to enable this mechanism.  */
+
+static int indent_level = 0;
+
+void __cyg_profile_func_enter(void *this_function, void *call_site) DONT_INSTRUMENT;
+void __cyg_profile_func_enter(void *this_function, void *call_site)
+{
+	void *const pointers[] = { this_function, call_site };
+	char **symbols = NULL;
+
+	symbols = backtrace_symbols(pointers, 2);
+	if (symbols == NULL)
+		goto end;
+
+	fprintf(stderr, "%*s from %s\n", (int) strlen(symbols[0]) + indent_level, symbols[0], symbols[1]);
+
+end:
+	if (symbols != NULL)
+		free(symbols);
+
+	if (indent_level < INT_MAX)
+		indent_level++;
+}
+
+void __cyg_profile_func_exit(void *this_function UNUSED, void *call_site UNUSED) DONT_INSTRUMENT;
+void __cyg_profile_func_exit(void *this_function UNUSED, void *call_site UNUSED)
+{
+	if (indent_level > 0)
+		indent_level--;
+}
diff --git a/5.1.0/src/cli/cli.h b/5.1.0/src/cli/cli.h
new file mode 100644
index 0000000..67bd92b
--- /dev/null
+++ b/5.1.0/src/cli/cli.h
@@ -0,0 +1,65 @@
+/* This file is automatically generated from the documentation. EDIT AT YOUR OWN RISK. */
+
+#ifndef CLI_H
+#define CLI_H
+
+#include <stddef.h>
+#include "tracee/tracee.h"
+#include "attribute.h"
+
+typedef struct {
+	const char *name;
+	char separator;
+	const char *value;
+} Argument;
+
+struct Cli;
+typedef int (*option_handler_t)(Tracee *tracee, const struct Cli *cli, const char *value);
+
+typedef struct {
+	const char *class;
+	option_handler_t handler;
+	const char *description;
+	const char *detail;
+	Argument arguments[5];
+} Option;
+
+#define END_OF_OPTIONS { .class = NULL,								\
+			 .arguments = {{ .name = NULL, .separator = '\0', .value = NULL }},	\
+			 .handler = NULL,							\
+			 .description = NULL,							\
+			 .detail = NULL								\
+			}
+
+typedef int (*initialization_hook_t)(Tracee *tracee, const struct Cli *cli,
+				size_t argc, char *const argv[], size_t cursor);
+typedef struct Cli {
+	const char *name;
+	const char *version;
+	const char *subtitle;
+	const char *synopsis;
+	const char *colophon;
+	const char *logo;
+
+	initialization_hook_t pre_initialize_bindings;
+	initialization_hook_t post_initialize_bindings;
+	initialization_hook_t pre_initialize_cwd;
+	initialization_hook_t post_initialize_cwd;
+	initialization_hook_t pre_initialize_exe;
+	initialization_hook_t post_initialize_exe;
+	void *private;
+
+	const Option options[];
+} Cli;
+
+extern const Cli *get_proot_cli(TALLOC_CTX *context);
+extern const Cli * WEAK get_care_cli(TALLOC_CTX *context);
+
+extern void print_usage(Tracee *tracee, const Cli *cli, bool detailed);
+extern void print_version(const Cli *cli);
+extern int parse_integer_option(const Tracee *tracee, int *variable, const char *value, const char *option);
+extern const char *expand_front_variable(TALLOC_CTX *context, const char *string);
+
+extern bool exit_failure;
+
+#endif /* CLI_H */
diff --git a/5.1.0/src/cli/note.c b/5.1.0/src/cli/note.c
new file mode 100644
index 0000000..83f8865
--- /dev/null
+++ b/5.1.0/src/cli/note.c
@@ -0,0 +1,97 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <errno.h>  /* errno, */
+#include <string.h> /* strerror(3), */
+#include <stdarg.h> /* va_*, */
+#include <stdio.h>  /* vfprintf(3), */
+#include <limits.h> /* INT_MAX, */
+
+#include "cli/note.h"
+#include "tracee/tracee.h"
+
+int global_verbose_level;
+const char *global_tool_name;
+
+/**
+ * Print @message to the standard error stream according to its
+ * @severity and @origin.
+ */
+void note(const Tracee *tracee, Severity severity, Origin origin, const char *message, ...)
+{
+	const char *tool_name;
+	va_list extra_params;
+	int verbose_level;
+
+	if (tracee == NULL) {
+		verbose_level = global_verbose_level;
+		tool_name     = global_tool_name ?: "";
+	}
+	else {
+		verbose_level = tracee->verbose;
+		tool_name     = tracee->tool_name;
+	}
+
+	if (verbose_level < 0 && severity != ERROR)
+		return;
+
+	switch (severity) {
+	case WARNING:
+		fprintf(stderr, "%s warning: ", tool_name);
+		break;
+
+	case ERROR:
+		fprintf(stderr, "%s error: ", tool_name);
+		break;
+
+	case INFO:
+	default:
+		fprintf(stderr, "%s info: ", tool_name);
+		break;
+	}
+
+	if (origin == TALLOC)
+		fprintf(stderr, "talloc: ");
+
+	va_start(extra_params, message);
+	vfprintf(stderr, message, extra_params);
+	va_end(extra_params);
+
+	switch (origin) {
+	case SYSTEM:
+		fprintf(stderr, ": ");
+		perror(NULL);
+		break;
+
+	case TALLOC:
+		break;
+
+	case INTERNAL:
+	case USER:
+	default:
+		fprintf(stderr, "\n");
+		break;
+	}
+
+	return;
+}
+
diff --git a/5.1.0/src/cli/note.h b/5.1.0/src/cli/note.h
new file mode 100644
index 0000000..4993872
--- /dev/null
+++ b/5.1.0/src/cli/note.h
@@ -0,0 +1,54 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef NOTE_H
+#define NOTE_H
+
+#include "tracee/tracee.h"
+#include "attribute.h"
+
+/* Specify where a notice is coming from. */
+typedef enum {
+	SYSTEM,
+	INTERNAL,
+	USER,
+	TALLOC,
+} Origin;
+
+/* Specify the severity of a notice. */
+typedef enum {
+	ERROR,
+	WARNING,
+	INFO,
+} Severity;
+
+#define VERBOSE(tracee, level, message, args...) do {			\
+		if (tracee == NULL || tracee->verbose >= (level))	\
+			note(tracee, INFO, INTERNAL, (message), ## args); \
+	} while (0)
+
+extern void note(const Tracee *tracee, Severity severity, Origin origin, const char *message, ...) FORMAT(printf, 4, 5);
+
+extern int global_verbose_level;
+extern const char *global_tool_name;
+
+#endif /* NOTE_H */
diff --git a/5.1.0/src/cli/proot.c b/5.1.0/src/cli/proot.c
new file mode 100644
index 0000000..e46d87e
--- /dev/null
+++ b/5.1.0/src/cli/proot.c
@@ -0,0 +1,324 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <string.h>    /* str*(3), */
+#include <assert.h>    /* assert(3), */
+#include <stdio.h>     /* printf(3), fflush(3), */
+#include <unistd.h>    /* write(2), */
+
+#include "cli/cli.h"
+#include "cli/note.h"
+#include "extension/extension.h"
+#include "path/binding.h"
+#include "attribute.h"
+
+/* These should be included last.  */
+#include "build.h"
+#include "cli/proot.h"
+
+static int handle_option_r(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	Binding *binding;
+
+	/* ``chroot $PATH`` is semantically equivalent to ``mount
+	 * --bind $PATH /``.  */
+	binding = new_binding(tracee, value, "/", true);
+	if (binding == NULL)
+		return -1;
+
+	return 0;
+}
+
+static int handle_option_b(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	char *host;
+	char *guest;
+
+	host = talloc_strdup(tracee->ctx, value);
+	if (host == NULL) {
+		note(tracee, ERROR, INTERNAL, "can't allocate memory");
+		return -1;
+	}
+
+	guest = strchr(host, ':');
+	if (guest != NULL) {
+		*guest = '\0';
+		guest++;
+	}
+
+	new_binding(tracee, host, guest, true);
+	return 0;
+}
+
+static int handle_option_q(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	const char *ptr;
+	size_t nb_args;
+	bool last;
+	size_t i;
+
+	nb_args = 0;
+	ptr = value;
+	while (1) {
+		nb_args++;
+
+		/* Keep consecutive non-space characters.  */
+		while (*ptr != ' ' && *ptr != '\0')
+			ptr++;
+
+		/* End-of-string ?  */
+		if (*ptr == '\0')
+			break;
+
+		/* Skip consecutive space separators.  */
+		while (*ptr == ' ' && *ptr != '\0')
+			ptr++;
+
+		/* End-of-string ?  */
+		if (*ptr == '\0')
+			break;
+	}
+
+	tracee->qemu = talloc_zero_array(tracee, char *, nb_args + 1);
+	if (tracee->qemu == NULL)
+		return -1;
+	talloc_set_name_const(tracee->qemu, "@qemu");
+
+	i = 0;
+	ptr = value;
+	do {
+		const void *start;
+		const void *end;
+		last = true;
+
+		/* Keep consecutive non-space characters.  */
+		start = ptr;
+		while (*ptr != ' ' && *ptr != '\0')
+			ptr++;
+		end = ptr;
+
+		/* End-of-string ?  */
+		if (*ptr == '\0')
+			goto next;
+
+		/* Remove consecutive space separators.  */
+		while (*ptr == ' ' && *ptr != '\0')
+			ptr++;
+
+		/* End-of-string ?  */
+		if (*ptr == '\0')
+			goto next;
+
+		last = false;
+	next:
+		tracee->qemu[i] = talloc_strndup(tracee->qemu, start, end - start);
+		if (tracee->qemu[i] == NULL)
+			return -1;
+		i++;
+	} while (!last);
+	assert(i == nb_args);
+
+	new_binding(tracee, "/", HOST_ROOTFS, true);
+	new_binding(tracee, "/dev/null", "/etc/ld.so.preload", false);
+
+	return 0;
+}
+
+static int handle_option_w(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	tracee->fs->cwd = talloc_strdup(tracee->fs, value);
+	if (tracee->fs->cwd == NULL)
+		return -1;
+	talloc_set_name_const(tracee->fs->cwd, "$cwd");
+	return 0;
+}
+
+static int handle_option_k(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	int status;
+
+	status = initialize_extension(tracee, kompat_callback, value);
+	if (status < 0)
+		note(tracee, WARNING, INTERNAL, "option \"-k %s\" discarded", value);
+
+	return 0;
+}
+
+static int handle_option_i(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	(void) initialize_extension(tracee, fake_id0_callback, value);
+	return 0;
+}
+
+static int handle_option_0(Tracee *tracee, const Cli *cli, const char *value UNUSED)
+{
+	return handle_option_i(tracee, cli, "0:0");
+}
+
+static int handle_option_v(Tracee *tracee, const Cli *cli UNUSED, const char *value)
+{
+	int status;
+
+	status = parse_integer_option(tracee, &tracee->verbose, value, "-v");
+	if (status < 0)
+		return status;
+
+	global_verbose_level = tracee->verbose;
+	return 0;
+}
+
+extern unsigned char WEAK _binary_licenses_start;
+extern unsigned char WEAK _binary_licenses_end;
+
+static int handle_option_V(Tracee *tracee UNUSED, const Cli *cli, const char *value UNUSED)
+{
+	size_t size;
+
+	print_version(cli);
+	printf("\n%s\n", cli->colophon);
+	fflush(stdout);
+
+	size = &_binary_licenses_end - &_binary_licenses_start;
+	if (size > 0)
+		write(1, &_binary_licenses_start, size);
+
+	exit_failure = false;
+	return -1;
+}
+
+static int handle_option_h(Tracee *tracee, const Cli *cli, const char *value UNUSED)
+{
+	print_usage(tracee, cli, true);
+	exit_failure = false;
+	return -1;
+}
+
+static void new_bindings(Tracee *tracee, const char *bindings[], const char *value)
+{
+	int i;
+
+	for (i = 0; bindings[i] != NULL; i++) {
+		const char *path;
+
+		path = (strcmp(bindings[i], "*path*") != 0
+			? expand_front_variable(tracee->ctx, bindings[i])
+			: value);
+
+		new_binding(tracee, path, NULL, false);
+	}
+}
+
+static int handle_option_R(Tracee *tracee, const Cli *cli, const char *value)
+{
+	int status;
+
+	status = handle_option_r(tracee, cli, value);
+	if (status < 0)
+		return status;
+
+	new_bindings(tracee, recommended_bindings, value);
+
+	return 0;
+}
+
+static int handle_option_S(Tracee *tracee, const Cli *cli, const char *value)
+{
+	int status;
+
+	status = handle_option_0(tracee, cli, value);
+	if (status < 0)
+		return status;
+
+	status = handle_option_r(tracee, cli, value);
+	if (status < 0)
+		return status;
+
+	new_bindings(tracee, recommended_su_bindings, value);
+
+	return 0;
+}
+
+/**
+ * Initialize @tracee->qemu.
+ */
+static int post_initialize_exe(Tracee *tracee, const Cli *cli UNUSED,
+			size_t argc UNUSED, char *const argv[] UNUSED, size_t cursor UNUSED)
+{
+	char path[PATH_MAX];
+	int status;
+
+	/* Nothing else to do ?  */
+	if (tracee->qemu == NULL)
+		return 0;
+
+	/* Resolve the full guest path to tracee->qemu[0].  */
+	status = which(tracee->reconf.tracee, tracee->reconf.paths, path, tracee->qemu[0]);
+	if (status < 0)
+		return -1;
+
+	/* Actually tracee->qemu[0] has to be a host path from the tracee's
+	 * point-of-view, not from the PRoot's point-of-view.  See
+	 * translate_execve() for details.  */
+	if (tracee->reconf.tracee != NULL) {
+		status = detranslate_path(tracee->reconf.tracee, path, NULL);
+		if (status < 0)
+			return -1;
+	}
+
+	tracee->qemu[0] = talloc_strdup(tracee->qemu, path);
+	if (tracee->qemu[0] == NULL)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * Initialize @tracee's fields that are mandatory for PRoot but that
+ * are not required on the command line, i.e.  "-w" and "-r".
+ */
+static int pre_initialize_bindings(Tracee *tracee, const Cli *cli,
+			size_t argc UNUSED, char *const argv[] UNUSED, size_t cursor)
+{
+	int status;
+
+	/* Default to "." if no CWD were specified.  */
+	if (tracee->fs->cwd == NULL) {
+		status = handle_option_w(tracee, cli, ".");
+		if (status < 0)
+			return -1;
+	}
+
+	 /* The default guest rootfs is "/" if none was specified.  */
+	if (get_root(tracee) == NULL) {
+		status = handle_option_r(tracee, cli, "/");
+		if (status < 0)
+			return -1;
+	}
+
+	return cursor;
+}
+
+const Cli *get_proot_cli(TALLOC_CTX *context UNUSED)
+{
+	global_tool_name = proot_cli.name;
+	return &proot_cli;
+}
diff --git a/5.1.0/src/cli/proot.h b/5.1.0/src/cli/proot.h
new file mode 100644
index 0000000..a06abd7
--- /dev/null
+++ b/5.1.0/src/cli/proot.h
@@ -0,0 +1,273 @@
+/* This file is automatically generated from the documentation. EDIT AT YOUR OWN RISK. */
+
+#ifndef PROOT_CLI_H
+#define PROOT_CLI_H
+
+#include "cli/cli.h"
+
+#ifndef VERSION
+#define VERSION "5.1.0"
+#endif
+
+static const char *recommended_bindings[] = {
+	"/etc/host.conf",
+	"/etc/hosts",
+	"/etc/hosts.equiv",
+	"/etc/mtab",
+	"/etc/netgroup",
+	"/etc/networks",
+	"/etc/passwd",
+	"/etc/group",
+	"/etc/nsswitch.conf",
+	"/etc/resolv.conf",
+	"/etc/localtime",
+	"/dev/",
+	"/sys/",
+	"/proc/",
+	"/tmp/",
+	"/run/",
+	"/var/run/dbus/system_bus_socket",
+/*	"/var/tmp/kdecache-$LOGNAME", */
+	"$HOME",
+	"*path*",
+	NULL,
+};
+
+static const char *recommended_su_bindings[] = {
+	"/etc/host.conf",
+	"/etc/hosts",
+	"/etc/nsswitch.conf",
+	"/etc/resolv.conf",
+	"/dev/",
+	"/sys/",
+	"/proc/",
+	"/tmp/",
+	"/run/shm",
+	"$HOME",
+	"*path*",
+	NULL,
+};
+
+static int handle_option_r(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_b(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_q(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_w(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_v(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_V(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_h(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_k(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_0(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_i(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_R(Tracee *tracee, const Cli *cli, const char *value);
+static int handle_option_S(Tracee *tracee, const Cli *cli, const char *value);
+
+static int pre_initialize_bindings(Tracee *, const Cli *, size_t, char *const *, size_t);
+static int post_initialize_exe(Tracee *, const Cli *, size_t, char *const *, size_t);
+
+static Cli proot_cli = {
+	.version  = VERSION,
+	.name     = "proot",
+	.subtitle = "chroot, mount --bind, and binfmt_misc without privilege/setup",
+	.synopsis = "proot [option] ... [command]",
+	.colophon = "Visit http://proot.me for help, bug reports, suggestions, patchs, ...\n\
+Copyright (C) 2014 STMicroelectronics, licensed under GPL v2 or later.",
+	.logo = "\
+ _____ _____              ___\n\
+|  __ \\  __ \\_____  _____|   |_\n\
+|   __/     /  _  \\/  _  \\    _|\n\
+|__|  |__|__\\_____/\\_____/\\____|",
+
+	.pre_initialize_bindings = pre_initialize_bindings,
+	.post_initialize_exe = post_initialize_exe,
+
+	.options = {
+	{ .class = "Regular options",
+	  .arguments = {
+		{ .name = "-r", .separator = ' ', .value = "path" },
+		{ .name = "--rootfs", .separator = '=', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_r,
+	  .description = "Use *path* as the new guest root file-system, default is /.",
+	  .detail = "\tThe specified path typically contains a Linux distribution where\n\
+\tall new programs will be confined.  The default rootfs is /\n\
+\twhen none is specified, this makes sense when the bind mechanism\n\
+\tis used to relocate host files and directories, see the -b\n\
+\toption and the Examples section for details.\n\
+\t\n\
+\tIt is recommended to use the -R or -S options instead.",
+	},
+	{ .class = "Regular options",
+	  .arguments = {
+		{ .name = "-b", .separator = ' ', .value = "path" },
+		{ .name = "--bind", .separator = '=', .value = "path" },
+		{ .name = "-m", .separator = ' ', .value = "path" },
+		{ .name = "--mount", .separator = '=', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_b,
+	  .description = "Make the content of *path* accessible in the guest rootfs.",
+	  .detail = "\tThis option makes any file or directory of the host rootfs\n\
+\taccessible in the confined environment just as if it were part of\n\
+\tthe guest rootfs.  By default the host path is bound to the same\n\
+\tpath in the guest rootfs but users can specify any other location\n\
+\twith the syntax: -b *host_path*:*guest_location*.  If the\n\
+\tguest location is a symbolic link, it is dereferenced to ensure\n\
+\tthe new content is accessible through all the symbolic links that\n\
+\tpoint to the overlaid content.  In most cases this default\n\
+\tbehavior shouldn't be a problem, although it is possible to\n\
+\texplicitly not dereference the guest location by appending it the\n\
+\t! character: -b *host_path*:*guest_location!*.",
+	},
+	{ .class = "Regular options",
+	  .arguments = {
+		{ .name = "-q", .separator = ' ', .value = "command" },
+		{ .name = "--qemu", .separator = '=', .value = "command" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_q,
+	  .description = "Execute guest programs through QEMU as specified by *command*.",
+	  .detail = "\tEach time a guest program is going to be executed, PRoot inserts\n\
+\tthe QEMU user-mode command in front of the initial request.\n\
+\tThat way, guest programs actually run on a virtual guest CPU\n\
+\temulated by QEMU user-mode.  The native execution of host programs\n\
+\tis still effective and the whole host rootfs is bound to\n\
+\t/host-rootfs in the guest environment.",
+	},
+	{ .class = "Regular options",
+	  .arguments = {
+		{ .name = "-w", .separator = ' ', .value = "path" },
+		{ .name = "--pwd", .separator = '=', .value = "path" },
+		{ .name = "--cwd", .separator = '=', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_w,
+	  .description = "Set the initial working directory to *path*.",
+	  .detail = "\tSome programs expect to be launched from a given directory but do\n\
+\tnot perform any chdir by themselves.  This option avoids the\n\
+\tneed for running a shell and then entering the directory manually.",
+	},
+	{ .class = "Regular options",
+	  .arguments = {
+		{ .name = "-v", .separator = ' ', .value = "value" },
+		{ .name = "--verbose", .separator = '=', .value = "value" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_v,
+	  .description = "Set the level of debug information to *value*.",
+	  .detail = "\tThe higher the integer value is, the more detailed debug\n\
+\tinformation is printed to the standard error stream.  A negative\n\
+\tvalue makes PRoot quiet except on fatal errors.",
+	},
+	{ .class = "Regular options",
+	  .arguments = {
+		{ .name = "-V", .separator = '\0', .value = NULL },
+		{ .name = "--version", .separator = '\0', .value = NULL },
+		{ .name = "--about", .separator = '\0', .value = NULL },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_V,
+	  .description = "Print version, copyright, license and contact, then exit.",
+	  .detail = "",
+	},
+	{ .class = "Regular options",
+	  .arguments = {
+		{ .name = "-h", .separator = '\0', .value = NULL },
+		{ .name = "--help", .separator = '\0', .value = NULL },
+		{ .name = "--usage", .separator = '\0', .value = NULL },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_h,
+	  .description = "Print the version and the command-line usage, then exit.",
+	  .detail = "",
+	},
+	{ .class = "Extension options",
+	  .arguments = {
+		{ .name = "-k", .separator = ' ', .value = "string" },
+		{ .name = "--kernel-release", .separator = '=', .value = "string" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_k,
+	  .description = "Make current kernel appear as kernel release *string*.",
+	  .detail = "\tIf a program is run on a kernel older than the one expected by its\n\
+\tGNU C library, the following error is reported: \"FATAL: kernel too\n\
+\told\".  To be able to run such programs, PRoot can emulate some of\n\
+\tthe features that are available in the kernel release specified by\n\
+\t*string* but that are missing in the current kernel.",
+	},
+	{ .class = "Extension options",
+	  .arguments = {
+		{ .name = "-0", .separator = '\0', .value = NULL },
+		{ .name = "--root-id", .separator = '\0', .value = NULL },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_0,
+	  .description = "Make current user appear as \"root\" and fake its privileges.",
+	  .detail = "\tSome programs will refuse to work if they are not run with \"root\"\n\
+\tprivileges, even if there is no technical reason for that.  This\n\
+\tis typically the case with package managers.  This option allows\n\
+\tusers to bypass this kind of limitation by faking the user/group\n\
+\tidentity, and by faking the success of some operations like\n\
+\tchanging the ownership of files, changing the root directory to\n\
+\t/, ...  Note that this option is quite limited compared to\n\
+\tfakeroot.",
+	},
+	{ .class = "Extension options",
+	  .arguments = {
+		{ .name = "-i", .separator = ' ', .value = "string" },
+		{ .name = "--change-id", .separator = '=', .value = "string" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_i,
+	  .description = "Make current user and group appear as *string* \"uid:gid\".",
+	  .detail = "\tThis option makes the current user and group appear as uid and\n\
+\tgid.  Likewise, files actually owned by the current user and\n\
+\tgroup appear as if they were owned by uid and gid instead.\n\
+\tNote that the -0 option is the same as -i 0:0.",
+	},
+	{ .class = "Alias options",
+	  .arguments = {
+		{ .name = "-R", .separator = ' ', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_R,
+	  .description = "Alias: -r *path* + a couple of recommended -b.",
+	  .detail = "\tPrograms isolated in *path*, a guest rootfs, might still need to\n\
+\taccess information about the host system, as it is illustrated in\n\
+\tthe Examples section of the manual.  These host information\n\
+\tare typically: user/group definition, network setup, run-time\n\
+\tinformation, users' files, ...  On all Linux distributions, they\n\
+\tall lie in a couple of host files and directories that are\n\
+\tautomatically bound by this option:\n\
+\t\n\
+\t    * /etc/host.conf\n\
+\t    * /etc/hosts\n\
+\t    * /etc/hosts.equiv\n\
+\t    * /etc/mtab\n\
+\t    * /etc/netgroup\n\
+\t    * /etc/networks\n\
+\t    * /etc/passwd\n\
+\t    * /etc/group\n\
+\t    * /etc/nsswitch.conf\n\
+\t    * /etc/resolv.conf\n\
+\t    * /etc/localtime\n\
+\t    * /dev/\n\
+\t    * /sys/\n\
+\t    * /proc/\n\
+\t    * /tmp/\n\
+\t    * $HOME",
+	},
+	{ .class = "Alias options",
+	  .arguments = {
+		{ .name = "-S", .separator = ' ', .value = "path" },
+		{ .name = NULL, .separator = '\0', .value = NULL } },
+	  .handler = handle_option_S,
+	  .description = "Alias: -0 -r *path* + a couple of recommended -b.",
+	  .detail = "\tThis option is useful to safely create and install packages into\n\
+\tthe guest rootfs.  It is similar to the -R option expect it\n\
+\tenables the -0 option and binds only the following minimal set\n\
+\tof paths to avoid unexpected changes on host files:\n\
+\t\n\
+\t    * /etc/host.conf\n\
+\t    * /etc/hosts\n\
+\t    * /etc/nsswitch.conf\n\
+\t    * /dev/\n\
+\t    * /sys/\n\
+\t    * /proc/\n\
+\t    * /tmp/\n\
+\t    * $HOME",
+	},
+	END_OF_OPTIONS,
+	},
+};
+
+#endif /* PROOT_CLI_H */
diff --git a/5.1.0/src/compat.h b/5.1.0/src/compat.h
new file mode 100644
index 0000000..e991c39
--- /dev/null
+++ b/5.1.0/src/compat.h
@@ -0,0 +1,247 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+/* Local definitions for compatibility with old and/or broken distros... */
+#    ifndef AT_NULL
+#        define AT_NULL			0
+#    endif
+#    ifndef AT_PHDR
+#        define AT_PHDR			3
+#    endif
+#    ifndef AT_PHENT
+#        define AT_PHENT		4
+#    endif
+#    ifndef AT_PHNUM
+#        define AT_PHNUM		5
+#    endif
+#    ifndef AT_BASE
+#        define AT_BASE			7
+#    endif
+#    ifndef AT_ENTRY
+#        define AT_ENTRY		9
+#    endif
+#    ifndef AT_RANDOM
+#        define AT_RANDOM		25
+#    endif
+#    ifndef AT_EXECFN
+#        define AT_EXECFN		31
+#    endif
+#    ifndef AT_SYSINFO
+#        define AT_SYSINFO		32
+#    endif
+#    ifndef AT_SYSINFO_EHDR
+#        define AT_SYSINFO_EHDR		33
+#    endif
+#    ifndef AT_FDCWD
+#        define AT_FDCWD		-100
+#    endif
+#    ifndef AT_SYMLINK_FOLLOW
+#        define AT_SYMLINK_FOLLOW	0x400
+#    endif
+#    ifndef AT_REMOVEDIR
+#        define AT_REMOVEDIR		0x200
+#    endif
+#    ifndef AT_SYMLINK_NOFOLLOW
+#        define AT_SYMLINK_NOFOLLOW	0x100
+#    endif
+#    ifndef IN_DONT_FOLLOW
+#        define IN_DONT_FOLLOW		0x02000000
+#    endif
+#    ifndef WIFCONTINUED
+#        define WIFCONTINUED(status)	((status) == 0xffff)
+#    endif
+#    ifndef PTRACE_GETREGS
+#        define PTRACE_GETREGS		12
+#    endif
+#    ifndef PTRACE_SETREGS
+#        define PTRACE_SETREGS		13
+#    endif
+#    ifndef PTRACE_GETFPREGS
+#        define PTRACE_GETFPREGS	14
+#    endif
+#    ifndef PTRACE_SETFPREGS
+#        define PTRACE_SETFPREGS	15
+#    endif
+#    ifndef PTRACE_GETFPXREGS
+#        define PTRACE_GETFPXREGS	18
+#    endif
+#    ifndef PTRACE_SETFPXREGS
+#        define PTRACE_SETFPXREGS	19
+#    endif
+#    ifndef PTRACE_SETOPTIONS
+#        define PTRACE_SETOPTIONS	0x4200
+#    endif
+#    ifndef PTRACE_GETEVENTMSG
+#        define PTRACE_GETEVENTMSG	0x4201
+#    endif
+#    ifndef PTRACE_GETREGSET
+#        define PTRACE_GETREGSET	0x4204
+#    endif
+#    ifndef PTRACE_SETREGSET
+#        define PTRACE_SETREGSET	0x4205
+#    endif
+#    ifndef PTRACE_SEIZE
+#        define PTRACE_SEIZE		0x4206
+#    endif
+#    ifndef PTRACE_INTERRUPT
+#        define PTRACE_INTERRUPT	0x4207
+#    endif
+#    ifndef PTRACE_LISTEN
+#        define PTRACE_LISTEN		0x4208
+#    endif
+#    ifndef PTRACE_O_TRACESYSGOOD
+#        define PTRACE_O_TRACESYSGOOD	0x00000001
+#    endif
+#    ifndef PTRACE_O_TRACEFORK
+#        define PTRACE_O_TRACEFORK	0x00000002
+#    endif
+#    ifndef PTRACE_O_TRACEVFORK
+#        define PTRACE_O_TRACEVFORK	0x00000004
+#    endif
+#    ifndef PTRACE_O_TRACECLONE
+#        define PTRACE_O_TRACECLONE	0x00000008
+#    endif
+#    ifndef PTRACE_O_TRACEEXEC
+#        define PTRACE_O_TRACEEXEC	0x00000010
+#    endif
+#    ifndef PTRACE_O_TRACEVFORKDONE
+#        define PTRACE_O_TRACEVFORKDONE	0x00000020
+#    endif
+#    ifndef PTRACE_O_TRACEEXIT
+#        define PTRACE_O_TRACEEXIT	0x00000040
+#    endif
+#    ifndef PTRACE_O_TRACESECCOMP
+#        define PTRACE_O_TRACESECCOMP	0x00000080
+#    endif
+#    ifndef PTRACE_EVENT_FORK
+#        define PTRACE_EVENT_FORK	1
+#    endif
+#    ifndef PTRACE_EVENT_VFORK
+#        define PTRACE_EVENT_VFORK	2
+#    endif
+#    ifndef PTRACE_EVENT_CLONE
+#        define PTRACE_EVENT_CLONE	3
+#    endif
+#    ifndef PTRACE_EVENT_EXEC
+#        define PTRACE_EVENT_EXEC	4
+#    endif
+#    ifndef PTRACE_EVENT_VFORK_DONE
+#        define PTRACE_EVENT_VFORK_DONE	5
+#    endif
+#    ifndef PTRACE_EVENT_EXIT
+#        define PTRACE_EVENT_EXIT	6
+#    endif
+#    ifndef PTRACE_EVENT_SECCOMP
+#        define PTRACE_EVENT_SECCOMP	7
+#    endif
+#    ifndef PTRACE_EVENT_SECCOMP2
+#        if PTRACE_EVENT_SECCOMP == 7
+#            define PTRACE_EVENT_SECCOMP2	8
+#        elif PTRACE_EVENT_SECCOMP == 8
+#            define PTRACE_EVENT_SECCOMP2	7
+#        else
+#            error "unknown PTRACE_EVENT_SECCOMP value"
+#        endif
+#    endif
+#    ifndef PTRACE_SET_SYSCALL
+#        define PTRACE_SET_SYSCALL	23
+#    endif
+#    ifndef PTRACE_GET_THREAD_AREA
+#        define PTRACE_GET_THREAD_AREA	25
+#    endif
+#    ifndef PTRACE_SET_THREAD_AREA
+#        define PTRACE_SET_THREAD_AREA	26
+#    endif
+#    ifndef PTRACE_GETVFPREGS
+#        define PTRACE_GETVFPREGS	27
+#    endif
+#    ifndef PTRACE_ARCH_PRCTL
+#        define PTRACE_ARCH_PRCTL	30
+#    endif
+#    ifndef ARCH_SET_GS
+#        define ARCH_SET_GS	0x1001
+#    endif
+#    ifndef ARCH_SET_FS
+#        define ARCH_SET_FS	0x1002
+#    endif
+#    ifndef ARCH_GET_GS
+#        define ARCH_GET_FS	0x1003
+#    endif
+#    ifndef ARCH_GET_FS
+#        define ARCH_GET_GS	0x1004
+#    endif
+#    ifndef PTRACE_SINGLEBLOCK
+#        define PTRACE_SINGLEBLOCK	33
+#    endif
+#    ifndef ADDR_NO_RANDOMIZE
+#        define ADDR_NO_RANDOMIZE	0x0040000
+#    endif
+#    ifndef SYS_ACCEPT4
+#        define SYS_ACCEPT4		18
+#    endif
+#    ifndef TALLOC_FREE
+#        define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx = NULL; } while(0)
+#    endif
+#    ifndef PR_SET_NAME
+#        define PR_SET_NAME		15
+#    endif
+#    ifndef PR_SET_NO_NEW_PRIVS
+#        define PR_SET_NO_NEW_PRIVS	38
+#    endif
+#    ifndef PR_SET_SECCOMP
+#        define PR_SET_SECCOMP		22
+#    endif
+#    ifndef SECCOMP_MODE_FILTER
+#        define SECCOMP_MODE_FILTER	2
+#    endif
+#    ifndef talloc_get_type_abort
+#        define talloc_get_type_abort talloc_get_type
+#    endif
+#    ifndef FUTEX_PRIVATE_FLAG
+#        define FUTEX_PRIVATE_FLAG	128
+#    endif
+#    ifndef EFD_SEMAPHORE
+#        define EFD_SEMAPHORE		1
+#    endif
+#    ifndef F_DUPFD_CLOEXEC
+#        define F_DUPFD_CLOEXEC		1030
+#    endif
+#    ifndef O_RDONLY
+#        define O_RDONLY		00000000
+#    endif
+#    ifndef O_CLOEXEC
+#        define O_CLOEXEC		02000000
+#    endif
+#    ifndef MAP_PRIVATE
+#        define MAP_PRIVATE			0x02
+#    endif
+#    ifndef MAP_FIXED
+#        define MAP_FIXED			0x10
+#    endif
+#    ifndef MAP_ANONYMOUS
+#        define MAP_ANONYMOUS			0x20
+#    endif
+
+#endif /* COMPAT_H */
diff --git a/5.1.0/src/execve/aoxp.c b/5.1.0/src/execve/aoxp.c
new file mode 100644
index 0000000..8a78eaa
--- /dev/null
+++ b/5.1.0/src/execve/aoxp.c
@@ -0,0 +1,439 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/limits.h> /* ARG_MAX, */
+#include <assert.h>   /* assert(3), */
+#include <string.h>   /* strlen(3), memcmp(3), memcpy(3), */
+#include <strings.h>  /* bzero(3), */
+#include <stdbool.h>  /* bool, true, false, */
+#include <errno.h>    /* E*,  */
+#include <stdarg.h>   /* va_*, */
+#include <stdint.h>   /* uint32_t, */
+#include <talloc.h>   /* talloc_*, */
+
+#include "arch.h"
+#include "tracee/tracee.h"
+#include "tracee/mem.h"
+#include "tracee/abi.h"
+#include "build.h"
+
+struct mixed_pointer {
+	/* Pointer -- in tracee's address space -- to the current
+	 * object, if local == NULL.  */
+	word_t remote;
+
+	/* Pointer -- in tracer's address space -- to the current
+	 * object, if local != NULL.  */
+	void *local;
+};
+
+#include "execve/aoxp.h"
+
+/**
+ * Read object pointed to by @array[@index] from tracee's memory, then
+ * make @local_pointer points to the locally *cached* version.  This
+ * function returns -errno when an error occured, otherwise 0.
+ */
+int read_xpointee_as_object(ArrayOfXPointers *array, size_t index, void **local_pointer)
+{
+	int status;
+	int size;
+
+	assert(index < array->length);
+
+	/* Already cached locally?  */
+	if (array->_xpointers[index].local != NULL)
+		goto end;
+
+	/* Remote NULL is mapped to local NULL.  */
+	if (array->_xpointers[index].remote == 0) {
+		array->_xpointers[index].local = NULL;
+		goto end;
+	}
+
+	size = sizeof_xpointee(array, index);
+	if (size < 0)
+		return size;
+
+	array->_xpointers[index].local = talloc_size(array, size);
+	if (array->_xpointers[index].local == NULL)
+		return -ENOMEM;
+
+	/* Copy locally the remote object.  */
+	status = read_data(TRACEE(array), array->_xpointers[index].local,
+			   array->_xpointers[index].remote, size);
+	if (status < 0) {
+		array->_xpointers[index].local = NULL;
+		return status;
+	}
+
+end:
+	*local_pointer = array->_xpointers[index].local;
+	return 0;
+}
+
+/**
+ * Read string pointed to by @array[@index] from tracee's memory, then
+ * make @local_pointer points to the locally *cached* version.  This
+ * function returns -errno when an error occured, otherwise 0.
+ */
+int read_xpointee_as_string(ArrayOfXPointers *array, size_t index, char **local_pointer)
+{
+	char tmp[ARG_MAX];
+	int status;
+
+	assert(index < array->length);
+
+	/* Already cached locally?  */
+	if (array->_xpointers[index].local != NULL)
+		goto end;
+
+	/* Remote NULL is mapped to local NULL.  */
+	if (array->_xpointers[index].remote == 0) {
+		array->_xpointers[index].local = NULL;
+		goto end;
+	}
+
+	/* Copy locally the remote string into a temporary buffer.  */
+	status = read_string(TRACEE(array), tmp, array->_xpointers[index].remote, ARG_MAX);
+	if (status < 0)
+		return status;
+	if (status >= ARG_MAX)
+		return -ENOMEM;
+
+	/* Save the local string in a "persistent" buffer.  */
+	array->_xpointers[index].local = talloc_strdup(array, tmp);
+	if (array->_xpointers[index].local == NULL)
+		return -ENOMEM;
+
+end:
+	*local_pointer = array->_xpointers[index].local;
+	return 0;
+}
+
+/**
+ * This function returns the number of bytes of the string pointed to
+ * by @array[@index], otherwise -errno if an error occured.
+ */
+int sizeof_xpointee_as_string(ArrayOfXPointers *array, size_t index)
+{
+	char *string;
+	int status;
+
+	assert(index < array->length);
+
+	status = read_xpointee_as_string(array, index, &string);
+	if (status < 0)
+		return status;
+
+	if (string == NULL)
+		return 0;
+
+	return strlen(string) + 1;
+}
+
+/**
+ * Compare object pointed to by @array[@index] with object pointed to
+ * by @local_reference.  This function returns 1 if they are
+ * equivalent, 0 otherwise.  On error, -errno is returned.
+ */
+int compare_xpointee_generic(ArrayOfXPointers *array, size_t index, const void *local_reference)
+{
+	void *object;
+	int status;
+
+	assert(index < array->length);
+
+	status = read_xpointee(array, index, &object);
+	if (status < 0)
+		return status;
+
+	if (object == NULL && local_reference == NULL)
+		return 1;
+
+	if (object == NULL && local_reference != NULL)
+		return 0;
+
+	if (object != NULL && local_reference == NULL)
+		return 0;
+
+	status = sizeof_xpointee(array, index);
+	if (status < 0)
+		return status;
+
+	return (int) (memcmp(object, local_reference, status) == 0);
+}
+
+/**
+ * This function returns the index in @array of the first pointee
+ * equivalent to the @local_reference pointee, otherwise it returns
+ * -errno if an error occured.
+ */
+int find_xpointee(ArrayOfXPointers *array, const void *local_reference)
+{
+	size_t i;
+
+	for (i = 0; i < array->length; i++) {
+		int status;
+
+		status = compare_xpointee(array, i, local_reference);
+		if (status < 0)
+			return status;
+		if (status != 0)
+			break;
+	}
+
+	return i;
+}
+
+/**
+ * Make @array[@index] points to a copy of the string pointed to by
+ * @string.  This function returns -errno when an error occured,
+ * otherwise 0.
+ */
+int write_xpointee_as_string(ArrayOfXPointers *array, size_t index, const char *string)
+{
+	assert(index < array->length);
+
+	array->_xpointers[index].local = talloc_strdup(array, string);
+	if (array->_xpointers[index].local == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * Make @array[@index ... @index + @nb_xpointees] points to a copy of
+ * the variadic arguments.  This function returns -errno when an error
+ * occured, otherwise 0.
+ */
+int write_xpointees(ArrayOfXPointers *array, size_t index, size_t nb_xpointees, ...)
+{
+	va_list va_xpointees;
+	int status;
+	size_t i;
+
+	va_start(va_xpointees, nb_xpointees);
+
+	for (i = 0; i < nb_xpointees; i++) {
+		void *object = va_arg(va_xpointees, void *);
+
+		status = write_xpointee(array, index + i, object);
+		if (status < 0)
+			goto end;
+	}
+	status = 0;
+
+end:
+	va_end(va_xpointees);
+	return status;
+}
+
+
+/**
+ * Resize the @array at the given @index by the @delta_nb_entries.
+ * This function returns -errno when an error occured, otherwise 0.
+ */
+int resize_array_of_xpointers(ArrayOfXPointers *array, size_t index, ssize_t delta_nb_entries)
+{
+	size_t nb_moved_entries;
+	size_t new_length;
+	void *tmp;
+
+	assert(index < array->length);
+
+	if (delta_nb_entries == 0)
+		return 0;
+
+	new_length = array->length + delta_nb_entries;
+	nb_moved_entries = array->length - index;
+
+	if (delta_nb_entries > 0) {
+		tmp = talloc_realloc(array, array->_xpointers, XPointer, new_length);
+		if (tmp == NULL)
+			return -ENOMEM;
+		array->_xpointers = tmp;
+
+		memmove(array->_xpointers + index + delta_nb_entries, array->_xpointers + index,
+			nb_moved_entries * sizeof(XPointer));
+
+		bzero(array->_xpointers + index, delta_nb_entries * sizeof(XPointer));
+	}
+	else {
+		assert(delta_nb_entries <= 0);
+		assert(index >= (size_t) -delta_nb_entries);
+
+		memmove(array->_xpointers + index + delta_nb_entries, array->_xpointers + index,
+			nb_moved_entries * sizeof(XPointer));
+
+		tmp = talloc_realloc(array, array->_xpointers, XPointer, new_length);
+		if (tmp == NULL)
+			return -ENOMEM;
+		array->_xpointers = tmp;
+	}
+
+	array->length = new_length;
+	return 0;
+}
+
+/**
+ * Copy into *@array_ the pointer array pointed to by @reg from
+ * @tracee's memory space.  Only the first @nb_entries are copied,
+ * unless it is 0 then all the entries up to the NULL pointer are
+ * copied.  This function returns -errno when an error occured,
+ * otherwise 0.
+ */
+int fetch_array_of_xpointers(Tracee *tracee, ArrayOfXPointers **array_, Reg reg, size_t nb_entries)
+{
+	word_t pointer = 1; /* ie. != 0 */
+	word_t address;
+	ArrayOfXPointers *array;
+	size_t i;
+
+	assert(array_ != NULL);
+
+	*array_ = talloc_zero(tracee->ctx, ArrayOfXPointers);
+	if (*array_ == NULL)
+		return -ENOMEM;
+	array = *array_;
+
+	address = peek_reg(tracee, CURRENT, reg);
+
+	for (i = 0; nb_entries != 0 ? i < nb_entries : pointer != 0; i++) {
+		void *tmp = talloc_realloc(array, array->_xpointers, XPointer, i + 1);
+		if (tmp == NULL)
+			return -ENOMEM;
+		array->_xpointers = tmp;
+
+		pointer = peek_word(tracee, address + i * sizeof_word(tracee));
+		if (errno != 0)
+			return -errno;
+
+		array->_xpointers[i].remote = pointer;
+		array->_xpointers[i].local = NULL;
+	}
+	array->length = i;
+
+	/* By default, assume it is an array of string pointers.  */
+	array->read_xpointee   = (read_xpointee_t) read_xpointee_as_string;
+	array->sizeof_xpointee = sizeof_xpointee_as_string;
+	array->write_xpointee  = (write_xpointee_t) write_xpointee_as_string;
+
+	/* By default, use generic callbacks: they rely on
+	 * array->read_xpointee() and array->sizeof_xpointee().  */
+	array->compare_xpointee = compare_xpointee_generic;
+
+	return 0;
+}
+
+/**
+ * Copy @array into tracee's memory space, then put in @reg the
+ * address where it was copied.  This function returns -errno if an
+ * error occured, otherwise 0.
+ */
+int push_array_of_xpointers(ArrayOfXPointers *array, Reg reg)
+{
+	Tracee *tracee;
+	struct iovec *local;
+	size_t local_count;
+	size_t total_size;
+	word_t *pod_array;
+	word_t tracee_ptr;
+	int status;
+	size_t i;
+
+	/* Nothing to do, for sure.  */
+	if (array == NULL)
+		return 0;
+
+	tracee = TRACEE(array);
+
+	/* The pointer table is a POD array in the tracee's memory.  */
+	pod_array = talloc_zero_size(tracee->ctx, array->length * sizeof_word(tracee));
+	if (pod_array == NULL)
+		return -ENOMEM;
+
+	/* There's one vector per modified pointee + one vector for the
+	 * pod array.  */
+	local = talloc_zero_array(tracee->ctx, struct iovec, array->length + 1);
+	if (local == NULL)
+		return -ENOMEM;
+
+	/* The pod array is expected to be at the beginning of the
+	 * allocated memory by the caller.  */
+	total_size = array->length * sizeof_word(tracee);
+	local[0].iov_base = pod_array;
+	local[0].iov_len  = total_size;
+	local_count = 1;
+
+	/* Create one vector for each modified pointee.  */
+	for (i = 0; i < array->length; i++) {
+		ssize_t size;
+
+		if (array->_xpointers[i].local == NULL)
+			continue;
+
+		/* At this moment, we only know the offsets in the
+		 * tracee's memory block. */
+		array->_xpointers[i].remote = total_size;
+
+		size = sizeof_xpointee(array, i);
+		if (size < 0)
+			return size;
+		total_size += size;
+
+		local[local_count].iov_base = array->_xpointers[i].local;
+		local[local_count].iov_len  = size;
+		local_count++;
+	}
+
+	/* Nothing has changed, don't update anything.  */
+	if (local_count == 1)
+		return 0;
+	assert(local_count < array->length + 1);
+
+	/* Modified pointees and the pod array are stored in a tracee's
+	 * memory block.  */
+	tracee_ptr = alloc_mem(tracee, total_size);
+	if (tracee_ptr == 0)
+		return -E2BIG;
+
+	/* Now, we know the absolute addresses in the tracee's
+	 * memory.  */
+	for (i = 0; i < array->length; i++) {
+		if (array->_xpointers[i].local != NULL)
+			array->_xpointers[i].remote += tracee_ptr;
+
+		if (is_32on64_mode(tracee))
+			((uint32_t *) pod_array)[i] = array->_xpointers[i].remote;
+		else
+			pod_array[i] = array->_xpointers[i].remote;
+	}
+
+	/* Write all the modified pointees and the pod array at once.  */
+	status = writev_data(tracee, tracee_ptr, local, local_count);
+	if (status < 0)
+		return status;
+
+	poke_reg(tracee, reg, tracee_ptr);
+	return 0;
+}
diff --git a/5.1.0/src/execve/aoxp.h b/5.1.0/src/execve/aoxp.h
new file mode 100644
index 0000000..3ccfc35
--- /dev/null
+++ b/5.1.0/src/execve/aoxp.h
@@ -0,0 +1,80 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef AOXP_H
+#define AOXP_H
+
+#include <stdbool.h>
+
+#include "tracee/reg.h"
+#include "arch.h"
+
+typedef struct array_of_xpointers ArrayOfXPointers;
+typedef int (*read_xpointee_t)(ArrayOfXPointers *array, size_t index, void **object);
+typedef int (*write_xpointee_t)(ArrayOfXPointers *array, size_t index, const void *object);
+typedef int (*compare_xpointee_t)(ArrayOfXPointers *array, size_t index, const void *reference);
+typedef int (*sizeof_xpointee_t)(ArrayOfXPointers *array, size_t index);
+
+typedef struct mixed_pointer XPointer;
+struct array_of_xpointers {
+	XPointer *_xpointers;
+	size_t length;
+
+	read_xpointee_t    read_xpointee;
+	write_xpointee_t   write_xpointee;
+	compare_xpointee_t compare_xpointee;
+	sizeof_xpointee_t  sizeof_xpointee;
+};
+
+static inline int read_xpointee(ArrayOfXPointers *array, size_t index, void **object)
+{
+	return array->read_xpointee(array, index, object);
+}
+
+static inline int write_xpointee(ArrayOfXPointers *array, size_t index, const void *object)
+{
+	return array->write_xpointee(array, index, object);
+}
+
+static inline int compare_xpointee(ArrayOfXPointers *array, size_t index, const void *reference)
+{
+	return array->compare_xpointee(array, index, reference);
+}
+
+static inline int sizeof_xpointee(ArrayOfXPointers *array, size_t index)
+{
+	return array->sizeof_xpointee(array, index);
+}
+
+extern int find_xpointee(ArrayOfXPointers *array, const void *reference);
+extern int resize_array_of_xpointers(ArrayOfXPointers *array, size_t index, ssize_t nb_delta_entries);
+extern int fetch_array_of_xpointers(Tracee *tracee, ArrayOfXPointers **array, Reg reg, size_t nb_entries);
+extern int push_array_of_xpointers(ArrayOfXPointers *array, Reg reg);
+
+extern int read_xpointee_as_object(ArrayOfXPointers *array, size_t index, void **object);
+extern int read_xpointee_as_string(ArrayOfXPointers *array, size_t index, char **string);
+extern int write_xpointee_as_string(ArrayOfXPointers *array, size_t index, const char *string);
+extern int write_xpointees(ArrayOfXPointers *array, size_t index, size_t nb_xpointees, ...);
+extern int compare_xpointee_generic(ArrayOfXPointers *array, size_t index, const void *reference);
+extern int sizeof_xpointee_as_string(ArrayOfXPointers *array, size_t index);
+
+#endif /* AOXP_H */
diff --git a/5.1.0/src/execve/auxv.c b/5.1.0/src/execve/auxv.c
new file mode 100644
index 0000000..f3eb97e
--- /dev/null
+++ b/5.1.0/src/execve/auxv.c
@@ -0,0 +1,184 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/auxvec.h>  /* AT_*,  */
+#include <assert.h>        /* assert(3),  */
+#include <errno.h>         /* E*,  */
+#include <unistd.h>        /* write(3), close(3), */
+#include <sys/types.h>     /* open(2), */
+#include <sys/stat.h>      /* open(2), */
+#include <fcntl.h>         /* open(2), */
+
+#include "execve/auxv.h"
+#include "syscall/sysnum.h"
+#include "tracee/tracee.h"
+#include "tracee/mem.h"
+#include "tracee/reg.h"
+#include "tracee/abi.h"
+#include "arch.h"
+
+
+/**
+ * Add the given vector [@type, @value] to @vectors.  This function
+ * returns -errno if an error occurred, otherwise 0.
+ */
+int add_elf_aux_vector(ElfAuxVector **vectors, word_t type, word_t value)
+{
+	ElfAuxVector *tmp;
+	size_t nb_vectors;
+
+	assert(*vectors != NULL);
+
+	nb_vectors = talloc_array_length(*vectors);
+
+	/* Sanity checks.  */
+	assert(nb_vectors > 0);
+	assert((*vectors)[nb_vectors - 1].type == AT_NULL);
+
+	tmp = talloc_realloc(talloc_parent(*vectors), *vectors, ElfAuxVector, nb_vectors + 1);
+	if (tmp == NULL)
+		return -ENOMEM;
+	*vectors = tmp;
+
+	/* Replace the sentinel with the new vector.  */
+	(*vectors)[nb_vectors - 1].type  = type;
+	(*vectors)[nb_vectors - 1].value = value;
+
+	/* Restore the sentinel.  */
+	(*vectors)[nb_vectors].type  = AT_NULL;
+	(*vectors)[nb_vectors].value = 0;
+
+	return 0;
+}
+
+/**
+ * Get the address of the the ELF auxiliary vectors table for the
+ * given @tracee.  This function returns 0 if an error occurred.
+ */
+word_t get_elf_aux_vectors_address(const Tracee *tracee)
+{
+	word_t address;
+	word_t data;
+
+	/* Sanity check: this works only in execve sysexit.  */
+	assert(IS_IN_SYSEXIT2(tracee, PR_execve));
+
+	/* Right after execve, the stack layout is:
+	 *
+	 *     argc, argv[0], ..., 0, envp[0], ..., 0, auxv[0].type, auxv[0].value, ..., 0, 0
+	 */
+	address = peek_reg(tracee, CURRENT, STACK_POINTER);
+
+	/* Read: argc */
+	data = peek_word(tracee, address);
+	if (errno != 0)
+		return 0;
+
+	/* Skip: argc, argv, 0 */
+	address += (1 + data + 1) * sizeof_word(tracee);
+
+	/* Skip: envp, 0 */
+	do {
+		data = peek_word(tracee, address);
+		if (errno != 0)
+			return 0;
+		address += sizeof_word(tracee);
+	} while (data != 0);
+
+	return address;
+}
+
+/**
+ * Fetch ELF auxiliary vectors stored at the given @address in
+ * @tracee's memory.  This function returns NULL if an error occurred,
+ * otherwise it returns a pointer to the new vectors, in an ABI
+ * independent form (the Talloc parent of this pointer is
+ * @tracee->ctx).
+ */
+ElfAuxVector *fetch_elf_aux_vectors(const Tracee *tracee, word_t address)
+{
+	ElfAuxVector *vectors = NULL;
+	ElfAuxVector vector;
+	int status;
+
+	/* It is assumed the sentinel always exists.  */
+	vectors = talloc_array(tracee->ctx, ElfAuxVector, 1);
+	if (vectors == NULL)
+		return NULL;
+	vectors[0].type  = AT_NULL;
+	vectors[0].value = 0;
+
+	while (1) {
+		vector.type = peek_word(tracee, address);
+		if (errno != 0)
+			return NULL;
+		address += sizeof_word(tracee);
+
+		if (vector.type == AT_NULL)
+			break; /* Already added.  */
+
+		vector.value = peek_word(tracee, address);
+		if (errno != 0)
+			return NULL;
+		address += sizeof_word(tracee);
+
+		status = add_elf_aux_vector(&vectors, vector.type, vector.value);
+		if (status < 0)
+			return NULL;
+	}
+
+	return vectors;
+}
+
+/**
+ * Push ELF auxiliary @vectors to the given @address in @tracee's
+ * memory.  This function returns -errno if an error occurred,
+ * otherwise 0.
+ */
+int push_elf_aux_vectors(const Tracee* tracee, ElfAuxVector *vectors, word_t address)
+{
+	size_t i;
+
+	for (i = 0; vectors[i].type != AT_NULL; i++) {
+		poke_word(tracee, address, vectors[i].type);
+		if (errno != 0)
+			return -errno;
+		address += sizeof_word(tracee);
+
+		poke_word(tracee, address, vectors[i].value);
+		if (errno != 0)
+			return -errno;
+		address += sizeof_word(tracee);
+	}
+
+	poke_word(tracee, address, AT_NULL);
+	if (errno != 0)
+		return -errno;
+	address += sizeof_word(tracee);
+
+	poke_word(tracee, address, 0);
+	if (errno != 0)
+		return -errno;
+	address += sizeof_word(tracee);
+
+	return 0;
+}
diff --git a/5.1.0/src/execve/auxv.h b/5.1.0/src/execve/auxv.h
new file mode 100644
index 0000000..12ceb0d
--- /dev/null
+++ b/5.1.0/src/execve/auxv.h
@@ -0,0 +1,39 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef AUXV
+#define AUXV
+
+#include "tracee/tracee.h"
+#include "arch.h"
+
+typedef struct elf_aux_vector {
+	word_t type;
+	word_t value;
+} ElfAuxVector;
+
+extern word_t get_elf_aux_vectors_address(const Tracee *tracee);
+extern ElfAuxVector *fetch_elf_aux_vectors(const Tracee *tracee, word_t address);
+extern int add_elf_aux_vector(ElfAuxVector **vectors, word_t type, word_t value);
+extern int push_elf_aux_vectors(const Tracee* tracee, ElfAuxVector *vectors, word_t address);
+
+#endif /* AUXV */
diff --git a/5.1.0/src/execve/elf.c b/5.1.0/src/execve/elf.c
new file mode 100644
index 0000000..c87ae0e
--- /dev/null
+++ b/5.1.0/src/execve/elf.c
@@ -0,0 +1,178 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <fcntl.h>  /* open(2), */
+#include <unistd.h> /* read(2), close(2), */
+#include <errno.h>  /* EACCES, ENOTSUP, */
+#include <stdint.h> /* UINT64_MAX, */
+#include <limits.h> /* PATH_MAX, */
+#include <string.h> /* str*(3), memcpy(3), */
+#include <assert.h> /* assert(3), */
+#include <talloc.h> /* talloc_*, */
+#include <stdbool.h> /* bool, true, false,  */
+
+#include "execve/elf.h"
+#include "tracee/tracee.h"
+#include "cli/note.h"
+#include "arch.h"
+
+#include "compat.h"
+
+/**
+ * Open the ELF file @t_path and extract its header into @elf_header.
+ * This function returns -errno if an error occured, otherwise the
+ * file descriptor for @t_path.
+ */
+int open_elf(const char *t_path, ElfHeader *elf_header)
+{
+	int fd;
+	int status;
+
+	/*
+	 * Read the ELF header.
+	 */
+
+	fd = open(t_path, O_RDONLY);
+	if (fd < 0)
+		return -errno;
+
+	/* Check if it is an ELF file.  */
+	status = read(fd, elf_header, sizeof(ElfHeader));
+	if (status < 0) {
+		status = -errno;
+		goto end;
+	}
+	if ((size_t) status < sizeof(ElfHeader)
+	    || ELF_IDENT(*elf_header, 0) != 0x7f
+	    || ELF_IDENT(*elf_header, 1) != 'E'
+	    || ELF_IDENT(*elf_header, 2) != 'L'
+	    || ELF_IDENT(*elf_header, 3) != 'F') {
+		status = -ENOEXEC;
+		goto end;
+	}
+
+	/* Check if it is a known class (32-bit or 64-bit).  */
+	if (   !IS_CLASS32(*elf_header)
+	    && !IS_CLASS64(*elf_header)) {
+		status = -ENOEXEC;
+		goto end;
+	}
+
+	status = 0;
+end:
+	/* Delayed error handling.  */
+	if (status < 0) {
+		close(fd);
+		return status;
+	}
+
+	return fd;
+}
+
+/**
+ * Invoke @callback(..., @data) for each program headers from the
+ * specified ELF file (referenced by @fd, with the given @elf_header).
+ * This function returns -errno if an error occured, or it returns
+ * immediately the value != 0 returned by @callback, otherwise 0.
+ */
+int iterate_program_headers(const Tracee *tracee, int fd, const ElfHeader *elf_header,
+			program_headers_iterator_t callback, void *data)
+{
+	ProgramHeader program_header;
+
+	uint64_t elf_phoff;
+	uint16_t elf_phentsize;
+	uint16_t elf_phnum;
+
+	int status;
+	int i;
+
+	/* Get class-specific fields. */
+	elf_phnum     = ELF_FIELD(*elf_header, phnum);
+	elf_phentsize = ELF_FIELD(*elf_header, phentsize);
+	elf_phoff     = ELF_FIELD(*elf_header, phoff);
+
+	/*
+	 * Some sanity checks regarding the current
+	 * support of the ELF specification in PRoot.
+	 */
+
+	if (elf_phnum >= 0xffff) {
+		note(tracee, WARNING, INTERNAL, "%d: big PH tables are not yet supported.", fd);
+		return -ENOTSUP;
+	}
+
+	if (!KNOWN_PHENTSIZE(*elf_header, elf_phentsize)) {
+		note(tracee, WARNING, INTERNAL, "%d: unsupported size of program header.", fd);
+		return -ENOTSUP;
+	}
+
+	status = (int) lseek(fd, elf_phoff, SEEK_SET);
+	if (status < 0)
+		return -errno;
+
+	for (i = 0; i < elf_phnum; i++) {
+		status = read(fd, &program_header, elf_phentsize);
+		if (status != elf_phentsize)
+			return (status < 0 ? -errno : -ENOTSUP);
+
+		status = callback(elf_header, &program_header, data);
+		if (status != 0)
+			return status;
+	}
+
+	return 0;
+}
+
+/**
+ * Check if @host_path is an ELF file for the host architecture.
+ */
+bool is_host_elf(const Tracee *tracee, const char *host_path)
+{
+	int host_elf_machine[] = HOST_ELF_MACHINE;
+	static int force_foreign = -1;
+	ElfHeader elf_header;
+	uint16_t elf_machine;
+	int fd;
+	int i;
+
+	if (force_foreign < 0)
+		force_foreign = (getenv("PROOT_FORCE_FOREIGN_BINARY") != NULL);
+
+	if (force_foreign > 0 || !tracee->qemu)
+		return false;
+
+	fd = open_elf(host_path, &elf_header);
+	if (fd < 0)
+		return false;
+	close(fd);
+
+	elf_machine = ELF_FIELD(elf_header, machine);
+	for (i = 0; host_elf_machine[i] != 0; i++) {
+		if (host_elf_machine[i] == elf_machine) {
+			VERBOSE(tracee, 1, "'%s' is a host ELF", host_path);
+			return true;
+		}
+	}
+
+	return false;
+}
diff --git a/5.1.0/src/execve/elf.h b/5.1.0/src/execve/elf.h
new file mode 100644
index 0000000..83e70ac
--- /dev/null
+++ b/5.1.0/src/execve/elf.h
@@ -0,0 +1,178 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef ELF_H
+#define ELF_H
+
+#define EI_NIDENT 16
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct {
+	unsigned char e_ident[EI_NIDENT];
+	uint16_t      e_type;
+	uint16_t      e_machine;
+	uint32_t      e_version;
+	uint32_t      e_entry;
+	uint32_t      e_phoff;
+	uint32_t      e_shoff;
+	uint32_t      e_flags;
+	uint16_t      e_ehsize;
+	uint16_t      e_phentsize;
+	uint16_t      e_phnum;
+	uint16_t      e_shentsize;
+	uint16_t      e_shnum;
+	uint16_t      e_shstrndx;
+} ElfHeader32;
+
+typedef struct {
+	unsigned char e_ident[EI_NIDENT];
+	uint16_t      e_type;
+	uint16_t      e_machine;
+	uint32_t      e_version;
+	uint64_t      e_entry;
+	uint64_t      e_phoff;
+	uint64_t      e_shoff;
+	uint32_t      e_flags;
+	uint16_t      e_ehsize;
+	uint16_t      e_phentsize;
+	uint16_t      e_phnum;
+	uint16_t      e_shentsize;
+	uint16_t      e_shnum;
+	uint16_t      e_shstrndx;
+} ElfHeader64;
+
+typedef union {
+	ElfHeader32 class32;
+	ElfHeader64 class64;
+} ElfHeader;
+
+typedef struct {
+	uint32_t   p_type;
+	uint32_t   p_offset;
+	uint32_t   p_vaddr;
+	uint32_t   p_paddr;
+	uint32_t   p_filesz;
+	uint32_t   p_memsz;
+	uint32_t   p_flags;
+	uint32_t   p_align;
+} ProgramHeader32;
+
+typedef struct {
+	uint32_t   p_type;
+	uint32_t   p_flags;
+	uint64_t   p_offset;
+	uint64_t   p_vaddr;
+	uint64_t   p_paddr;
+	uint64_t   p_filesz;
+	uint64_t   p_memsz;
+	uint64_t   p_align;
+} ProgramHeader64;
+
+typedef union {
+	ProgramHeader32 class32;
+	ProgramHeader64 class64;
+} ProgramHeader;
+
+/* Object type:  */
+#define ET_REL          1
+#define ET_EXEC         2
+#define ET_DYN          3
+#define ET_CORE         4
+
+/* Segment flags:  */
+#define PF_X 1
+#define PF_W 2
+#define PF_R 4
+
+typedef enum {
+	PT_LOAD    = 1,
+	PT_DYNAMIC = 2,
+	PT_INTERP  = 3
+} SegmentType;
+
+typedef struct {
+	int32_t d_tag;
+	uint32_t d_val;
+} DynamicEntry32;
+
+typedef struct {
+	int64_t d_tag;
+	uint64_t d_val;
+} DynamicEntry64;
+
+typedef union {
+	DynamicEntry32 class32;
+	DynamicEntry64 class64;
+} DynamicEntry;
+
+typedef enum {
+	DT_STRTAB  = 5,
+	DT_RPATH   = 15,
+	DT_RUNPATH = 29
+} DynamicType;
+
+/* The following macros are also compatible with ELF 64-bit. */
+#define ELF_IDENT(header, index) (header).class32.e_ident[(index)]
+#define ELF_CLASS(header) ELF_IDENT(header, 4)
+#define IS_CLASS32(header) (ELF_CLASS(header) == 1)
+#define IS_CLASS64(header) (ELF_CLASS(header) == 2)
+
+/* Helper to access a @field of the structure ElfHeaderXX. */
+#define ELF_FIELD(header, field)		\
+	(IS_CLASS64(header)			\
+	 ? (header).class64. e_ ## field	\
+	 : (header).class32. e_ ## field)
+
+/* Helper to access a @field of the structure ProgramHeaderXX */
+#define PROGRAM_FIELD(ehdr, phdr, field)	\
+	(IS_CLASS64(ehdr)			\
+	 ? (phdr).class64. p_ ## field		\
+	 : (phdr).class32. p_ ## field)
+
+/* Helper to access a @field of the structure DynamicEntryXX */
+#define DYNAMIC_FIELD(ehdr, dynent, field)	\
+	(IS_CLASS64(ehdr)			\
+	 ? (dynent).class64. d_ ## field	\
+	 : (dynent).class32. d_ ## field)
+
+#define KNOWN_PHENTSIZE(header, size)					\
+	(   (IS_CLASS32(header) && (size) == sizeof(ProgramHeader32)) \
+	 || (IS_CLASS64(header) && (size) == sizeof(ProgramHeader64)))
+
+#define IS_POSITION_INDENPENDANT(elf_header)	\
+	(ELF_FIELD((elf_header), type) == ET_DYN)
+
+#include "tracee/tracee.h"
+
+extern int open_elf(const char *t_path, ElfHeader *elf_header);
+
+extern bool is_host_elf(const Tracee *tracee, const char *t_path);
+
+typedef int (* program_headers_iterator_t)(const ElfHeader *elf_header,
+					const ProgramHeader *program_header, void *data);
+
+extern int iterate_program_headers(const Tracee *tracee, int fd, const ElfHeader *elf_header,
+				program_headers_iterator_t callback, void *data);
+
+#endif /* ELF_H */
diff --git a/5.1.0/src/execve/enter.c b/5.1.0/src/execve/enter.c
new file mode 100644
index 0000000..4c163a1
--- /dev/null
+++ b/5.1.0/src/execve/enter.c
@@ -0,0 +1,667 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>  /* lstat(2), lseek(2), */
+#include <sys/stat.h>   /* lstat(2), lseek(2), fchmod(2), */
+#include <unistd.h>     /* access(2), lstat(2), close(2), read(2), */
+#include <errno.h>      /* E*, */
+#include <assert.h>     /* assert(3), */
+#include <talloc.h>     /* talloc*, */
+#include <sys/mman.h>   /* PROT_*, */
+#include <string.h>     /* strlen(3), strcpy(3), */
+#include <stdlib.h>     /* getenv(3), */
+#include <stdio.h>      /* fwrite(3), */
+#include <assert.h>     /* assert(3), */
+
+#include "execve/execve.h"
+#include "execve/shebang.h"
+#include "execve/aoxp.h"
+#include "execve/ldso.h"
+#include "execve/elf.h"
+#include "path/path.h"
+#include "path/temp.h"
+#include "tracee/tracee.h"
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "arch.h"
+#include "cli/note.h"
+
+#define P(a) PROGRAM_FIELD(load_info->elf_header, *program_header, a)
+
+/**
+ * Add @program_header (type PT_LOAD) to @load_info->mappings.  This
+ * function returns -errno if an error occured, otherwise it returns
+ * 0.
+ */
+static int add_mapping(const Tracee *tracee UNUSED, LoadInfo *load_info,
+		const ProgramHeader *program_header)
+{
+	size_t index;
+	word_t start_address;
+	word_t end_address;
+	static word_t page_size = 0;
+	static word_t page_mask = 0;
+
+	if (page_size == 0) {
+		page_size = sysconf(_SC_PAGE_SIZE);
+		if ((int) page_size <= 0)
+			page_size = 0x1000;
+		page_mask = ~(page_size - 1);
+	}
+
+	if (load_info->mappings == NULL)
+		index = 0;
+	else
+		index = talloc_array_length(load_info->mappings);
+
+	load_info->mappings = talloc_realloc(load_info, load_info->mappings, Mapping, index + 1);
+	if (load_info->mappings == NULL)
+		return -ENOMEM;
+
+	start_address = P(vaddr) & page_mask;
+	end_address   = (P(vaddr) + P(filesz) + page_size) & page_mask;
+
+	load_info->mappings[index].fd     = -1; /* Unknown yet.  */
+	load_info->mappings[index].offset = P(offset) & page_mask;
+	load_info->mappings[index].addr   = start_address;
+	load_info->mappings[index].length = end_address - start_address;
+	load_info->mappings[index].flags  = MAP_PRIVATE | MAP_FIXED;
+	load_info->mappings[index].prot   =  ( (P(flags) & PF_R ? PROT_READ  : 0)
+					| (P(flags) & PF_W ? PROT_WRITE : 0)
+					| (P(flags) & PF_X ? PROT_EXEC  : 0));
+
+	/* "If the segment's memory size p_memsz is larger than the
+	 * file size p_filesz, the "extra" bytes are defined to hold
+	 * the value 0 and to follow the segment's initialized area."
+	 * -- man 7 elf.  */
+	if (P(memsz) > P(filesz)) {
+		/* How many extra bytes in the current page?  */
+		load_info->mappings[index].clear_length = end_address - P(vaddr) - P(filesz);
+
+		/* Create new pages for the remaining extra bytes.  */
+		start_address = end_address;
+		end_address   = (P(vaddr) + P(memsz) + page_size) & page_mask;
+		if (end_address > start_address) {
+			index++;
+			load_info->mappings = talloc_realloc(load_info, load_info->mappings,
+							Mapping, index + 1);
+			if (load_info->mappings == NULL)
+				return -ENOMEM;
+
+			load_info->mappings[index].fd     = -1;  /* Anonymous.  */
+			load_info->mappings[index].offset =  0;
+			load_info->mappings[index].addr   = start_address;
+			load_info->mappings[index].length = end_address - start_address;
+			load_info->mappings[index].clear_length = 0;
+			load_info->mappings[index].flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
+			load_info->mappings[index].prot   = load_info->mappings[index - 1].prot;
+		}
+	}
+	else
+		load_info->mappings[index].clear_length = 0;
+
+	return 0;
+}
+
+/**
+ * Translate @user_path into @host_path and check if this latter exists, is
+ * executable and is a regular file.  This function returns -errno if
+ * an error occured, 0 otherwise.
+ */
+int translate_and_check_exec(Tracee *tracee, char host_path[PATH_MAX], const char *user_path)
+{
+	struct stat statl;
+	int status;
+
+	if (user_path[0] == '\0')
+		return -ENOEXEC;
+
+	status = translate_path(tracee, host_path, AT_FDCWD, user_path, true);
+	if (status < 0)
+		return status;
+
+	status = access(host_path, F_OK);
+	if (status < 0)
+		return -ENOENT;
+
+	status = access(host_path, X_OK);
+	if (status < 0)
+		return -EACCES;
+
+	status = lstat(host_path, &statl);
+	if (status < 0)
+		return -EPERM;
+
+	return 0;
+}
+
+/**
+ * Add @program_header (type PT_INTERP) to @load_info->interp.  This
+ * function returns -errno if an error occured, otherwise it returns
+ * 0.
+ */
+static int add_interp(Tracee *tracee, int fd, LoadInfo *load_info,
+		const ProgramHeader *program_header)
+{
+	char host_path[PATH_MAX];
+	char *user_path;
+	int status;
+
+	/* Only one PT_INTERP segment is allowed.  */
+	if (load_info->interp != NULL)
+		return -EINVAL;
+
+	load_info->interp = talloc_zero(load_info, LoadInfo);
+	if (load_info->interp == NULL)
+		return -ENOMEM;
+
+	user_path = talloc_size(tracee->ctx, P(filesz) + 1);
+	if (user_path == NULL)
+		return -ENOMEM;
+
+	/* Remember pread(2) doesn't change the
+	 * current position in the file.  */
+	status = pread(fd, user_path, P(filesz), P(offset));
+	if ((size_t) status != P(filesz)) /* Unexpected size.  */
+		status = -EACCES;
+	if (status < 0)
+		return status;
+
+	user_path[P(filesz)] = '\0';
+
+	/* When a QEMU command was specified:
+	 *
+	 * - if it's a foreign binary we are reading the ELF
+	 *   interpreter of QEMU instead.
+	 *
+	 * - if it's a host binary, we are reading its ELF
+	 *   interpreter.
+	 *
+	 * In both case, it lies in "/host-rootfs" from a guest
+	 * point-of-view.  */
+	if (tracee->qemu != NULL && user_path[0] == '/') {
+		user_path = talloc_asprintf(tracee->ctx, "%s%s", HOST_ROOTFS, user_path);
+		if (user_path == NULL)
+			return -ENOMEM;
+	}
+
+	status = translate_and_check_exec(tracee, host_path, user_path);
+	if (status < 0)
+		return status;
+
+	load_info->interp->host_path = talloc_strdup(load_info->interp, host_path);
+	if (load_info->interp->host_path == NULL)
+		return -ENOMEM;
+
+	load_info->interp->user_path = talloc_strdup(load_info->interp, user_path);
+	if (load_info->interp->user_path == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+#undef P
+
+struct add_load_info_data {
+	LoadInfo *load_info;
+	Tracee *tracee;
+	int fd;
+};
+
+/**
+ * This function is a program header iterator.  It invokes
+ * add_mapping() or add_interp(), according to the type of
+ * @program_header.  This function returns -errno if an error
+ * occurred, otherwise 0.
+ */
+static int add_load_info(const ElfHeader *elf_header,
+			const ProgramHeader *program_header, void *data_)
+{
+	struct add_load_info_data *data = data_;
+	int status;
+
+	switch (PROGRAM_FIELD(*elf_header, *program_header, type)) {
+	case PT_LOAD:
+		status = add_mapping(data->tracee, data->load_info, program_header);
+		if (status < 0)
+			return status;
+		break;
+
+	case PT_INTERP:
+		status = add_interp(data->tracee, data->fd, data->load_info, program_header);
+		if (status < 0)
+			return status;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * Extract the load info from @load->host_path.  This function returns
+ * -errno if an error occured, otherwise it returns 0.
+ */
+static int extract_load_info(Tracee *tracee, LoadInfo *load_info)
+{
+	struct add_load_info_data data;
+	int fd = -1;
+	int status;
+
+	assert(load_info != NULL);
+	assert(load_info->host_path != NULL);
+
+	fd = open_elf(load_info->host_path, &load_info->elf_header);
+	if (fd < 0)
+		return fd;
+
+	/* Sanity check.  */
+	switch (ELF_FIELD(load_info->elf_header, type)) {
+	case ET_EXEC:
+	case ET_DYN:
+		break;
+
+	default:
+		status = -EINVAL;
+		goto end;
+	}
+
+	data.load_info = load_info;
+	data.tracee    = tracee;
+	data.fd        = fd;
+
+	status = iterate_program_headers(tracee, fd, &load_info->elf_header, add_load_info, &data);
+end:
+	if (fd >= 0)
+		close(fd);
+
+	return status;
+}
+
+/**
+ * Add @load_base to each adresses of @load_info.
+ */
+static void add_load_base(LoadInfo *load_info, word_t load_base)
+{
+	size_t nb_mappings;
+	size_t i;
+
+	nb_mappings = talloc_array_length(load_info->mappings);
+	for (i = 0; i < nb_mappings; i++)
+		load_info->mappings[i].addr += load_base;
+
+	if (IS_CLASS64(load_info->elf_header))
+		load_info->elf_header.class64.e_entry += load_base;
+	else
+		load_info->elf_header.class32.e_entry += load_base;
+}
+
+/**
+ * Compute the final load address for each position independant
+ * objects of @tracee.
+ *
+ * TODO: support for ASLR.
+ */
+static void compute_load_addresses(Tracee *tracee)
+{
+	if (IS_POSITION_INDENPENDANT(tracee->load_info->elf_header)
+	    && tracee->load_info->mappings[0].addr == 0) {
+#if defined(HAS_LOADER_32BIT)
+		if (IS_CLASS32(tracee->load_info->elf_header))
+			add_load_base(tracee->load_info, EXEC_PIC_ADDRESS_32);
+		else
+#endif
+		add_load_base(tracee->load_info, EXEC_PIC_ADDRESS);
+	}
+
+	/* Nothing more to do?  */
+	if (tracee->load_info->interp == NULL)
+		return;
+
+	if (IS_POSITION_INDENPENDANT(tracee->load_info->interp->elf_header)
+	    && tracee->load_info->interp->mappings[0].addr == 0) {
+#if defined(HAS_LOADER_32BIT)
+		if (IS_CLASS32(tracee->load_info->elf_header))
+			add_load_base(tracee->load_info->interp, INTERP_PIC_ADDRESS_32);
+		else
+#endif
+		add_load_base(tracee->load_info->interp, INTERP_PIC_ADDRESS);
+	}
+}
+
+/**
+ * Expand in argv[] and envp[] the runner for @user_path, if needed.
+ * This function returns -errno if an error occurred, otherwise 0.  On
+ * success, both @host_path and @user_path point to the program to
+ * execute (respectively from host and guest point-of-views), and both
+ * @tracee's argv[] (pointed to by SYSARG_2) @tracee's envp[] (pointed
+ * to by SYSARG_3) are correctly updated.
+ */
+static int expand_runner(Tracee* tracee, char host_path[PATH_MAX], char user_path[PATH_MAX])
+{
+	ArrayOfXPointers *envp;
+	char *argv0;
+	int status;
+
+	/* Execution of host programs when QEMU is in use relies on
+	 * LD_ environment variables.  */
+	status = fetch_array_of_xpointers(tracee, &envp, SYSARG_3, 0);
+	if (status < 0)
+		return status;
+
+	/* Environment variables should be compared with the "name"
+	 * part of the "name=value" string format.  */
+	envp->compare_xpointee = (compare_xpointee_t) compare_xpointee_env;
+
+	/* No need to adjust argv[] if it's a host binary (a.k.a
+	 * mixed-mode).  */
+	if (!is_host_elf(tracee, host_path)) {
+		ArrayOfXPointers *argv;
+		size_t nb_qemu_args;
+		size_t i;
+
+		status = fetch_array_of_xpointers(tracee, &argv, SYSARG_2, 0);
+		if (status < 0)
+			return status;
+
+		status = read_xpointee_as_string(argv, 0, &argv0);
+		if (status < 0)
+			return status;
+
+		/* Assuming PRoot was invoked this way:
+		 *
+		 *     proot -q 'qemu-arm -cpu cortex-a9' ...
+		 *
+		 * a call to:
+		 *
+		 *     execve("/bin/true", { "true", NULL }, ...)
+		 *
+		 * becomes:
+		 *
+		 *     execve("/usr/bin/qemu",
+		 *           { "qemu", "-cpu", "cortex-a9", "-0", "true", "/bin/true", NULL }, ...)
+		 */
+
+		nb_qemu_args = talloc_array_length(tracee->qemu) - 1;
+		status = resize_array_of_xpointers(argv, 1, nb_qemu_args + 2);
+		if (status < 0)
+			return status;
+
+		for (i = 0; i < nb_qemu_args; i++) {
+			status = write_xpointee(argv, i, tracee->qemu[i]);
+			if (status < 0)
+				return status;
+		}
+
+		status = write_xpointees(argv, i, 3, "-0", argv0, user_path);
+		if (status < 0)
+			return status;
+
+		/* Ensure LD_ features should not be applied to QEMU
+		 * iteself.  */
+		status = ldso_env_passthru(tracee, envp, argv, "-E", "-U", i);
+		if (status < 0)
+			return status;
+
+		status = push_array_of_xpointers(argv, SYSARG_2);
+		if (status < 0)
+			return status;
+
+		/* Launch the runner in lieu of the initial
+		 * program. */
+		assert(strlen(tracee->qemu[0]) + strlen(HOST_ROOTFS) < PATH_MAX);
+		assert(tracee->qemu[0][0] == '/');
+
+		strcpy(host_path, tracee->qemu[0]);
+
+		strcpy(user_path, HOST_ROOTFS);
+		strcat(user_path, host_path);
+	}
+
+	/* Provide information to the host dynamic linker to find host
+	 * libraries (remember the guest root file-system contains
+	 * libraries for the guest architecture only).  */
+	status = rebuild_host_ldso_paths(tracee, host_path, envp);
+	if (status < 0)
+		return status;
+
+	status = push_array_of_xpointers(envp, SYSARG_3);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+extern unsigned char _binary_loader_exe_start;
+extern unsigned char _binary_loader_exe_end;
+
+extern unsigned char WEAK _binary_loader_m32_exe_start;
+extern unsigned char WEAK _binary_loader_m32_exe_end;
+
+/**
+ * Extract the built-in loader.  This function returns NULL if an
+ * error occurred, otherwise it returns the path to the extracted
+ * loader.  Note: @tracee is only used for notification purpose.
+ */
+static char *extract_loader(const Tracee *tracee, bool wants_32bit_version)
+{
+	char path[PATH_MAX];
+	size_t status2;
+	void *start;
+	size_t size;
+	int status;
+	int fd;
+
+	char *loader_path = NULL;
+	FILE *file = NULL;
+
+	file = open_temp_file(NULL, "prooted");
+	if (file == NULL)
+		goto end;
+	fd = fileno(file);
+
+	if (wants_32bit_version) {
+		start = (void *) &_binary_loader_m32_exe_start;
+		size  = (size_t)(&_binary_loader_m32_exe_end-&_binary_loader_m32_exe_start);
+	}
+	else {
+		start = (void *) &_binary_loader_exe_start;
+		size  = (size_t) (&_binary_loader_exe_end-&_binary_loader_exe_start);
+	}
+
+	status2 = write(fd, start, size);
+	if (status2 != size) {
+		note(tracee, ERROR, SYSTEM, "can't write the loader");
+		goto end;
+	}
+
+	status = fchmod(fd, S_IRUSR|S_IXUSR);
+	if (status < 0) {
+		note(tracee, ERROR, SYSTEM, "can't change loader permissions (u+rx)");
+		goto end;
+	}
+
+	status = readlink_proc_pid_fd(getpid(), fd, path);
+	if (status < 0) {
+		note(tracee, ERROR, INTERNAL, "can't retrieve loader path (/proc/self/fd/)");
+		goto end;
+	}
+
+	loader_path = talloc_strdup(talloc_autofree_context(), path);
+	if (loader_path == NULL) {
+		note(tracee, ERROR, INTERNAL, "can't allocate memory");
+		goto end;
+	}
+
+	if (tracee->verbose >= 2)
+		note(tracee, INFO, INTERNAL, "loader: %s", loader_path);
+
+end:
+	if (file != NULL) {
+		status = fclose(file);
+		if (status < 0)
+			note(tracee, WARNING, SYSTEM, "can't close loader file");
+	}
+
+	return loader_path;
+}
+
+/**
+ * Get the path to the loader for the given @tracee.  This function
+ * returns NULL if an error occurred.
+ */
+static inline const char *get_loader_path(const Tracee *tracee)
+{
+	static char *loader_path = NULL;
+
+#if defined(HAS_LOADER_32BIT)
+	static char *loader32_path = NULL;
+
+	if (IS_CLASS32(tracee->load_info->elf_header)) {
+		loader32_path = loader32_path ?: getenv("PROOT_LOADER_32") ?: extract_loader(tracee, true);
+		return loader32_path;
+	}
+	else
+#endif
+	{
+		loader_path = loader_path ?: getenv("PROOT_LOADER") ?: extract_loader(tracee, false);
+		return loader_path;
+	}
+}
+
+/**
+ * Extract all the information that will be required by
+ * translate_load_*().  This function returns -errno if an error
+ * occured, otherwise 0.
+ */
+int translate_execve_enter(Tracee *tracee)
+{
+	char user_path[PATH_MAX];
+	char host_path[PATH_MAX];
+	char new_exe[PATH_MAX];
+	char *raw_path;
+	const char *loader_path;
+	int status;
+
+	if (IS_NOTIFICATION_PTRACED_LOAD_DONE(tracee)) {
+		/* Syscalls can now be reported to its ptracer.  */
+		tracee->as_ptracee.ignore_loader_syscalls = false;
+
+		/* Cancel this spurious execve, it was only used as a
+		 * notification.  */
+		set_sysnum(tracee, PR_void);
+		return 0;
+	}
+
+	status = get_sysarg_path(tracee, user_path, SYSARG_1);
+	if (status < 0)
+		return status;
+
+	/* Remember the user path before it is overwritten by
+	 * expand_shebang().  This "raw" path is useful to fix the
+	 * value of AT_EXECFN and /proc/{@tracee->pid}/comm.  */
+	raw_path = talloc_strdup(tracee->ctx, user_path);
+	if (raw_path == NULL)
+		return -ENOMEM;
+
+	status = expand_shebang(tracee, host_path, user_path);
+	if (status < 0)
+		/* The Linux kernel actually returns -EACCES when
+		 * trying to execute a directory.  */
+		return status == -EISDIR ? -EACCES : status;
+
+	/* user_path is modified only if there's an interpreter
+	 * (ie. for a script or with qemu).  */
+	if (status == 0 && tracee->qemu == NULL)
+		TALLOC_FREE(raw_path);
+
+	/* Remember the new value for "/proc/self/exe".  It points to
+	 * a canonicalized guest path, hence detranslate_path()
+	 * instead of using user_path directly.  */
+	strcpy(new_exe, host_path);
+	status = detranslate_path(tracee, new_exe, NULL);
+	if (status >= 0) {
+		talloc_unlink(tracee, tracee->new_exe);
+		tracee->new_exe = talloc_strdup(tracee, new_exe);
+	}
+	else
+		tracee->new_exe = NULL;
+
+	if (tracee->qemu != NULL) {
+		status = expand_runner(tracee, host_path, user_path);
+		if (status < 0)
+			return status;
+	}
+
+	TALLOC_FREE(tracee->load_info);
+
+	tracee->load_info = talloc_zero(tracee, LoadInfo);
+	if (tracee->load_info == NULL)
+		return -ENOMEM;
+
+	tracee->load_info->host_path = talloc_strdup(tracee->load_info, host_path);
+	if (tracee->load_info->host_path == NULL)
+		return -ENOMEM;
+
+	tracee->load_info->user_path = talloc_strdup(tracee->load_info, user_path);
+	if (tracee->load_info->user_path == NULL)
+		return -ENOMEM;
+
+	tracee->load_info->raw_path = (raw_path != NULL
+			? talloc_reparent(tracee->ctx, tracee->load_info, raw_path)
+			: talloc_reference(tracee->load_info, tracee->load_info->user_path));
+	if (tracee->load_info->raw_path == NULL)
+		return -ENOMEM;
+
+	status = extract_load_info(tracee, tracee->load_info);
+	if (status < 0)
+		return status;
+
+	if (tracee->load_info->interp != NULL) {
+		status = extract_load_info(tracee, tracee->load_info->interp);
+		if (status < 0)
+			return status;
+
+		/* An ELF interpreter is supposed to be
+		 * standalone.  */
+		if (tracee->load_info->interp->interp != NULL)
+			return -EINVAL;
+	}
+
+	compute_load_addresses(tracee);
+
+	/* Execute the loader instead of the program.  */
+	loader_path = get_loader_path(tracee);
+	if (loader_path == NULL)
+		return -ENOENT;
+
+	status = set_sysarg_path(tracee, loader_path, SYSARG_1);
+	if (status < 0)
+		return status;
+
+	/* Mask to its ptracer syscalls performed by the loader.  */
+	tracee->as_ptracee.ignore_loader_syscalls = true;
+
+	return 0;
+}
diff --git a/5.1.0/src/execve/execve.h b/5.1.0/src/execve/execve.h
new file mode 100644
index 0000000..2296094
--- /dev/null
+++ b/5.1.0/src/execve/execve.h
@@ -0,0 +1,63 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef EXECVE_H
+#define EXECVE_H
+
+#include <linux/limits.h>    /* PATH_MAX, */
+
+#include "tracee/tracee.h"
+#include "execve/elf.h"
+#include "arch.h"
+
+extern int translate_execve_enter(Tracee *tracee);
+extern void translate_execve_exit(Tracee *tracee);
+extern int translate_and_check_exec(Tracee *tracee, char host_path[PATH_MAX], const char *user_path);
+
+typedef struct mapping {
+	word_t addr;
+	word_t length;
+	word_t clear_length;
+	word_t prot;
+	word_t flags;
+	word_t fd;
+	word_t offset;
+} Mapping;
+
+typedef struct load_info {
+	char *host_path;
+	char *user_path;
+	char *raw_path;
+	Mapping *mappings;
+	ElfHeader elf_header;
+
+	struct load_info *interp;
+} LoadInfo;
+
+#define IS_NOTIFICATION_PTRACED_LOAD_DONE(tracee) (			\
+		(tracee)->as_ptracee.ptracer != NULL			\
+		&& peek_reg((tracee), CURRENT, SYSARG_1) == (word_t) 1	\
+		&& peek_reg((tracee), CURRENT, SYSARG_4) == (word_t) 2	\
+		&& peek_reg((tracee), CURRENT, SYSARG_5) == (word_t) 3	\
+		&& peek_reg((tracee), CURRENT, SYSARG_6) == (word_t) 4)
+
+#endif /* EXECVE_H */
diff --git a/5.1.0/src/execve/exit.c b/5.1.0/src/execve/exit.c
new file mode 100644
index 0000000..576fb03
--- /dev/null
+++ b/5.1.0/src/execve/exit.c
@@ -0,0 +1,445 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/auxvec.h>  /* AT_*,  */
+#include <talloc.h>     /* talloc*, */
+#include <sys/mman.h>   /* MAP_*, */
+#include <assert.h>     /* assert(3), */
+#include <string.h>     /* strlen(3), strerror(3), */
+#include <strings.h>    /* bzero(3), */
+#include <signal.h>     /* kill(2), SIG*, */
+#include <unistd.h>     /* write(2), */
+#include <errno.h>      /* E*, */
+
+#include "execve/execve.h"
+#include "execve/elf.h"
+#include "loader/script.h"
+#include "tracee/reg.h"
+#include "tracee/abi.h"
+#include "tracee/mem.h"
+#include "syscall/sysnum.h"
+#include "execve/auxv.h"
+#include "path/binding.h"
+#include "path/temp.h"
+#include "cli/note.h"
+
+
+/**
+ * Fill @path with the content of @vectors, formatted according to
+ * @ptracee's current ABI.
+ */
+static int fill_file_with_auxv(const Tracee *ptracee, const char *path,
+			const ElfAuxVector *vectors)
+{
+	const ssize_t current_sizeof_word = sizeof_word(ptracee);
+	ssize_t status;
+	int fd = -1;
+	int i;
+
+	fd = open(path, O_WRONLY);
+	if (fd < 0)
+		return -1;
+
+	i = 0;
+	do {
+		status = write(fd, &vectors[i].type, current_sizeof_word);
+		if (status < current_sizeof_word) {
+			status = -1;
+			goto end;
+		}
+
+		status = write(fd, &vectors[i].value, current_sizeof_word);
+		if (status < current_sizeof_word) {
+			status = -1;
+			goto end;
+		}
+	} while (vectors[i++].type != AT_NULL);
+
+	status = 0;
+end:
+	if (fd >= 0)
+		(void) close(fd);
+
+	return status;
+}
+
+/**
+ * Bind content of @vectors over /proc/{@ptracee->pid}/auxv.  This
+ * function returns -1 if an error occurred, otherwise 0.
+ */
+static int bind_proc_pid_auxv(const Tracee *ptracee)
+{
+	word_t vectors_address;
+	ElfAuxVector *vectors;
+
+	const char *guest_path;
+	const char *host_path;
+	Binding *binding;
+	int status;
+
+	vectors_address = get_elf_aux_vectors_address(ptracee);
+	if (vectors_address == 0)
+		return -1;
+
+	vectors = fetch_elf_aux_vectors(ptracee, vectors_address);
+	if (vectors == NULL)
+		return -1;
+
+	/* Path to these ELF auxiliary vectors.  */
+	guest_path = talloc_asprintf(ptracee->ctx, "/proc/%d/auxv", ptracee->pid);
+	if (guest_path == NULL)
+		return -1;
+
+	/* Remove binding to this path, if any.  It contains ELF
+	 * auxiliary vectors of the previous execve(2).  */
+	binding = get_binding(ptracee, GUEST, guest_path);
+	if (binding != NULL && compare_paths(binding->guest.path, guest_path) == PATHS_ARE_EQUAL) {
+		remove_binding_from_all_lists(ptracee, binding);
+		TALLOC_FREE(binding);
+	}
+
+	host_path = create_temp_file(ptracee->ctx, "auxv");
+	if (host_path == NULL)
+		return -1;
+
+	status = fill_file_with_auxv(ptracee, host_path, vectors);
+	if (status < 0)
+		return -1;
+
+	/* Note: this binding will be removed once ptracee gets freed.  */
+	binding = insort_binding3(ptracee, ptracee->life_context, host_path, guest_path);
+	if (binding == NULL)
+		return -1;
+
+	/* This temporary file (host_path) will be removed once the
+	 * binding is freed.  */
+	talloc_reparent(ptracee->ctx, binding, host_path);
+
+	return 0;
+}
+
+/**
+ * Convert @mappings into load @script statements at the given @cursor
+ * position.  This function returns the new cursor position.
+ */
+static void *transcript_mappings(void *cursor, const Mapping *mappings)
+{
+	size_t nb_mappings;
+	size_t i;
+
+	nb_mappings = talloc_array_length(mappings);
+	for (i = 0; i < nb_mappings; i++) {
+		LoadStatement *statement = cursor;
+
+		if ((mappings[i].flags & MAP_ANONYMOUS) != 0)
+			statement->action = LOAD_ACTION_MMAP_ANON;
+		else
+			statement->action = LOAD_ACTION_MMAP_FILE;
+
+		statement->mmap.addr   = mappings[i].addr;
+		statement->mmap.length = mappings[i].length;
+		statement->mmap.prot   = mappings[i].prot;
+		statement->mmap.offset = mappings[i].offset;
+		statement->mmap.clear_length = mappings[i].clear_length;
+
+		cursor += LOAD_STATEMENT_SIZE(*statement, mmap);
+	}
+
+	return cursor;
+}
+
+/**
+ * Convert @tracee->load_info into a load script, then transfer this
+ * latter into @tracee's memory.
+ */
+static int transfer_load_script(Tracee *tracee)
+{
+	const word_t stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER);
+	word_t entry_point;
+
+	size_t script_size;
+	size_t strings_size;
+	size_t string1_size;
+	size_t string2_size;
+	size_t string3_size;
+	size_t padding_size;
+
+	word_t string1_address;
+	word_t string2_address;
+	word_t string3_address;
+
+	void *buffer;
+	size_t buffer_size;
+
+	LoadStatement *statement;
+	void *cursor;
+	int status;
+
+	/* Strings addresses are required to generate the load script,
+	 * for "open" actions.  Since I want to generate it in one
+	 * pass, these strings will be put right below the current
+	 * stack pointer -- the only known adresses so far -- in the
+	 * "strings area".  */
+	string1_size = strlen(tracee->load_info->user_path) + 1;
+
+	string2_size = (tracee->load_info->interp == NULL ? 0
+			: strlen(tracee->load_info->interp->user_path) + 1);
+
+	string3_size = (tracee->load_info->raw_path == tracee->load_info->user_path ? 0
+			: strlen(tracee->load_info->raw_path) + 1);
+
+	/* A padding will be appended at the end of the load script
+	 * (a.k.a "strings area") to ensure this latter is aligned on
+	 * a word boundary, for sake of performance.  */
+	padding_size = (stack_pointer - string1_size - string2_size - string3_size)
+			% sizeof_word(tracee);
+
+	strings_size = string1_size + string2_size + string3_size + padding_size;
+	string1_address = stack_pointer - strings_size;
+	string2_address = stack_pointer - strings_size + string1_size;
+	string3_address = (string3_size == 0
+			? string1_address
+			: stack_pointer - strings_size + string1_size + string2_size);
+
+	/* Compute the size of the load script.  */
+	script_size =
+		LOAD_STATEMENT_SIZE(*statement, open)
+		+ (LOAD_STATEMENT_SIZE(*statement, mmap)
+			* talloc_array_length(tracee->load_info->mappings))
+		+ (tracee->load_info->interp == NULL ? 0
+			: LOAD_STATEMENT_SIZE(*statement, open)
+			+ (LOAD_STATEMENT_SIZE(*statement, mmap)
+				* talloc_array_length(tracee->load_info->interp->mappings)))
+		+ LOAD_STATEMENT_SIZE(*statement, start);
+
+	/* Allocate enough room for both the load script and the
+	 * strings area.  */
+	buffer_size = script_size + strings_size;
+	buffer = talloc_zero_size(tracee->ctx, buffer_size);
+	if (buffer == NULL)
+		return -ENOMEM;
+
+	cursor = buffer;
+
+	/* Load script statement: open.  */
+	statement = cursor;
+	statement->action = LOAD_ACTION_OPEN;
+	statement->open.string_address = string1_address;
+
+	cursor += LOAD_STATEMENT_SIZE(*statement, open);
+
+	/* Load script statements: mmap.  */
+	cursor = transcript_mappings(cursor, tracee->load_info->mappings);
+
+	if (tracee->load_info->interp != NULL) {
+		/* Load script statement: open.  */
+		statement = cursor;
+		statement->action = LOAD_ACTION_OPEN_NEXT;
+		statement->open.string_address = string2_address;
+
+		cursor += LOAD_STATEMENT_SIZE(*statement, open);
+
+		/* Load script statements: mmap.  */
+		cursor = transcript_mappings(cursor, tracee->load_info->interp->mappings);
+
+		entry_point = ELF_FIELD(tracee->load_info->interp->elf_header, entry);
+	}
+	else
+		entry_point = ELF_FIELD(tracee->load_info->elf_header, entry);
+
+	/* Load script statement: start.  */
+	statement = cursor;
+
+	/* Start of the program slightly differs when ptraced.  */
+	if (tracee->as_ptracee.ptracer != NULL)
+		statement->action = LOAD_ACTION_START_TRACED;
+	else
+		statement->action = LOAD_ACTION_START;
+
+	statement->start.stack_pointer = stack_pointer;
+	statement->start.entry_point   = entry_point;
+	statement->start.at_phent = ELF_FIELD(tracee->load_info->elf_header, phentsize);
+	statement->start.at_phnum = ELF_FIELD(tracee->load_info->elf_header, phnum);
+	statement->start.at_entry = ELF_FIELD(tracee->load_info->elf_header, entry);
+	statement->start.at_phdr  = ELF_FIELD(tracee->load_info->elf_header, phoff)
+				  + tracee->load_info->mappings[0].addr;
+	statement->start.at_execfn = string3_address;
+
+	cursor += LOAD_STATEMENT_SIZE(*statement, start);
+
+	/* Sanity check.  */
+	assert((uintptr_t) cursor - (uintptr_t) buffer == script_size);
+
+	/* Convert the load script to the expected format.  */
+	if (is_32on64_mode(tracee)) {
+		int i;
+		for (i = 0; buffer + i * sizeof(uint64_t) < cursor; i++)
+			((uint32_t *) buffer)[i] = ((uint64_t *) buffer)[i];
+	}
+
+	/* Concatenate the load script and the strings.  */
+	memcpy(cursor, tracee->load_info->user_path, string1_size);
+	cursor += string1_size;
+
+	if (string2_size != 0) {
+		memcpy(cursor, tracee->load_info->interp->user_path, string2_size);
+		cursor += string2_size;
+	}
+
+	if (string3_size != 0) {
+		memcpy(cursor, tracee->load_info->raw_path, string3_size);
+		cursor += string3_size;
+	}
+
+	/* Sanity check.  */
+	cursor += padding_size;
+	assert((uintptr_t) cursor - (uintptr_t) buffer == buffer_size);
+
+	/* Allocate enough room in tracee's memory for the load
+	 * script, and make the first user argument points to this
+	 * location.  Note that it is safe to update the stack pointer
+	 * manually since we are in execve sysexit.  However it should
+	 * be done before transfering data since the kernel might not
+	 * allow page faults below the stack pointer.  */
+	poke_reg(tracee, STACK_POINTER, stack_pointer - buffer_size);
+	poke_reg(tracee, USERARG_1, stack_pointer - buffer_size);
+
+	/* Copy everything in the tracee's memory at once.  */
+	status = write_data(tracee, stack_pointer - buffer_size, buffer, buffer_size);
+	if (status < 0)
+		return status;
+
+	/* Tracee's stack content is now as follow:
+	 *
+	 *   +------------+ <- initial stack pointer (higher address)
+	 *   |  padding   |
+	 *   +------------+
+	 *   |  string3   |
+	 *   +------------+
+	 *   |  string2   |
+	 *   +------------+
+	 *   |  string1   |
+	 *   +------------+
+	 *   |   start    |
+	 *   +------------+
+	 *   | mmap anon  |
+	 *   +------------+
+	 *   | mmap file  |
+	 *   +------------+
+	 *   | open next  |
+	 *   +------------+
+	 *   | mmap anon. |
+	 *   +------------+
+	 *   | mmap file  |
+	 *   +------------+
+	 *   |   open     |
+	 *   +------------+ <- stack pointer, sysarg1 (word aligned)
+	 */
+
+	/* Remember we are in the sysexit stage, so be sure the
+	 * current register values will be used as-is at the end.  */
+	save_current_regs(tracee, ORIGINAL);
+	tracee->_regs_were_changed = true;
+
+	return 0;
+}
+
+/**
+ * Start the loading of @tracee.  This function returns no error since
+ * it's either too late to do anything useful (the calling process is
+ * already replaced) or the error reported by the kernel
+ * (syscall_result < 0) will be propagated as-is.
+ */
+void translate_execve_exit(Tracee *tracee)
+{
+	word_t syscall_result;
+	int status;
+
+	if (IS_NOTIFICATION_PTRACED_LOAD_DONE(tracee)) {
+		/* Be sure not to confuse the ptracer with an
+		 * unexpected syscall/returned value.  */
+		poke_reg(tracee, SYSARG_RESULT, 0);
+		set_sysnum(tracee, PR_execve);
+
+		/* According to most ABIs, all registers have
+		 * undefined values at program startup except:
+		 *
+		 * - the stack pointer
+		 * - the instruction pointer
+		 * - the rtld_fini pointer
+		 * - the state flags
+		 */
+		poke_reg(tracee, STACK_POINTER, peek_reg(tracee, ORIGINAL, SYSARG_2));
+		poke_reg(tracee, INSTR_POINTER, peek_reg(tracee, ORIGINAL, SYSARG_3));
+		poke_reg(tracee, RTLD_FINI, 0);
+		poke_reg(tracee, STATE_FLAGS, 0);
+
+		/* Restore registers with their current values.  */
+		save_current_regs(tracee, ORIGINAL);
+		tracee->_regs_were_changed = true;
+
+		/* This is is required to make GDB work correctly
+		 * under PRoot, however it deserves to be used
+		 * unconditionally.  */
+		(void) bind_proc_pid_auxv(tracee);
+
+		/* If the PTRACE_O_TRACEEXEC option is *not* in effect
+		 * for the execing tracee, the kernel delivers an
+		 * extra SIGTRAP to the tracee after execve(2)
+		 * *returns*.  This is an ordinary signal (similar to
+		 * one which can be generated by "kill -TRAP"), not a
+		 * special kind of ptrace-stop.  Employing
+		 * PTRACE_GETSIGINFO for this signal returns si_code
+		 * set to 0 (SI_USER).  This signal may be blocked by
+		 * signal mask, and thus may be delivered (much)
+		 * later. -- man 2 ptrace
+		 *
+		 * This signal is delayed so far since the program was
+		 * not fully loaded yet; GDB would get "invalid
+		 * adress" errors otherwise.  */
+		if ((tracee->as_ptracee.options & PTRACE_O_TRACEEXEC) == 0)
+			kill(tracee->pid, SIGTRAP);
+
+		return;
+	}
+
+	syscall_result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+	if ((int) syscall_result < 0)
+		return;
+
+	/* Execve happened; commit the new "/proc/self/exe".  */
+	if (tracee->new_exe != NULL) {
+		(void) talloc_unlink(tracee, tracee->exe);
+		tracee->exe = talloc_reference(tracee, tracee->new_exe);
+		talloc_set_name_const(tracee->exe, "$exe");
+	}
+
+	/* New processes have no heap.  */
+	bzero(tracee->heap, sizeof(Heap));
+
+	/* Transfer the load script to the loader.  */
+	status = transfer_load_script(tracee);
+	if (status < 0)
+		note(tracee, ERROR, INTERNAL, "can't transfer load script: %s", strerror(-status));
+
+	return;
+}
diff --git a/5.1.0/src/execve/ldso.c b/5.1.0/src/execve/ldso.c
new file mode 100644
index 0000000..7285786
--- /dev/null
+++ b/5.1.0/src/execve/ldso.c
@@ -0,0 +1,569 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdbool.h> /* bool, true, false, */
+#include <string.h>  /* strlen(3), strcpy(3), strcat(3), strcmp(3), */
+#include <stdlib.h>  /* getenv(3), */
+#include <assert.h>  /* assert(3), */
+#include <errno.h>   /* ENOMEM, */
+#include <unistd.h>  /* close(2), */
+#include <linux/limits.h>  /* PATH_MAX, ARG_MAX, */
+
+#include "execve/ldso.h"
+#include "execve/elf.h"
+#include "execve/aoxp.h"
+#include "tracee/tracee.h"
+#include "cli/note.h"
+
+/**
+ * Check if the environment @variable has the given @name.
+ */
+bool is_env_name(const char *variable, const char *name)
+{
+	size_t length = strlen(name);
+
+	return (variable[0] == name[0]
+		&& length < strlen(variable)
+		&& variable[length] == '='
+		&& strncmp(variable, name, length) == 0);
+}
+
+/**
+ * This function returns 1 or 0 depending on the equivalence of the
+ * @reference environment variable and the one pointed to by the entry
+ * in @envp at the given @index, otherwise it returns -errno when an
+ * error occured.
+ */
+int compare_xpointee_env(ArrayOfXPointers *envp, size_t index, const char *reference)
+{
+	char *value;
+	int status;
+
+	assert(index < envp->length);
+
+	status = read_xpointee_as_string(envp, index, &value);
+	if (status < 0)
+		return status;
+
+	if (value == NULL)
+		return 0;
+
+	return (int)is_env_name(value, reference);
+}
+
+/**
+ * This function ensures that environment variables related to the
+ * dynamic linker are applied to the emulated program, not to QEMU
+ * itself.  For instance, let's say the user has entered the
+ * command-line below:
+ *
+ *     env LD_TRACE_LOADED_OBJECTS=1 /bin/ls
+ *
+ * It should be converted to:
+ *
+ *     qemu -E LD_TRACE_LOADED_OBJECTS=1 /bin/ls
+ *
+ * instead of:
+ *
+ *     env LD_TRACE_LOADED_OBJECTS=1 qemu /bin/ls
+ *
+ * Note that the LD_LIBRARY_PATH variable is always required to run
+ * QEMU (a host binary):
+ *
+ *     env LD_LIBRARY_PATH=... qemu -U LD_LIBRARY_PATH /bin/ls
+ *
+ * or when LD_LIBRARY_PATH was also specified by the user:
+ *
+ *     env LD_LIBRARY_PATH=... qemu -E LD_LIBRARY_PATH=... /bin/ls
+ *
+ * This funtion returns -errno if an error occured, otherwise 0.
+ */
+int ldso_env_passthru(const Tracee *tracee, ArrayOfXPointers *envp, ArrayOfXPointers *argv,
+		const char *define, const char *undefine, size_t offset)
+{
+	bool has_seen_library_path = false;
+	int status;
+	size_t i;
+
+	for (i = 0; i < envp->length; i++) {
+		bool is_known = false;
+		char *env;
+
+		status = read_xpointee_as_string(envp, i, &env);
+		if (status < 0)
+			return status;
+
+		/* Skip variables that do not start with "LD_".  */
+		if (env == NULL || strncmp(env, "LD_", sizeof("LD_") - 1) != 0)
+			continue;
+
+		/* When a host program executes a guest program, use
+		 * the value of LD_LIBRARY_PATH as it was before being
+		 * swapped by the mixed-mode support.  */
+		if (   tracee->host_ldso_paths != NULL
+		    && tracee->guest_ldso_paths != NULL
+		    && is_env_name(env, "LD_LIBRARY_PATH")
+		    && strcmp(env, tracee->host_ldso_paths) == 0)
+			env = (char *) tracee->guest_ldso_paths;
+
+#define PASSTHRU(check, name)						\
+		if (is_env_name(env, name)) {				\
+			check |= true;					\
+			/* Errors are not fatal here.  */		\
+			status = resize_array_of_xpointers(argv, offset, 2);	\
+			if (status >= 0) {				\
+				status = write_xpointees(argv, offset, 2, define, env); \
+				if (status < 0)				\
+					return status;			\
+			}						\
+			write_xpointee(envp, i, "");			\
+			continue;					\
+		}							\
+
+		PASSTHRU(has_seen_library_path, "LD_LIBRARY_PATH");
+		PASSTHRU(is_known, "LD_PRELOAD");
+		PASSTHRU(is_known, "LD_BIND_NOW");
+		PASSTHRU(is_known, "LD_TRACE_LOADED_OBJECTS");
+		PASSTHRU(is_known, "LD_AOUT_LIBRARY_PATH");
+		PASSTHRU(is_known, "LD_AOUT_PRELOAD");
+		PASSTHRU(is_known, "LD_AUDIT");
+		PASSTHRU(is_known, "LD_BIND_NOT");
+		PASSTHRU(is_known, "LD_DEBUG");
+		PASSTHRU(is_known, "LD_DEBUG_OUTPUT");
+		PASSTHRU(is_known, "LD_DYNAMIC_WEAK");
+		PASSTHRU(is_known, "LD_HWCAP_MASK");
+		PASSTHRU(is_known, "LD_KEEPDIR");
+		PASSTHRU(is_known, "LD_NOWARN");
+		PASSTHRU(is_known, "LD_ORIGIN_PATH");
+		PASSTHRU(is_known, "LD_POINTER_GUARD");
+		PASSTHRU(is_known, "LD_PROFILE");
+		PASSTHRU(is_known, "LD_PROFILE_OUTPUT");
+		PASSTHRU(is_known, "LD_SHOW_AUXV");
+		PASSTHRU(is_known, "LD_USE_LOAD_BIAS");
+		PASSTHRU(is_known, "LD_VERBOSE");
+		PASSTHRU(is_known, "LD_WARN");
+	}
+
+	if (!has_seen_library_path) {
+		/* Errors are not fatal here.  */
+		status = resize_array_of_xpointers(argv, offset, 2);
+		if (status >= 0) {
+			status = write_xpointees(argv, offset, 2, undefine, "LD_LIBRARY_PATH");
+			if (status < 0)
+				return status;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Add to @host_ldso_paths the list of @paths prefixed with the path
+ * to the host rootfs.
+ */
+static int add_host_ldso_paths(char host_ldso_paths[ARG_MAX], const char *paths)
+{
+	char *cursor1;
+	const char *cursor2;
+
+	cursor1 = host_ldso_paths + strlen(host_ldso_paths);
+	cursor2 = paths;
+
+	do {
+		bool is_absolute;
+		size_t length1;
+		size_t length2 = strcspn(cursor2, ":");
+
+		is_absolute = (*cursor2 == '/');
+
+		length1 = 1 + length2;
+		if (is_absolute)
+			length1 += strlen(HOST_ROOTFS);
+
+		/* Check there's enough room.  */
+		if (cursor1 + length1 >= host_ldso_paths + ARG_MAX)
+			return -ENOEXEC;
+
+		if (cursor1 != host_ldso_paths) {
+			strcpy(cursor1, ":");
+			cursor1++;
+		}
+
+		/* Since we are executing a host binary under a
+		 * QEMUlated environment, we have to access its
+		 * library paths through the "host-rootfs" binding.
+		 * Technically it means a path like "/lib" is accessed
+		 * as "${HOST_ROOTFS}/lib" to avoid conflict with the
+		 * guest "/lib".  */
+		if (is_absolute) {
+			strcpy(cursor1, HOST_ROOTFS);
+			cursor1 += strlen(HOST_ROOTFS);
+		}
+
+		strncpy(cursor1, cursor2, length2);
+		cursor1 += length2;
+
+		cursor2 += length2 + 1;
+	} while (*(cursor2 - 1) != '\0');
+
+	*cursor1 = '\0';
+
+	return 0;
+}
+
+struct find_program_header_data {
+	ProgramHeader *program_header;
+	SegmentType type;
+	uint64_t address;
+};
+
+/**
+ * This function is a program header iterator.  It stops the iteration
+ * (by returning 1) once it has found a program header that matches
+ * @data.  This function returns -errno if an error occurred,
+ * otherwise 0 or 1.
+ */
+static int find_program_header(const ElfHeader *elf_header,
+			const ProgramHeader *program_header, void *data_)
+{
+	struct find_program_header_data *data = data_;
+
+	if (PROGRAM_FIELD(*elf_header, *program_header, type) == data->type) {
+		uint64_t start;
+		uint64_t end;
+
+		memcpy(data->program_header, program_header, sizeof(ProgramHeader));
+
+		if (data->address == (uint64_t) -1)
+			return 1;
+
+		start = PROGRAM_FIELD(*elf_header, *program_header, vaddr);
+		end   = start + PROGRAM_FIELD(*elf_header, *program_header, memsz);
+
+		if (start < end
+			&& data->address >= start
+			&& data->address <= end)
+			return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Add to @xpaths the paths (':'-separated list) from the file
+ * referenced by @fd at the given @offset.  This function returns
+ * -errno if an error occured, otherwise 0.
+ */
+static int add_xpaths(const Tracee *tracee, int fd, uint64_t offset, char **xpaths)
+{
+	char *paths = NULL;
+	char *tmp;
+
+	size_t length;
+	size_t size;
+	int status;
+
+	status = (int) lseek(fd, offset, SEEK_SET);
+	if (status < 0)
+		return -errno;
+
+	/* Read the complete list of paths.  */
+	length = 0;
+	paths = NULL;
+	do {
+		size = length + 1024;
+
+		tmp = talloc_realloc(tracee->ctx, paths, char, size);
+		if (!tmp)
+			return -ENOMEM;
+		paths = tmp;
+
+		status = read(fd, paths + length, 1024);
+		if (status < 0)
+			return status;
+
+		length += strnlen(paths + length, 1024);
+	} while (length == size);
+
+	/* Concatene this list of paths to xpaths.  */
+	if (!*xpaths) {
+		*xpaths = talloc_array(tracee->ctx, char, length + 1);
+		if (!*xpaths)
+			return -ENOMEM;
+
+		strcpy(*xpaths, paths);
+	}
+	else {
+		length += strlen(*xpaths);
+		length++; /* ":" separator */
+
+		tmp = talloc_realloc(tracee->ctx, *xpaths, char, length + 1);
+		if (!tmp)
+			return -ENOMEM;
+		*xpaths = tmp;
+
+		strcat(*xpaths, ":");
+		strcat(*xpaths, paths);
+	}
+
+	/* I don't know if DT_R*PATH entries are unique.  In
+	 * doubt I support multiple entries.  */
+	return 0;
+}
+
+/**
+ * Put the RPATH and RUNPATH dynamic entries from the file referenced
+ * by @fd -- which has the provided @elf_header -- in @rpaths and
+ * @runpaths respectively.  This function returns -errno if an error
+ * occured, otherwise 0.
+ */
+static int read_ldso_rpaths(const Tracee* tracee, int fd, const ElfHeader *elf_header,
+		char **rpaths, char **runpaths)
+{
+	ProgramHeader dynamic_segment;
+	ProgramHeader strtab_segment;
+	struct find_program_header_data data;
+	uint64_t strtab_address = (uint64_t) -1;
+	off_t strtab_offset;
+	int status;
+	size_t i;
+
+	uint64_t offsetof_dynamic_segment;
+	uint64_t sizeof_dynamic_segment;
+	size_t sizeof_dynamic_entry;
+
+	data.program_header = &dynamic_segment;
+	data.type = PT_DYNAMIC;
+	data.address = (uint64_t) -1;
+
+	status = iterate_program_headers(tracee, fd, elf_header, find_program_header, &data);
+	if (status <= 0)
+		return status;
+
+	offsetof_dynamic_segment = PROGRAM_FIELD(*elf_header, dynamic_segment, offset);
+	sizeof_dynamic_segment   = PROGRAM_FIELD(*elf_header, dynamic_segment, filesz);
+
+	if (IS_CLASS32(*elf_header))
+		sizeof_dynamic_entry = sizeof(DynamicEntry32);
+	else
+		sizeof_dynamic_entry = sizeof(DynamicEntry64);
+
+	if (sizeof_dynamic_segment % sizeof_dynamic_entry != 0)
+		return -ENOEXEC;
+
+/**
+ * Invoke @embedded_code on each dynamic entry of the given @type.
+ */
+#define FOREACH_DYNAMIC_ENTRY(type, embedded_code)					\
+	for (i = 0; i < sizeof_dynamic_segment / sizeof_dynamic_entry; i++) {		\
+		DynamicEntry dynamic_entry;						\
+		uint64_t value;								\
+											\
+		/* embedded_code may change the file offset.  */			\
+		status = (int) lseek(fd, offsetof_dynamic_segment + i * sizeof_dynamic_entry, \
+				SEEK_SET);						\
+		if (status < 0)								\
+			return -errno;							\
+											\
+		status = read(fd, &dynamic_entry, sizeof_dynamic_entry);		\
+		if (status < 0)								\
+			return status;							\
+											\
+		if (DYNAMIC_FIELD(*elf_header, dynamic_entry, tag) != type)		\
+			continue;							\
+											\
+		value =	DYNAMIC_FIELD(*elf_header, dynamic_entry, val);			\
+											\
+		embedded_code								\
+	}
+
+	/* Get the address of the *first* string table.  The ELF
+	 * specification doesn't mention if it may have several string
+	 * table references.  */
+	FOREACH_DYNAMIC_ENTRY(DT_STRTAB, {
+		strtab_address = value;
+		break;
+	})
+
+	if (strtab_address == (uint64_t) -1)
+		return 0;
+
+	data.program_header = &strtab_segment;
+	data.type = PT_LOAD;
+	data.address = strtab_address;
+
+	/* Search the program header that contains the given string table.  */
+	status = iterate_program_headers(tracee, fd, elf_header, find_program_header, &data);
+	if (status < 0)
+		return status;
+
+	strtab_offset = PROGRAM_FIELD(*elf_header, strtab_segment, offset)
+		+ (strtab_address - PROGRAM_FIELD(*elf_header, strtab_segment, vaddr));
+
+	FOREACH_DYNAMIC_ENTRY(DT_RPATH,	{
+		if (strtab_offset < 0 || (uint64_t) strtab_offset > UINT64_MAX - value)
+			return -ENOEXEC;
+
+		status = add_xpaths(tracee, fd, strtab_offset + value, rpaths);
+		if (status < 0)
+			return status;
+	})
+
+	FOREACH_DYNAMIC_ENTRY(DT_RUNPATH, {
+		if (strtab_offset < 0 || (uint64_t) strtab_offset > UINT64_MAX - value)
+			return -ENOEXEC;
+
+		status = add_xpaths(tracee, fd, strtab_offset + value, runpaths);
+		if (status < 0)
+			return status;
+	})
+
+#undef FOREACH_DYNAMIC_ENTRY
+
+	return 0;
+}
+
+/**
+ * Rebuild the variable LD_LIBRARY_PATH in @envp for the program
+ * @host_path according to its RPATH, RUNPATH, and the initial
+ * LD_LIBRARY_PATH.  This function returns -errno if an error occured,
+ * 1 if RPATH/RUNPATH entries were found, 0 otherwise.
+ */
+int rebuild_host_ldso_paths(Tracee *tracee, const char host_path[PATH_MAX], ArrayOfXPointers *envp)
+{
+	static char *initial_ldso_paths = NULL;
+	ElfHeader elf_header;
+
+	char host_ldso_paths[ARG_MAX] = "";
+	bool rpath_found = false;
+
+	char *rpaths   = NULL;
+	char *runpaths = NULL;
+
+	size_t length1;
+	size_t length2;
+
+	size_t index;
+	int status;
+	int fd;
+
+	fd = open_elf(host_path, &elf_header);
+	if (fd < 0)
+		return fd;
+
+	status = read_ldso_rpaths(tracee, fd, &elf_header, &rpaths, &runpaths);
+	close(fd);
+	if (status < 0)
+		return status;
+
+	/* 1. DT_RPATH  */
+	if (rpaths && !runpaths) {
+		status = add_host_ldso_paths(host_ldso_paths, rpaths);
+		if (status < 0)
+			return 0; /* Not fatal.  */
+		rpath_found = true;
+	}
+
+	/* 2. LD_LIBRARY_PATH  */
+	if (initial_ldso_paths == NULL)
+		initial_ldso_paths = strdup(getenv("LD_LIBRARY_PATH") ?: "/");
+	if (initial_ldso_paths != NULL && initial_ldso_paths[0] != '\0') {
+		status = add_host_ldso_paths(host_ldso_paths, initial_ldso_paths);
+		if (status < 0)
+			return 0; /* Not fatal.  */
+	}
+
+	/* 3. DT_RUNPATH  */
+	if (runpaths) {
+		status = add_host_ldso_paths(host_ldso_paths, runpaths);
+		if (status < 0)
+			return 0; /* Not fatal.  */
+		rpath_found = true;
+	}
+
+	/* 4. /etc/ld.so.cache NYI.  */
+
+	/* 5. /lib[32|64], /usr/lib[32|64] + /usr/local/lib[32|64]  */
+	/* 6. /lib, /usr/lib + /usr/local/lib  */
+	if (IS_CLASS32(elf_header))
+		status = add_host_ldso_paths(host_ldso_paths,
+#if defined(ARCH_X86) || defined(ARCH_X86_64)
+					"/lib/i386-linux-gnu:/usr/lib/i386-linux-gnu:"
+#endif
+					"/lib32:/usr/lib32:/usr/local/lib32"
+					":/lib:/usr/lib:/usr/local/lib");
+	else
+		status = add_host_ldso_paths(host_ldso_paths,
+#if defined(ARCH_X86_64)
+					"/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:"
+#endif
+					"/lib64:/usr/lib64:/usr/local/lib64"
+					":/lib:/usr/lib:/usr/local/lib");
+	if (status < 0)
+		return 0; /* Not fatal.  */
+
+	status = find_xpointee(envp, "LD_LIBRARY_PATH");
+	if (status < 0)
+		return 0; /* Not fatal.  */
+	index = (size_t) status;
+
+	if (index == envp->length) {
+		/* Allocate a new entry at the end of envp[] when
+		 * LD_LIBRARY_PATH was not found.  */
+
+		index = (envp->length > 0 ? envp->length - 1 : 0);
+		status = resize_array_of_xpointers(envp, index, 1);
+		if (status < 0)
+			return 0; /* Not fatal.  */
+	}
+	else if (tracee->guest_ldso_paths == NULL) {
+		/* Remember guest LD_LIBRARY_PATH in order to restore
+		 * it when a host program will execute a guest
+		 * program.  */
+		char *env;
+
+		/* Errors are not fatal here.  */
+		status = read_xpointee_as_string(envp, index, &env);
+		if (status >= 0)
+			tracee->guest_ldso_paths = talloc_strdup(tracee, env);
+	}
+
+	/* Forge the new LD_LIBRARY_PATH variable from
+	 * host_ldso_paths.  */
+	length1 = strlen("LD_LIBRARY_PATH=");
+	length2 = strlen(host_ldso_paths);
+	if (ARG_MAX - length2 - 1 < length1)
+		return 0; /* Not fatal.  */
+
+	memmove(host_ldso_paths + length1, host_ldso_paths, length2 + 1);
+	memcpy(host_ldso_paths, "LD_LIBRARY_PATH=" , length1);
+
+	write_xpointee(envp, index, host_ldso_paths);
+
+	/* The guest LD_LIBRARY_PATH will be restored only if the host
+	 * program didn't change it explicitly, so remember its
+	 * initial value.  */
+	if (tracee->host_ldso_paths == NULL)
+		tracee->host_ldso_paths = talloc_strdup(tracee, host_ldso_paths);
+
+	return (int) rpath_found;
+}
diff --git a/5.1.0/src/execve/ldso.h b/5.1.0/src/execve/ldso.h
new file mode 100644
index 0000000..b2406da
--- /dev/null
+++ b/5.1.0/src/execve/ldso.h
@@ -0,0 +1,42 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef LDSO_H
+#define LDSO_H
+
+#include <linux/limits.h>
+#include <stdbool.h>
+
+#include "execve/aoxp.h"
+#include "execve/elf.h"
+
+extern int ldso_env_passthru(const Tracee *tracee, ArrayOfXPointers *envp, ArrayOfXPointers *argv,
+			const char *define, const char *undefine, size_t offset);
+
+extern int rebuild_host_ldso_paths(Tracee *tracee, const char t_program[PATH_MAX],
+				ArrayOfXPointers *envp);
+
+extern int compare_xpointee_env(ArrayOfXPointers *envp, size_t index, const char *name);
+
+extern bool is_env_name(const char *variable, const char *name);
+
+#endif /* LDSO_H */
diff --git a/5.1.0/src/execve/shebang.c b/5.1.0/src/execve/shebang.c
new file mode 100644
index 0000000..bbffac8
--- /dev/null
+++ b/5.1.0/src/execve/shebang.c
@@ -0,0 +1,307 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>     /* open(2), */
+#include <sys/stat.h>      /* open(2), */
+#include <fcntl.h>         /* open(2), */
+#include <linux/limits.h>  /* PATH_MAX, */
+#include <linux/binfmts.h> /* BINPRM_BUF_SIZE, */
+#include <unistd.h>        /* read(2), close(2), */
+#include <errno.h>         /* -E*, */
+#include <sys/param.h>     /* MAXSYMLINKS, */
+#include <stdbool.h>       /* bool, */
+#include <assert.h>        /* assert(3), */
+
+#include "execve/shebang.h"
+#include "execve/execve.h"
+#include "execve/aoxp.h"
+#include "tracee/tracee.h"
+#include "attribute.h"
+
+/**
+ * Extract into @user_path and @argument the shebang from @host_path.
+ * This function returns -errno if an error occured, 1 if a shebang
+ * was found and extracted, otherwise 0.
+ *
+ * Extract from "man 2 execve":
+ *
+ *     On Linux, the entire string following the interpreter name is
+ *     passed as a *single* argument to the interpreter, and this
+ *     string can include white space.
+ */
+static int extract_shebang(const Tracee *tracee UNUSED, const char *host_path,
+		char user_path[PATH_MAX], char argument[BINPRM_BUF_SIZE])
+{
+	char tmp2[2];
+	char tmp;
+
+	size_t current_length;
+	size_t i;
+
+	int status;
+	int fd;
+
+	/* Assumption.  */
+	assert(BINPRM_BUF_SIZE < PATH_MAX);
+
+	argument[0] = '\0';
+
+	/* Inspect the executable.  */
+	fd = open(host_path, O_RDONLY);
+	if (fd < 0)
+		return -errno;
+
+	status = read(fd, tmp2, 2 * sizeof(char));
+	if (status < 0) {
+		status = -errno;
+		goto end;
+	}
+	if ((size_t) status < 2 * sizeof(char)) { /* EOF */
+		status = 0;
+		goto end;
+	}
+
+	/* Check if it really is a script text. */
+	if (tmp2[0] != '#' || tmp2[1] != '!') {
+		status = 0;
+		goto end;
+	}
+	current_length = 2;
+	user_path[0] = '\0';
+
+	/* Skip leading spaces. */
+	do {
+		status = read(fd, &tmp, sizeof(char));
+		if (status < 0) {
+			status = -errno;
+			goto end;
+		}
+		if ((size_t) status < sizeof(char)) { /* EOF */
+			status = -ENOEXEC;
+			goto end;
+		}
+
+		current_length++;
+	} while ((tmp == ' ' || tmp == '\t') && current_length < BINPRM_BUF_SIZE);
+
+	/* Slurp the interpreter path until the first space or end-of-line. */
+	for (i = 0; current_length < BINPRM_BUF_SIZE; current_length++, i++) {
+		switch (tmp) {
+		case ' ':
+		case '\t':
+			/* Remove spaces in between the interpreter
+			 * and the hypothetical argument. */
+			user_path[i] = '\0';
+			break;
+
+		case '\n':
+		case '\r':
+			/* There is no argument. */
+			user_path[i] = '\0';
+			argument[0] = '\0';
+			status = 1;
+			goto end;
+
+		default:
+			/* There is an argument if the previous
+			 * character in user_path[] is '\0'. */
+			if (i > 1 && user_path[i - 1] == '\0')
+				goto argument;
+			else
+				user_path[i] = tmp;
+			break;
+		}
+
+		status = read(fd, &tmp, sizeof(char));
+		if (status < 0) {
+			status = -errno;
+			goto end;
+		}
+		if ((size_t) status < sizeof(char)) { /* EOF */
+			user_path[i] = '\0';
+			argument[0] = '\0';
+			status = 1;
+			goto end;
+		}
+	}
+
+	/* The interpreter path is too long, truncate it. */
+	user_path[i] = '\0';
+	argument[0] = '\0';
+	status = 1;
+	goto end;
+
+argument:
+
+	/* Slurp the argument until the end-of-line. */
+	for (i = 0; current_length < BINPRM_BUF_SIZE; current_length++, i++) {
+		switch (tmp) {
+		case '\n':
+		case '\r':
+			argument[i] = '\0';
+
+			/* Remove trailing spaces. */
+			for (i--; i > 0 && (argument[i] == ' ' || argument[i] == '\t'); i--)
+				argument[i] = '\0';
+
+			status = 1;
+			goto end;
+
+		default:
+			argument[i] = tmp;
+			break;
+		}
+
+		status = read(fd, &tmp, sizeof(char));
+		if (status < 0) {
+			status = -errno;
+			goto end;
+		}
+		if ((size_t) status < sizeof(char)) { /* EOF */
+			argument[0] = '\0';
+			status = 1;
+			goto end;
+		}
+	}
+
+	/* The argument is too long, truncate it. */
+	argument[i] = '\0';
+	status = 1;
+
+end:
+	close(fd);
+
+	/* Did an error occur or isn't a script? */
+	if (status <= 0)
+		return status;
+
+	return 1;
+}
+
+/**
+ * Expand in argv[] the shebang of @user_path, if any.  This function
+ * returns -errno if an error occurred, 1 if a shebang was found and
+ * extracted, otherwise 0.  On success, both @host_path and @user_path
+ * point to the program to execute (respectively from host
+ * point-of-view and as-is), and @tracee's argv[] (pointed to by
+ * SYSARG_2) is correctly updated.
+ */
+int expand_shebang(Tracee *tracee, char host_path[PATH_MAX], char user_path[PATH_MAX])
+{
+	ArrayOfXPointers *argv = NULL;
+	bool has_shebang = false;
+
+	char argument[BINPRM_BUF_SIZE];
+	int status;
+	size_t i;
+
+	/* "The interpreter must be a valid pathname for an executable
+	 *  which is not itself a script [1].  If the filename
+	 *  argument of execve() specifies an interpreter script, then
+	 *  interpreter will be invoked with the following arguments:
+	 *
+	 *    interpreter [optional-arg] filename arg...
+	 *
+	 * where arg...  is the series of words pointed to by the argv
+	 * argument of execve()." -- man 2 execve
+	 *
+	 * [1]: as of this writing (3.10.17) this is true only for the
+	 *      ELF interpreter; ie. a script can use a script as
+	 *      interpreter.
+	 */
+	for (i = 0; i < MAXSYMLINKS; i++) {
+		char *old_user_path;
+
+		/* Translate this path (user -> host), then check it is executable.  */
+		status = translate_and_check_exec(tracee, host_path, user_path);
+		if (status < 0)
+			return status;
+
+		/* Remember the initial user path.  */
+		old_user_path = talloc_strdup(tracee->ctx, user_path);
+		if (old_user_path == NULL)
+			return -ENOMEM;
+
+		/* Extract into user_path and argument the shebang from host_path.  */
+		status = extract_shebang(tracee, host_path, user_path, argument);
+		if (status < 0)
+			return status;
+
+		/* No more shebang.  */
+		if (status == 0)
+			break;
+		has_shebang = true;
+
+		/* Translate new path (user -> host), then check it is executable.  */
+		status = translate_and_check_exec(tracee, host_path, user_path);
+		if (status < 0)
+			return status;
+
+		/* Fetch argv[] only on demand.  */
+		if (argv == NULL) {
+			status = fetch_array_of_xpointers(tracee, &argv, SYSARG_2, 0);
+			if (status < 0)
+				return status;
+		}
+
+		/* Assuming the shebang of "script" is "#!/bin/sh -x",
+		 * a call to:
+		 *
+		 *     execve("./script", { "script.sh", NULL }, ...)
+		 *
+		 * becomes:
+		 *
+		 *     execve("/bin/sh", { "/bin/sh", "-x", "./script", NULL }, ...)
+		 *
+		 * See commit 8c8fbe85 about "argv->length == 1".  */
+		if (argument[0] != '\0') {
+			status = resize_array_of_xpointers(argv, 0, 2 + (argv->length == 1));
+			if (status < 0)
+				return status;
+
+			status = write_xpointees(argv, 0, 3, user_path, argument, old_user_path);
+			if (status < 0)
+				return status;
+		}
+		else {
+			status = resize_array_of_xpointers(argv, 0, 1 + (argv->length == 1));
+			if (status < 0)
+				return status;
+
+			status = write_xpointees(argv, 0, 2, user_path, old_user_path);
+			if (status < 0)
+				return status;
+		}
+	}
+
+	if (i == MAXSYMLINKS)
+		return -ELOOP;
+
+	/* Push argv[] only on demand.  */
+	if (argv != NULL) {
+		status = push_array_of_xpointers(argv, SYSARG_2);
+		if (status < 0)
+			return status;
+	}
+
+	return (has_shebang ? 1 : 0);
+}
diff --git a/5.1.0/src/execve/shebang.h b/5.1.0/src/execve/shebang.h
new file mode 100644
index 0000000..1834a98
--- /dev/null
+++ b/5.1.0/src/execve/shebang.h
@@ -0,0 +1,32 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef SHEBANG_H
+#define SHEBANG_H
+
+#include <linux/limits.h>  /* PATH_MAX, ARG_MAX, */
+
+#include "tracee/tracee.h"
+
+extern int expand_shebang(Tracee *tracee, char host_path[PATH_MAX], char user_path[PATH_MAX]);
+
+#endif /* SHEBANG_H */
diff --git a/5.1.0/src/extension/care/archive.c b/5.1.0/src/extension/care/archive.c
new file mode 100644
index 0000000..414d05c
--- /dev/null
+++ b/5.1.0/src/extension/care/archive.c
@@ -0,0 +1,540 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>   /* open(2), lseek(2), */
+#include <sys/stat.h>    /* open(2), */
+#include <fcntl.h>       /* open(2), */
+#include <unistd.h>      /* read(2), readlink(2), close(2), lseek(2), */
+#include <errno.h>       /* errno, EACCES, */
+#include <assert.h>      /* assert(3), */
+#include <linux/limits.h> /* PATH_MAX, */
+#include <string.h>      /* strlen(3), strcmp(3), */
+#include <stdbool.h>     /* bool, true, false, */
+#include <talloc.h>      /* talloc(3), */
+#include <archive.h>     /* archive_*(3), */
+#include <archive_entry.h> /* archive_entry*(3), */
+
+#include "extension/care/archive.h"
+#include "tracee/tracee.h"
+#include "cli/note.h"
+
+typedef struct {
+	int (*set_format)(struct archive *);
+	int (*add_filter)(struct archive *);
+	int hardlink_resolver_strategy;
+	const char *options;
+	enum { NOT_SPECIAL = 0, SELF_EXTRACTING, RAW } special;
+} Format;
+
+/**
+ * Move *@cursor backward -- within in the given @string -- if it
+ * reads @suffix once moved.
+ */
+static bool slurp_suffix(const char *string, const char **cursor, const char *suffix)
+{
+	size_t length;
+
+	length = strlen(suffix);
+	if (*cursor - length < string || strncmp(*cursor - length, suffix, length) != 0)
+		return false;
+
+	*cursor -= length;
+	return true;
+}
+
+/**
+ * Detect the expected format for the given @string.  This function
+ * returns -1 if an error occurred, otherwise it returns 0 and updates
+ * the @format structure and @suffix_length with the number of
+ * characters that describes the parsed format.
+ */
+static int parse_suffix(const Tracee* tracee, Format *format,
+			const char *string, size_t *suffix_length)
+{
+	const char *cursor;
+	bool found;
+
+	bool no_wrapper_found = false;
+	bool no_filter_found  = false;
+	bool no_format_found  = false;
+
+	cursor = string + strlen(string);
+	bzero(format, sizeof(Format));
+
+/* parse_special: */
+
+	found = slurp_suffix(string, &cursor, "/");
+	if (found)
+		goto end;
+
+	found = slurp_suffix(string, &cursor, ".raw");
+	if (found) {
+		format->special = SELF_EXTRACTING;
+		goto parse_filter;
+	}
+
+	found = slurp_suffix(string, &cursor, ".bin");
+	if (found) {
+#if defined(CARE_BINARY_IS_PORTABLE)
+		format->special = SELF_EXTRACTING;
+		goto parse_filter;
+#else
+		note(tracee, ERROR, USER, "This version of CARE was built "
+					    "without self-extracting (.bin) support");
+		return -1;
+#endif
+	}
+
+	no_wrapper_found = true;
+
+parse_filter:
+
+	found = slurp_suffix(string, &cursor, ".gz");
+	if (found) {
+		format->add_filter = archive_write_add_filter_gzip;
+		format->options    = "gzip:compression-level=1";
+		goto parse_format;
+	}
+
+	found = slurp_suffix(string, &cursor, ".lzo");
+	if (found) {
+		format->add_filter = archive_write_add_filter_lzop;
+		format->options	   = "lzop:compression-level=1";
+		goto parse_format;
+	}
+
+	found = slurp_suffix(string, &cursor, ".tgz");
+	if (found) {
+		format->add_filter = archive_write_add_filter_gzip;
+		format->options    = "gzip:compression-level=1";
+		format->set_format = archive_write_set_format_gnutar;
+		format->hardlink_resolver_strategy = ARCHIVE_FORMAT_TAR_GNUTAR;
+		goto sanity_checks;
+	}
+
+	found = slurp_suffix(string, &cursor, ".tzo");
+	if (found) {
+		format->add_filter = archive_write_add_filter_lzop;
+		format->options    = "lzop:compression-level=1";
+		format->set_format = archive_write_set_format_gnutar;
+		format->hardlink_resolver_strategy = ARCHIVE_FORMAT_TAR_GNUTAR;
+		goto sanity_checks;
+	}
+
+	no_filter_found = true;
+
+parse_format:
+
+	found = slurp_suffix(string, &cursor, ".cpio");
+	if (found) {
+		format->set_format = archive_write_set_format_cpio;
+		format->hardlink_resolver_strategy = ARCHIVE_FORMAT_CPIO_POSIX;
+		goto sanity_checks;
+	}
+
+	found = slurp_suffix(string, &cursor, ".tar");
+	if (found) {
+		format->set_format = archive_write_set_format_gnutar;
+		format->hardlink_resolver_strategy = ARCHIVE_FORMAT_TAR_GNUTAR;
+		goto sanity_checks;
+	}
+
+	no_format_found = true;
+
+sanity_checks:
+
+	if (no_filter_found && no_format_found) {
+		format->add_filter = archive_write_add_filter_lzop;
+		format->options	  = "lzop:compression-level=1";
+		format->set_format = archive_write_set_format_gnutar;
+		format->hardlink_resolver_strategy = ARCHIVE_FORMAT_TAR_GNUTAR;
+
+#if defined(CARE_BINARY_IS_PORTABLE)
+		format->special = SELF_EXTRACTING;
+		if (no_wrapper_found)
+			note(tracee, WARNING, USER,
+				"unknown suffix, assuming self-extracting format.");
+#else
+		format->special = RAW;
+		if (no_wrapper_found)
+			note(tracee, WARNING, USER,
+				"unknown suffix, assuming raw format.");
+#endif
+
+		no_wrapper_found = false;
+		no_filter_found  = false;
+		no_format_found  = false;
+	}
+
+	if (no_format_found) {
+		note(tracee, WARNING, USER, "unknown format, assuming tar format.");
+		format->set_format = archive_write_set_format_gnutar;
+		format->hardlink_resolver_strategy = ARCHIVE_FORMAT_TAR_GNUTAR;
+
+		no_format_found = false;
+	}
+
+end:
+	*suffix_length = strlen(cursor);
+	return 0;
+}
+
+/**
+ * Copy "/proc/self/exe" into @destination.  This function returns -1
+ * if an error occured, otherwise the file descriptor of the
+ * destination.
+ */
+static int copy_self_exe(const Tracee *tracee, const char *destination)
+{
+	int output_fd;
+	int input_fd;
+	int status;
+
+	input_fd = open("/proc/self/exe", O_RDONLY);
+	if (input_fd < 0) {
+		note(tracee, ERROR, SYSTEM, "can't open '/proc/self/exe'");
+		return -1;
+	}
+
+	output_fd = open(destination, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU|S_IRGRP|S_IXGRP);
+	if (output_fd < 0) {
+		note(tracee, ERROR, SYSTEM, "can't open/create '%s'", destination);
+		status = -1;
+		goto end;
+	}
+
+	while (1) {
+		uint8_t buffer[4 * 1024];
+		ssize_t size;
+
+		status = read(input_fd, buffer, sizeof(buffer));
+		if (status < 0) {
+			note(tracee, ERROR, SYSTEM, "can't read '/proc/self/exe'");
+			goto end;
+		}
+
+		if (status == 0)
+			break;
+
+		size = status;
+		status = write(output_fd, buffer, size);
+		if (status < 0) {
+			note(tracee, ERROR, SYSTEM, "can't write '%s'", destination);
+			goto end;
+		}
+		if (status != size)
+			note(tracee, WARNING, INTERNAL,
+				"wrote %zd bytes instead of %zd", (size_t) status, size);
+	}
+
+end:
+	(void) close(input_fd);
+
+	if (status < 0) {
+		(void) close(output_fd);
+		return -1;
+	}
+
+	return output_fd;
+}
+
+/**
+ * Create a new archive structure (memory allocation attached to
+ * @context) for the given @output file.  This function returns NULL
+ * on error, otherwise the newly allocated archive structure. See
+ * parse_suffix() for the meaning of @suffix_length.
+ */
+Archive *new_archive(TALLOC_CTX *context, const Tracee* tracee,
+		const char *output, size_t *suffix_length)
+{
+	Format format;
+	Archive *archive;
+	int status;
+
+	assert(output != NULL);
+
+	status = parse_suffix(tracee, &format, output, suffix_length);
+	if (status < 0)
+		return NULL;
+
+	archive = talloc_zero(context, Archive);
+	if (archive == NULL) {
+		note(tracee, ERROR, INTERNAL, "can't allocate archive structure");
+		return NULL;
+	}
+	archive->fd = -1;
+
+	/* No format was set, content will be copied into a directory
+	 * instead of being archived.  */
+	if (format.set_format == NULL) {
+		int flags = ARCHIVE_EXTRACT_PERM
+			| ARCHIVE_EXTRACT_TIME
+			| ARCHIVE_EXTRACT_ACL
+			| ARCHIVE_EXTRACT_FFLAGS
+			| ARCHIVE_EXTRACT_XATTR
+			| (geteuid() == 0 ? ARCHIVE_EXTRACT_OWNER : 0);
+
+		archive->handle = archive_write_disk_new();
+		if (archive->handle == NULL) {
+			note(tracee, WARNING, INTERNAL, "can't initialize archive structure");
+			return NULL;
+		}
+
+		status = archive_write_disk_set_options(archive->handle, flags);
+		if (status != ARCHIVE_OK) {
+			note(tracee, ERROR, INTERNAL, "can't set archive options: %s",
+				archive_error_string(archive->handle));
+			return NULL;
+		}
+
+		status = archive_write_disk_set_standard_lookup(archive->handle);
+		if (status != ARCHIVE_OK) {
+			note(tracee, ERROR, INTERNAL, "can't set archive lookup: %s",
+				archive_error_string(archive->handle));
+			return NULL;
+		}
+
+		archive->hardlink_resolver = archive_entry_linkresolver_new();
+		if (archive->hardlink_resolver != NULL)
+			archive_entry_linkresolver_set_strategy(archive->hardlink_resolver,
+								ARCHIVE_FORMAT_TAR);
+
+		return archive;
+	}
+
+	archive->handle = archive_write_new();
+	if (archive->handle == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't initialize archive structure");
+		return NULL;
+	}
+
+	assert(format.set_format != NULL);
+	status = format.set_format(archive->handle);
+	if (status != ARCHIVE_OK) {
+		note(tracee, ERROR, INTERNAL, "can't set archive format: %s",
+			archive_error_string(archive->handle));
+		return NULL;
+	}
+
+	if (format.hardlink_resolver_strategy != 0) {
+		archive->hardlink_resolver = archive_entry_linkresolver_new();
+		if (archive->hardlink_resolver != NULL)
+			archive_entry_linkresolver_set_strategy(archive->hardlink_resolver,
+								format.hardlink_resolver_strategy);
+	}
+
+	if (format.add_filter != NULL) {
+		status = format.add_filter(archive->handle);
+		if (status != ARCHIVE_OK) {
+			note(tracee, ERROR, INTERNAL, "can't add archive filter: %s",
+				archive_error_string(archive->handle));
+			return NULL;
+		}
+	}
+
+	if (format.options != NULL) {
+		status = archive_write_set_options(archive->handle, format.options);
+		if (status != ARCHIVE_OK) {
+			note(tracee, ERROR, INTERNAL, "can't set archive options: %s",
+				archive_error_string(archive->handle));
+			return NULL;
+		}
+	}
+
+	switch (format.special) {
+	case SELF_EXTRACTING:
+		archive->fd = copy_self_exe(tracee, output);
+		if (archive->fd < 0)
+			return NULL;
+
+		/* Remember where the CARE binary ends.  */
+		archive->offset = lseek(archive->fd, 0, SEEK_CUR);
+
+		status = archive_write_open_fd(archive->handle, archive->fd);
+		break;
+
+	case RAW:
+		archive->fd = open(output, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP);
+		if (archive->fd < 0) {
+			note(tracee, ERROR, SYSTEM, "can't open/create '%s'", output);
+			return NULL;
+		}
+
+		status = write(archive->fd, "RAW", strlen("RAW"));
+		if (status != strlen("RAW")) {
+			note(tracee, ERROR, SYSTEM, "can't write '%s'", output);
+			(void) close(archive->fd);
+			return NULL;
+		}
+
+		/* Remember where the "RAW" string ends.  */
+		archive->offset = lseek(archive->fd, 0, SEEK_CUR);
+
+		status = archive_write_open_fd(archive->handle, archive->fd);
+		break;
+
+	default:
+		status = archive_write_open_filename(archive->handle, output);
+		break;
+	}
+	if (status != ARCHIVE_OK) {
+		note(tracee, ERROR, INTERNAL, "can't open archive '%s': %s",
+			output, archive_error_string(archive->handle));
+		return NULL;
+	}
+
+	return archive;
+}
+
+/**
+ * Finalize the given @archive.  This function returns -1 if an error
+ * occurred, otherwise 0.
+ */
+int finalize_archive(Archive *archive)
+{
+	int status;
+
+	if (archive == NULL || archive->handle == NULL)
+		return -1;
+
+	if (archive->hardlink_resolver != NULL)
+		archive_entry_linkresolver_free(archive->hardlink_resolver);
+
+	status = archive_write_close(archive->handle);
+	if (status != ARCHIVE_OK)
+		return -1;
+
+	status = archive_write_free(archive->handle);
+	if (status != ARCHIVE_OK)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * Put the content of @path into @archive, with the specified @statl
+ * status, at the given @alternate_path (NULL if unchanged).  This
+ * function returns -1 if an error occurred, otherwise 0.  Note: this
+ * function can be called with @tracee == NULL.
+ */
+int archive(const Tracee* tracee, Archive *archive,
+	const char *path, const char *alternate_path, const struct stat *statl)
+{
+	struct archive_entry *entry = NULL;
+	ssize_t status;
+	mode_t type;
+	size_t size;
+	int fd = -1;
+
+	if (archive == NULL || archive->handle == NULL)
+		return -1;
+
+	entry = archive_entry_new();
+	if (entry == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't create archive entry for '%s': %s",
+			path, archive_error_string(archive->handle));
+		status = -1;
+		goto end;
+	}
+
+	archive_entry_set_pathname(entry, alternate_path ?: path);
+	archive_entry_copy_stat(entry, statl);
+
+	if (archive->hardlink_resolver != NULL) {
+		struct archive_entry *unused;
+		archive_entry_linkify(archive->hardlink_resolver, &entry, &unused);
+	}
+
+	/* Get status only once hardlinks were resolved.  */
+	size = archive_entry_size(entry);
+	type = archive_entry_filetype(entry);
+
+	if (type == AE_IFLNK) {
+		char target[PATH_MAX];
+		status = readlink(path, target, PATH_MAX);
+		if (status >= PATH_MAX) {
+			status = -1;
+			errno = ENAMETOOLONG;
+		}
+		if (status < 0) {
+			note(tracee, WARNING, SYSTEM, "can't readlink '%s'", path);
+			status = -1;
+			goto end;
+		}
+		target[status] = '\0';
+
+		/* Must be done before archive_write_header().  */
+		archive_entry_set_symlink(entry, target);
+	}
+
+	status = archive_write_header(archive->handle, entry);
+	if (status != ARCHIVE_OK) {
+		note(tracee, WARNING, INTERNAL, "can't write header for '%s': %s",
+			path, archive_error_string(archive->handle));
+		status = -1;
+		goto end;
+	}
+
+	/* No content to archive?  */
+	if (type != AE_IFREG || size == 0) {
+		status = 0;
+		goto end;
+	}
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		if (errno != EACCES)
+			note(tracee, WARNING, SYSTEM, "can't open '%s'", path);
+		status = -1;
+		goto end;
+	}
+
+	/* Copy the content from the file into the archive.  */
+	do {
+		uint8_t buffer[4096];
+
+		status = read(fd, buffer, sizeof(buffer));
+		if (status < 0) {
+			note(tracee, WARNING, SYSTEM, "can't read '%s'", path);
+			status = -1;
+			goto end;
+		}
+
+		size = archive_write_data(archive->handle, buffer, status);
+		if ((size_t) status != size) {
+			note(tracee, WARNING, INTERNAL, "can't archive '%s' content: %s",
+				path, archive_error_string(archive->handle));
+			status = -1;
+			goto end;
+		}
+	} while (status > 0);
+	status = 0;
+
+end:
+	if (fd >= 0)
+		(void) close(fd);
+
+	if (entry != NULL)
+		archive_entry_free(entry);
+
+	return status;
+}
diff --git a/5.1.0/src/extension/care/archive.h b/5.1.0/src/extension/care/archive.h
new file mode 100644
index 0000000..3b588b0
--- /dev/null
+++ b/5.1.0/src/extension/care/archive.h
@@ -0,0 +1,47 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef ARCHIVE_H
+#define ARCHIVE_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+
+#include "tracee/tracee.h"
+
+typedef struct {
+	struct archive *handle;
+	struct archive_entry_linkresolver *hardlink_resolver;
+
+	/* Information used to create an self-extracting archive.  */
+	off_t offset;
+	int fd;
+} Archive;
+
+extern Archive *new_archive(TALLOC_CTX *context, const Tracee* tracee,
+				const char *output, size_t *prefix_length);
+extern int finalize_archive(Archive *archive);
+extern int archive(const Tracee* tracee, Archive *archive,
+		const char *path, const char *alternate_path, const struct stat *statl);
+
+#endif /* ARCHIVE_H */
diff --git a/5.1.0/src/extension/care/care.c b/5.1.0/src/extension/care/care.c
new file mode 100644
index 0000000..6587149
--- /dev/null
+++ b/5.1.0/src/extension/care/care.c
@@ -0,0 +1,604 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>    /* struct stat, */
+#include <sys/stat.h>     /* struct stat, */
+#include <unistd.h>       /* lstat(2), */
+#include <linux/limits.h> /* PATH_MAX, */
+#include <string.h>       /* strlen(3), */
+#include <assert.h>       /* assert(3), */
+#include <time.h>         /* time(2), localtime(3), */
+#include <stddef.h>       /* offsetof(3), */
+#include <talloc.h>       /* talloc*, */
+#include <uthash.h>       /* ut*, UT*, HASH*, */
+#include <sys/queue.h>    /* STAILQ_*, */
+#include <inttypes.h>     /* PRI*, */
+#include <linux/auxvec.h> /* AT_*, */
+
+#include "extension/care/care.h"
+#include "extension/care/final.h"
+#include "extension/care/archive.h"
+#include "extension/extension.h"
+#include "tracee/tracee.h"
+#include "tracee/mem.h"
+#include "execve/auxv.h"
+#include "path/canon.h"
+#include "path/path.h"
+#include "path/binding.h"
+#include "cli/note.h"
+
+/* Make uthash use talloc.  */
+#undef  uthash_malloc
+#undef  uthash_free
+#define uthash_malloc(size) talloc_size(care, size)
+#define uthash_free(pointer, size) TALLOC_FREE(pointer)
+
+/* Hash entry.  */
+typedef struct Entry {
+	UT_hash_handle hh;
+	char *path;
+} Entry;
+
+/**
+ * Add a copy of @value at the end if the given @list.  All the newly
+ * talloc'ed elements (duplicated value, item, list head) are attached
+ * to the given @context.  This function returns NULL if an error
+ * occurred, otherwise the newly talloc'ed item.
+ */
+Item *queue_item(TALLOC_CTX *context, List **list, const char *value)
+{
+	Item *item;
+
+	if (*list == NULL) {
+		*list = talloc_zero(context, List);
+		if (*list == NULL)
+			return NULL;
+
+		STAILQ_INIT(*list);
+	}
+
+	item = talloc_zero(*list, Item);
+	if (item == NULL)
+		return NULL;
+
+	item->load = talloc_strdup(item, value);
+	if (item->load == NULL)
+		return NULL;
+
+	STAILQ_INSERT_TAIL(*list, item, link);
+	return item;
+}
+
+/**
+ * Generate a valid archive @care->output from @care.
+ */
+static void generate_output_name(const Tracee *tracee, Care *care)
+{
+	struct tm *splitted_time;
+	time_t flat_time;
+
+	flat_time = time(NULL);
+	splitted_time = localtime(&flat_time);
+	if (splitted_time == NULL) {
+		note(tracee, ERROR, INTERNAL,
+			"can't generate a valid output name from the current time, "
+			"please specify an ouput name explicitly");
+		return;
+	}
+
+	care->output = talloc_asprintf(care, "care-%02d%02d%02d%02d%02d%02d.%s",
+					splitted_time->tm_year - 100, splitted_time->tm_mon + 1,
+					splitted_time->tm_mday, splitted_time->tm_hour,
+					splitted_time->tm_min, splitted_time->tm_sec,
+#if defined(CARE_BINARY_IS_PORTABLE)
+					"bin"
+#else
+					"raw"
+#endif
+		);
+	if (care->output == NULL) {
+		note(tracee, ERROR, INTERNAL,
+			"can't generate a valid output name from the current time, "
+			"please specify an ouput name explicitly");
+		return;
+	}
+}
+
+/**
+ * Genereate @extension->config from @options.  This function returns
+ * -1 if an error ocurred, otherwise 0.
+ */
+static int generate_care(Extension *extension, const Options *options)
+{
+	size_t suffix_length;
+	const char *cursor;
+	Tracee *tracee;
+	Item *item2;
+	Item *item;
+	Care *care;
+
+	tracee = TRACEE(extension);
+
+	extension->config = talloc_zero(extension, Care);
+	if (extension->config == NULL)
+		return -1;
+	care = extension->config;
+
+	care->command = options->command;
+	care->ipc_are_volatile = !options->ignore_default_config;
+
+	if (options->output != NULL)
+		care->output = talloc_strdup(care, options->output);
+	else
+		generate_output_name(tracee, care);
+	if (care->output == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't get output name");
+		return -1;
+	}
+
+	care->initial_cwd = talloc_strdup(care, tracee->fs->cwd);
+	if (care->initial_cwd == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't allocate cwd");
+		return -1;
+	}
+
+	care->archive = new_archive(care, tracee, care->output, &suffix_length);
+	if (care->archive == NULL)
+		return -1;
+
+	cursor = strrchr(care->output, '/');
+	if (cursor == NULL || strlen(cursor) == 1)
+		cursor = care->output;
+	else
+		cursor++;
+
+	care->prefix = talloc_strndup(care, cursor, strlen(cursor) - suffix_length);
+	if (care->prefix == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't allocate archive prefix");
+		return -1;
+	}
+
+	/* Copy & canonicalize volatile paths.  */
+	if (options->volatile_paths != NULL) {
+		char path[PATH_MAX];
+		int status;
+
+		STAILQ_FOREACH(item, options->volatile_paths, link) {
+			/* Initial state before canonicalization.  */
+			strcpy(path, "/");
+
+			status = canonicalize(tracee, (const char *) item->load, false, path, 0);
+			if (status < 0)
+				continue;
+
+			/* Sanity check.  */
+			if (strcmp(path, "/") == 0) {
+				const char *string;
+				const char *name;
+
+				name = talloc_get_name(item);
+				string = name == NULL || name[0] != '$'
+					? talloc_asprintf(tracee->ctx, "'%s'",
+							(const char *) item->load)
+					: talloc_asprintf(tracee->ctx, "'%s' (%s)",
+							(const char *) item->load, name);
+
+				note(tracee, WARNING, USER,
+					"path %s was declared volatile but it leads to '/', "
+					"as a consequence it will *not* be considered volatile.",
+					string);
+				continue;
+			}
+
+			item2 = queue_item(care, &care->volatile_paths, path);
+			if (item2 == NULL)
+				continue;
+
+			/* Preserve the non expanded form.  */
+			talloc_set_name_const(item2, talloc_get_name(item));
+
+			VERBOSE(tracee, 1, "volatile path: %s",	(const char *) item2->load);
+		}
+	}
+
+	/* Copy volatile env. variables.  */
+	if (options->volatile_envars != NULL) {
+		STAILQ_FOREACH(item, options->volatile_envars, link) {
+			item2 = queue_item(care, &care->volatile_envars, item->load);
+			if (item2 == NULL)
+				continue;
+
+			VERBOSE(tracee, 1, "volatile envar: %s", (const char *) item2->load);
+		}
+	}
+
+	/* Convert the limit from megabytes to bytes, as expected by
+	 * handle_host_path().  */
+	care->max_size = options->max_size * 1024 * 1024;
+
+	/* handle_host_path() can now be safely used.  */
+	care->is_ready = true;
+
+	talloc_set_destructor(care, finalize_care);
+	return 0;
+}
+
+/**
+ * Add @path_ to the list of @care->concealed_accesses.  This function
+ * does *not* check for duplicated entries.
+ */
+static void register_concealed_access(const Tracee *tracee, Care *care, const char *path_)
+{
+	char path[PATH_MAX];
+	size_t length;
+	int status;
+
+	length = strlen(path_);
+	if (length >= PATH_MAX)
+		return;
+	memcpy(path, path_, length + 1);
+
+	/* It was a concealed access if, and only if, the path was
+	 * part of a asymmetric binding.  */
+	status = substitute_binding(tracee, HOST, path);
+	if (status != 1)
+		return;
+
+	/* Do not register accesses that would not succeed even if the
+	 * path was revealed, i.e. the path does not exist at all.  */
+	status = access(path, F_OK);
+	if (status < 0)
+		return;
+
+	queue_item(care, &care->concealed_accesses, path);
+	VERBOSE(tracee, 1, "concealed: %s", path);
+}
+
+/**
+ * Archive @path if needed.
+ */
+static void handle_host_path(Extension *extension, const char *path)
+{
+	struct stat statl;
+	bool as_dentries;
+	char *location;
+	Tracee *tracee;
+	Entry *entry;
+	Care *care;
+	int status;
+
+	care = talloc_get_type_abort(extension->config, Care);
+	tracee = TRACEE(extension);
+
+	if (!care->is_ready)
+		return;
+
+	/* Don't archive if the path was already seen before.
+	 * This ensures the rootfs is re-created as it was
+	 * before any file creation or modification. */
+	HASH_FIND_STR(care->entries, path, entry);
+	if (entry != NULL)
+		return;
+
+	switch (get_sysnum(tracee, ORIGINAL)) {
+	case PR_getdents:
+	case PR_getdents64:
+		/* Don't archive if the dentry was already seen
+		 * before, it would be useless.  */
+		HASH_FIND_STR(care->dentries, path, entry);
+		if (entry != NULL)
+			return;
+		as_dentries = true;
+		break;
+
+	default:
+		as_dentries = false;
+		break;
+	}
+
+	entry = talloc_zero(care, Entry);
+	if (entry == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't allocate entry for '%s'", path);
+		return;
+	}
+
+	entry->path = talloc_strdup(entry, path);
+	if (entry->path == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't allocate name for '%s'", path);
+		return;
+	}
+
+	/* Remember this new entry.  */
+	if (as_dentries)
+		HASH_ADD_KEYPTR(hh, care->dentries, entry->path, strlen(entry->path), entry);
+	else
+		HASH_ADD_KEYPTR(hh, care->entries, entry->path, strlen(entry->path), entry);
+
+	/* Don't use faccessat(2) here since it would require Linux >=
+	 * 2.6.16 and Glibc >= 2.4, whereas CARE is supposed to work
+	 * on any Linux 2.6 systems.  */
+	status = lstat(path, &statl);
+	if (status < 0) {
+		register_concealed_access(tracee, care, path);
+		return;
+	}
+
+	/* FIFOs and Unix domain sockets should be volatile.  */
+	if (S_ISFIFO(statl.st_mode) || S_ISSOCK(statl.st_mode)) {
+		if (care->ipc_are_volatile) {
+			Item *item = queue_item(care, &care->volatile_paths, path);
+			if (item != NULL)
+				VERBOSE(tracee, 0, "volatile path: %s", path);
+			else
+				note(tracee, WARNING, USER,
+					"can't declare '%s' (fifo or socket) as volatile", path);
+			return;
+		}
+		else
+			note(tracee, WARNING, USER,
+				"'%1$s' might be explicitely declared volatile (-p %1$s)", path);
+	}
+
+	/* Don't archive the content of dentries, this save a lot of
+	 * space!  */
+	if (as_dentries)
+		statl.st_size = 0;
+
+	if (care->volatile_paths != NULL) {
+		Item *item;
+
+		STAILQ_FOREACH(item, care->volatile_paths, link) {
+			switch (compare_paths(item->load, path)) {
+			case PATHS_ARE_EQUAL:
+				/* It's a volatile path, archive it as
+				 * empty to preserve its dentry.  */
+				statl.st_size = 0;
+				break;
+
+			case PATH1_IS_PREFIX:
+				/* Don't archive it's a sub-part of a
+				 * volatile path.  */
+				return;
+
+			default:
+				continue;
+			}
+			break;
+		}
+	}
+
+	if (care->max_size >= 0 && statl.st_size > care->max_size) {
+		note(tracee, WARNING, USER,
+			"file '%s' is archived with a null size since it is bigger than %"
+			PRIi64 "MB, you can specify an alternate limit with the option -m.",
+			path, care->max_size / 1024 / 1024);
+		statl.st_size = 0;
+	}
+
+	/* Format the location within the archive.  */
+	location = NULL;
+	assert(path[0] == '/');
+	location = talloc_asprintf(tracee->ctx, "%s/rootfs%s", care->prefix, path);
+	if (location == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't allocate location for '%s'", path);
+		return;
+	}
+
+	status = archive(tracee, care->archive, path, location, &statl);
+	if (status == 0)
+		VERBOSE(tracee, 1, "archived: %s", path);
+}
+
+typedef struct {
+	uint32_t d_ino;
+	uint32_t next;
+	uint16_t size;
+	char name[];
+} Dirent32;
+
+typedef struct {
+	uint64_t d_ino;
+	uint64_t next;
+	uint16_t size;
+	char name[];
+} Dirent64;
+
+typedef struct {
+	uint64_t inode;
+	int64_t  next;
+	uint16_t size;
+	uint8_t  type;
+	char name[];
+} NewDirent;
+
+/**
+ * Archive all the entries returned by getdents syscalls.
+ */
+static void handle_getdents(Tracee *tracee, bool is_new_getdents)
+{
+	char component[PATH_MAX];
+	char path[PATH_MAX];
+	uint64_t offset;
+	int status;
+
+	word_t result;
+	word_t buffer;
+	word_t fd;
+
+	Dirent32 dirent32;
+	Dirent64 dirent64;
+	NewDirent new_dirent;
+
+	result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+	if ((int) result < 0)
+		return;
+
+	fd     = peek_reg(tracee, ORIGINAL, SYSARG_1);
+	buffer = peek_reg(tracee, ORIGINAL, SYSARG_2);
+
+	offset = 0;
+	while (offset < result) {
+		word_t name_offset;
+		word_t address;
+		size_t size;
+
+		address = buffer + offset;
+
+		if (!is_new_getdents) {
+#if defined(ARCH_X86_64)
+			const bool is_32bit = is_32on64_mode(tracee);
+#else
+			const bool is_32bit = true;
+#endif
+			if (is_32bit) {
+				name_offset = offsetof(Dirent32, name);
+				status = read_data(tracee, &dirent32, address, sizeof(dirent32));
+				size = dirent32.size;
+			}
+			else {
+				name_offset = offsetof(Dirent64, name);
+				status = read_data(tracee, &dirent64, address, sizeof(dirent64));
+				size = dirent64.size;
+			}
+		} else {
+			name_offset = offsetof(NewDirent, name);
+			status = read_data(tracee, &new_dirent, address, sizeof(new_dirent));
+			size = new_dirent.size;
+		}
+		if (status < 0) {
+			note(tracee, WARNING, INTERNAL, "can't read dentry");
+			break;
+		}
+
+		status = read_string(tracee, component, address + name_offset, PATH_MAX);
+		if (status < 0 || status >= PATH_MAX) {
+			note(tracee, WARNING, INTERNAL, "can't read dentry" );
+			goto next;
+		}
+
+		/* Archive through the host_path notification. */
+		strcpy(path, "/");
+		translate_path(tracee, path, fd, component, false);
+	next:
+		offset += size;
+	}
+
+	if (offset != result)
+		note(tracee, WARNING, INTERNAL, "dentry table out of sync.");
+}
+
+/**
+ * Set AT_HWCAP to 0 to ensure no processor specific extensions will
+ * be used, for the sake of reproducibility across different CPUs.
+ * This function assumes the "argv, envp, auxv" stuff is pointed to by
+ * @tracee's stack pointer, as expected right after a successful call
+ * to execve(2).
+ */
+static int adjust_elf_auxv(Tracee *tracee)
+{
+	ElfAuxVector *vectors;
+	ElfAuxVector *vector;
+	word_t vectors_address;
+
+	vectors_address = get_elf_aux_vectors_address(tracee);
+	if (vectors_address == 0)
+		return 0;
+
+	vectors = fetch_elf_aux_vectors(tracee, vectors_address);
+	if (vectors == NULL)
+		return 0;
+
+	for (vector = vectors; vector->type != AT_NULL; vector++) {
+		if (vector->type == AT_HWCAP)
+			vector->value = 0;
+	}
+
+	push_elf_aux_vectors(tracee, vectors, vectors_address);
+
+	return 0;
+}
+
+/* List of syscalls handled by this extensions.  */
+static FilteredSysnum filtered_sysnums[] = {
+	{ PR_getdents,		FILTER_SYSEXIT },
+	{ PR_getdents64,	FILTER_SYSEXIT },
+	FILTERED_SYSNUM_END,
+};
+
+/**
+ * Handler for this @extension.  It is triggered each time an @event
+ * occurred.  See ExtensionEvent for the meaning of @data1 and @data2.
+ */
+int care_callback(Extension *extension, ExtensionEvent event,
+		intptr_t data1, intptr_t data2 UNUSED)
+{
+	Tracee *tracee;
+
+	switch (event) {
+	case INITIALIZATION:
+		extension->filtered_sysnums = filtered_sysnums;
+		return generate_care(extension, (Options *) data1);
+
+	case NEW_STATUS: {
+		int status = (int) data1;
+		if (WIFEXITED(status)) {
+			Care *care = talloc_get_type_abort(extension->config, Care);
+			care->last_exit_status = WEXITSTATUS(status);
+		}
+		return 0;
+	}
+
+	case HOST_PATH:
+		handle_host_path(extension, (const char *) data1);
+		return 0;
+
+	case SYSCALL_EXIT_START:
+		tracee = TRACEE(extension);
+
+		switch (get_sysnum(tracee, ORIGINAL)) {
+		case PR_getdents:
+			handle_getdents(tracee, false);
+			break;
+
+		case PR_getdents64:
+			handle_getdents(tracee, true);
+			break;
+
+		case PR_execve: {
+			word_t result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+
+			/* Note: this can be done only before PRoot pushes the
+			 * load script into tracee's stack.  */
+			if ((int) result >= 0)
+				adjust_elf_auxv(tracee);
+			break;
+		}
+
+		default:
+			break;
+		}
+		return 0;
+
+	default:
+		return 0;
+	}
+}
diff --git a/5.1.0/src/extension/care/care.h b/5.1.0/src/extension/care/care.h
new file mode 100644
index 0000000..aae86a7
--- /dev/null
+++ b/5.1.0/src/extension/care/care.h
@@ -0,0 +1,80 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef CARE_H
+#define CARE_H
+
+#include <stdbool.h>
+#include <sys/queue.h> /* STAILQ_*, */
+
+#include "extension/care/archive.h"
+
+/* Generic item for a STAILQ list.  */
+typedef struct item {
+	const void *load;
+	STAILQ_ENTRY(item) link;
+} Item;
+
+typedef STAILQ_HEAD(list, item) List;
+
+/* CARE CLI configuration.  */
+typedef struct {
+	const char *output;
+	char *const *command;
+
+	List *concealed_paths;
+	List *revealed_paths;
+	List *volatile_paths;
+	List *volatile_envars;
+
+	bool ignore_default_config;
+
+	int max_size;
+} Options;
+
+/* CARE internal configuration.  */
+typedef struct {
+	struct Entry *entries;
+	struct Entry *dentries;
+
+	char *const *command;
+	List *volatile_paths;
+	List *volatile_envars;
+	List *concealed_accesses;
+
+	const char *prefix;
+	const char *output;
+	const char *initial_cwd;
+	bool ipc_are_volatile;
+
+	Archive *archive;
+	int64_t max_size;
+
+	int last_exit_status;
+
+	bool is_ready;
+} Care;
+
+extern Item *queue_item(TALLOC_CTX *context, List **list, const char *value);
+
+#endif /* CARE_H */
+
diff --git a/5.1.0/src/extension/care/extract.c b/5.1.0/src/extension/care/extract.c
new file mode 100644
index 0000000..7f3c326
--- /dev/null
+++ b/5.1.0/src/extension/care/extract.c
@@ -0,0 +1,315 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>  /* open(2), fstat(2), lseek(2), */
+#include <sys/stat.h>   /* open(2), fstat(2), */
+#include <sys/stat.h>   /* open(2), */
+#include <fcntl.h>      /* open(2), */
+#include <stdint.h>     /* *int*_t, *INT*_MAX, */
+#include <unistd.h>     /* fstat(2), read(2), lseek(2), */
+#include <sys/mman.h>   /* mmap(2), MAP_*, */
+#include <stdbool.h>    /* bool, true, false, */
+#include <assert.h>     /* assert(3), */
+#include <errno.h>      /* errno(3), */
+#include <string.h>     /* strerror(3), */
+#include <inttypes.h>   /* PRI*, */
+#include <endian.h>     /* be64toh(3), */
+#include <archive.h>    /* archive_*(3), */
+#include <archive_entry.h> /* archive_entry*(3), */
+
+#include "extension/care/extract.h"
+#include "cli/note.h"
+
+/**
+ * Extract the given @archive into the current working directory.
+ * This function returns -1 if an error occured, otherwise 0.
+ */
+static int extract_archive(struct archive *archive)
+{
+	struct archive_entry *entry;
+	int result = 0;
+	int status;
+
+	int flags = ARCHIVE_EXTRACT_PERM
+		  | ARCHIVE_EXTRACT_TIME
+		  | ARCHIVE_EXTRACT_ACL
+		  | ARCHIVE_EXTRACT_FFLAGS
+		  | ARCHIVE_EXTRACT_XATTR;
+
+	/* Avoid spurious warnings.  One should test for the CAP_CHOWN
+	 * capability instead but libarchive only does this test: */
+	if (geteuid() == 0)
+		flags |= ARCHIVE_EXTRACT_OWNER;
+
+	while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
+		status = archive_read_extract(archive, entry, flags);
+		switch (status) {
+		case ARCHIVE_OK:
+			note(NULL, INFO, USER, "extracted: %s", archive_entry_pathname(entry));
+			break;
+
+		default:
+			result = -1;
+			note(NULL, ERROR, INTERNAL, "%s: %s",
+				archive_error_string(archive),
+				strerror(archive_errno(archive)));
+			break;
+		}
+	}
+
+	return result;
+}
+
+/* Data used by archive_[open/read/close] callbacks.  */
+typedef struct
+{
+	uint8_t buffer[4096];
+	const char *path;
+	size_t size;
+	int fd;
+} CallbackData;
+
+/**
+ * This callback is invoked by archive_open().  It returns ARCHIVE_OK
+ * if the underlying file or data source is successfully opened.  If
+ * the open fails, it calls archive_set_error() to register an error
+ * code and message and returns ARCHIVE_FATAL.
+ *
+ *  -- man 3 archive_read_open.
+ */
+static int open_callback(struct archive *archive, void *data_)
+{
+	CallbackData *data = talloc_get_type_abort(data_, CallbackData);
+	AutoExtractInfo info;
+	struct stat statf;
+	off_t offset;
+	int status;
+
+	/* Note: data->fd will be closed by close_callback().  */
+	data->fd = open(data->path, O_RDONLY);
+	if (data->fd < 0) {
+		archive_set_error(archive, errno, "can't open archive");
+		return ARCHIVE_FATAL;
+	}
+
+	status = fstat(data->fd, &statf);
+	if (status < 0) {
+		archive_set_error(archive, errno, "can't stat archive");
+		return ARCHIVE_FATAL;
+	}
+
+	/* Assume it's a regular archive if it physically can't be a
+	 * self-extracting one.  */
+	if (statf.st_size < (off_t) sizeof(AutoExtractInfo))
+		return ARCHIVE_OK;
+
+	offset = lseek(data->fd, statf.st_size - sizeof(AutoExtractInfo), SEEK_SET);
+	if (offset == (off_t) -1) {
+		archive_set_error(archive, errno, "can't seek in archive");
+		return ARCHIVE_FATAL;
+	}
+
+	status = read(data->fd, &info, sizeof(AutoExtractInfo));
+	if (status < 0) {
+		archive_set_error(archive, errno, "can't read archive");
+		return ARCHIVE_FATAL;
+	}
+
+	if (   status == sizeof(AutoExtractInfo)
+	    && strcmp(info.signature, AUTOEXTRACT_SIGNATURE) == 0) {
+		/* This is a self-extracting archive, retrive it's
+		 * offset and size.  */
+
+		data->size = be64toh(info.size);
+		offset = statf.st_size - data->size - sizeof(AutoExtractInfo);
+
+		note(NULL, INFO, USER,
+			"archive found: offset = %" PRIu64 ", size = %" PRIu64 "",
+			(uint64_t) offset, data->size);
+	}
+	else {
+		/* This is not a self-extracting archive, assume it's
+		 * a regular one...  */
+		offset = 0;
+
+		/* ... unless a self-extracting archive really was
+		 * expected.  */
+		if (strcmp(data->path, "/proc/self/exe") == 0)
+			return ARCHIVE_FATAL;
+	}
+
+	offset = lseek(data->fd, offset, SEEK_SET);
+	if (offset == (off_t) -1) {
+		archive_set_error(archive, errno, "can't seek in archive");
+		return ARCHIVE_FATAL;
+	}
+
+	return ARCHIVE_OK;
+}
+
+/**
+ * This callback is invoked whenever the library requires raw bytes
+ * from the archive.  The read callback reads data into a buffer, set
+ * the @buffer argument to point to the available data, and return a
+ * count of the number of bytes available.  The library will invoke
+ * the read callback again only after it has consumed this data.  The
+ * library imposes no constraints on the size of the data blocks
+ * returned.  On end-of-file, the read callback returns zero.  On
+ * error, the read callback should invoke archive_set_error() to
+ * register an error code and message and returns -1.
+ *
+ *  -- man 3 archive_read_open.
+ */
+static ssize_t read_callback(struct archive *archive, void *data_, const void **buffer)
+{
+	CallbackData *data = talloc_get_type_abort(data_, CallbackData);
+	ssize_t size;
+
+	size = read(data->fd, data->buffer, sizeof(data->buffer));
+	if (size < 0) {
+		archive_set_error(archive, errno, "can't read archive");
+		return -1;
+	}
+
+	*buffer = data->buffer;
+	return size;
+}
+
+/**
+ * This callback is invoked by archive_close() when the archive
+ * processing is complete.  The callback returns ARCHIVE_OK on
+ * success.  On failure, the callback invokes archive_set_error() to
+ * register an error code and message and returns ARCHIVE_FATAL.
+ *
+ * -- man 3 archive_read_open
+ */
+static int close_callback(struct archive *archive, void *data_)
+{
+	CallbackData *data = talloc_get_type_abort(data_, CallbackData);
+	int status;
+
+	status = close(data->fd);
+	if (status < 0) {
+		archive_set_error(archive, errno, "can't close archive");
+		return ARCHIVE_WARN;
+	}
+
+	return ARCHIVE_OK;
+}
+
+/**
+ * Extract the archive stored at the given @path.  This function
+ * returns -1 if an error occurred, otherwise 0.
+ */
+int extract_archive_from_file(const char *path)
+{
+	struct archive *archive = NULL;
+	CallbackData *data = NULL;
+	int status2;
+	int status;
+
+	archive = archive_read_new();
+	if (archive == NULL) {
+		note(NULL, ERROR, INTERNAL, "can't initialize archive structure");
+		status = -1;
+		goto end;
+	}
+
+	status = archive_read_support_format_cpio(archive);
+	if (status != ARCHIVE_OK) {
+		note(NULL, ERROR, INTERNAL, "can't set archive format: %s",
+			archive_error_string(archive));
+		status = -1;
+		goto end;
+	}
+
+	status = archive_read_support_format_gnutar(archive);
+	if (status != ARCHIVE_OK) {
+		note(NULL, ERROR, INTERNAL, "can't set archive format: %s",
+			archive_error_string(archive));
+		status = -1;
+		goto end;
+	}
+
+	status = archive_read_support_filter_gzip(archive);
+	if (status != ARCHIVE_OK) {
+		note(NULL, ERROR, INTERNAL, "can't add archive filter: %s",
+			archive_error_string(archive));
+		status = -1;
+		goto end;
+	}
+
+	status = archive_read_support_filter_lzop(archive);
+	if (status != ARCHIVE_OK) {
+		note(NULL, ERROR, INTERNAL, "can't add archive filter: %s",
+			archive_error_string(archive));
+		status = -1;
+		goto end;
+	}
+
+	data = talloc_zero(NULL, CallbackData);
+	if (data == NULL) {
+		note(NULL, ERROR, INTERNAL, "can't allocate callback data");
+		status = -1;
+		goto end;
+
+	}
+
+	data->path = talloc_strdup(data, path);
+	if (data->path == NULL) {
+		note(NULL, ERROR, INTERNAL, "can't allocate callback data path");
+		status = -1;
+		goto end;
+
+	}
+
+	status = archive_read_open(archive, data, open_callback, read_callback, close_callback);
+	if (status != ARCHIVE_OK) {
+		/* Don't complain if no error message were registered,
+		 * ie. when testing for a self-extracting archive.  */
+		if (archive_error_string(archive) != NULL)
+			note(NULL, ERROR, INTERNAL, "can't read archive: %s",
+				archive_error_string(archive));
+		status = -1;
+		goto end;
+	}
+
+	status = extract_archive(archive);
+end:
+	if (archive != NULL) {
+		status2 = archive_read_close(archive);
+		if (status2 != ARCHIVE_OK) {
+			note(NULL, WARNING, INTERNAL, "can't close archive: %s",
+				archive_error_string(archive));
+		}
+
+		status2 = archive_read_free(archive);
+		if (status2 != ARCHIVE_OK) {
+			note(NULL, WARNING, INTERNAL, "can't free archive: %s",
+				archive_error_string(archive));
+		}
+	}
+
+	TALLOC_FREE(data);
+
+	return status;
+}
diff --git a/5.1.0/src/extension/care/extract.h b/5.1.0/src/extension/care/extract.h
new file mode 100644
index 0000000..b79f624
--- /dev/null
+++ b/5.1.0/src/extension/care/extract.h
@@ -0,0 +1,38 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef EXTRACT_H
+#define EXTRACT_H
+
+#include <stdint.h>
+#include "attribute.h"
+
+#define AUTOEXTRACT_SIGNATURE "I_LOVE_PIZZA"
+
+typedef struct {
+	char signature[sizeof(AUTOEXTRACT_SIGNATURE)];
+	uint64_t size;
+} PACKED AutoExtractInfo;
+
+extern int WEAK extract_archive_from_file(const char *path);
+
+#endif /* EXTRACT_H */
diff --git a/5.1.0/src/extension/care/final.c b/5.1.0/src/extension/care/final.c
new file mode 100644
index 0000000..0a5f9fd
--- /dev/null
+++ b/5.1.0/src/extension/care/final.c
@@ -0,0 +1,476 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <unistd.h>       /* lstat(2), readlink(2), getpid(2), wirte(2), lseek(2), get*id(2), */
+#include <sys/types.h>    /* get*id(2), */
+#include <sys/stat.h>     /* struct stat, fchmod(2), */
+#include <linux/limits.h> /* PATH_MAX, */
+#include <sys/utsname.h>  /* uname(2), */
+#include <stdio.h>        /* fprintf(3), fclose(3), */
+#include <errno.h>        /* errno, ENAMETOOLONG, */
+#include <string.h>       /* strcpy(3), */
+#include <endian.h>       /* htobe64(3), */
+#include <assert.h>       /* assert(3), */
+
+#include "extension/care/final.h"
+#include "extension/care/care.h"
+#include "extension/care/extract.h"
+#include "execve/ldso.h"
+#include "path/path.h"
+#include "path/temp.h"
+#include "cli/note.h"
+
+/**
+ * Find in @care->volatile_envars the given @envar (format
+ * "name=value").  This function returns the name of the variable if
+ * found (format "name"), NULL otherwise.
+ */
+static const char *find_volatile_envar(const Care *care, const char *envar)
+{
+	const Item *volatile_envar;
+
+	if (care->volatile_envars == NULL)
+		return NULL;
+
+	STAILQ_FOREACH(volatile_envar, care->volatile_envars, link) {
+		if (is_env_name(envar, volatile_envar->load))
+			return volatile_envar->load;
+	}
+
+	return NULL;
+}
+
+extern char **environ;
+
+/**
+ * Archive in @care->archive the content of @file with the given
+ * @name, then close it.  This function returns < 0 if an error
+ * occured, otherwise 0.  Note: this function is called in @care's
+ * destructor.
+ */
+static int archive_close_file(const Care *care, FILE *file, const char *name)
+{
+	char path[PATH_MAX];
+	struct stat statl;
+	char *location;
+	int status;
+	int fd;
+
+	/* Ensure everything is written into the file before archiving
+	 * it.  */
+	fflush(file);
+
+	fd = fileno(file);
+
+	status = fstat(fd, &statl);
+	if (status < 0) {
+		note(NULL, ERROR, SYSTEM, "can't get '%s' status", name);
+		goto end;
+	}
+
+	location = talloc_asprintf(care, "%s/%s", care->prefix, name);
+	if (location == NULL) {
+		note(NULL, ERROR, INTERNAL, "can't allocate location for '%s'", name);
+		status = -1;
+		goto end;
+	}
+
+	status = readlink_proc_pid_fd(getpid(), fd, path);
+	if (status < 0) {
+		note(NULL, ERROR, INTERNAL, "can't readlink(/proc/self/fd/%d)", fd);
+		goto end;
+	}
+
+	status = archive(NULL, care->archive, path, location, &statl);
+end:
+	(void) fclose(file);
+	return status;
+}
+
+/**
+ * Return a copy -- attached to @context -- of @input with all '
+ * (single quote) characters escaped.
+ */
+static const char *escape_quote(TALLOC_CTX *context, const char *input)
+{
+	char *output;
+	size_t length;
+	size_t i;
+
+	output = talloc_strdup(context, "");
+	if (output == NULL)
+		return NULL;
+
+	length = strlen(input);
+	for (i = 0; i < length; i++) {
+		char buffer[2] = { input[i], '\0' };
+
+		if (buffer[0] == '\'')
+			output = talloc_strdup_append_buffer(output, "'\\''");
+		else
+			output = talloc_strdup_append_buffer(output, buffer);
+		if (output == NULL)
+			return NULL;
+	}
+
+	return output;
+}
+
+/* Helpers for archive_* functions.  */
+#define N(format, ...)							\
+	do {								\
+		if (fprintf(file, format "\n", ##__VA_ARGS__) < 0) {	\
+			note(NULL, ERROR, INTERNAL, "can't write file"); \
+			(void) fclose(file);				\
+			return -1;					\
+		}							\
+	} while (0)
+
+#define C(format, ...) N(format " \\", ##__VA_ARGS__)
+
+/**
+ * Archive the "re-execute.sh" file, according to the given @care.
+ * This function returns < 0 if an error occured, 0 otherwise.  Note:
+ * this function is called in @care's destructor.
+ */
+static int archive_re_execute_sh(Care *care)
+{
+	struct utsname utsname;
+	const Item *item;
+	FILE *file;
+	int status;
+	int i;
+
+	file = open_temp_file(NULL, "care");
+	if (file == NULL) {
+		note(NULL, ERROR, INTERNAL, "can't create temporary file for 're-execute.sh'");
+		return -1;
+	}
+
+	status = fchmod(fileno(file), 0755);
+	if (status < 0)
+		note(NULL, WARNING, SYSTEM, "can't make 're-execute.sh' executable");
+
+	N("#! /bin/sh");
+	N("");
+	N("export XAUTHORITY=\"${XAUTHORITY:-$HOME/.Xauthority}\"");
+	N("export ICEAUTHORITY=\"${ICEAUTHORITY:-$HOME/.ICEauthority}\"");
+	N("");
+
+	N("nbargs=$#");
+	C("[ $nbargs -ne 0 ] || set --");
+	for (i = 0; care->command != NULL && care->command[i] != NULL; i++)
+		C("'%s'", care->command[i]);
+	N("");
+
+	N("PROOT=\"${PROOT-$(dirname $0)/proot}\"");
+	N("");
+
+	N("if [ ! -e ${PROOT} ]; then");
+	N("    PROOT=$(which proot)");
+	N("fi");
+	N("");
+
+	N("if [ -z ${PROOT} ]; then");
+	N("    echo '**********************************************************************'");
+	N("    echo '\"proot\" command not found, please get it from http://proot.me'");
+	N("    echo '**********************************************************************'");
+	N("    exit 1");
+	N("fi");
+	N("");
+
+	N("if [ x$PROOT_NO_SECCOMP != x ]; then");
+	N("    PROOT_NO_SECCOMP=\"PROOT_NO_SECCOMP=$PROOT_NO_SECCOMP\"");
+	N("fi");
+	N("");
+
+	C("env --ignore-environment");
+	C("PROOT_IGNORE_MISSING_BINDINGS=1");
+	C("$PROOT_NO_SECCOMP");
+
+	for (i = 0; environ[i] != NULL; i++) {
+		const char *volatile_envar;
+
+		volatile_envar = find_volatile_envar(care, environ[i]);
+		if (volatile_envar != NULL)
+			C("'%1$s'=\"$%1$s\" ", volatile_envar);
+		else {
+			const char *string = escape_quote(care, environ[i]);
+			C("'%s' ", string ?: environ[i]);
+		}
+	}
+
+	C("\"${PROOT-$(dirname $0)/proot}\"");
+
+	if (care->volatile_paths != NULL) {
+		/* If a volatile path is relative to $HOME, use an
+		 * asymmetric binding.  For instance:
+		 *
+		 *     -b $HOME/.Xauthority:/home/user/.Xauthority
+		 *
+		 * where "/home/user" was the $HOME during the
+		 * original execution.  */
+		STAILQ_FOREACH(item, care->volatile_paths, link) {
+			const char *name = talloc_get_name(item);
+			if (name[0] == '$')
+				C("-b \"%s:%s\" ", name, (char *) item->load);
+			else
+				C("-b \"%s\" ", (char *) item->load);
+		}
+	}
+
+	status = uname(&utsname);
+	if (status < 0) {
+		note(NULL, WARNING, SYSTEM, "can't get kernel release");
+		C("-k 3.17.0");
+	}
+	else {
+		C("-k '\\%s\\%s\\%s\\%s\\%s\\%s\\0\\' ",
+			utsname.sysname,
+			utsname.nodename,
+			utsname.release,
+			utsname.version,
+			utsname.machine,
+			utsname.domainname);
+	}
+
+	C("-i %d:%d", getuid(), getgid());
+	C("-w '%s' ", care->initial_cwd);
+	C("-r \"$(dirname $0)/rootfs\"");
+
+	/* In case the program retrieves its DSOs from /proc/self/maps
+	 * (eg. VLC). */
+	C("-b \"$(dirname $0)/rootfs\"");
+	N("${1+\"$@\"}");
+	N("");
+
+	N("status=$?");
+	N("if [ $status -ne %d ] && [ $nbargs -eq 0 ]; then", care->last_exit_status);
+	N("echo \"care: The reproduced execution didn't return the same exit status as the\"");
+	N("echo \"care: original execution.  If it is unexpected, please report this bug\"");
+	N("echo \"care: to CARE/PRoot developers:\"");
+	N("echo \"care:     * mailing list: reproducible@googlegroups.com; or\"");
+	N("echo \"care:     * forum: https://groups.google.com/forum/?fromgroups#!forum/reproducible; or\"");
+	N("echo \"care:     * issue tracker: https://github.com/cedric-vincent/PRoot/issues/\"");
+	N("fi");
+	N("");
+	N("exit $status");
+
+	return archive_close_file(care, file, "re-execute.sh");
+}
+
+/**
+ * Archive the "concealed-accesses.txt" file in @care->archive,
+ * according to the content of @care->concealed_accesses.  This
+ * function returns < 0 if an error occured, 0 otherwise.  Note: this
+ * function is called in @care's destructor.
+ */
+static int archive_concealed_accesses_txt(const Care *care)
+{
+	const Item *item;
+	FILE *file;
+
+	if (care->concealed_accesses == NULL)
+		return 0;
+
+	file = open_temp_file(NULL, "care");
+	if (file == NULL) {
+		note(NULL, WARNING, INTERNAL,
+			"can't create temporary file for 'concealed-accesses.txt'");
+		return -1;
+	}
+
+	STAILQ_FOREACH(item, care->concealed_accesses, link)
+		N("%s", (char *) item->load);
+
+	return archive_close_file(care, file, "concealed-accesses.txt");
+}
+
+/**
+ * Archive the "README.txt" file in @care->archive.  This function
+ * returns < 0 if an error occured, 0 otherwise.  Note: this function
+ * is called in @care's destructor.
+ */
+static int archive_readme_txt(const Care *care)
+{
+	FILE *file;
+
+	file = open_temp_file(NULL, "care");
+	if (file == NULL) {
+		note(NULL, WARNING, INTERNAL, "can't create temporary file for 'README.txt'");
+		return -1;
+	}
+
+	N("This archive was created with CARE: http://reproducible.io. It contains:");
+	N("");
+	N("re-execute.sh");
+	N("    start the re-execution of the initial command as originally");
+	N("    specified.  It is also possible to specify an alternate command.");
+	N("    For example, assuming gcc was archived, it can be re-invoked");
+	N("    differently:");
+	N("");
+	N("        $ ./re-execute.sh gcc --version");
+	N("        gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2");
+	N("");
+	N("        $ echo 'int main(void) { return puts(\"OK\"); }' > rootfs/foo.c");
+	N("        $ ./re-execute.sh gcc -Wall /foo.c");
+	N("        $ foo.c: In function \"main\":");
+	N("        $ foo.c:1:1: warning: implicit declaration of function \"puts\"");
+	N("");
+	N("rootfs/");
+	N("    directory where all the files used during the original execution");
+	N("    were archived, they will be required for the reproduced execution.");
+	N("");
+	N("proot");
+	N("    virtualization tool invoked by re-execute.sh to confine the");
+	N("    reproduced execution into the rootfs.  It also emulates the");
+	N("    missing kernel features if needed.");
+	N("");
+	N("concealed-accesses.txt");
+	N("    list of accessed paths that were concealed during the original");
+	N("    execution.  Its main purpose is to know what are the paths that");
+	N("    should be revealed if the the original execution didn't go as");
+	N("    expected.  It is absolutely useless for the reproduced execution.");
+	N("");
+
+	return archive_close_file(care, file, "README.txt");
+}
+
+#undef N
+#undef C
+
+#if !defined(CARE_BINARY_IS_PORTABLE)
+static int archive_myself(const Care *care) UNUSED;
+#endif
+
+/**
+ * Archive the content pointed to by "/proc/self/exe" in
+ * "@care->archive:@care->prefix/proot".  Note: this function is
+ * called in @care's destructor.
+ */
+static int archive_myself(const Care *care)
+{
+	char path[PATH_MAX];
+	struct stat statl;
+	char *location;
+	int status;
+
+	status = readlink("/proc/self/exe", path, PATH_MAX);
+	if (status >= PATH_MAX) {
+		status = -1;
+		errno = ENAMETOOLONG;
+	}
+	if (status < 0) {
+		note(NULL, ERROR, SYSTEM, "can't readlink '/proc/self/exe'");
+		return status;
+	}
+	path[status] = '\0';
+
+	status = lstat(path, &statl);
+	if (status < 0) {
+		note(NULL, ERROR, INTERNAL, "can't lstat '%s'", path);
+		return status;
+	}
+
+	location = talloc_asprintf(care, "%s/proot", care->prefix);
+	if (location == NULL) {
+		note(NULL, ERROR, INTERNAL, "can't allocate location for 'proot'");
+		return -1;
+	}
+
+	return archive(NULL, care->archive, path, location, &statl);
+}
+
+/**
+ * Archive "re-execute.sh" & "proot" from @care.  This function
+ * always returns 0.  Note: this is a Talloc destructor.
+ */
+int finalize_care(Care *care)
+{
+	char *extractor;
+	int status;
+
+	/* Generate & archive the "re-execute.sh" script. */
+	status = archive_re_execute_sh(care);
+	if (status < 0)
+		note(NULL, WARNING, INTERNAL, "can't archive 're-execute.sh'");
+
+	/* Generate & archive the "concealed-accesses.txt" file. */
+	status = archive_concealed_accesses_txt(care);
+	if (status < 0)
+		note(NULL, WARNING, INTERNAL, "can't archive 'concealed-accesses.txt'");
+
+	/* Generate & archive the "README.txt" file. */
+	status = archive_readme_txt(care);
+	if (status < 0)
+		note(NULL, WARNING, INTERNAL, "can't archive 'README.txt'");
+
+#if defined(CARE_BINARY_IS_PORTABLE)
+	/* Archive "care" as "proot", these are the same binary. */
+	status = archive_myself(care);
+	if (status < 0)
+		note(NULL, WARNING, INTERNAL, "can't archive 'proot'");
+#endif
+
+	finalize_archive(care->archive);
+
+	/* Append self/raw extracting information if needed.  */
+	if (care->archive->fd >= 0 && care->archive->offset > 0) {
+		AutoExtractInfo info;
+		off_t position;
+
+		strcpy(info.signature, AUTOEXTRACT_SIGNATURE);
+
+		/* Compute the size of the archive.  */
+		position = lseek(care->archive->fd, 0, SEEK_CUR);
+		assert(position > care->archive->offset);
+		info.size = htobe64(position - care->archive->offset);
+
+		status = write(care->archive->fd, &info, sizeof(info));
+		if (status != sizeof(info))
+			note(NULL, WARNING, SYSTEM, "can't write extracting information");
+
+		(void) close(care->archive->fd);
+		care->archive->fd = -1;
+
+		if (care->archive->offset == strlen("RAW"))
+			extractor = talloc_asprintf(care, "`care -x %s`", care->output);
+		else
+			extractor = talloc_asprintf(care, "`%2$s%1$s` or `care -x %1$s`",
+						care->output, care->output[0] == '/' ? "" : "./");
+	}
+	else if (care->output[strlen(care->output) - 1] != '/')
+		extractor = talloc_asprintf(care, "`care -x %s`", care->output);
+	else
+		extractor = NULL;
+
+	note(NULL, INFO, USER,
+		"----------------------------------------------------------------------");
+	note(NULL, INFO, USER, "Hints:");
+	note(NULL, INFO, USER,
+		"  - search for \"conceal\" in `care -h` if the execution didn't go as expected.");
+
+	if (extractor != NULL)
+		note(NULL, INFO, USER, "  - run %s to extract the output archive correctly.", extractor);
+
+	return 0;
+}
diff --git a/5.1.0/src/extension/care/final.h b/5.1.0/src/extension/care/final.h
new file mode 100644
index 0000000..9ea1bbb
--- /dev/null
+++ b/5.1.0/src/extension/care/final.h
@@ -0,0 +1,30 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef CARE_FINAL_H
+#define CARE_FINAL_H
+
+#include "care.h"
+
+extern int finalize_care(Care *care);
+
+#endif /* CARE_FINAL_H */
diff --git a/5.1.0/src/extension/extension.c b/5.1.0/src/extension/extension.c
new file mode 100644
index 0000000..997104b
--- /dev/null
+++ b/5.1.0/src/extension/extension.c
@@ -0,0 +1,150 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <assert.h>     /* assert(3), */
+#include <talloc.h>     /* talloc_*, */
+#include <sys/queue.h>  /* LIST_*, */
+#include <strings.h>    /* bzero(3), */
+
+#include "extension/extension.h"
+#include "cli/note.h"
+#include "build.h"
+
+#include "compat.h"
+
+/**
+ * Remove an @extension from its tracee's list, then send it the
+ * "REMOVED" event.
+ *
+ * Note: this is a Talloc destructor.
+ */
+static int remove_extension(Extension *extension)
+{
+	LIST_REMOVE(extension, link);
+	extension->callback(extension, REMOVED, 0, 0);
+
+	bzero(extension, sizeof(Extension));
+	return 0;
+}
+
+/**
+ * Allocate a new extension for the given @callback then attach it to
+ * its @tracee.  This function returns NULL on error, otherwise the
+ * new extension.
+ */
+static Extension *new_extension(Tracee *tracee, extension_callback_t callback)
+{
+	Extension *extension;
+
+	/* Lazy allocation of the list head. */
+	if (tracee->extensions == NULL) {
+		tracee->extensions = talloc_zero(tracee, Extensions);
+		if (tracee->extensions == NULL)
+			return NULL;
+	}
+
+	/* Allocate a new extension. */
+	extension = talloc_zero(tracee->extensions, Extension);
+	if (extension == NULL)
+		return NULL;
+	extension->callback = callback;
+
+	/* Attach it to its tracee. */
+	LIST_INSERT_HEAD(tracee->extensions, extension, link);
+	talloc_set_destructor(extension, remove_extension);
+
+	return extension;
+}
+
+/**
+ * Initialize a new extension for the given @callback then attach it
+ * to its @tracee.  The parameter @cli is its argument that was passed
+ * to the command-line interface.  This function return -1 if an error
+ * occurred, otherwise 0.
+ */
+int initialize_extension(Tracee *tracee, extension_callback_t callback, const char *cli)
+{
+	Extension *extension;
+	int status;
+
+	extension = new_extension(tracee, callback);
+	if (extension == NULL) {
+		note(tracee, WARNING, INTERNAL, "can't create a new extension");
+		return -1;
+	}
+
+	/* Remove the new extension if its initialized has failed.  */
+	status = extension->callback(extension, INITIALIZATION, (intptr_t) cli, 0);
+	if (status < 0) {
+		TALLOC_FREE(extension);
+		return status;
+	}
+
+	return 0;
+}
+
+/**
+ * Rebuild a new list of extensions for this @child from its @parent.
+ * The inheritance model is controlled by the @parent.
+ */
+void inherit_extensions(Tracee *child, Tracee *parent, word_t clone_flags)
+{
+	Extension *parent_extension;
+	Extension *child_extension;
+	int status;
+
+	if (parent->extensions == NULL)
+		return;
+
+	/* Sanity check.  */
+	assert(child->extensions == NULL || clone_flags == CLONE_RECONF);
+
+	LIST_FOREACH(parent_extension, parent->extensions, link) {
+		/* Ask the parent how this extension is
+		 * inheritable.  */
+		status = parent_extension->callback(parent_extension, INHERIT_PARENT,
+						(intptr_t)child, clone_flags);
+
+		/* Not inheritable.  */
+		if (status < 0)
+			continue;
+
+		/* Inheritable...  */
+		child_extension = new_extension(child, parent_extension->callback);
+		if (child_extension == NULL) {
+			note(parent, WARNING, INTERNAL,
+				"can't create a new extension for pid %d", child->pid);
+			continue;
+		}
+
+		if (status == 0) {
+			/* ... with a shared config or ...  */
+			child_extension->config =
+				talloc_reference(child_extension, parent_extension->config);
+		}
+		else {
+			/* ... with another inheritance model.  */
+			child_extension->callback(child_extension, INHERIT_CHILD,
+						(intptr_t)parent_extension, clone_flags);
+		}
+	}
+}
diff --git a/5.1.0/src/extension/extension.h b/5.1.0/src/extension/extension.h
new file mode 100644
index 0000000..3edafa2
--- /dev/null
+++ b/5.1.0/src/extension/extension.h
@@ -0,0 +1,183 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef EXTENSION_H
+#define EXTENSION_H
+
+#include <sys/queue.h> /* LIST_, */
+#include <stdint.h>    /* intptr_t, */
+#include <stdbool.h>   /* bool, */
+
+#include "tracee/tracee.h"
+#include "syscall/seccomp.h"
+
+/* List of possible events.  */
+typedef enum {
+	/* A guest path passed as an argument of the current syscall
+	 * is about to be translated: "(char *) data1" is the base for
+	 * "(char *) data2" -- the guest path -- if this latter is
+	 * relative.  If the extension returns > 0, then PRoot skips
+	 * its own handling.  If the extension returns < 0, then PRoot
+	 * reports this errno as-is.  */
+	GUEST_PATH,
+
+	/* A canonicalized host path is being accessed during the
+	 * translation of a guest path: "(char *) data1" is the
+	 * canonicalized host path and "(bool) data2" is true if it is
+	 * the final path.  Note that several host paths are accessed
+	 * for a given guest path since PRoot has to walk along all
+	 * parent directories and symlinks in order to translate it.
+	 * If the extension returns < 0, then PRoot reports this errno
+	 * as-is.  */
+	HOST_PATH,
+
+	/* The tracee enters a syscall, and PRoot hasn't do anything
+	 * yet.  If the extension returns > 0, then PRoot skips its
+	 * own handling.  If the extension returns < 0, then PRoot
+	 * cancels the syscall and reports this errno to the
+	 * tracee.  */
+	SYSCALL_ENTER_START,
+
+	/* The tracee enters a syscall, and PRoot has already handled
+	 * it: "(int) data1" is the current status, it is < 0 when
+	 * something went wrong.  If the extension returns < 0, then
+	 * PRoot cancels the syscall and reports this errno to the
+	 * tracee.  */
+	SYSCALL_ENTER_END,
+
+	/* The tracee exits a syscall, and PRoot hasn't do anything
+	 * yet.  If the extension returns > 0, then PRoot skips its
+	 * own handling.  If the extension returns < 0, then PRoot
+	 * reports this errno to the tracee.  */
+	SYSCALL_EXIT_START,
+
+	/* The tracee exits a syscall, and PRoot has already handled
+	 * it.  If the extension returns < 0, then PRoot reports this
+	 * errno to the tracee.  */
+	SYSCALL_EXIT_END,
+
+	/* The tracee is stopped either because of a syscall or a
+	 * signal: "(int) data1" is its new status as reported by
+	 * waitpid(2).  If the extension returns != 0, then PRoot
+	 * skips its own handling.  */
+	NEW_STATUS,
+
+	/* Ask how this extension is inheritable: "(Tracee *) data1"
+	 * is the child tracee and "(bool) data2" is the clone(2)
+	 * flags (CLONE_RECONF for sub-reconfiguration).  The meaning
+	 * of the returned value is:
+	 *
+	 *   < 0 : not inheritable
+	 *  == 0 : inheritable + shared configuration.
+	 *   > 0 : inheritable + call INHERIT_CHILD.  */
+	INHERIT_PARENT,
+
+	/* Control the inheritance: "(Extension *) data1" is the
+	 * extension of the parent and "(word_t) data2" is the clone(2)
+	 * flags (CLONE_RECONF for sub-reconfiguration).  For instance
+	 * the extension for the child could use a configuration
+	 * different from the parent's configuration.  */
+	INHERIT_CHILD,
+
+	/* The tracee enters a "chained" syscall, that is, an
+	 * unrequested syscall inserted by PRoot after an actual
+	 * syscall.  If the extension returns < 0, then PRoot cancels
+	 * the syscall and reports this errno to the tracee.  */
+	SYSCALL_CHAINED_ENTER,
+
+	/* The tracee exists a "chained" syscall, that is, an
+	 * unrequested syscall inserted by PRoot after an actual
+	 * syscall.  */
+	SYSCALL_CHAINED_EXIT,
+
+	/* Initialize the extension: "(const char *) data1" is its
+	 * argument that was passed to the command-line interface.  If
+	 * the extension returns < 0, then PRoot removed it.  */
+	INITIALIZATION,
+
+	/* The extension is not attached to its tracee anymore
+	 * (destructor).  */
+	REMOVED,
+
+	/* Print the current configuration of the extension.  See
+	 * print_config() as an example.  */
+	PRINT_CONFIG,
+
+	/* Print the usage of the extension: "(bool) data1" is true
+	 * for a detailed usage.  See print_usage() as an example.  */
+	PRINT_USAGE,
+} ExtensionEvent;
+
+#define CLONE_RECONF ((word_t) -1)
+
+struct extension;
+typedef int (*extension_callback_t)(struct extension *extension, ExtensionEvent event,
+				intptr_t data1, intptr_t data2);
+
+typedef struct extension {
+	/* Function to be called when any event occured.  */
+	extension_callback_t callback;
+
+	/* A chunk of memory allocated by any talloc functions.
+	 * Mainly useful to store a configuration.  */
+	TALLOC_CTX *config;
+
+	/* List of sysnum handled by this extension.  */
+	const FilteredSysnum *filtered_sysnums;
+
+	/* Link to the next and previous extensions.  Note the order
+	 * is *never* garantee.  */
+	LIST_ENTRY(extension) link;
+} Extension;
+
+typedef LIST_HEAD(extensions, extension) Extensions;
+
+extern int initialize_extension(Tracee *tracee, extension_callback_t callback, const char *cli);
+extern void inherit_extensions(Tracee *child, Tracee *parent, word_t clone_flags);
+
+/**
+ * Notify all extensions of @tracee that the given @event occured.
+ * See ExtensionEvent for the meaning of @data1 and @data2.
+ */
+static inline int notify_extensions(Tracee *tracee, ExtensionEvent event,
+				intptr_t data1, intptr_t data2)
+{
+	Extension *extension;
+
+	if (tracee->extensions == NULL)
+		return 0;
+
+	LIST_FOREACH(extension, tracee->extensions, link) {
+		int status = extension->callback(extension, event, data1, data2);
+		if (status != 0)
+			return status;
+	}
+
+	return 0;
+}
+
+/* Built-in extensions.  */
+extern int kompat_callback(Extension *extension, ExtensionEvent event, intptr_t d1, intptr_t d2);
+extern int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t d1, intptr_t d2);
+extern int care_callback(Extension *extension, ExtensionEvent event, intptr_t d1, intptr_t d2);
+
+#endif /* EXTENSION_H */
diff --git a/5.1.0/src/extension/fake_id0/fake_id0.c b/5.1.0/src/extension/fake_id0/fake_id0.c
new file mode 100644
index 0000000..346f4dc
--- /dev/null
+++ b/5.1.0/src/extension/fake_id0/fake_id0.c
@@ -0,0 +1,868 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <assert.h>      /* assert(3), */
+#include <stdint.h>      /* intptr_t, */
+#include <errno.h>       /* E*, */
+#include <sys/stat.h>    /* chmod(2), stat(2) */
+#include <sys/types.h>   /* uid_t, gid_t, get*id(2), */
+#include <unistd.h>      /* get*id(2),  */
+#include <sys/ptrace.h>  /* linux.git:c0a3a20b  */
+#include <linux/audit.h> /* AUDIT_ARCH_*,  */
+#include <string.h>      /* memcpy(3), */
+#include <stdlib.h>      /* strtol(3), */
+#include <linux/auxvec.h>/* AT_,  */
+
+#include "extension/extension.h"
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "syscall/seccomp.h"
+#include "tracee/tracee.h"
+#include "tracee/abi.h"
+#include "tracee/mem.h"
+#include "execve/auxv.h"
+#include "path/binding.h"
+#include "arch.h"
+
+typedef struct {
+	uid_t ruid;
+	uid_t euid;
+	uid_t suid;
+	uid_t fsuid;
+
+	gid_t rgid;
+	gid_t egid;
+	gid_t sgid;
+	gid_t fsgid;
+} Config;
+
+typedef struct {
+	char *path;
+	mode_t mode;
+} ModifiedNode;
+
+/* List of syscalls handled by this extensions.  */
+static FilteredSysnum filtered_sysnums[] = {
+	{ PR_capset,		FILTER_SYSEXIT },
+	{ PR_chmod,		FILTER_SYSEXIT },
+	{ PR_chown,		FILTER_SYSEXIT },
+	{ PR_chown32,		FILTER_SYSEXIT },
+	{ PR_chroot,		FILTER_SYSEXIT },
+	{ PR_execve,		FILTER_SYSEXIT },
+	{ PR_fchmod,		FILTER_SYSEXIT },
+	{ PR_fchmodat,		FILTER_SYSEXIT },
+	{ PR_fchown,		FILTER_SYSEXIT },
+	{ PR_fchown32,		FILTER_SYSEXIT },
+	{ PR_fchownat,		FILTER_SYSEXIT },
+	{ PR_fstat,		FILTER_SYSEXIT },
+	{ PR_fstat,		FILTER_SYSEXIT },
+	{ PR_fstat64,		FILTER_SYSEXIT },
+	{ PR_fstatat64,		FILTER_SYSEXIT },
+	{ PR_getegid,		FILTER_SYSEXIT },
+	{ PR_getegid32,		FILTER_SYSEXIT },
+	{ PR_geteuid,		FILTER_SYSEXIT },
+	{ PR_geteuid32,		FILTER_SYSEXIT },
+	{ PR_getgid,		FILTER_SYSEXIT },
+	{ PR_getgid32,		FILTER_SYSEXIT },
+	{ PR_getgroups,		FILTER_SYSEXIT },
+	{ PR_getgroups32,	FILTER_SYSEXIT },
+	{ PR_getresgid,		FILTER_SYSEXIT },
+	{ PR_getresgid32,	FILTER_SYSEXIT },
+	{ PR_getresuid,		FILTER_SYSEXIT },
+	{ PR_getresuid32,	FILTER_SYSEXIT },
+	{ PR_getuid,		FILTER_SYSEXIT },
+	{ PR_getuid32,		FILTER_SYSEXIT },
+	{ PR_lchown,		FILTER_SYSEXIT },
+	{ PR_lchown32,		FILTER_SYSEXIT },
+	{ PR_lstat,		FILTER_SYSEXIT },
+	{ PR_lstat64,		FILTER_SYSEXIT },
+	{ PR_mknod,		FILTER_SYSEXIT },
+	{ PR_mknodat,		FILTER_SYSEXIT },
+	{ PR_newfstatat,	FILTER_SYSEXIT },
+	{ PR_oldlstat,		FILTER_SYSEXIT },
+	{ PR_oldstat,		FILTER_SYSEXIT },
+	{ PR_setfsgid,		FILTER_SYSEXIT },
+	{ PR_setfsgid32,	FILTER_SYSEXIT },
+	{ PR_setfsuid,		FILTER_SYSEXIT },
+	{ PR_setfsuid32,	FILTER_SYSEXIT },
+	{ PR_setgid,		FILTER_SYSEXIT },
+	{ PR_setgid32,		FILTER_SYSEXIT },
+	{ PR_setgroups,		FILTER_SYSEXIT },
+	{ PR_setgroups32,	FILTER_SYSEXIT },
+	{ PR_setregid,		FILTER_SYSEXIT },
+	{ PR_setregid32,	FILTER_SYSEXIT },
+	{ PR_setreuid,		FILTER_SYSEXIT },
+	{ PR_setreuid32,	FILTER_SYSEXIT },
+	{ PR_setresgid,		FILTER_SYSEXIT },
+	{ PR_setresgid32,	FILTER_SYSEXIT },
+	{ PR_setresuid,		FILTER_SYSEXIT },
+	{ PR_setresuid32,	FILTER_SYSEXIT },
+	{ PR_setuid,		FILTER_SYSEXIT },
+	{ PR_setuid32,		FILTER_SYSEXIT },
+	{ PR_setxattr,		FILTER_SYSEXIT },
+	{ PR_setdomainname,	FILTER_SYSEXIT },
+	{ PR_sethostname,	FILTER_SYSEXIT },
+	{ PR_lsetxattr,		FILTER_SYSEXIT },
+	{ PR_fsetxattr,		FILTER_SYSEXIT },
+	{ PR_stat,		FILTER_SYSEXIT },
+	{ PR_stat64,		FILTER_SYSEXIT },
+	{ PR_statfs,		FILTER_SYSEXIT },
+	{ PR_statfs64,		FILTER_SYSEXIT },
+	FILTERED_SYSNUM_END,
+};
+
+/**
+ * Restore the @node->mode for the given @node->path.
+ *
+ * Note: this is a Talloc destructor.
+ */
+static int restore_mode(ModifiedNode *node)
+{
+	(void) chmod(node->path, node->mode);
+	return 0;
+}
+
+/**
+ * Force permissions of @path to "rwx" during the path translation of
+ * current @tracee's syscall, in order to simulate CAP_DAC_OVERRIDE.
+ * The original permissions are restored through talloc destructors.
+ * See canonicalize() for the meaning of @is_final.
+ */
+static void override_permissions(const Tracee *tracee, const char *path, bool is_final)
+{
+	ModifiedNode *node;
+	struct stat perms;
+	mode_t new_mode;
+	int status;
+
+	/* Get the meta-data */
+	status = stat(path, &perms);
+	if (status < 0)
+		return;
+
+	/* Copy the current permissions */
+	new_mode = perms.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+
+	/* Add read and write permissions to everything.  */
+	new_mode |= (S_IRUSR | S_IWUSR);
+
+	/* Always add 'x' bit to directories */
+	if (S_ISDIR(perms.st_mode))
+		new_mode |= S_IXUSR;
+
+	/* Patch the permissions only if needed.  */
+	if (new_mode == (perms.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
+		return;
+
+	node = talloc_zero(tracee->ctx, ModifiedNode);
+	if (node == NULL)
+		return;
+
+	if (!is_final) {
+		/* Restore the previous mode of any non final components.  */
+		node->mode = perms.st_mode;
+	}
+	else {
+		switch (get_sysnum(tracee, ORIGINAL)) {
+		/* For chmod syscalls: restore the new mode of the final component.  */
+		case PR_chmod:
+			node->mode = peek_reg(tracee, ORIGINAL, SYSARG_2);
+			break;
+
+		case PR_fchmodat:
+			node->mode = peek_reg(tracee, ORIGINAL, SYSARG_3);
+			break;
+
+		/* For stat syscalls: don't touch the mode of the final component.  */
+		case PR_fstatat64:
+		case PR_lstat:
+		case PR_lstat64:
+		case PR_newfstatat:
+		case PR_oldlstat:
+		case PR_oldstat:
+		case PR_stat:
+		case PR_stat64:
+		case PR_statfs:
+		case PR_statfs64:
+			return;
+
+		/* Otherwise: restore the previous mode of the final component.  */
+		default:
+			node->mode = perms.st_mode;
+			break;
+		}
+	}
+
+	node->path = talloc_strdup(node, path);
+	if (node->path == NULL) {
+		/* Keep only consistent nodes.  */
+		TALLOC_FREE(node);
+		return;
+	}
+
+	/* The mode restoration works because Talloc destructors are
+	 * called in reverse order.  */
+	talloc_set_destructor(node, restore_mode);
+
+	(void) chmod(path, new_mode);
+
+	return;
+}
+
+/**
+ * Adjust current @tracee's syscall parameters according to @config.
+ * This function always returns 0.
+ */
+static int handle_sysenter_end(Tracee *tracee, const Config *config)
+{
+	word_t sysnum;
+
+	sysnum = get_sysnum(tracee, ORIGINAL);
+	switch (sysnum) {
+	case PR_setuid:
+	case PR_setuid32:
+	case PR_setgid:
+	case PR_setgid32:
+	case PR_setreuid:
+	case PR_setreuid32:
+	case PR_setregid:
+	case PR_setregid32:
+	case PR_setresuid:
+	case PR_setresuid32:
+	case PR_setresgid:
+	case PR_setresgid32:
+	case PR_setfsuid:
+	case PR_setfsuid32:
+	case PR_setfsgid:
+	case PR_setfsgid32:
+		/* These syscalls are fully emulated.  */
+		set_sysnum(tracee, PR_void);
+		return 0;
+
+	case PR_chown:
+	case PR_chown32:
+	case PR_lchown:
+	case PR_lchown32:
+	case PR_fchown:
+	case PR_fchown32:
+	case PR_fchownat: {
+		Reg uid_sysarg;
+		Reg gid_sysarg;
+		uid_t uid;
+		gid_t gid;
+
+		if (sysnum == PR_fchownat) {
+			uid_sysarg = SYSARG_3;
+			gid_sysarg = SYSARG_4;
+		}
+		else {
+			uid_sysarg = SYSARG_2;
+			gid_sysarg = SYSARG_3;
+		}
+
+		uid = peek_reg(tracee, ORIGINAL, uid_sysarg);
+		gid = peek_reg(tracee, ORIGINAL, gid_sysarg);
+
+		/* Swap actual and emulated ids to get a chance of
+		 * success.  */
+		if (uid == config->ruid)
+			poke_reg(tracee, uid_sysarg, getuid());
+		if (gid == config->rgid)
+			poke_reg(tracee, gid_sysarg, getgid());
+
+		return 0;
+	}
+
+	case PR_setgroups:
+	case PR_setgroups32:
+	case PR_getgroups:
+	case PR_getgroups32:
+		/* TODO */
+
+	default:
+		return 0;
+	}
+
+	/* Never reached  */
+	assert(0);
+	return 0;
+
+}
+
+/**
+ * Copy config->@field to the tracee's memory location pointed to by @sysarg.
+ */
+#define POKE_MEM_ID(sysarg, field) do {					\
+	poke_uint16(tracee, peek_reg(tracee, ORIGINAL, sysarg), config->field);	\
+	if (errno != 0)							\
+		return -errno;						\
+} while (0)
+
+/**
+ * Emulate setuid(2) and setgid(2).
+ */
+#define SETXID(id) do {							\
+	id ## _t id = peek_reg(tracee, ORIGINAL, SYSARG_1);		\
+	bool allowed;							\
+									\
+	/* "EPERM: The user is not privileged (does not have the	\
+	 * CAP_SETUID capability) and uid does not match the real UID	\
+	 * or saved set-user-ID of the calling process." -- man		\
+	 * setuid */							\
+	allowed = (config->euid == 0 /* TODO: || HAS_CAP(SETUID) */	\
+		|| id == config->r ## id				\
+		|| id == config->e ## id				\
+		|| id == config->s ## id);				\
+	if (!allowed)							\
+		return -EPERM;						\
+									\
+	/* "If the effective UID of the caller is root, the real UID	\
+	 * and saved set-user-ID are also set." -- man setuid */	\
+	if (config->e ## id == 0) {					\
+		config->r ## id = id;					\
+		config->s ## id = id;					\
+	}								\
+									\
+	/* "whenever the effective user ID is changed, fsuid will also	\
+	 * be changed to the new value of the effective user ID."  --	\
+	 * man setfsuid */						\
+	config->e ## id  = id;						\
+	config->fs ## id = id;						\
+									\
+	poke_reg(tracee, SYSARG_RESULT, 0);				\
+	return 0;							\
+} while (0)
+
+/**
+ * Check whether @id is set or not.
+ */
+#define UNSET_ID(id) (id == (uid_t) -1)
+
+/**
+ * Check whether @id is change or not.
+ */
+#define UNCHANGED_ID(id) (UNSET_ID(id) || id == config->id)
+
+/**
+ * Emulate setreuid(2) and setregid(2).
+ */
+#define SETREXID(id) do {						\
+	id ## _t r ## id = peek_reg(tracee, ORIGINAL, SYSARG_1);	\
+	id ## _t e ## id = peek_reg(tracee, ORIGINAL, SYSARG_2);	\
+	bool allowed;							\
+									\
+	/* "Unprivileged processes may only set the effective user ID	\
+	 * to the real user ID, the effective user ID, or the saved	\
+	 * set-user-ID.							\
+	 *								\
+	 * Unprivileged users may only set the real user ID to the	\
+	 * real user ID or the effective user ID."			\
+	 *
+	 * "EPERM: The calling process is not privileged (does not	\
+	 * have the CAP_SETUID) and a change other than:		\
+	 * 1. swapping the effective user ID with the real user ID,	\
+	 *    or;							\
+	 * 2. setting one to the value of the other, or ;		\
+	 * 3. setting the effective user ID to the value of the saved	\
+	 *    set-user-ID						\
+	 * was specified." -- man setreuid				\
+	 *								\
+	 * Is it possible to "ruid <- euid" and "euid <- suid" at the	\
+	 * same time?  */						\
+	allowed = (config->euid == 0 /* TODO: || HAS_CAP(SETUID) */	\
+		|| (UNCHANGED_ID(e ## id) && UNCHANGED_ID(r ## id))	\
+		|| (r ## id == config->e ## id && (e ## id == config->r ## id || UNCHANGED_ID(e ## id))) \
+		|| (e ## id == config->r ## id && (r ## id == config->e ## id || UNCHANGED_ID(r ## id))) \
+		|| (e ## id == config->s ## id && UNCHANGED_ID(r ## id))); \
+	if (!allowed)							\
+		return -EPERM;						\
+									\
+	/* "Supplying a value of -1 for either the real or effective	\
+	 * user ID forces the system to leave that ID unchanged.	\
+	 * [...]  If the real user ID is set or the effective user ID	\
+	 * is set to a value not equal to the previous real user ID,	\
+	 * the saved set-user-ID will be set to the new effective user	\
+	 * ID." -- man setreuid */					\
+	if (!UNSET_ID(e ## id)) {					\
+		if (e ## id != config->r ## id)				\
+			config->s ## id = e ## id;			\
+									\
+		config->e ## id  = e ## id;				\
+		config->fs ## id = e ## id;				\
+	}								\
+									\
+	/* Since it changes the current ruid value, this has to be	\
+	 * done after euid handling. */					\
+	if (!UNSET_ID(r ## id)) {					\
+		if (!UNSET_ID(e ## id))					\
+			config->s ## id = e ## id;			\
+		config->r ## id = r ## id;				\
+	}								\
+									\
+	poke_reg(tracee, SYSARG_RESULT, 0);				\
+	return 0;							\
+} while (0)
+
+/**
+ * Check if @var is equal to any config->r{@type}id's.
+ */
+#define EQUALS_ANY_ID(var, type)  (var == config->r ## type ## id \
+				|| var == config->e ## type ## id \
+				|| var == config->s ## type ## id)
+
+/**
+ * Emulate setresuid(2) and setresgid(2).
+ */
+#define SETRESXID(type) do {						\
+	type ## id_t r ## type ## id = peek_reg(tracee, ORIGINAL, SYSARG_1);	\
+	type ## id_t e ## type ## id = peek_reg(tracee, ORIGINAL, SYSARG_2);	\
+	type ## id_t s ## type ## id = peek_reg(tracee, ORIGINAL, SYSARG_3);	\
+	bool allowed;							\
+									\
+	/* "Unprivileged user processes may change the real UID,	\
+	 * effective UID, and saved set-user-ID, each to one of: the	\
+	 * current real UID, the current effective UID or the current	\
+	 * saved set-user-ID.						\
+	 *								\
+	 * Privileged processes (on Linux, those having the CAP_SETUID	\
+	 * capability) may set the real UID, effective UID, and saved	\
+	 * set-user-ID to arbitrary values." -- man setresuid */	\
+	allowed = (config->euid == 0 /* || HAS_CAP(SETUID) */		\
+		|| ((UNSET_ID(r ## type ## id) || EQUALS_ANY_ID(r ## type ## id, type)) \
+		 && (UNSET_ID(e ## type ## id) || EQUALS_ANY_ID(e ## type ## id, type)) \
+		 && (UNSET_ID(s ## type ## id) || EQUALS_ANY_ID(s ## type ## id, type)))); \
+	if (!allowed)							\
+		return -EPERM;						\
+									\
+	/* "If one of the arguments equals -1, the corresponding value	\
+	 * is not changed." -- man setresuid */				\
+	if (!UNSET_ID(r ## type ## id))					\
+		config->r ## type ## id = r ## type ## id;		\
+									\
+	if (!UNSET_ID(e ## type ## id)) {				\
+		/* "the file system UID is always set to the same	\
+		 * value as the (possibly new) effective UID." -- man	\
+		 * setresuid */						\
+		config->e ## type ## id  = e ## type ## id;		\
+		config->fs ## type ## id = e ## type ## id;		\
+	}								\
+									\
+	if (!UNSET_ID(s ## type ## id))					\
+		config->s ## type ## id = s ## type ## id;		\
+									\
+	poke_reg(tracee, SYSARG_RESULT, 0);				\
+	return 0;							\
+} while (0)
+
+/**
+ * Emulate setfsuid(2) and setfsgid(2).
+ */
+#define SETFSXID(type) do {						\
+	uid_t fs ## type ## id = peek_reg(tracee, ORIGINAL, SYSARG_1); 	\
+	uid_t old_fs ## type ## id = config->fs ## type ## id;		\
+	bool allowed;							\
+									\
+	/* "setfsuid() will succeed only if the caller is the		\
+	 * superuser or if fsuid matches either the real user ID,	\
+	 * effective user ID, saved set-user-ID, or the current value	\
+	 * of fsuid." -- man setfsuid */				\
+	allowed = (config->euid == 0 /* TODO: || HAS_CAP(SETUID) */	\
+		|| fs ## type ## id == config->fs ## type ## id		\
+		|| EQUALS_ANY_ID(fs ## type ## id, type));		\
+	if (allowed)							\
+		config->fs ## type ## id = fs ## type ## id;		\
+									\
+	/* "On success, the previous value of fsuid is returned.  On	\
+	 * error, the current value of fsuid is returned." -- man	\
+	 * setfsuid */							\
+	poke_reg(tracee, SYSARG_RESULT, old_fs ## type ## id);		\
+	return 0;							\
+} while (0)
+
+/**
+ * Adjust current @tracee's syscall result according to @config.  This
+ * function returns -errno if an error occured, otherwise 0.
+ */
+static int handle_sysexit_end(Tracee *tracee, Config *config)
+{
+	word_t sysnum;
+	word_t result;
+
+	sysnum = get_sysnum(tracee, ORIGINAL);
+	switch (sysnum) {
+
+	case PR_setuid:
+	case PR_setuid32:
+		SETXID(uid);
+
+	case PR_setgid:
+	case PR_setgid32:
+		SETXID(gid);
+
+	case PR_setreuid:
+	case PR_setreuid32:
+		SETREXID(uid);
+
+	case PR_setregid:
+	case PR_setregid32:
+		SETREXID(gid);
+
+	case PR_setresuid:
+	case PR_setresuid32:
+		SETRESXID(u);
+
+	case PR_setresgid:
+	case PR_setresgid32:
+		SETRESXID(g);
+
+	case PR_setfsuid:
+	case PR_setfsuid32:
+		SETFSXID(u);
+
+	case PR_setfsgid:
+	case PR_setfsgid32:
+		SETFSXID(g);
+
+	case PR_getuid:
+	case PR_getuid32:
+		poke_reg(tracee, SYSARG_RESULT, config->ruid);
+		return 0;
+
+	case PR_getgid:
+	case PR_getgid32:
+		poke_reg(tracee, SYSARG_RESULT, config->rgid);
+		return 0;
+
+	case PR_geteuid:
+	case PR_geteuid32:
+		poke_reg(tracee, SYSARG_RESULT, config->euid);
+		return 0;
+
+	case PR_getegid:
+	case PR_getegid32:
+		poke_reg(tracee, SYSARG_RESULT, config->egid);
+		return 0;
+
+	case PR_getresuid:
+	case PR_getresuid32:
+		POKE_MEM_ID(SYSARG_1, ruid);
+		POKE_MEM_ID(SYSARG_2, euid);
+		POKE_MEM_ID(SYSARG_3, suid);
+		return 0;
+
+	case PR_getresgid:
+	case PR_getresgid32:
+		POKE_MEM_ID(SYSARG_1, rgid);
+		POKE_MEM_ID(SYSARG_2, egid);
+		POKE_MEM_ID(SYSARG_3, sgid);
+		return 0;
+
+	case PR_setdomainname:
+	case PR_sethostname:
+	case PR_setgroups:
+	case PR_setgroups32:
+	case PR_mknod:
+	case PR_mknodat:
+	case PR_capset:
+	case PR_setxattr:
+	case PR_lsetxattr:
+	case PR_fsetxattr:
+	case PR_chmod:
+	case PR_chown:
+	case PR_fchmod:
+	case PR_fchown:
+	case PR_lchown:
+	case PR_chown32:
+	case PR_fchown32:
+	case PR_lchown32:
+	case PR_fchmodat:
+	case PR_fchownat: {
+		word_t result;
+
+		/* Override only permission errors.  */
+		result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+		if ((int) result != -EPERM)
+			return 0;
+
+		/* Force success if the tracee was supposed to have
+		 * the capability.  */
+		if (config->euid == 0) /* TODO: || HAS_CAP(...) */
+			poke_reg(tracee, SYSARG_RESULT, 0);
+
+		return 0;
+	}
+
+	case PR_fstatat64:
+	case PR_newfstatat:
+	case PR_stat64:
+	case PR_lstat64:
+	case PR_fstat64:
+	case PR_stat:
+	case PR_lstat:
+	case PR_fstat: {
+		word_t address;
+		Reg sysarg;
+		uid_t uid;
+		gid_t gid;
+
+		/* Override only if it succeed.  */
+		result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+		if (result != 0)
+			return 0;
+
+		/* Get the address of the 'stat' structure.  */
+		if (sysnum == PR_fstatat64 || sysnum == PR_newfstatat)
+			sysarg = SYSARG_3;
+		else
+			sysarg = SYSARG_2;
+
+		address = peek_reg(tracee, ORIGINAL, sysarg);
+
+		/* Sanity checks.  */
+		assert(__builtin_types_compatible_p(uid_t, uint32_t));
+		assert(__builtin_types_compatible_p(gid_t, uint32_t));
+
+		/* Get the uid & gid values from the 'stat' structure.  */
+		uid = peek_uint32(tracee, address + offsetof_stat_uid(tracee));
+		if (errno != 0)
+			uid = 0; /* Not fatal.  */
+
+		gid = peek_uint32(tracee, address + offsetof_stat_gid(tracee));
+		if (errno != 0)
+			gid = 0; /* Not fatal.  */
+
+		/* Override only if the file is owned by the current user.
+		 * Errors are not fatal here.  */
+		if (uid == getuid())
+			poke_uint32(tracee, address + offsetof_stat_uid(tracee), config->ruid);
+
+		if (gid == getgid())
+			poke_uint32(tracee, address + offsetof_stat_gid(tracee), config->rgid);
+
+		return 0;
+	}
+
+	case PR_chroot: {
+		char path[PATH_MAX];
+		word_t input;
+		int status;
+
+		if (config->euid != 0) /* TODO: && !HAS_CAP(SYS_CHROOT) */
+			return 0;
+
+		/* Override only permission errors.  */
+		result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+		if ((int) result != -EPERM)
+			return 0;
+
+		input = peek_reg(tracee, MODIFIED, SYSARG_1);
+
+		status = read_path(tracee, path, input);
+		if (status < 0)
+			return status;
+
+		/* Only "new rootfs == current rootfs" is supported yet.  */
+		status = compare_paths(get_root(tracee), path);
+		if (status != PATHS_ARE_EQUAL)
+			return 0;
+
+		/* Force success.  */
+		poke_reg(tracee, SYSARG_RESULT, 0);
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+}
+
+#undef POKE_MEM_ID
+#undef SETXID
+#undef UNSET_ID
+#undef UNCHANGED_ID
+#undef SETREXID
+#undef EQUALS_ANY_ID
+#undef SETRESXID
+#undef SETFSXID
+
+/**
+ * Adjust some ELF auxiliary vectors.  This function assumes the
+ * "argv, envp, auxv" stuff is pointed to by @tracee's stack pointer,
+ * as expected right after a successful call to execve(2).
+ */
+static int adjust_elf_auxv(Tracee *tracee, Config *config)
+{
+	ElfAuxVector *vectors;
+	ElfAuxVector *vector;
+	word_t vectors_address;
+
+	vectors_address = get_elf_aux_vectors_address(tracee);
+	if (vectors_address == 0)
+		return 0;
+
+	vectors = fetch_elf_aux_vectors(tracee, vectors_address);
+	if (vectors == NULL)
+		return 0;
+
+	for (vector = vectors; vector->type != AT_NULL; vector++) {
+		switch (vector->type) {
+		case AT_UID:
+			vector->value = config->ruid;
+			break;
+
+		case AT_EUID:
+			vector->value = config->euid;
+			break;
+
+		case AT_GID:
+			vector->value = config->rgid;
+			break;
+
+		case AT_EGID:
+			vector->value = config->egid;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	push_elf_aux_vectors(tracee, vectors, vectors_address);
+
+	return 0;
+}
+
+/**
+ * Handler for this @extension.  It is triggered each time an @event
+ * occurred.  See ExtensionEvent for the meaning of @data1 and @data2.
+ */
+int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t data1, intptr_t data2)
+{
+	switch (event) {
+	case INITIALIZATION: {
+		const char *uid_string = (const char *) data1;
+		const char *gid_string;
+		Config *config;
+		int uid, gid;
+
+		errno = 0;
+		uid = strtol(uid_string, NULL, 10);
+		if (errno != 0)
+			uid = getuid();
+
+		gid_string = strchr(uid_string, ':');
+		if (gid_string == NULL) {
+			errno = EINVAL;
+		}
+		else {
+			errno = 0;
+			gid = strtol(gid_string + 1, NULL, 10);
+		}
+		/* Fallback to the current gid if an error occured.  */
+		if (errno != 0)
+			gid = getgid();
+
+		extension->config = talloc(extension, Config);
+		if (extension->config == NULL)
+			return -1;
+
+		config = talloc_get_type_abort(extension->config, Config);
+		config->ruid  = uid;
+		config->euid  = uid;
+		config->suid  = uid;
+		config->fsuid = uid;
+		config->rgid  = gid;
+		config->egid  = gid;
+		config->sgid  = gid;
+		config->fsgid = gid;
+
+		extension->filtered_sysnums = filtered_sysnums;
+		return 0;
+	}
+
+	case INHERIT_PARENT: /* Inheritable for sub reconfiguration ...  */
+		return 1;
+
+	case INHERIT_CHILD: {
+		/* Copy the parent configuration to the child.  The
+		 * structure should not be shared as uid/gid changes
+		 * in one process should not affect other processes.
+		 * This assertion is not true for POSIX threads
+		 * sharing the same group, however Linux threads never
+		 * share uid/gid information.  As a consequence, the
+		 * GlibC emulates the POSIX behavior on Linux by
+		 * sending a signal to all group threads to cause them
+		 * to invoke the system call too.  Finally, PRoot
+		 * doesn't have to worry about clone flags.
+		 */
+
+		Extension *parent = (Extension *) data1;
+		extension->config = talloc_zero(extension, Config);
+		if (extension->config == NULL)
+			return -1;
+
+		memcpy(extension->config, parent->config, sizeof(Config));
+		return 0;
+	}
+
+	case HOST_PATH: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+
+		/* Force permissions if the tracee was supposed to
+		 * have the capability.  */
+		if (config->euid == 0) /* TODO: || HAS_CAP(DAC_OVERRIDE) */
+			override_permissions(tracee, (char*) data1, (bool) data2);
+		return 0;
+	}
+
+	case SYSCALL_ENTER_END: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+
+		return handle_sysenter_end(tracee, config);
+	}
+
+	case SYSCALL_EXIT_END: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+
+		return handle_sysexit_end(tracee, config);
+	}
+
+	case SYSCALL_EXIT_START: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+		word_t result = peek_reg(tracee, CURRENT, SYSARG_RESULT);;
+		word_t sysnum = get_sysnum(tracee, ORIGINAL);
+
+		/* Note: this can be done only before PRoot pushes the
+		 * load script into tracee's stack.  */
+		if ((int) result >= 0 && sysnum == PR_execve)
+			adjust_elf_auxv(tracee, config);
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+}
diff --git a/5.1.0/src/extension/kompat/kompat.c b/5.1.0/src/extension/kompat/kompat.c
new file mode 100644
index 0000000..2bbadb8
--- /dev/null
+++ b/5.1.0/src/extension/kompat/kompat.c
@@ -0,0 +1,1063 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdint.h>        /* intptr_t, */
+#include <stdlib.h>        /* strtoul(3), */
+#include <linux/version.h> /* KERNEL_VERSION, */
+#include <assert.h>        /* assert(3), */
+#include <sys/utsname.h>   /* uname(2), utsname, */
+#include <string.h>        /* str*(3), memcpy(3), */
+#include <talloc.h>        /* talloc_*, */
+#include <fcntl.h>         /* AT_*,  */
+#include <sys/ptrace.h>    /* linux.git:c0a3a20b  */
+#include <errno.h>         /* errno,  */
+#include <linux/auxvec.h>  /* AT_,  */
+#include <linux/futex.h>   /* FUTEX_PRIVATE_FLAG */
+#include <sys/param.h>     /* MIN, */
+
+#include "extension/extension.h"
+#include "syscall/seccomp.h"
+#include "syscall/sysnum.h"
+#include "syscall/chain.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/abi.h"
+#include "tracee/mem.h"
+#include "execve/auxv.h"
+#include "cli/note.h"
+#include "arch.h"
+
+#include "attribute.h"
+#include "compat.h"
+
+#define MAX_ARG_SHIFT 2
+typedef struct {
+	int expected_release;
+	word_t new_sysarg_num;
+	struct {
+		Reg sysarg;     /* first argument to be moved.  */
+		size_t nb_args; /* number of arguments to be moved.  */
+		int offset;     /* offset to be applied.  */
+	} shifts[MAX_ARG_SHIFT];
+} Modif;
+
+#define NONE {{0, 0, 0}}
+
+typedef struct {
+	int actual_release;
+	int virtual_release;
+	struct utsname utsname;
+	word_t hwcap;
+} Config;
+
+/**
+ * Return whether the @expected_release is newer than
+ * @config->actual_release and older than @config->virtual_release.
+ */
+static bool needs_kompat(const Config *config, int expected_release)
+{
+	return (expected_release > config->actual_release
+		&& expected_release <= config->virtual_release);
+}
+
+/**
+ * Modify the current syscall of @tracee as described by @modif
+ * regarding the given @config.  This function returns whether the
+ * syscall was modified or not.
+ */
+static bool modify_syscall(Tracee *tracee, const Config *config, const Modif *modif)
+{
+	size_t i, j;
+	word_t syscall;
+
+	assert(config != NULL);
+
+	if (!needs_kompat(config, modif->expected_release))
+		return false;
+
+	/* Check if this syscall is supported on this architecture.  */
+	syscall = detranslate_sysnum(get_abi(tracee), modif->new_sysarg_num);
+	if (syscall == SYSCALL_AVOIDER)
+		return false;
+
+	set_sysnum(tracee, modif->new_sysarg_num);
+
+	/* Shift syscall arguments.  */
+	for (i = 0; i < MAX_ARG_SHIFT; i++) {
+		Reg sysarg     = modif->shifts[i].sysarg;
+		size_t nb_args = modif->shifts[i].nb_args;
+		int offset     = modif->shifts[i].offset;
+
+		for (j = 0; j < nb_args; j++) {
+			word_t arg = peek_reg(tracee, CURRENT, sysarg + j);
+			poke_reg(tracee, sysarg + j + offset, arg);
+		}
+	}
+
+	return true;
+}
+
+/**
+ * Return the numeric value for the given kernel @release.
+ */
+static int parse_kernel_release(const char *release)
+{
+	unsigned long major = 0;
+	unsigned long minor = 0;
+	unsigned long revision = 0;
+	char *cursor = (char *)release;
+
+	major = strtoul(cursor, &cursor, 10);
+
+	if (*cursor == '.') {
+		cursor++;
+		minor = strtoul(cursor, &cursor, 10);
+	}
+
+	if (*cursor == '.') {
+		cursor++;
+		revision = strtoul(cursor, &cursor, 10);
+	}
+
+	return KERNEL_VERSION(major, minor, revision);
+}
+
+/**
+ * Remove @discarded_flags from the given @tracee's @sysarg register
+ * if the actual kernel release is not compatible with the
+ * @expected_release.
+ */
+static void discard_fd_flags(Tracee *tracee, const Config *config,
+			int discarded_flags, int expected_release, Reg sysarg)
+{
+	word_t flags;
+
+	if (!needs_kompat(config, expected_release))
+		return;
+
+	flags = peek_reg(tracee, CURRENT, sysarg);
+	poke_reg(tracee, sysarg, flags & ~discarded_flags);
+}
+
+/**
+ * Replace current @tracee's syscall with an older and compatible one
+ * whenever it's required, i.e. when the syscall is supported by the
+ * kernel as specified by @config->virtual_release but it isn't
+ * supported by the actual kernel.
+ */
+static int handle_sysenter_end(Tracee *tracee, Config *config)
+{
+	/* Note: syscalls like "openat" can be replaced by "open" since PRoot
+	 * has canonicalized "fd + path" into "path".  */
+	switch (get_sysnum(tracee, ORIGINAL)) {
+	case PR_accept4: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,28),
+			.new_sysarg_num   = PR_accept,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_dup3: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_dup2,
+			.shifts		  = NONE
+		};
+
+		/* "If oldfd equals newfd, then dup3() fails with the
+		 * error EINVAL" -- man dup3 */
+		if (peek_reg(tracee, CURRENT, SYSARG_1) == peek_reg(tracee, CURRENT, SYSARG_2))
+			return -EINVAL;
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_epoll_create1: {
+		bool modified;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_epoll_create,
+			.shifts		  = NONE
+		};
+
+		/* "the size argument is ignored, but must be greater
+		 * than zero" -- man epoll_create */
+		modified = modify_syscall(tracee, config, &modif);
+		if (modified)
+			poke_reg(tracee, SYSARG_1, 1);
+		return 0;
+	}
+
+	case PR_epoll_pwait: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,19),
+			.new_sysarg_num   = PR_epoll_wait,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_eventfd2: {
+		bool modified;
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_eventfd,
+			.shifts		  = NONE
+		};
+
+		modified = modify_syscall(tracee, config, &modif);
+		if (modified) {
+			/* EFD_SEMAPHORE can't be emulated with eventfd.  */
+			flags = peek_reg(tracee, CURRENT, SYSARG_2);
+			if ((flags & EFD_SEMAPHORE) != 0)
+				return -EINVAL;
+		}
+		return 0;
+	}
+
+	case PR_faccessat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_access,
+			.shifts	= { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_fchmodat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_chmod,
+			.shifts	= { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_fchownat: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts	= { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1 }
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_5);
+		modif.new_sysarg_num = ((flags & AT_SYMLINK_NOFOLLOW) != 0
+					? PR_lchown
+					: PR_chown);
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_fcntl: {
+		word_t command;
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,24)))
+			return 0;
+
+		command = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (command == F_DUPFD_CLOEXEC)
+			poke_reg(tracee, SYSARG_2, F_DUPFD);
+
+		return 0;
+	}
+
+	case PR_newfstatat:
+	case PR_fstatat64: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_4);
+		if ((flags & ~AT_SYMLINK_NOFOLLOW) != 0)
+			return -EINVAL; /* Exposed by LTP.  */
+
+#if defined(ARCH_X86_64)
+		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
+			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_lstat : PR_lstat64);
+		else
+			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_stat : PR_stat64);
+#else
+		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
+			modif.new_sysarg_num = PR_lstat64;
+		else
+			modif.new_sysarg_num = PR_stat64;
+#endif
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_futex: {
+		word_t operation;
+		static bool warned = false;
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,22)) || config->actual_release == 0)
+			return 0;
+
+		operation = peek_reg(tracee, CURRENT, SYSARG_2);
+		if ((operation & FUTEX_PRIVATE_FLAG) == 0)
+			return 0;
+
+		if (!warned) {
+			warned = true;
+			note(tracee, WARNING, USER,
+				"kompat: this kernel doesn't support private futexes "
+				"and PRoot can't emulate them.  Expect some troubles...");
+		}
+
+		poke_reg(tracee, SYSARG_2, operation & ~FUTEX_PRIVATE_FLAG);
+		return 0;
+	}
+
+	case PR_futimesat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_utimes,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_inotify_init1: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_inotify_init,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_linkat: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_link,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 1,
+					.offset  = -1 },
+				    [1] = {
+					.sysarg  = SYSARG_4,
+					.nb_args = 1,
+					.offset  = -2 }
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_5);
+		if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
+			return -EINVAL; /* Exposed by LTP.  */
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_mkdirat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_mkdir,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 2,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_mknodat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_mknod,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_openat: {
+		bool modified;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_open,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1 }
+			}
+		};
+		modified = modify_syscall(tracee, config, &modif);
+		discard_fd_flags(tracee, config, O_CLOEXEC, KERNEL_VERSION(2,6,23),
+				modified ? SYSARG_2 : SYSARG_3);
+		return 0;
+	}
+
+	case PR_open:
+		discard_fd_flags(tracee, config, O_CLOEXEC, KERNEL_VERSION(2,6,23), SYSARG_2);
+		return 0;
+
+	case PR_pipe2: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_pipe,
+			.shifts		  = NONE
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_pselect6: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts		  = NONE
+		};
+#if defined(ARCH_X86_64)
+		modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_select : PR__newselect);
+#else
+		modif.new_sysarg_num = PR__newselect;
+#endif
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_readlinkat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_readlink,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 3,
+					.offset  = -1}
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_renameat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_rename,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 1,
+					.offset  =-1 },
+				    [1] = {
+					    .sysarg  = SYSARG_4,
+					    .nb_args = 1,
+					    .offset  = -2 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_renameat2: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(3,15,0),
+			.new_sysarg_num   = PR_rename,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 1,
+					.offset  =-1 },
+				    [1] = {
+					    .sysarg  = SYSARG_4,
+					    .nb_args = 1,
+					    .offset  = -2 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_signalfd4: {
+		bool modified;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,27),
+			.new_sysarg_num   = PR_signalfd,
+			.shifts		  = NONE
+		};
+
+		/* "In Linux up to version 2.6.26, the flags argument
+		 * is unused, and must be specified as zero." -- man
+		 * signalfd */
+		modified = modify_syscall(tracee, config, &modif);
+		if (modified)
+			poke_reg(tracee, SYSARG_4, 0);
+		return 0;
+	}
+
+	case PR_socket:
+	case PR_socketpair:
+	case PR_timerfd_create:
+		discard_fd_flags(tracee, config, O_CLOEXEC | O_NONBLOCK,
+				KERNEL_VERSION(2,6,27), SYSARG_2);
+		return 0;
+
+	case PR_symlinkat: {
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.new_sysarg_num   = PR_symlink,
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_3,
+					.nb_args = 1,
+					.offset  = -1 }
+			}
+		};
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	case PR_unlinkat: {
+		word_t flags;
+		Modif modif = {
+			.expected_release = KERNEL_VERSION(2,6,16),
+			.shifts = { [0] = {
+					.sysarg  = SYSARG_2,
+					.nb_args = 1,
+					.offset  = -1
+				}
+			}
+		};
+
+		flags = peek_reg(tracee, CURRENT, SYSARG_3);
+		modif.new_sysarg_num = ((flags & AT_REMOVEDIR) != 0
+					? PR_rmdir
+					: PR_unlink);
+
+		modify_syscall(tracee, config, &modif);
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Adjust some ELF auxiliary vectors to improve the compatibility.
+ * This function assumes the "argv, envp, auxv" stuff is pointed to by
+ * @tracee's stack pointer, as expected right after a successful call
+ * to execve(2).
+ */
+static void adjust_elf_auxv(Tracee *tracee, Config *config)
+{
+	ElfAuxVector *vectors;
+	ElfAuxVector *vector;
+	word_t vectors_address;
+	word_t stack_pointer;
+	void *argv_envp;
+	size_t size;
+	int status;
+
+	vectors_address = get_elf_aux_vectors_address(tracee);
+	if (vectors_address == 0)
+		return;
+
+	vectors = fetch_elf_aux_vectors(tracee, vectors_address);
+	if (vectors == NULL)
+		return;
+
+	for (vector = vectors; vector->type != AT_NULL; vector++) {
+		switch (vector->type) {
+		/* Discard AT_SYSINFO* vectors: they can be used to
+		 * get the OS release number from memory instead of
+		 * from the uname syscall, and only this latter is
+		 * currently hooked by PRoot.  */
+		case AT_SYSINFO_EHDR:
+		case AT_SYSINFO:
+			vector->type  = AT_IGNORE;
+			vector->value = 0;
+			break;
+
+		case AT_HWCAP:
+			if (config->hwcap != (word_t) -1)
+				vector->value = config->hwcap;
+			break;
+
+		case AT_RANDOM:
+			/* Skip only if not in forced mode.  */
+			if (config->actual_release != 0)
+				goto end;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	/* Add the AT_RANDOM vector only if needed.  */
+	if (!needs_kompat(config, KERNEL_VERSION(2,6,29)))
+		goto end;
+
+	status = add_elf_aux_vector(&vectors, AT_RANDOM, vectors_address);
+	if (status < 0)
+		goto end; /* Not fatal.  */
+
+	/* Since a new vector needs to be added, the ELF auxiliary
+	 * vectors array can't be pushed in place.  As a consequence,
+	 * argv[] and envp[] arrays are moved one vector downward to
+	 * make room for the new ELF auxiliary vectors array.
+	 * Remember, the stack layout is as follow right after execve:
+	 *
+	 *     argv[], envp[], auxv[]
+	 */
+	stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER);
+	size = vectors_address - stack_pointer;
+	argv_envp = talloc_size(tracee->ctx, size);
+	if (argv_envp == NULL)
+		goto end;
+
+	status = read_data(tracee, argv_envp, stack_pointer, size);
+	if (status < 0)
+		goto end;
+
+	/* Allocate enough room in tracee's stack for the new ELF
+	 * auxiliary vector.  */
+	stack_pointer   -= 2 * sizeof_word(tracee);
+	vectors_address -= 2 * sizeof_word(tracee);
+
+	/* Note that it is safe to update the stack pointer manually
+	 * since we are in execve sysexit.  However it should be done
+	 * before transfering data since the kernel might not allow
+	 * page faults below the stack pointer.  */
+	poke_reg(tracee, STACK_POINTER, stack_pointer);
+
+	status = write_data(tracee, stack_pointer, argv_envp, size);
+	if (status < 0)
+		return;
+
+end:
+	push_elf_aux_vectors(tracee, vectors, vectors_address);
+	return;
+}
+
+/**
+ * Append to the @tracee's current syscall enough calls to fcntl(@fd)
+ * in order to set the flags from the original @sysarg register, if
+ * there are also set in @emulated_flags.
+ */
+static void emulate_fd_flags(Tracee *tracee, word_t fd, Reg sysarg, int emulated_flags)
+{
+	word_t flags;
+
+	flags = peek_reg(tracee, ORIGINAL, sysarg);
+	if (flags == 0)
+		return;
+
+	if ((emulated_flags & flags & O_CLOEXEC) != 0)
+		register_chained_syscall(tracee, PR_fcntl, fd, F_SETFD, FD_CLOEXEC, 0, 0, 0);
+
+	if ((emulated_flags & flags & O_NONBLOCK) != 0)
+		register_chained_syscall(tracee, PR_fcntl, fd, F_SETFL, O_NONBLOCK, 0, 0, 0);
+
+	force_chain_final_result(tracee, peek_reg(tracee, CURRENT, SYSARG_RESULT));
+}
+
+/**
+ * Adjust the results/output parameters for syscalls that were
+ * modified in handle_sysenter_end().  This function returns -errno if
+ * an error occured, otherwise 0.
+ */
+static int handle_sysexit_end(Tracee *tracee, Config *config)
+{
+	word_t result;
+	word_t sysnum;
+	int status;
+
+	result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+	sysnum = get_sysnum(tracee, ORIGINAL);
+
+	/* Error reported by the kernel.  */
+	status = (int) result;
+	if (status < 0)
+		return 0;
+
+	switch (sysnum) {
+	case PR_uname: {
+		word_t address;
+
+		address = peek_reg(tracee, ORIGINAL, SYSARG_1);
+
+		/* The layout of struct utsname does not depend on the
+		 * architecture, it only depends on the kernel
+		 * version.  In this regards, this structure is stable
+		 * since < 2.6.0.  */
+		status = write_data(tracee, address, &config->utsname, sizeof(config->utsname));
+		if (status < 0)
+			return status;
+		return 0;
+	}
+
+	case PR_setdomainname:
+	case PR_sethostname: {
+		word_t address;
+		word_t length;
+		char *name;
+
+		name = (sysnum == PR_setdomainname
+			? config->utsname.domainname
+			: config->utsname.nodename);
+
+		length = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (length > sizeof(config->utsname.domainname) - 1)
+			return -EINVAL;
+
+		/* Because of the test above.  */
+		assert(sizeof(config->utsname.domainname) == sizeof(config->utsname.nodename));
+
+		address = peek_reg(tracee, ORIGINAL, SYSARG_1);
+		status  = read_data(tracee, name, address, length);
+		if (status < 0)
+			return status;
+
+		/* "name does not require a terminating null byte." --
+		 * man 2 set{domain,host}name.  */
+		name[length] = '\0';
+
+		return 0;
+	}
+
+	case PR_accept4:
+		if (get_sysnum(tracee, MODIFIED) == PR_accept)
+			emulate_fd_flags(tracee, result, SYSARG_4, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_dup3:
+		if (get_sysnum(tracee, MODIFIED) == PR_dup2)
+			emulate_fd_flags(tracee, peek_reg(tracee, ORIGINAL, SYSARG_2),
+					SYSARG_3, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_epoll_create1:
+		if (get_sysnum(tracee, MODIFIED) == PR_epoll_create)
+			emulate_fd_flags(tracee, result, SYSARG_1, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_eventfd2:
+		if (get_sysnum(tracee, MODIFIED) == PR_eventfd)
+			emulate_fd_flags(tracee, result, SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_fcntl: {
+		word_t command;
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,24)))
+			return 0;
+
+		command = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (command != F_DUPFD_CLOEXEC)
+			return 0;
+
+		register_chained_syscall(tracee, PR_fcntl, result, F_SETFD, FD_CLOEXEC, 0, 0, 0);
+		force_chain_final_result(tracee, peek_reg(tracee, CURRENT, SYSARG_RESULT));
+		return 0;
+	}
+
+	case PR_inotify_init1:
+		if (get_sysnum(tracee, MODIFIED) == PR_inotify_init)
+			emulate_fd_flags(tracee, result, SYSARG_1, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_open:
+		if (needs_kompat(config, KERNEL_VERSION(2,6,23)))
+			emulate_fd_flags(tracee, result, SYSARG_2, O_CLOEXEC);
+		return 0;
+
+	case PR_openat:
+		if (needs_kompat(config, KERNEL_VERSION(2,6,23)))
+			emulate_fd_flags(tracee, result, SYSARG_3, O_CLOEXEC);
+		return 0;
+
+	case PR_pipe2: {
+		int fds[2];
+
+		if (get_sysnum(tracee, MODIFIED) != PR_pipe)
+			return 0;
+
+		status = read_data(tracee, fds, peek_reg(tracee, MODIFIED, SYSARG_1), sizeof(fds));
+		if (status < 0)
+			return 0;
+
+		emulate_fd_flags(tracee, fds[0], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		emulate_fd_flags(tracee, fds[1], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+
+		return 0;
+	}
+
+	case PR_signalfd4:
+		if (get_sysnum(tracee, MODIFIED) == PR_signalfd)
+			emulate_fd_flags(tracee, result, SYSARG_4, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_socket:
+	case PR_timerfd_create:
+		if (needs_kompat(config, KERNEL_VERSION(2,6,27)))
+			emulate_fd_flags(tracee, result, SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		return 0;
+
+	case PR_socketpair: {
+		int fds[2];
+
+		if (!needs_kompat(config, KERNEL_VERSION(2,6,27)))
+			return 0;
+
+		status = read_data(tracee, fds, peek_reg(tracee, MODIFIED, SYSARG_4), sizeof(fds));
+		if (status < 0)
+			return 0;
+
+		emulate_fd_flags(tracee, fds[0], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+		emulate_fd_flags(tracee, fds[1], SYSARG_2, O_CLOEXEC | O_NONBLOCK);
+
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Fill @config->utsname and @config->hwcap according to the content
+ * of @string.  This function returns -1 if there is a parsing error,
+ * otherwise 0.
+ */
+static int parse_utsname(Config *config, const char *string)
+{
+	struct utsname utsname;
+	int status;
+
+	assert(string != NULL);
+
+	status = uname(&utsname);
+	if (status < 0 || getenv("PROOT_FORCE_KOMPAT") != NULL)
+		config->actual_release = 0;
+	else
+		config->actual_release = parse_kernel_release(utsname.release);
+
+	/* Check whether it is the simple format (ie. release number),
+	 * or the complex one:
+	 *
+	 *     '\sysname\nodename\release\version\machine\domainname\hwcap\'
+	 *
+	 * This complex format is ugly on purpose: it ain't to be used
+	 * directly by users.  */
+	if (string[0] == '\\') {
+		const char *start;
+		const char *end;
+		char *end2;
+
+		/* Initial state of the parser.  */
+		end = string;
+
+#define PARSE(field) do {						\
+			size_t length;					\
+									\
+			start = end + 1;				\
+			end   = strchr(start, '\\');			\
+			if (end == NULL) {				\
+				note(NULL, ERROR, USER,			\
+					"can't find %s field in '%s'", #field, string);	\
+				return -1;				\
+			}						\
+									\
+			length = end - start;				\
+			length = MIN(length, sizeof(config->utsname.field) - 1); \
+			strncpy(config->utsname.field, start, length);	\
+			config->utsname.field[length] = '\0';		\
+		} while(0)
+
+		PARSE(sysname);
+		PARSE(nodename);
+		PARSE(release);
+		PARSE(version);
+		PARSE(machine);
+		PARSE(domainname);
+
+#undef PARSE
+
+		/* The hwcap field is parsed as an hexadecimal value.  */
+		errno = 0;
+		config->hwcap = strtol(end + 1, &end2, 16);
+		if (errno != 0 || end2[0] != '\\') {
+			note(NULL, ERROR, USER, "can't find hwcap field in '%s'", string);
+			return -1;
+		}
+	}
+	else {
+		size_t length;
+
+		memcpy(&config->utsname, &utsname, sizeof(config->utsname));
+
+		length = MIN(strlen(string), sizeof(config->utsname.release) - 1);
+		strncpy(config->utsname.release, string, length);
+		config->utsname.release[length] = '\0';
+
+		config->hwcap = (word_t) -1;
+	}
+
+	config->virtual_release = parse_kernel_release(config->utsname.release);
+
+	return 0;
+}
+
+/* List of syscalls handled by this extensions.  */
+static FilteredSysnum filtered_sysnums[] = {
+	{ PR_accept4,		FILTER_SYSEXIT },
+	{ PR_dup3,		FILTER_SYSEXIT },
+	{ PR_epoll_create1,	FILTER_SYSEXIT },
+	{ PR_epoll_pwait, 	0 },
+	{ PR_eventfd2, 		FILTER_SYSEXIT },
+	{ PR_execve, 		FILTER_SYSEXIT },
+	{ PR_faccessat, 	0 },
+	{ PR_fchmodat, 		0 },
+	{ PR_fchownat, 		0 },
+	{ PR_fcntl, 		FILTER_SYSEXIT },
+	{ PR_fstatat64, 	0 },
+	{ PR_futimesat, 	0 },
+	{ PR_futex, 		0 },
+	{ PR_inotify_init1, 	FILTER_SYSEXIT },
+	{ PR_linkat, 		0 },
+	{ PR_mkdirat, 		0 },
+	{ PR_mknodat, 		0 },
+	{ PR_newfstatat, 	0 },
+	{ PR_open, 		FILTER_SYSEXIT },
+	{ PR_openat, 		FILTER_SYSEXIT },
+	{ PR_pipe2, 		FILTER_SYSEXIT },
+	{ PR_pselect6, 		0 },
+	{ PR_readlinkat, 	0 },
+	{ PR_renameat, 		0 },
+	{ PR_renameat2,		0 },
+	{ PR_setdomainname,	FILTER_SYSEXIT },
+	{ PR_sethostname,	FILTER_SYSEXIT },
+	{ PR_signalfd4, 	FILTER_SYSEXIT },
+	{ PR_socket,		FILTER_SYSEXIT },
+	{ PR_socketpair,	FILTER_SYSEXIT },
+	{ PR_symlinkat, 	0 },
+	{ PR_timerfd_create,	FILTER_SYSEXIT },
+	{ PR_uname, 		FILTER_SYSEXIT },
+	{ PR_unlinkat, 		0 },
+	FILTERED_SYSNUM_END,
+};
+
+/**
+ * Handler for this @extension.  It is triggered each time an @event
+ * occured.  See ExtensionEvent for the meaning of @data1 and @data2.
+ */
+int kompat_callback(Extension *extension, ExtensionEvent event,
+		intptr_t data1, intptr_t data2 UNUSED)
+{
+	int status;
+
+	switch (event) {
+	case INITIALIZATION: {
+		Config *config;
+
+		extension->config = talloc_zero(extension, Config);
+		if (extension->config == NULL)
+			return -1;
+		config = extension->config;
+
+		status = parse_utsname(config, (const char *) data1);
+		if (status < 0)
+			return -1;
+
+		extension->filtered_sysnums = filtered_sysnums;
+		return 0;
+	}
+
+	case SYSCALL_ENTER_END: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+
+		/* Nothing to do if this syscall is being discarded
+		 * (because of an error detected by PRoot).  */
+		if ((int) data1 < 0)
+			return 0;
+
+		return handle_sysenter_end(tracee, config);
+	}
+
+	case SYSCALL_EXIT_END: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+
+		return handle_sysexit_end(tracee, config);
+	}
+
+	case SYSCALL_EXIT_START: {
+		Tracee *tracee = TRACEE(extension);
+		Config *config = talloc_get_type_abort(extension->config, Config);
+		word_t result = peek_reg(tracee, CURRENT, SYSARG_RESULT);;
+		word_t sysnum = get_sysnum(tracee, ORIGINAL);
+
+		/* Note: this can be done only before PRoot pushes the
+		 * load script into tracee's stack.  */
+		if ((int) result >= 0 && sysnum == PR_execve)
+			adjust_elf_auxv(tracee, config);
+		return 0;
+	}
+
+	default:
+		return 0;
+	}
+}
diff --git a/5.1.0/src/loader/assembly-arm.h b/5.1.0/src/loader/assembly-arm.h
new file mode 100644
index 0000000..365b822
--- /dev/null
+++ b/5.1.0/src/loader/assembly-arm.h
@@ -0,0 +1,92 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+/* According to the ARM EABI, all registers have undefined values at
+ * program startup except:
+ *
+ * - the instruction pointer (r15)
+ * - the stack pointer (r13)
+ * - the rtld_fini pointer (r0)
+ */
+#define BRANCH(stack_pointer, destination) do {			\
+	asm volatile (						\
+		"// Restore initial stack pointer.	\n\t"	\
+		"mov sp, %0				\n\t"	\
+		"					\n\t"	\
+		"// Clear rtld_fini.			\n\t"	\
+		"mov r0, #0				\n\t"	\
+		"					\n\t"	\
+		"// Start the program.			\n\t"	\
+		"mov pc, %1				\n"	\
+		: /* no output */				\
+		: "r" (stack_pointer), "r" (destination)	\
+		: "memory", "sp", "r0", "pc");			\
+	__builtin_unreachable();				\
+	} while (0)
+
+#define PREPARE_ARGS_1(arg1_)				\
+	register word_t arg1 asm("r0") = arg1_;		\
+
+#define PREPARE_ARGS_3(arg1_, arg2_, arg3_)		\
+	PREPARE_ARGS_1(arg1_)				\
+	register word_t arg2 asm("r1") = arg2_;		\
+	register word_t arg3 asm("r2") = arg3_;		\
+
+#define PREPARE_ARGS_6(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_)	\
+	PREPARE_ARGS_3(arg1_, arg2_, arg3_)				\
+	register word_t arg4 asm("r3") = arg4_;				\
+	register word_t arg5 asm("r4") = arg5_;				\
+	register word_t arg6 asm("r5") = arg6_;
+
+#define OUTPUT_CONTRAINTS_1			\
+	"r" (arg1)
+
+#define OUTPUT_CONTRAINTS_3			\
+	OUTPUT_CONTRAINTS_1,			\
+	"r" (arg2), "r" (arg3)
+
+#define OUTPUT_CONTRAINTS_6				\
+	OUTPUT_CONTRAINTS_3,				\
+	"r" (arg4), "r" (arg5), "r" (arg6)
+
+#define SYSCALL(number_, nb_args, args...)			\
+	({							\
+		register word_t number asm("r7") = number_;	\
+		register word_t result asm("r0");		\
+		PREPARE_ARGS_##nb_args(args)			\
+			asm volatile (				\
+				"svc #0x00000000	\n\t"	\
+				: "=r" (result)			\
+				: "r" (number),			\
+				OUTPUT_CONTRAINTS_##nb_args	\
+				: "memory");			\
+			result;					\
+	})
+
+#define OPEN	5
+#define CLOSE	6
+#define MMAP	192
+#define MMAP_OFFSET_SHIFT 12
+#define EXECVE	11
+#define EXIT	1
+#define PRCTL	172
+
diff --git a/5.1.0/src/loader/assembly-arm64.h b/5.1.0/src/loader/assembly-arm64.h
new file mode 100644
index 0000000..b9b1822
--- /dev/null
+++ b/5.1.0/src/loader/assembly-arm64.h
@@ -0,0 +1,93 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#define BRANCH(stack_pointer, destination) do {			\
+	asm volatile (						\
+		"// Restore initial stack pointer.	\n\t"	\
+		"mov sp, %0				\n\t"	\
+		"					\n\t"	\
+		"// Clear rtld_fini.			\n\t"	\
+		"mov x0, #0				\n\t"	\
+		"					\n\t"	\
+		"// Start the program.			\n\t"	\
+		"br %1					\n"	\
+		: /* no output */				\
+		: "r" (stack_pointer), "r" (destination)	\
+		: "memory", "sp", "x0");			\
+	__builtin_unreachable();				\
+	} while (0)
+
+#define PREPARE_ARGS_1(arg1_)				\
+	register word_t arg1 asm("x0") = arg1_;		\
+
+#define PREPARE_ARGS_3(arg1_, arg2_, arg3_)		\
+	PREPARE_ARGS_1(arg1_)				\
+	register word_t arg2 asm("x1") = arg2_;		\
+	register word_t arg3 asm("x2") = arg3_;		\
+
+#define PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_)	\
+	PREPARE_ARGS_3(arg1_, arg2_, arg3_)		\
+	register word_t arg4 asm("x3") = arg4_;
+
+#define PREPARE_ARGS_6(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_)	\
+	PREPARE_ARGS_3(arg1_, arg2_, arg3_)				\
+	register word_t arg4 asm("x3") = arg4_;				\
+	register word_t arg5 asm("x4") = arg5_;				\
+	register word_t arg6 asm("x5") = arg6_;
+
+#define OUTPUT_CONTRAINTS_1			\
+	"r" (arg1)
+
+#define OUTPUT_CONTRAINTS_3			\
+	OUTPUT_CONTRAINTS_1,			\
+	"r" (arg2), "r" (arg3)
+
+#define OUTPUT_CONTRAINTS_4			\
+	OUTPUT_CONTRAINTS_3,			\
+	"r" (arg4)
+
+#define OUTPUT_CONTRAINTS_6				\
+	OUTPUT_CONTRAINTS_3,				\
+	"r" (arg4), "r" (arg5), "r" (arg6)
+
+#define SYSCALL(number_, nb_args, args...)			\
+	({							\
+		register word_t number asm("w8") = number_;	\
+		register word_t result asm("x0");		\
+		PREPARE_ARGS_##nb_args(args)			\
+			asm volatile (				\
+				"svc #0x00000000	\n\t"	\
+				: "=r" (result)			\
+				: "r" (number),			\
+				OUTPUT_CONTRAINTS_##nb_args	\
+				: "memory");			\
+			result;					\
+	})
+
+#define OPENAT	56
+#define CLOSE	57
+#define MMAP	222
+#define MMAP_OFFSET_SHIFT 0
+#define EXECVE	221
+#define EXIT	93
+#define PRCTL	167
+
diff --git a/5.1.0/src/loader/assembly-x86.h b/5.1.0/src/loader/assembly-x86.h
new file mode 100644
index 0000000..2357953
--- /dev/null
+++ b/5.1.0/src/loader/assembly-x86.h
@@ -0,0 +1,67 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+/* According to the x86 ABI, all registers have undefined values at
+ * program startup except:
+ *
+ * - the instruction pointer (rip)
+ * - the stack pointer (rsp)
+ * - the rtld_fini pointer (rdx)
+ * - the system flags (eflags)
+ */
+#define BRANCH(stack_pointer, destination) do {			\
+	asm volatile (						\
+		"// Restore initial stack pointer.	\n\t"	\
+		"movl %0, %%esp				\n\t"	\
+		"                      			\n\t"	\
+		"// Clear state flags.			\n\t"	\
+		"pushl $0				\n\t"	\
+		"popfl					\n\t"	\
+		"                      			\n\t"	\
+		"// Clear rtld_fini.			\n\t"	\
+		"movl $0, %%edx				\n\t"	\
+		"                      			\n\t"	\
+		"// Start the program.			\n\t"	\
+		"jmpl *%%eax				\n"	\
+		: /* no output */				\
+		: "irm" (stack_pointer), "a" (destination)	\
+		: "memory", "cc", "esp", "edx");		\
+	__builtin_unreachable();				\
+	} while (0)
+
+extern word_t syscall_6(word_t number,
+			word_t arg1, word_t arg2, word_t arg3,
+			word_t arg4, word_t arg5, word_t arg6);
+
+extern word_t syscall_3(word_t number, word_t arg1, word_t arg2, word_t arg3);
+
+extern word_t syscall_1(word_t number, word_t arg1);
+
+#define SYSCALL(number, nb_args, args...) syscall_##nb_args(number, args)
+
+#define OPEN	5
+#define CLOSE	6
+#define MMAP	192
+#define MMAP_OFFSET_SHIFT 12
+#define EXECVE	11
+#define EXIT	1
+#define PRCTL	172
diff --git a/5.1.0/src/loader/assembly-x86_64.h b/5.1.0/src/loader/assembly-x86_64.h
new file mode 100644
index 0000000..1575aea
--- /dev/null
+++ b/5.1.0/src/loader/assembly-x86_64.h
@@ -0,0 +1,95 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+/* According to the x86_64 ABI, all registers have undefined values at
+ * program startup except:
+ *
+ * - the instruction pointer (rip)
+ * - the stack pointer (rsp)
+ * - the rtld_fini pointer (rdx)
+ * - the system flags (rflags)
+ */
+#define BRANCH(stack_pointer, destination) do {			\
+	asm volatile (						\
+		"// Restore initial stack pointer.	\n\t"	\
+		"movq %0, %%rsp				\n\t"	\
+		"					\n\t"	\
+		"// Clear state flags.			\n\t"	\
+		"pushq $0				\n\t"	\
+		"popfq					\n\t"	\
+		"					\n\t"	\
+		"// Clear rtld_fini.			\n\t"	\
+		"movq $0, %%rdx				\n\t"	\
+		"					\n\t"	\
+		"// Start the program.			\n\t"	\
+		"jmpq *%%rax				\n"	\
+		: /* no output */				\
+		: "irm" (stack_pointer), "a" (destination)	\
+		: "memory", "cc", "rsp", "rdx");		\
+	__builtin_unreachable();				\
+	} while (0)
+
+#define PREPARE_ARGS_1(arg1_)				\
+	register word_t arg1 asm("rdi") = arg1_;	\
+
+#define PREPARE_ARGS_3(arg1_, arg2_, arg3_)		\
+	PREPARE_ARGS_1(arg1_)				\
+	register word_t arg2 asm("rsi") = arg2_;	\
+	register word_t arg3 asm("rdx") = arg3_;	\
+
+#define PREPARE_ARGS_6(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_)	\
+	PREPARE_ARGS_3(arg1_, arg2_, arg3_)				\
+	register word_t arg4 asm("r10") = arg4_;			\
+	register word_t arg5 asm("r8")  = arg5_;			\
+	register word_t arg6 asm("r9")  = arg6_;
+
+#define OUTPUT_CONTRAINTS_1			\
+	"r" (arg1)
+
+#define OUTPUT_CONTRAINTS_3			\
+	OUTPUT_CONTRAINTS_1,			\
+	"r" (arg2), "r" (arg3)
+
+#define OUTPUT_CONTRAINTS_6			\
+	OUTPUT_CONTRAINTS_3,			\
+	"r" (arg4), "r" (arg5), "r" (arg6)
+
+#define SYSCALL(number_, nb_args, args...)				\
+	({								\
+		register word_t number asm("rax") = number_;		\
+		register word_t result asm("rax");			\
+		PREPARE_ARGS_##nb_args(args)				\
+			asm volatile (					\
+				"syscall		\n\t"		\
+				: "=r" (result)				\
+				: "r" (number),				\
+				OUTPUT_CONTRAINTS_##nb_args		\
+				: "memory", "cc", "rcx", "r11");	\
+			result;						\
+	})
+
+#define OPEN	2
+#define CLOSE	3
+#define MMAP	9
+#define EXECVE	59
+#define EXIT	60
+#define PRCTL	157
diff --git a/5.1.0/src/loader/assembly.S b/5.1.0/src/loader/assembly.S
new file mode 100644
index 0000000..ca46997
--- /dev/null
+++ b/5.1.0/src/loader/assembly.S
@@ -0,0 +1,62 @@
+#if defined(__i386__)
+	.text
+
+/*
+	ABI	user-land  kernel-land
+	======  =========  ===========
+	number	%eax	   %eax
+	arg1	%edx	   %ebx
+	arg2	%ecx	   %ecx
+	arg3	16(%esp)   %edx
+	arg4	12(%esp)   %esi
+	arg5	8(%esp)	   %edi
+	arg6	4(%esp)    %ebp
+	result	N/A	   %eax
+*/
+.globl	syscall_6
+.type	syscall_6, @function
+syscall_6:
+	/* Callee-saved registers.  */
+	pushl	%ebp	// %esp -= 0x04
+	pushl	%edi	// %esp -= 0x08
+	pushl	%esi	// %esp -= 0x0c
+	pushl	%ebx	// %esp -= 0x10
+
+//	mov	%eax, %eax		// number
+	mov	%edx, %ebx		// arg1
+//	mov	%ecx, %ecx		// arg2
+	mov	0x14(%esp), %edx	// arg3
+	mov	0x18(%esp), %esi	// arg4
+	mov	0x1c(%esp), %edi	// arg5
+	mov	0x20(%esp), %ebp	// arg6
+
+	int	$0x80
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	popl	%ebp
+
+//	mov	%eax, %eax		// result
+	ret
+
+.globl	syscall_3
+.type	syscall_3, @function
+syscall_3:
+	pushl	%ebx
+	mov	%edx, %ebx
+	mov	0x8(%esp), %edx
+	int	$0x80
+	popl	%ebx
+	ret
+
+.globl	syscall_1
+.type	syscall_1, @function
+syscall_1:
+	pushl	%ebx
+	mov	%edx, %ebx
+	int	$0x80
+	popl	%ebx
+	ret
+
+#endif /* defined(__i386__) */
diff --git a/5.1.0/src/loader/loader.c b/5.1.0/src/loader/loader.c
new file mode 100644
index 0000000..88d37ea
--- /dev/null
+++ b/5.1.0/src/loader/loader.c
@@ -0,0 +1,263 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdbool.h>     /* bool, true, false,  */
+
+#define NO_LIBC_HEADER
+#include "loader/script.h"
+#include "compat.h"
+#include "arch.h"
+
+#define GCC_VERSION (__GNUC__ * 10000			\
+			+ __GNUC_MINOR__ * 100		\
+			+ __GNUC_PATCHLEVEL__)
+
+#if GCC_VERSION < 40500
+#define __builtin_unreachable()
+#endif
+
+#if defined(ARCH_X86_64)
+#    include "loader/assembly-x86_64.h"
+#elif defined(ARCH_ARM_EABI)
+#    include "loader/assembly-arm.h"
+#elif defined(ARCH_ARM64)
+#    include "loader/assembly-arm64.h"
+#elif defined(ARCH_X86)
+#    include "loader/assembly-x86.h"
+#else
+#    error "Unsupported architecture"
+#endif
+
+#if !defined(MMAP_OFFSET_SHIFT)
+#    define MMAP_OFFSET_SHIFT 0
+#endif
+
+#define FATAL() do {						\
+		SYSCALL(EXIT, 1, 182);				\
+		__builtin_unreachable();			\
+	} while (0)
+
+#define unlikely(expr) __builtin_expect(!!(expr), 0)
+
+/**
+ * Clear the memory from @start (inclusive) to @end (exclusive).
+ */
+static inline void clear(word_t start, word_t end)
+{
+	byte_t *start_misaligned;
+	byte_t *end_misaligned;
+
+	word_t *start_aligned;
+	word_t *end_aligned;
+
+	/* Compute the number of mis-aligned bytes.  */
+	word_t start_bytes = start % sizeof(word_t);
+	word_t end_bytes   = end % sizeof(word_t);
+
+	/* Compute aligned addresses.  */
+	start_aligned = (word_t *) (start_bytes ? start + sizeof(word_t) - start_bytes : start);
+	end_aligned   = (word_t *) (end - end_bytes);
+
+	/* Clear leading mis-aligned bytes.  */
+	start_misaligned = (byte_t *) start;
+	while (start_misaligned < (byte_t *) start_aligned)
+		*start_misaligned++ = 0;
+
+	/* Clear aligned bytes.  */
+	while (start_aligned < end_aligned)
+		*start_aligned++ = 0;
+
+	/* Clear trailing mis-aligned bytes.  */
+	end_misaligned = (byte_t *) end_aligned;
+	while (end_misaligned < (byte_t *) end)
+		*end_misaligned++ = 0;
+}
+
+/**
+ * Return the address of the last path component of @string_.  Note
+ * that @string_ is not modified.
+ */
+static inline word_t basename(word_t string_)
+{
+	byte_t *string = (byte_t *) string_;
+	byte_t *cursor;
+
+	for (cursor = string; *cursor != 0; cursor++)
+		;
+
+	for (; *cursor != (byte_t) '/' && cursor > string; cursor--)
+		;
+
+	if (cursor != string)
+		cursor++;
+
+	return (word_t) cursor;
+}
+
+/**
+ * Interpret the load script pointed to by @cursor.
+ */
+void _start(void *cursor)
+{
+	bool traced = false;
+	bool reset_at_base = true;
+	word_t at_base = 0;
+
+	word_t fd = -1;
+	word_t status;
+
+	while(1) {
+		LoadStatement *stmt = cursor;
+
+		switch (stmt->action) {
+		case LOAD_ACTION_OPEN_NEXT:
+			status = SYSCALL(CLOSE, 1, fd);
+			if (unlikely((int) status < 0))
+				FATAL();
+			/* Fall through.  */
+
+		case LOAD_ACTION_OPEN:
+#ifdef OPENAT
+			fd = SYSCALL(OPENAT, 4, AT_FDCWD, stmt->open.string_address, O_RDONLY, 0);
+#else
+			fd = SYSCALL(OPEN, 3, stmt->open.string_address, O_RDONLY, 0);
+#endif
+			if (unlikely((int) fd < 0))
+				FATAL();
+
+			reset_at_base = true;
+
+			cursor += LOAD_STATEMENT_SIZE(*stmt, open);
+			break;
+
+		case LOAD_ACTION_MMAP_FILE:
+			status = SYSCALL(MMAP, 6, stmt->mmap.addr, stmt->mmap.length,
+					stmt->mmap.prot, MAP_PRIVATE | MAP_FIXED, fd,
+					stmt->mmap.offset >> MMAP_OFFSET_SHIFT);
+			if (unlikely(status != stmt->mmap.addr))
+				FATAL();
+
+			if (stmt->mmap.clear_length != 0)
+				clear(stmt->mmap.addr + stmt->mmap.length - stmt->mmap.clear_length,
+					stmt->mmap.addr + stmt->mmap.length);
+
+			if (reset_at_base) {
+				at_base = stmt->mmap.addr;
+				reset_at_base = false;
+			}
+
+			cursor += LOAD_STATEMENT_SIZE(*stmt, mmap);
+			break;
+
+		case LOAD_ACTION_MMAP_ANON:
+			status = SYSCALL(MMAP, 6, stmt->mmap.addr, stmt->mmap.length,
+					stmt->mmap.prot, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+			if (unlikely(status != stmt->mmap.addr))
+				FATAL();
+
+			cursor += LOAD_STATEMENT_SIZE(*stmt, mmap);
+			break;
+
+		case LOAD_ACTION_START_TRACED:
+			traced = true;
+			/* Fall through.  */
+
+		case LOAD_ACTION_START: {
+			word_t *cursor2 = (word_t *) stmt->start.stack_pointer;
+			const word_t argc = cursor2[0];
+			const word_t at_execfn = cursor2[1];
+			word_t name;
+
+			status = SYSCALL(CLOSE, 1, fd);
+			if (unlikely((int) status < 0))
+				FATAL();
+
+			/* Right after execve, the stack content is as follow:
+			 *
+			 *   +------+--------+--------+--------+
+			 *   | argc | argv[] | envp[] | auxv[] |
+			 *   +------+--------+--------+--------+
+			 */
+
+			/* Skip argv[].  */
+			cursor2 += argc + 1;
+
+			/* Skip envp[].  */
+			do cursor2++; while (cursor2[0] != 0);
+			cursor2++;
+
+			/* Adjust auxv[].  */
+			do {
+				switch (cursor2[0]) {
+				case AT_PHDR:
+					cursor2[1] = stmt->start.at_phdr;
+					break;
+
+				case AT_PHENT:
+					cursor2[1] = stmt->start.at_phent;
+					break;
+
+				case AT_PHNUM:
+					cursor2[1] = stmt->start.at_phnum;
+					break;
+
+				case AT_ENTRY:
+					cursor2[1] = stmt->start.at_entry;
+					break;
+
+				case AT_BASE:
+					cursor2[1] = at_base;
+					break;
+
+				case AT_EXECFN:
+					/* stmt->start.at_execfn can't be used for now since it is
+					 * currently stored in a location that will be scratched
+					 * by the process (below the final stack pointer).  */
+					cursor2[1] = at_execfn;
+					break;
+
+				default:
+					break;
+				}
+				cursor2 += 2;
+			} while (cursor2[0] != AT_NULL);
+
+			/* Note that only 2 arguments are actually necessary... */
+			name = basename(stmt->start.at_execfn);
+			SYSCALL(PRCTL, 3, PR_SET_NAME, name, 0);
+
+			if (unlikely(traced))
+				SYSCALL(EXECVE, 6, 1,
+					stmt->start.stack_pointer,
+					stmt->start.entry_point, 2, 3, 4);
+			else
+				BRANCH(stmt->start.stack_pointer, stmt->start.entry_point);
+			FATAL();
+		}
+
+		default:
+			FATAL();
+		}
+	}
+
+	FATAL();
+}
diff --git a/5.1.0/src/loader/script.h b/5.1.0/src/loader/script.h
new file mode 100644
index 0000000..38f55f9
--- /dev/null
+++ b/5.1.0/src/loader/script.h
@@ -0,0 +1,73 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef SCRIPT
+#define SCRIPT
+
+#include "arch.h"
+#include "attribute.h"
+
+struct load_statement {
+	word_t action;
+
+	union {
+		struct {
+			word_t string_address;
+		} open;
+
+		struct {
+			word_t addr;
+			word_t length;
+			word_t prot;
+			word_t offset;
+			word_t clear_length;
+		} mmap;
+
+		struct {
+			word_t stack_pointer;
+			word_t entry_point;
+			word_t at_phdr;
+			word_t at_phent;
+			word_t at_phnum;
+			word_t at_entry;
+			word_t at_execfn;
+		} start;
+	};
+} PACKED;
+
+typedef struct load_statement LoadStatement;
+
+#define LOAD_STATEMENT_SIZE(statement, type) \
+	(sizeof((statement).action) + sizeof((statement).type))
+
+/* Don't use enum, since sizeof(enum) doesn't have to be equal to
+ * sizeof(word_t).  Keep values in the same order as their respective
+ * actions appear in loader.c to get a change GCC produces a jump
+ * table.  */
+#define LOAD_ACTION_OPEN_NEXT		0
+#define LOAD_ACTION_OPEN		1
+#define LOAD_ACTION_MMAP_FILE		2
+#define LOAD_ACTION_MMAP_ANON		3
+#define LOAD_ACTION_START_TRACED	4
+#define LOAD_ACTION_START		5
+
+#endif /* SCRIPT */
diff --git a/5.1.0/src/path/binding.c b/5.1.0/src/path/binding.c
new file mode 100644
index 0000000..f53c18c
--- /dev/null
+++ b/5.1.0/src/path/binding.c
@@ -0,0 +1,735 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/stat.h> /* lstat(2), */
+#include <unistd.h>   /* getcwd(2), lstat(2), */
+#include <string.h>   /* string(3),  */
+#include <strings.h>  /* bzero(3), */
+#include <assert.h>   /* assert(3), */
+#include <limits.h>   /* PATH_MAX, */
+#include <errno.h>    /* E* */
+#include <sys/queue.h> /* CIRCLEQ_*, */
+#include <talloc.h>   /* talloc_*, */
+
+#include "path/binding.h"
+#include "path/path.h"
+#include "path/canon.h"
+#include "cli/note.h"
+
+#include "compat.h"
+
+#define HEAD(tracee, side)						\
+	(side == GUEST							\
+		? (tracee)->fs->bindings.guest				\
+		: (side == HOST						\
+			? (tracee)->fs->bindings.host			\
+			: (tracee)->fs->bindings.pending))
+
+#define NEXT(binding, side)						\
+	(side == GUEST							\
+		? CIRCLEQ_NEXT(binding, link.guest)			\
+		: (side == HOST						\
+			? CIRCLEQ_NEXT(binding, link.host)		\
+			: CIRCLEQ_NEXT(binding, link.pending)))
+
+#define CIRCLEQ_FOREACH_(tracee, binding, side)				\
+	for (binding = CIRCLEQ_FIRST(HEAD(tracee, side));		\
+	     binding != (void *) HEAD(tracee, side);			\
+	     binding = NEXT(binding, side))
+
+#define CIRCLEQ_INSERT_AFTER_(tracee, previous, binding, side) do {	\
+	switch (side) {							\
+	case GUEST: CIRCLEQ_INSERT_AFTER(HEAD(tracee, side), previous, binding, link.guest);   break; \
+	case HOST:  CIRCLEQ_INSERT_AFTER(HEAD(tracee, side), previous, binding, link.host);    break; \
+	default:    CIRCLEQ_INSERT_AFTER(HEAD(tracee, side), previous, binding, link.pending); break; \
+	}								\
+	(void) talloc_reference(HEAD(tracee, side), binding);		\
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE_(tracee, next, binding, side) do {	\
+	switch (side) {							\
+	case GUEST: CIRCLEQ_INSERT_BEFORE(HEAD(tracee, side), next, binding, link.guest);   break; \
+	case HOST:  CIRCLEQ_INSERT_BEFORE(HEAD(tracee, side), next, binding, link.host);    break; \
+	default:    CIRCLEQ_INSERT_BEFORE(HEAD(tracee, side), next, binding, link.pending); break; \
+	}								\
+	(void) talloc_reference(HEAD(tracee, side), binding);		\
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD_(tracee, binding, side) do {		\
+	switch (side) {							\
+	case GUEST: CIRCLEQ_INSERT_HEAD(HEAD(tracee, side), binding, link.guest);   break; \
+	case HOST:  CIRCLEQ_INSERT_HEAD(HEAD(tracee, side), binding, link.host);    break; \
+	default:    CIRCLEQ_INSERT_HEAD(HEAD(tracee, side), binding, link.pending); break; \
+	}								\
+	(void) talloc_reference(HEAD(tracee, side), binding);		\
+} while (0)
+
+#define IS_LINKED(binding, link)					\
+	((binding)->link.cqe_next != NULL && (binding)->link.cqe_prev != NULL)
+
+#define CIRCLEQ_REMOVE_(tracee, binding, name) do {			\
+	CIRCLEQ_REMOVE((tracee)->fs->bindings.name, binding, link.name);\
+	(binding)->link.name.cqe_next = NULL;				\
+	(binding)->link.name.cqe_prev = NULL;				\
+	talloc_unlink((tracee)->fs->bindings.name, binding);		\
+} while (0)
+
+
+/**
+ * Print all bindings (verbose purpose).
+ */
+static void print_bindings(const Tracee *tracee)
+{
+	const Binding *binding;
+
+	if (tracee->fs->bindings.guest == NULL)
+		return;
+
+	CIRCLEQ_FOREACH_(tracee, binding, GUEST) {
+		if (compare_paths(binding->host.path, binding->guest.path) == PATHS_ARE_EQUAL)
+			note(tracee, INFO, USER, "binding = %s", binding->host.path);
+		else
+			note(tracee, INFO, USER, "binding = %s:%s",
+				binding->host.path, binding->guest.path);
+	}
+}
+
+/**
+ * Get the binding for the given @path (relatively to the given
+ * binding @side).
+ */
+Binding *get_binding(const Tracee *tracee, Side side, const char path[PATH_MAX])
+{
+	Binding *binding;
+	size_t path_length = strlen(path);
+
+	/* Sanity checks.  */
+	assert(path != NULL && path[0] == '/');
+
+	CIRCLEQ_FOREACH_(tracee, binding, side) {
+		Comparison comparison;
+		const Path *ref;
+
+		switch (side) {
+		case GUEST:
+			ref = &binding->guest;
+			break;
+
+		case HOST:
+			ref = &binding->host;
+			break;
+
+		default:
+			assert(0);
+			return NULL;
+		}
+
+		comparison = compare_paths2(ref->path, ref->length, path, path_length);
+		if (   comparison != PATHS_ARE_EQUAL
+		    && comparison != PATH1_IS_PREFIX)
+			continue;
+
+		/* Avoid false positive when a prefix of the rootfs is
+		 * used as an asymmetric binding, ex.:
+		 *
+		 *     proot -m /usr:/location /usr/local/slackware
+		 */
+		if (   side == HOST
+		    && compare_paths(get_root(tracee), "/") != PATHS_ARE_EQUAL
+		    && belongs_to_guestfs(tracee, path))
+				continue;
+
+		return binding;
+	}
+
+	return NULL;
+}
+
+/**
+ * Get the binding path for the given @path (relatively to the given
+ * binding @side).
+ */
+const char *get_path_binding(const Tracee *tracee, Side side, const char path[PATH_MAX])
+{
+	const Binding *binding;
+
+	binding = get_binding(tracee, side, path);
+	if (!binding)
+		return NULL;
+
+	switch (side) {
+	case GUEST:
+		return binding->guest.path;
+
+	case HOST:
+		return binding->host.path;
+
+	default:
+		assert(0);
+		return NULL;
+	}
+}
+
+/**
+ * Return the path to the guest rootfs for the given @tracee, from the
+ * host point-of-view obviously.  Depending on whether
+ * initialize_bindings() was called or not, the path is retrieved from
+ * the "bindings.guest" list or from the "bindings.pending" list,
+ * respectively.
+ */
+const char *get_root(const Tracee* tracee)
+{
+	const Binding *binding;
+
+	if (tracee == NULL || tracee->fs == NULL)
+		return NULL;
+
+	if (tracee->fs->bindings.guest == NULL) {
+		if (tracee->fs->bindings.pending == NULL
+		    || CIRCLEQ_EMPTY(tracee->fs->bindings.pending))
+			return NULL;
+
+		binding = CIRCLEQ_LAST(tracee->fs->bindings.pending);
+		if (compare_paths(binding->guest.path, "/") != PATHS_ARE_EQUAL)
+			return NULL;
+
+		return binding->host.path;
+	}
+
+	assert(!CIRCLEQ_EMPTY(tracee->fs->bindings.guest));
+
+	binding = CIRCLEQ_LAST(tracee->fs->bindings.guest);
+
+	assert(strcmp(binding->guest.path, "/") == 0);
+
+	return binding->host.path;
+}
+
+/**
+ * Substitute the guest path (if any) with the host path in @path.
+ * This function returns:
+ *
+ *     * -errno if an error occured
+ *
+ *     * 0 if it is a binding location but no substitution is needed
+ *       ("symetric" binding)
+ *
+ *     * 1 if it is a binding location and a substitution was performed
+ *       ("asymmetric" binding)
+ */
+int substitute_binding(const Tracee *tracee, Side side, char path[PATH_MAX])
+{
+	const Path *reverse_ref;
+	const Path *ref;
+	const Binding *binding;
+
+	binding = get_binding(tracee, side, path);
+	if (!binding)
+		return -ENOENT;
+
+	/* Is it a "symetric" binding?  */
+	if (!binding->need_substitution)
+		return 0;
+
+	switch (side) {
+	case GUEST:
+		ref = &binding->guest;
+		reverse_ref = &binding->host;
+		break;
+
+	case HOST:
+		ref = &binding->host;
+		reverse_ref = &binding->guest;
+		break;
+
+	default:
+		assert(0);
+		return -EACCES;
+	}
+
+	substitute_path_prefix(path, ref->length, reverse_ref->path, reverse_ref->length);
+
+	return 1;
+}
+
+/**
+ * Remove @binding from all the @tracee's lists of bindings it belongs to.
+ */
+void remove_binding_from_all_lists(const Tracee *tracee, Binding *binding)
+{
+       if (IS_LINKED(binding, link.pending))
+	       CIRCLEQ_REMOVE_(tracee, binding, pending);
+
+       if (IS_LINKED(binding, link.guest))
+	       CIRCLEQ_REMOVE_(tracee, binding, guest);
+
+       if (IS_LINKED(binding, link.host))
+	       CIRCLEQ_REMOVE_(tracee, binding, host);
+}
+
+/**
+ * Insert @binding into the list of @bindings, in a sorted manner so
+ * as to make the substitution of nested bindings determistic, ex.:
+ *
+ *     -b /bin:/foo/bin -b /usr/bin/more:/foo/bin/more
+ *
+ * Note: "nested" from the @side point-of-view.
+ */
+static void insort_binding(const Tracee *tracee, Side side, Binding *binding)
+{
+	Binding *iterator;
+	Binding *previous = NULL;
+	Binding *next = CIRCLEQ_FIRST(HEAD(tracee, side));
+
+	/* Find where it should be added in the list.  */
+	CIRCLEQ_FOREACH_(tracee, iterator, side) {
+		Comparison comparison;
+		const Path *binding_path;
+		const Path *iterator_path;
+
+		switch (side) {
+		case PENDING:
+		case GUEST:
+			binding_path = &binding->guest;
+			iterator_path = &iterator->guest;
+			break;
+
+		case HOST:
+			binding_path = &binding->host;
+			iterator_path = &iterator->host;
+			break;
+
+		default:
+			assert(0);
+			return;
+		}
+
+		comparison = compare_paths2(binding_path->path, binding_path->length,
+					    iterator_path->path, iterator_path->length);
+		switch (comparison) {
+		case PATHS_ARE_EQUAL:
+			if (side == HOST) {
+				previous = iterator;
+				break;
+			}
+
+			if (tracee->verbose > 0 && getenv("PROOT_IGNORE_MISSING_BINDINGS") == NULL) {
+				note(tracee, WARNING, USER,
+					"both '%s' and '%s' are bound to '%s', "
+					"only the last binding is active.",
+					iterator->host.path, binding->host.path,
+					binding->guest.path);
+			}
+
+			/* Replace this iterator with the new binding.  */
+			CIRCLEQ_INSERT_AFTER_(tracee, iterator, binding, side);
+			remove_binding_from_all_lists(tracee, iterator);
+			return;
+
+		case PATH1_IS_PREFIX:
+			/* The new binding contains the iterator.  */
+			previous = iterator;
+			break;
+
+		case PATH2_IS_PREFIX:
+			/* The iterator contains the new binding.
+			 * Use the deepest container.  */
+			if (next == (void *) HEAD(tracee, side))
+				next = iterator;
+			break;
+
+		case PATHS_ARE_NOT_COMPARABLE:
+			break;
+
+		default:
+			assert(0);
+			return;
+		}
+	}
+
+	/* Insert this binding in the list.  */
+	if (previous != NULL)
+		CIRCLEQ_INSERT_AFTER_(tracee, previous, binding, side);
+	else if (next != (void *) HEAD(tracee, side))
+		CIRCLEQ_INSERT_BEFORE_(tracee, next, binding, side);
+	else
+		CIRCLEQ_INSERT_HEAD_(tracee, binding, side);
+}
+
+/**
+ * c.f. function above.
+ */
+static void insort_binding2(const Tracee *tracee, Binding *binding)
+{
+	binding->need_substitution =
+		compare_paths(binding->host.path, binding->guest.path) != PATHS_ARE_EQUAL;
+
+	insort_binding(tracee, GUEST, binding);
+	insort_binding(tracee, HOST, binding);
+}
+
+/**
+ * Create and insert a new binding (@host_path:@guest_path) into the
+ * list of @tracee's bindings.  The Talloc parent of this new binding
+ * is @context.  This function returns NULL if an error occurred,
+ * otherwise a pointer to the newly created binding.
+ */
+Binding *insort_binding3(const Tracee *tracee, const TALLOC_CTX *context,
+			const char host_path[PATH_MAX],
+			const char guest_path[PATH_MAX])
+{
+	Binding *binding;
+
+	binding = talloc_zero(context, Binding);
+	if (binding == NULL)
+		return NULL;
+
+	strcpy(binding->host.path, host_path);
+	strcpy(binding->guest.path, guest_path);
+
+	binding->host.length = strlen(binding->host.path);
+	binding->guest.length = strlen(binding->guest.path);
+
+	insort_binding2(tracee, binding);
+
+	return binding;
+}
+
+/**
+ * Free all bindings from @bindings.
+ *
+ * Note: this is a Talloc destructor.
+ */
+static int remove_bindings(Bindings *bindings)
+{
+	Binding *binding;
+	Tracee *tracee;
+
+	/* Unlink all bindings from the @link list.  */
+#define CIRCLEQ_REMOVE_ALL(name) do {				\
+	binding = CIRCLEQ_FIRST(bindings);			\
+	while (binding != (void *) bindings) {			\
+		Binding *next = CIRCLEQ_NEXT(binding, link.name);\
+		CIRCLEQ_REMOVE_(tracee, binding, name);		\
+		binding = next;					\
+	}							\
+} while (0)
+
+	/* Search which link is used by this list.  */
+	tracee = TRACEE(bindings);
+	if (bindings == tracee->fs->bindings.pending)
+		CIRCLEQ_REMOVE_ALL(pending);
+	else if (bindings == tracee->fs->bindings.guest)
+		CIRCLEQ_REMOVE_ALL(guest);
+	else if (bindings == tracee->fs->bindings.host)
+		CIRCLEQ_REMOVE_ALL(host);
+
+	bzero(bindings, sizeof(Bindings));
+
+	return 0;
+}
+
+/**
+ * Allocate a new binding "@host:@guest" and attach it to
+ * @tracee->fs->bindings.pending.  This function complains about
+ * missing @host path only if @must_exist is true.  This function
+ * returns the allocated binding on success, NULL on error.
+ */
+Binding *new_binding(Tracee *tracee, const char *host, const char *guest, bool must_exist)
+{
+	Binding *binding;
+	char base[PATH_MAX];
+	int status;
+
+	/* Lasy allocation of the list of bindings specified by the
+	 * user.  This list will be used by initialize_bindings().  */
+	if (tracee->fs->bindings.pending == NULL) {
+		tracee->fs->bindings.pending = talloc_zero(tracee->fs, Bindings);
+		if (tracee->fs->bindings.pending == NULL)
+			return NULL;
+		CIRCLEQ_INIT(tracee->fs->bindings.pending);
+		talloc_set_destructor(tracee->fs->bindings.pending, remove_bindings);
+	}
+
+	/* Allocate an empty binding.  */
+	binding = talloc_zero(tracee->ctx, Binding);
+	if (binding == NULL)
+		return NULL;
+
+	/* Canonicalize the host part of the binding, as expected by
+	 * get_binding().  */
+	status = realpath2(tracee->reconf.tracee, binding->host.path, host, true);
+	if (status < 0) {
+		if (must_exist && getenv("PROOT_IGNORE_MISSING_BINDINGS") == NULL)
+			note(tracee, WARNING, INTERNAL, "can't sanitize binding \"%s\": %s",
+				host, strerror(-status));
+		goto error;
+	}
+	binding->host.length = strlen(binding->host.path);
+
+	/* Symetric binding?  */
+	guest = guest ?: host;
+
+	/* When not absolute, assume the guest path is relative to the
+	 * current working directory, as with ``-b .`` for instance.  */
+	if (guest[0] != '/') {
+		status = getcwd2(tracee->reconf.tracee, base);
+		if (status < 0) {
+			note(tracee, WARNING, INTERNAL, "can't sanitize binding \"%s\": %s",
+				binding->guest.path, strerror(-status));
+			goto error;
+		}
+	}
+	else
+		strcpy(base, "/");
+
+	status = join_paths(2, binding->guest.path, base, guest);
+	if (status < 0) {
+		note(tracee, WARNING, SYSTEM, "can't sanitize binding \"%s\"",
+			binding->guest.path);
+		goto error;
+	}
+	binding->guest.length = strlen(binding->guest.path);
+
+	/* Keep the list of bindings specified by the user ordered,
+	 * for the sake of consistency.  For instance binding to "/"
+	 * has to be the last in the list.  */
+	insort_binding(tracee, PENDING, binding);
+
+	return binding;
+
+error:
+	TALLOC_FREE(binding);
+	return NULL;
+}
+
+/**
+ * Canonicalize the guest part of the given @binding, insert it into
+ * @tracee->fs->bindings.guest and @tracee->fs->bindings.host.  This
+ * function returns -1 if an error occured, 0 otherwise.
+ */
+static void initialize_binding(Tracee *tracee, Binding *binding)
+{
+	char path[PATH_MAX];
+	struct stat statl;
+	int status;
+
+	/* All bindings but "/" must be canonicalized.  The exception
+	 * for "/" is required to bootstrap the canonicalization.  */
+	if (compare_paths(binding->guest.path, "/") != PATHS_ARE_EQUAL) {
+		bool dereference;
+		size_t length;
+
+		strcpy(path, binding->guest.path);
+		length = strlen(path);
+		assert(length > 0);
+
+		/* Does the user explicitly tell not to dereference
+		 * guest path?  */
+		dereference = (path[length - 1] != '!');
+		if (!dereference)
+			path[length - 1] = '\0';
+
+		/* Initial state before canonicalization.  */
+		strcpy(binding->guest.path, "/");
+
+		/* Remember the type of the final component, it will
+		 * be used in build_glue() later.  */
+		status = lstat(binding->host.path, &statl);
+		tracee->glue_type = (status < 0 || S_ISBLK(statl.st_mode) || S_ISCHR(statl.st_mode)
+				? S_IFREG : statl.st_mode & S_IFMT);
+
+		/* Sanitize the guest path of the binding within the
+		   alternate rootfs since it is assumed by
+		   substitute_binding().  */
+		status = canonicalize(tracee, path, dereference, binding->guest.path, 0);
+		if (status < 0) {
+			note(tracee, WARNING, INTERNAL,
+				"sanitizing the guest path (binding) \"%s\": %s",
+				path, strerror(-status));
+			return;
+		}
+
+		/* Remove the trailing "/" or "/." as expected by
+		 * substitute_binding().  */
+		chop_finality(binding->guest.path);
+
+		/* Disable definitively the creation of the glue for
+		 * this binding.  */
+		tracee->glue_type = 0;
+	}
+
+	binding->guest.length = strlen(binding->guest.path);
+
+	insort_binding2(tracee, binding);
+}
+
+/**
+ * Add bindings induced by @new_binding when @tracee is being sub-reconfigured.
+ * For example, if the previous configuration ("-r /rootfs1") contains this
+ * binding:
+ *
+ *      -b /home/ced:/usr/local/ced
+ *
+ * and if the current configuration ("-r /rootfs2") introduces such a new
+ * binding:
+ *
+ *      -b /usr:/media
+ *
+ * then the following binding is induced:
+ *
+ *      -b /home/ced:/media/local/ced
+ */
+static void add_induced_bindings(Tracee *tracee, const Binding *new_binding)
+{
+	Binding *old_binding;
+	char path[PATH_MAX];
+	int status;
+
+	/* Only for reconfiguration.  */
+	if (tracee->reconf.tracee == NULL)
+		return;
+
+	/* From the example, PRoot has already converted "-b /usr:/media" into
+	 * "-b /rootfs1/usr:/media" in order to ensure the host part is really a
+	 * host path.  Here, the host part is converted back to "/usr" since the
+	 * comparison can't be made on "/rootfs1/usr".
+	 */
+	strcpy(path, new_binding->host.path);
+	status = detranslate_path(tracee->reconf.tracee, path, NULL);
+	if (status < 0)
+		return;
+
+	CIRCLEQ_FOREACH_(tracee->reconf.tracee, old_binding, GUEST) {
+		Binding *induced_binding;
+		Comparison comparison;
+		char path2[PATH_MAX];
+		size_t prefix_length;
+
+		/* Check if there's an induced binding by searching a common
+		 * path prefix in between new/old bindings:
+		 *
+		 *   -b /home/ced:[/usr]/local/ced
+		 *   -b [/usr]:/media
+		 */
+		comparison = compare_paths(path, old_binding->guest.path);
+		if (comparison != PATH1_IS_PREFIX)
+			continue;
+
+		/* Convert the path of this induced binding to the new
+		 * filesystem namespace.  From the example, "/usr/local/ced" is
+		 * converted into "/media/local/ced".  Note: substitute_binding
+		 * can't be used in this case since it would expect
+		 * "/rootfs1/usr/local/ced instead".
+		 */
+		prefix_length = strlen(path);
+		if (prefix_length == 1)
+			prefix_length = 0;
+
+		status = join_paths(2, path2, new_binding->guest.path, old_binding->guest.path + prefix_length);
+		if (status < 0)
+			continue;
+
+		/* Install the induced binding.  From the example:
+		 *
+		 *     -b /home/ced:/media/local/ced
+		 */
+		induced_binding = talloc_zero(tracee->ctx, Binding);
+		if (induced_binding == NULL)
+			continue;
+
+		strcpy(induced_binding->host.path, old_binding->host.path);
+		strcpy(induced_binding->guest.path, path2);
+
+		induced_binding->host.length = strlen(induced_binding->host.path);
+		induced_binding->guest.length = strlen(induced_binding->guest.path);
+
+		VERBOSE(tracee, 2, "induced binding: %s:%s (old) & %s:%s (new) -> %s:%s (induced)",
+			old_binding->host.path, old_binding->guest.path, path, new_binding->guest.path,
+			induced_binding->host.path, induced_binding->guest.path);
+
+		insort_binding2(tracee, induced_binding);
+	}
+}
+
+/**
+ * Allocate @tracee->fs->bindings.guest and
+ * @tracee->fs->bindings.host, then call initialize_binding() on each
+ * binding listed in @tracee->fs->bindings.pending.
+ */
+int initialize_bindings(Tracee *tracee)
+{
+	Binding *binding;
+
+	/* Sanity checks.  */
+	assert(get_root(tracee) != NULL);
+	assert(tracee->fs->bindings.pending != NULL);
+	assert(tracee->fs->bindings.guest == NULL);
+	assert(tracee->fs->bindings.host == NULL);
+
+	/* Allocate @tracee->fs->bindings.guest and
+	 * @tracee->fs->bindings.host.  */
+	tracee->fs->bindings.guest = talloc_zero(tracee->fs, Bindings);
+	tracee->fs->bindings.host  = talloc_zero(tracee->fs, Bindings);
+	if (tracee->fs->bindings.guest == NULL || tracee->fs->bindings.host == NULL) {
+		note(tracee, ERROR, INTERNAL, "can't allocate enough memory");
+		TALLOC_FREE(tracee->fs->bindings.guest);
+		TALLOC_FREE(tracee->fs->bindings.host);
+		return -1;
+	}
+
+	CIRCLEQ_INIT(tracee->fs->bindings.guest);
+	CIRCLEQ_INIT(tracee->fs->bindings.host);
+
+	talloc_set_destructor(tracee->fs->bindings.guest, remove_bindings);
+	talloc_set_destructor(tracee->fs->bindings.host, remove_bindings);
+
+	/* The binding to "/" has to be installed before other
+	 * bindings since this former is required to canonicalize
+	 * these latters.  */
+	binding = CIRCLEQ_LAST(tracee->fs->bindings.pending);
+	assert(compare_paths(binding->guest.path, "/") == PATHS_ARE_EQUAL);
+
+	/* Call initialize_binding() on each pending binding in
+	 * reverse order: the last binding "/" is used to bootstrap
+	 * the canonicalization.  */
+	while (binding != (void *) tracee->fs->bindings.pending) {
+		Binding *previous;
+		previous = CIRCLEQ_PREV(binding, link.pending);
+
+		/* Canonicalize then insert this binding into
+		 * tracee->fs->bindings.guest/host.  */
+		initialize_binding(tracee, binding);
+
+		/* Add induced bindings on sub-reconfiguration.  */
+		add_induced_bindings(tracee, binding);
+
+		binding = previous;
+	}
+
+	TALLOC_FREE(tracee->fs->bindings.pending);
+
+	if (tracee->verbose > 0)
+		print_bindings(tracee);
+
+	return 0;
+}
diff --git a/5.1.0/src/path/binding.h b/5.1.0/src/path/binding.h
new file mode 100644
index 0000000..de96aa6
--- /dev/null
+++ b/5.1.0/src/path/binding.h
@@ -0,0 +1,58 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef BINDING_H
+#define BINDING_H
+
+#include <limits.h> /* PATH_MAX, */
+#include <stdbool.h>
+
+#include "tracee/tracee.h"
+#include "path.h"
+
+typedef struct binding {
+	Path host;
+	Path guest;
+
+	bool need_substitution;
+	bool must_exist;
+
+	struct {
+		CIRCLEQ_ENTRY(binding) pending;
+		CIRCLEQ_ENTRY(binding) guest;
+		CIRCLEQ_ENTRY(binding) host;
+	} link;
+} Binding;
+
+typedef CIRCLEQ_HEAD(bindings, binding) Bindings;
+
+extern Binding *insort_binding3(const Tracee *tracee, const TALLOC_CTX *context,
+				const char host_path[PATH_MAX], const char guest_path[PATH_MAX]);
+extern Binding *new_binding(Tracee *tracee, const char *host, const char *guest, bool must_exist);
+extern int initialize_bindings(Tracee *tracee);
+extern const char *get_path_binding(const Tracee* tracee, Side side, const char path[PATH_MAX]);
+extern Binding *get_binding(const Tracee *tracee, Side side, const char path[PATH_MAX]);
+extern const char *get_root(const Tracee* tracee);
+extern int substitute_binding(const Tracee* tracee, Side side, char path[PATH_MAX]);
+extern void remove_binding_from_all_lists(const Tracee *tracee, Binding *binding);
+
+#endif /* BINDING_H */
diff --git a/5.1.0/src/path/canon.c b/5.1.0/src/path/canon.c
new file mode 100644
index 0000000..addb98a
--- /dev/null
+++ b/5.1.0/src/path/canon.c
@@ -0,0 +1,364 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h> /* pid_t */
+#include <limits.h>    /* PATH_MAX, */
+#include <sys/param.h> /* MAXSYMLINKS, */
+#include <errno.h>     /* E*, */
+#include <sys/stat.h>  /* lstat(2), S_ISREG(), */
+#include <unistd.h>    /* access(2), lstat(2), */
+#include <string.h>    /* string(3), */
+#include <assert.h>    /* assert(3), */
+#include <stdio.h>     /* sscanf(3), */
+
+#include "path/canon.h"
+#include "path/path.h"
+#include "path/binding.h"
+#include "path/glue.h"
+#include "path/proc.h"
+#include "extension/extension.h"
+
+/**
+ * Put an end-of-string ('\0') right before the last component of @path.
+ */
+static inline void pop_component(char *path)
+{
+	int offset;
+
+	/* Sanity checks. */
+	assert(path != NULL);
+
+	offset = strlen(path) - 1;
+	assert(offset >= 0);
+
+	/* Don't pop over "/", it doesn't mean anything. */
+	if (offset == 0) {
+		assert(path[0] == '/' && path[1] == '\0');
+		return;
+	}
+
+	/* Skip trailing path separators. */
+	while (offset > 1 && path[offset] == '/')
+		offset--;
+
+	/* Search for the previous path separator. */
+	while (offset > 1 && path[offset] != '/')
+		offset--;
+
+	/* Cut the end of the string before the last component. */
+	path[offset] = '\0';
+	assert(path[0] == '/');
+}
+
+/**
+ * Copy in @component the first path component pointed to by @cursor,
+ * this later is updated to point to the next component for a further
+ * call. This function returns:
+ *
+ *     - -errno if an error occured.
+ *
+ *     - FINAL_SLASH if it the last component of the path but we
+ *       really expect a directory.
+ *
+ *     - FINAL_NORMAL if it the last component of the path.
+ *
+ *     - 0 otherwise.
+ */
+static inline Finality next_component(char component[NAME_MAX], const char **cursor)
+{
+	const char *start;
+	ptrdiff_t length;
+	bool want_dir;
+
+	/* Sanity checks. */
+	assert(component != NULL);
+	assert(cursor    != NULL);
+
+	/* Skip leading path separators. */
+	while (**cursor != '\0' && **cursor == '/')
+		(*cursor)++;
+
+	/* Find the next component. */
+	start = *cursor;
+	while (**cursor != '\0' && **cursor != '/')
+		(*cursor)++;
+	length = *cursor - start;
+
+	if (length >= NAME_MAX)
+		return -ENAMETOOLONG;
+
+	/* Extract the component. */
+	strncpy(component, start, length);
+	component[length] = '\0';
+
+	/* Check if a [link to a] directory is expected. */
+	want_dir = (**cursor == '/');
+
+	/* Skip trailing path separators. */
+	while (**cursor != '\0' && **cursor == '/')
+		(*cursor)++;
+
+	if (**cursor == '\0')
+		return (want_dir
+			? FINAL_SLASH
+			: FINAL_NORMAL);
+
+	return NOT_FINAL;
+}
+
+/**
+ * Resolve bindings (if any) in @guest_path and copy the translated
+ * path into @host_path.  Also, this function checks that a non-final
+ * component is either a directory (returned value is 0) or a symlink
+ * (returned value is 1), otherwise it returns -errno (-ENOENT or
+ * -ENOTDIR).
+ */
+static inline int substitute_binding_stat(Tracee *tracee, Finality finality,
+					const char guest_path[PATH_MAX], char host_path[PATH_MAX])
+{
+	struct stat statl;
+	int status;
+
+	strcpy(host_path, guest_path);
+	status = substitute_binding(tracee, GUEST, host_path);
+	if (status < 0)
+		return status;
+
+	/* Don't notify extensions during the initialization of a binding.  */
+	if (tracee->glue_type == 0) {
+		status = notify_extensions(tracee, HOST_PATH, (intptr_t)host_path, finality);
+		if (status < 0)
+			return status;
+	}
+
+	statl.st_mode = 0;
+	status = lstat(host_path, &statl);
+
+	/* Build the glue between the hostfs and the guestfs during
+	 * the initialization of a binding.  */
+	if (status < 0 && tracee->glue_type != 0) {
+		statl.st_mode = build_glue(tracee, guest_path, host_path, finality);
+		if (statl.st_mode == 0)
+			status = -1;
+	}
+
+	/* Return an error if a non-final component isn't a
+	 * directory nor a symlink.  The error is "No such
+	 * file or directory" if this component doesn't exist,
+	 * otherwise the error is "Not a directory".  */
+	if (!IS_FINAL(finality) && !S_ISDIR(statl.st_mode) && !S_ISLNK(statl.st_mode))
+		return (status < 0 ? -ENOENT : -ENOTDIR);
+
+	return (S_ISLNK(statl.st_mode) ? 1 : 0);
+}
+
+/**
+ * Copy in @guest_path the canonicalization (see `man 3 realpath`) of
+ * @user_path regarding to @tracee->root.  The path to canonicalize
+ * could be either absolute or relative to @guest_path. When the last
+ * component of @user_path is a link, it is dereferenced only if
+ * @deref_final is true -- it is useful for syscalls like lstat(2).
+ * The parameter @recursion_level should be set to 0 unless you know
+ * what you are doing. This function returns -errno if an error
+ * occured, otherwise it returns 0.
+ */
+int canonicalize(Tracee *tracee, const char *user_path, bool deref_final,
+		 char guest_path[PATH_MAX], unsigned int recursion_level)
+{
+	char scratch_path[PATH_MAX];
+	Finality finality;
+	const char *cursor;
+	int status;
+
+	/* Avoid infinite loop on circular links.  */
+	if (recursion_level > MAXSYMLINKS)
+		return -ELOOP;
+
+	/* Sanity checks.  */
+	assert(user_path != NULL);
+	assert(guest_path != NULL);
+	assert(user_path != guest_path);
+
+	if (strnlen(guest_path, PATH_MAX) >= PATH_MAX)
+		return -ENAMETOOLONG;
+
+	if (user_path[0] != '/') {
+		/* Ensure 'guest_path' contains an absolute base of
+		 * the relative `user_path`.  */
+		if (guest_path[0] != '/')
+			return -EINVAL;
+	}
+	else
+		strcpy(guest_path, "/");
+
+	/* Canonicalize recursely 'user_path' into 'guest_path'.  */
+	cursor = user_path;
+	finality = NOT_FINAL;
+	while (!IS_FINAL(finality)) {
+		Comparison comparison;
+		char component[NAME_MAX];
+		char host_path[PATH_MAX];
+
+		finality = next_component(component, &cursor);
+		status = (int) finality;
+		if (status < 0)
+			return status;
+
+		if (strcmp(component, ".") == 0) {
+			if (IS_FINAL(finality))
+				finality = FINAL_DOT;
+			continue;
+		}
+
+		if (strcmp(component, "..") == 0) {
+			pop_component(guest_path);
+			if (IS_FINAL(finality))
+				finality = FINAL_SLASH;
+			continue;
+		}
+
+		status = join_paths(2, scratch_path, guest_path, component);
+		if (status < 0)
+			return status;
+
+		/* Resolve bindings and check that a non-final
+		 * component exists and either is a directory or is a
+		 * symlink.  For this latter case, we check that the
+		 * symlink points to a directory once it is
+		 * canonicalized, at the end of this loop.  */
+		status = substitute_binding_stat(tracee, finality, scratch_path, host_path);
+		if (status < 0)
+			return status;
+
+		/* Nothing special to do if it's not a link or if we
+		 * explicitly ask to not dereference 'user_path', as
+		 * required by syscalls like lstat(2). Obviously, this
+		 * later condition does not apply to intermediate path
+		 * components.  Errors are explicitly ignored since
+		 * they should be handled by the caller. */
+		if (status <= 0 || (finality == FINAL_NORMAL && !deref_final)) {
+			strcpy(scratch_path, guest_path);
+			status = join_paths(2, guest_path, scratch_path, component);
+			if (status < 0)
+				return status;
+			continue;
+		}
+
+		/* It's a link, so we have to dereference *and*
+		 * canonicalize to ensure we are not going outside the
+		 * new root.  */
+		comparison = compare_paths("/proc", guest_path);
+		switch (comparison) {
+		case PATHS_ARE_EQUAL:
+		case PATH1_IS_PREFIX:
+			/* Some links in "/proc" are generated
+			 * dynamically by the kernel.  PRoot has to
+			 * emulate some of them.  */
+			status = readlink_proc(tracee, scratch_path,
+					       guest_path, component, comparison);
+			switch (status) {
+			case CANONICALIZE:
+				/* The symlink is already dereferenced,
+				 * now canonicalize it.  */
+				goto canon;
+
+			case DONT_CANONICALIZE:
+				/* If and only very final, this symlink
+				 * shouldn't be dereferenced nor canonicalized.  */
+				if (finality == FINAL_NORMAL) {
+					strcpy(guest_path, scratch_path);
+					return 0;
+				}
+				break;
+
+			default:
+				if (status < 0)
+					return status;
+			}
+
+		default:
+			break;
+		}
+
+		status = readlink(host_path, scratch_path, sizeof(scratch_path));
+		if (status < 0)
+			return status;
+		else if (status == sizeof(scratch_path))
+			return -ENAMETOOLONG;
+		scratch_path[status] = '\0';
+
+		/* Remove the leading "root" part if needed, it's
+		 * useful for "/proc/self/cwd/" for instance.  */
+		status = detranslate_path(tracee, scratch_path, host_path);
+		if (status < 0)
+			return status;
+
+	canon:
+		/* Canonicalize recursively the referee in case it
+		 * is/contains a link, moreover if it is not an
+		 * absolute link then it is relative to
+		 * 'guest_path'. */
+		status = canonicalize(tracee, scratch_path, true, guest_path, recursion_level + 1);
+		if (status < 0)
+			return status;
+
+		/* Check that a non-final canonicalized/dereferenced
+		 * symlink exists and is a directory.  */
+		status = substitute_binding_stat(tracee, finality, guest_path, host_path);
+		if (status < 0)
+			return status;
+
+		/* Here, 'guest_path' shouldn't be a symlink anymore,
+		 * unless it is a named file descriptor.  */
+		assert(status != 1 || sscanf(guest_path, "/proc/%*d/fd/%d", &status) == 1);
+	}
+
+	/* At the exit stage of the first level of recursion,
+	 * `guest_path` is fully canonicalized but a terminating '/'
+	 * or a terminating '.' may be required to keep the initial
+	 * semantic of `user_path`.  */
+	if (recursion_level == 0) {
+		switch (finality) {
+		case FINAL_NORMAL:
+			break;
+
+		case FINAL_SLASH:
+			strcpy(scratch_path, guest_path);
+			status = join_paths(2, guest_path, scratch_path, "");
+			if (status < 0)
+				return status;
+			break;
+
+		case FINAL_DOT:
+			strcpy(scratch_path, guest_path);
+			status = join_paths(2, guest_path, scratch_path, ".");
+			if (status < 0)
+				return status;
+			break;
+
+		default:
+			assert(0);
+		}
+	}
+
+	return 0;
+}
diff --git a/5.1.0/src/path/canon.h b/5.1.0/src/path/canon.h
new file mode 100644
index 0000000..98a3dad
--- /dev/null
+++ b/5.1.0/src/path/canon.h
@@ -0,0 +1,34 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef CANON_H
+#define CANON_H
+
+#include <stdbool.h>
+#include <limits.h>
+
+#include "tracee/tracee.h"
+
+extern int canonicalize(Tracee *tracee, const char *user_path, bool deref_final,
+			char guest_path[PATH_MAX], unsigned int nb_recursion);
+
+#endif /* CANON_H */
diff --git a/5.1.0/src/path/glue.c b/5.1.0/src/path/glue.c
new file mode 100644
index 0000000..a21c548
--- /dev/null
+++ b/5.1.0/src/path/glue.c
@@ -0,0 +1,192 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h> /* mkdir(2), lstat(2), */
+#include <sys/stat.h> /* mkdir(2), lstat(2), */
+#include <fcntl.h>    /* mknod(2), */
+#include <unistd.h>   /* mknod(2), lstat(2), unlink(2), rmdir(2), */
+#include <string.h>   /* string(3),  */
+#include <assert.h>   /* assert(3), */
+#include <limits.h>   /* PATH_MAX, */
+#include <errno.h>    /* errno, E* */
+#include <talloc.h>   /* talloc_*, */
+
+#include "path/binding.h"
+#include "path/path.h"
+#include "path/temp.h"
+#include "cli/note.h"
+
+#include "compat.h"
+
+/**
+ * Remove @path if it is empty only.
+ *
+ * Note: this is a Talloc destructor.
+ */
+static int remove_placeholder(char *path)
+{
+	struct stat statl;
+	int status;
+
+	status = lstat(path, &statl);
+	if (status)
+		return 0; /* Not fatal.  */
+
+	if (!S_ISDIR(statl.st_mode)) {
+		if (statl.st_size != 0)
+			return 0; /* Not fatal.  */
+		status = unlink(path);
+	}
+	else
+		status = rmdir(path);
+	if (status)
+		return 0; /* Not fatal.  */
+
+	return 0;
+}
+
+/**
+ * Attach a copy of @path to the autofree context, and set its
+ * destructor to remove_placeholder().
+ */
+static void set_placeholder_destructor(const char *path)
+{
+	TALLOC_CTX *autofreed;
+	char *placeholder;
+
+	autofreed = talloc_autofree_context();
+	if (autofreed == NULL)
+		return;
+
+	placeholder = talloc_strdup(autofreed, path);
+	if (placeholder == NULL)
+		return;
+
+	talloc_set_destructor(placeholder, remove_placeholder);
+}
+
+/**
+ * Build in a temporary filesystem the glue between the guest part and
+ * the host part of the @binding_path.  This function returns the type
+ * of the bound path, otherwise 0 if an error occured.
+ *
+ * For example, assuming the host path "/opt" is mounted/bound to the
+ * guest path "/black/holes/and/revelations", and assuming this path
+ * can't be created in the guest rootfs (eg. permission denied), then
+ * it is created in a temporary rootfs and all these paths are glued
+ * that way:
+ *
+ *   $GUEST/black/ --> $GLUE/black/
+ *                               ./holes
+ *                               ./holes/and
+ *                               ./holes/and/revelations --> $HOST/opt/
+ *
+ * This glue allows operations on paths that do not exist in the guest
+ * rootfs but that were specified as the guest part of a binding.
+ */
+mode_t build_glue(Tracee *tracee, const char *guest_path, char host_path[PATH_MAX],
+		Finality finality)
+{
+	bool belongs_to_gluefs;
+	Comparison comparison;
+	Binding *binding;
+	mode_t type;
+	mode_t mode;
+	int status;
+
+	assert(tracee->glue_type != 0);
+
+	/* Create the temporary directory where the "glue" rootfs will
+	 * lie.  */
+	if (tracee->glue == NULL) {
+		tracee->glue = create_temp_directory(NULL, tracee->tool_name);
+		if (tracee->glue == NULL) {
+			note(tracee, ERROR, INTERNAL, "can't create glue rootfs");
+			return 0;
+		}
+		talloc_set_name_const(tracee->glue, "$glue");
+	}
+
+	comparison = compare_paths(tracee->glue, host_path);
+	belongs_to_gluefs = (comparison == PATHS_ARE_EQUAL || comparison == PATH1_IS_PREFIX);
+
+	/* If it's not a final component then it is a directory.  I definitely
+	 * hate how the potential type of the final component is propagated
+	 * from initialize_binding() down to here, sadly there's no elegant way
+	 * to know its type at this stage.  */
+	if (IS_FINAL(finality)) {
+		type = tracee->glue_type;
+		mode = (belongs_to_gluefs ? 0777 : 0);
+	}
+	else {
+		type = S_IFDIR;
+		mode = 0777;
+	}
+
+	if (getenv("PROOT_DONT_POLLUTE_ROOTFS") != NULL && !belongs_to_gluefs)
+		goto create_binding;
+
+	/* Try to create this component into the "guest" or "glue"
+	 * rootfs (depending if there were a glue previously).  */
+	if (S_ISDIR(type))
+		status = mkdir(host_path, mode);
+	else /* S_IFREG, S_IFCHR, S_IFBLK, S_IFIFO or S_IFSOCK.  */
+		status = mknod(host_path, mode | type, 0);
+
+	/* Remove placeholders from the guest rootfs once PRoot is
+	 * terminated.  */
+	if (status >= 0 && !belongs_to_gluefs)
+		set_placeholder_destructor(host_path);
+
+	/* Nothing else to do if the path already exists or if it is
+	 * the final component since it will be pointed to by the
+	 * binding being initialized (from the example,
+	 * "$GUEST/black/holes/and/revelations" -> "$HOST/opt").  */
+	if (status >= 0 || errno == EEXIST || IS_FINAL(finality))
+		return type;
+
+	/* mkdir/mknod are supposed to always succeed in
+	 * tracee->glue.  */
+	if (belongs_to_gluefs) {
+		note(tracee, WARNING, SYSTEM, "mkdir/mknod");
+		return 0;
+	}
+
+create_binding:
+	/* Sanity checks.  */
+	if (   strnlen(tracee->glue, PATH_MAX) >= PATH_MAX
+	    || strnlen(guest_path, PATH_MAX) >= PATH_MAX) {
+		note(tracee, WARNING, INTERNAL, "installing the binding: guest path too long");
+		return 0;
+	}
+
+	/* From the example, create the binding "/black" ->
+	 * "$GLUE/black".  */
+	binding = insort_binding3(tracee, tracee->glue, tracee->glue, guest_path);
+	if (binding == NULL)
+		return 0;
+
+	/* TODO: emulation of getdents(parent(guest_path)) to finalize
+	 * the glue, "black" in getdents("/") from the example.  */
+
+	return type;
+}
diff --git a/5.1.0/src/path/glue.h b/5.1.0/src/path/glue.h
new file mode 100644
index 0000000..5c82f0d
--- /dev/null
+++ b/5.1.0/src/path/glue.h
@@ -0,0 +1,34 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef GLUE_H
+#define GLUE_H
+
+#include <limits.h> /* PATH_MAX, */
+
+#include "tracee/tracee.h"
+#include "path.h"
+
+extern mode_t build_glue(Tracee *tracee, const char *guest_path, char host_path[PATH_MAX],
+			Finality finality);
+
+#endif /* GLUE_H */
diff --git a/5.1.0/src/path/path.c b/5.1.0/src/path/path.c
new file mode 100644
index 0000000..3656c11
--- /dev/null
+++ b/5.1.0/src/path/path.c
@@ -0,0 +1,732 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <string.h>    /* string(3), */
+#include <stdarg.h>    /* va_*(3), */
+#include <assert.h>    /* assert(3), */
+#include <fcntl.h>     /* AT_*,  */
+#include <unistd.h>    /* readlink*(2), *stat(2), getpid(2), */
+#include <sys/types.h> /* pid_t, */
+#include <sys/stat.h>  /* S_ISDIR, */
+#include <dirent.h>    /* opendir(3), readdir(3), */
+#include <stdio.h>     /* snprintf(3), */
+#include <errno.h>     /* E*, */
+#include <stddef.h>    /* ptrdiff_t, */
+
+#include "path/path.h"
+#include "path/binding.h"
+#include "path/canon.h"
+#include "path/proc.h"
+#include "extension/extension.h"
+#include "cli/note.h"
+#include "build.h"
+
+#include "compat.h"
+
+/**
+ * Copy in @result the concatenation of several paths (@number_paths)
+ * and adds a path separator ('/') in between when needed. This
+ * function returns -errno if an error occured, otherwise it returns 0.
+ */
+int join_paths(int number_paths, char result[PATH_MAX], ...)
+{
+	va_list paths;
+	size_t length;
+	int status;
+	int i;
+
+	result[0] = '\0';
+	length = 0;
+	status = 0;
+
+	/* Parse the list of variadic arguments. */
+	va_start(paths, result);
+	for (i = 0; i < number_paths; i++) {
+		const char *path;
+		size_t path_length;
+		size_t new_length;
+
+		path = va_arg(paths, const char *);
+		if (path == NULL)
+			continue;
+		path_length = strlen(path);
+
+		/* A new path separator is needed.  */
+		if (length > 0 && result[length - 1] != '/' && path[0] != '/') {
+			new_length = length + path_length + 1;
+			if (new_length + 1 >= PATH_MAX) {
+				status = -ENAMETOOLONG;
+				break;
+			}
+			strcat(result + length, "/");
+			strcat(result + length, path);
+			length = new_length;
+		}
+		/* There are already two path separators.  */
+		else if (length > 0 && result[length - 1] == '/' && path[0] == '/') {
+			new_length = length + path_length - 1;
+			if (new_length + 1 >= PATH_MAX) {
+				status = -ENAMETOOLONG;
+				break;
+			}
+			strcat(result + length, path + 1);
+			length += path_length - 1;
+		}
+		/* There's already one path separator or result[] is empty.  */
+		else {
+			new_length = length + path_length;
+			if (new_length + 1 >= PATH_MAX) {
+				status = -ENAMETOOLONG;
+				break;
+			}
+			strcat(result + length, path);
+			length += path_length;
+		}
+
+		status = 0;
+	}
+	va_end(paths);
+
+	return status;
+}
+
+/**
+ * Put in @host_path the full path to the given shell @command.  The
+ * @command is searched in @paths if not null, otherwise in $PATH
+ * (relatively to the @tracee's file-system name-space).  This
+ * function always returns -1 on error, otherwise 0.
+ */
+int which(Tracee *tracee, const char *paths, char host_path[PATH_MAX], const char *command)
+{
+	char path[PATH_MAX];
+	const char *cursor;
+	struct stat statr;
+	int status;
+
+	bool is_explicit;
+	bool found;
+
+	assert(command != NULL);
+	is_explicit = (strchr(command, '/') != NULL);
+
+	/* Is the command available without any $PATH look-up?  */
+	status = realpath2(tracee, host_path, command, true);
+	if (status == 0 && stat(host_path, &statr) == 0) {
+		if (is_explicit && !S_ISREG(statr.st_mode)) {
+			note(tracee, ERROR, USER, "'%s' is not a regular file", command);
+			return -EACCES;
+		}
+
+		if (is_explicit && (statr.st_mode & S_IXUSR) == 0) {
+			note(tracee, ERROR, USER, "'%s' is not executable", command);
+			return -EACCES;
+		}
+
+		found = true;
+
+		/* Don't dereference the final component to preserve
+		 * argv0 in case it is a symlink to script.  */
+		(void) realpath2(tracee, host_path, command, false);
+	}
+	else
+		found = false;
+
+	/* Is the the explicit command was found?  */
+	if (is_explicit) {
+		if (found)
+			return 0;
+		else
+			goto not_found;
+	}
+
+	/* Otherwise search the command in $PATH.  */
+	paths = paths ?: getenv("PATH");
+	if (paths == NULL || strcmp(paths, "") == 0)
+		goto not_found;
+
+	cursor = paths;
+	do {
+		size_t length;
+
+		length = strcspn(cursor, ":");
+		cursor += length + 1;
+
+		if (length >= PATH_MAX)
+			continue;
+		else if (length == 0)
+			strcpy(path, ".");
+		else {
+			strncpy(path, cursor - length - 1, length);
+			path[length] = '\0';
+		}
+
+		/* Avoid buffer-overflow.  */
+		if (length + strlen(command) + 2 >= PATH_MAX)
+			continue;
+
+		strcat(path, "/");
+		strcat(path, command);
+
+		status = realpath2(tracee, host_path, path, true);
+		if (status == 0
+		    && stat(host_path, &statr) == 0
+		    && S_ISREG(statr.st_mode)
+		    && (statr.st_mode & S_IXUSR) != 0) {
+			/* Don't dereference the final component to preserve
+			 * argv0 in case it is a symlink to script.  */
+			(void) realpath2(tracee, host_path, path, false);
+			return 0;
+		}
+	} while (*(cursor - 1) != '\0');
+
+not_found:
+	status = getcwd2(tracee, path);
+	if (status < 0)
+		strcpy(path, "<unknown>");
+
+	note(tracee, ERROR, USER, "'%s' not found (root = %s, cwd = %s, $PATH=%s)",
+		command, get_root(tracee), path, paths);
+
+	/* Check if the command was found without any $PATH look-up
+	 * but it didn't contain "/".  */
+	if (found && !is_explicit)
+		note(tracee, ERROR, USER,
+			"to execute a local program, use the './' prefix, for example: ./%s", command);
+
+	return -1;
+}
+
+/**
+ * Put in @host_path the canonicalized form of @path.  In the nominal
+ * case (@tracee == NULL), this function is barely equivalent to
+ * realpath(), but when doing sub-reconfiguration, the path is
+ * canonicalized relatively to the current @tracee's file-system
+ * name-space.  This function returns -errno on error, otherwise 0.
+ */
+int realpath2(Tracee *tracee, char host_path[PATH_MAX], const char *path, bool deref_final)
+{
+	int status;
+
+	if (tracee == NULL)
+		status = (realpath(path, host_path) == NULL ? -errno : 0);
+	else
+		status = translate_path(tracee, host_path, AT_FDCWD, path, deref_final);
+	return status;
+}
+
+/**
+ * Put in @guest_path the canonicalized current working directory.  In
+ * the nominal case (@tracee == NULL), this function is barely
+ * equivalent to realpath(), but when doing sub-reconfiguration, the
+ * path is canonicalized relatively to the current @tracee's
+ * file-system name-space.  This function returns -errno on error,
+ * otherwise 0.
+ */
+int getcwd2(Tracee *tracee, char guest_path[PATH_MAX])
+{
+	if (tracee == NULL) {
+		if (getcwd(guest_path, PATH_MAX) == NULL)
+			return -errno;
+	}
+	else {
+		if (strlen(tracee->fs->cwd) >= PATH_MAX)
+			return -ENAMETOOLONG;
+
+		strcpy(guest_path, tracee->fs->cwd);
+	}
+
+	return 0;
+}
+
+/**
+ * Remove the trailing "/" or "/.".
+ */
+void chop_finality(char *path)
+{
+	size_t length = strlen(path);
+
+	if (path[length - 1] == '.') {
+		assert(length >= 2);
+		/* Special case for "/." */
+		if (length == 2)
+			path[length - 1] = '\0';
+		else
+			path[length - 2] = '\0';
+	}
+	else if (path[length - 1] == '/') {
+		/* Special case for "/" */
+		if (length > 1)
+			path[length - 1] = '\0';
+	}
+}
+
+/**
+ * Put in @path the result of readlink(/proc/@pid/fd/@fd).  This
+ * function returns -errno if an error occured, othrwise 0.
+ */
+int readlink_proc_pid_fd(pid_t pid, int fd, char path[PATH_MAX])
+{
+	char link[32]; /* 32 > sizeof("/proc//cwd") + sizeof(#ULONG_MAX) */
+	int status;
+
+	/* Format the path to the "virtual" link. */
+	status = snprintf(link, sizeof(link), "/proc/%d/fd/%d",	pid, fd);
+	if (status < 0)
+		return -EBADF;
+	if ((size_t) status >= sizeof(link))
+		return -EBADF;
+
+	/* Read the value of this "virtual" link. */
+	status = readlink(link, path, PATH_MAX);
+	if (status < 0)
+		return -EBADF;
+	if (status >= PATH_MAX)
+		return -ENAMETOOLONG;
+	path[status] = '\0';
+
+	return 0;
+}
+
+/**
+ * Copy in @result the equivalent of "@tracee->root + canon(@dir_fd +
+ * @user_path)".  If @user_path is not absolute then it is relative to
+ * the directory referred by the descriptor @dir_fd (AT_FDCWD is for
+ * the current working directory).  See the documentation of
+ * canonicalize() for the meaning of @deref_final.  This function
+ * returns -errno if an error occured, otherwise 0.
+ */
+int translate_path(Tracee *tracee, char result[PATH_MAX], int dir_fd,
+		const char *user_path, bool deref_final)
+{
+	char guest_path[PATH_MAX];
+	int status;
+
+	/* Use "/" as the base if it is an absolute guest path. */
+	if (user_path[0] == '/') {
+		strcpy(result, "/");
+	}
+	/* It is relative to a directory referred by a descriptor, see
+	 * openat(2) for details. */
+	else if (dir_fd != AT_FDCWD) {
+		/* /proc/@tracee->pid/fd/@dir_fd -> result.  */
+		status = readlink_proc_pid_fd(tracee->pid, dir_fd, result);
+		if (status < 0)
+			return status;
+
+		/* Named file descriptors may reference special
+		 * objects like pipes, sockets, inodes, ...  Such
+		 * objects do not belong to the file-system.  */
+		if (result[0] != '/')
+			return -ENOTDIR;
+
+		/* Remove the leading "root" part of the base
+		 * (required!). */
+		status = detranslate_path(tracee, result, NULL);
+		if (status < 0)
+			return status;
+	}
+	/* It is relative to the current working directory.  */
+	else {
+		status = getcwd2(tracee, result);
+		if (status < 0)
+			return status;
+	}
+
+	VERBOSE(tracee, 2, "pid %d: translate(\"%s\" + \"%s\")",
+		tracee != NULL ? tracee->pid : 0, result, user_path);
+
+	status = notify_extensions(tracee, GUEST_PATH, (intptr_t) result, (intptr_t) user_path);
+	if (status < 0)
+		return status;
+	if (status > 0)
+		goto skip;
+
+	/* So far "result" was used as a base path, it's time to join
+	 * it to the user path.  */
+	assert(result[0] == '/');
+	status = join_paths(2, guest_path, result, user_path);
+	if (status < 0)
+		return status;
+	strcpy(result, "/");
+
+	/* Canonicalize regarding the new root. */
+	status = canonicalize(tracee, guest_path, deref_final, result, 0);
+	if (status < 0)
+		return status;
+
+	/* Final binding substitution to convert "result" into a host
+	 * path, since canonicalize() works from the guest
+	 * point-of-view.  */
+	status = substitute_binding(tracee, GUEST, result);
+	if (status < 0)
+		return status;
+
+skip:
+	VERBOSE(tracee, 2, "pid %d:          -> \"%s\"",
+		tracee != NULL ? tracee->pid : 0, result);
+	return 0;
+}
+
+/**
+ * Remove/substitute the leading part of a "translated" @path.  It
+ * returns 0 if no transformation is required (ie. symmetric binding),
+ * otherwise it returns the size in bytes of the updated @path,
+ * including the end-of-string terminator.  On error it returns
+ * -errno.
+ */
+int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[PATH_MAX])
+{
+	size_t prefix_length;
+	ssize_t new_length;
+
+	bool sanity_check;
+	bool follow_binding;
+
+	/* Sanity check.  */
+	if (strnlen(path, PATH_MAX) >= PATH_MAX)
+		return -ENAMETOOLONG;
+
+	/* Don't try to detranslate relative paths (typically the
+	 * target of a relative symbolic link). */
+	if (path[0] != '/')
+		return 0;
+
+	/* Is it a symlink?  */
+	if (t_referrer != NULL) {
+		Comparison comparison;
+
+		sanity_check = false;
+		follow_binding = false;
+
+		/* In some cases bindings have to be resolved.  */
+		comparison = compare_paths("/proc", t_referrer);
+		if (comparison == PATH1_IS_PREFIX) {
+			/* Some links in "/proc" are generated
+			 * dynamically by the kernel.  PRoot has to
+			 * emulate some of them.  */
+			char proc_path[PATH_MAX];
+			strcpy(proc_path, path);
+			new_length = readlink_proc2(tracee, proc_path, t_referrer);
+			if (new_length < 0)
+				return new_length;
+			if (new_length != 0) {
+				strcpy(path, proc_path);
+				return new_length + 1;
+			}
+
+			/* Always resolve bindings for symlinks in
+			 * "/proc", they always point to the emulated
+			 * file-system namespace by design. */
+			follow_binding = true;
+		}
+		else if (!belongs_to_guestfs(tracee, t_referrer)) {
+			const char *binding_referree;
+			const char *binding_referrer;
+
+			binding_referree = get_path_binding(tracee, HOST, path);
+			binding_referrer = get_path_binding(tracee, HOST, t_referrer);
+			assert(binding_referrer != NULL);
+
+			/* Resolve bindings for symlinks that belong
+			 * to a binding and point to the same binding.
+			 * For example, if "-b /lib:/foo" is specified
+			 * and the symlink "/lib/a -> /lib/b" exists
+			 * in the host rootfs namespace, then it
+			 * should appear as "/foo/a -> /foo/b" in the
+			 * guest rootfs namespace for consistency
+			 * reasons.  */
+			if (binding_referree != NULL) {
+				comparison = compare_paths(binding_referree, binding_referrer);
+				follow_binding = (comparison == PATHS_ARE_EQUAL);
+			}
+		}
+	}
+	else {
+		sanity_check = true;
+		follow_binding = true;
+	}
+
+	if (follow_binding) {
+		switch (substitute_binding(tracee, HOST, path)) {
+		case 0:
+			return 0;
+		case 1:
+			return strlen(path) + 1;
+		default:
+			break;
+		}
+	}
+
+	switch (compare_paths(get_root(tracee), path)) {
+	case PATH1_IS_PREFIX:
+		/* Remove the leading part, that is, the "root".  */
+		prefix_length = strlen(get_root(tracee));
+
+		/* Special case when path to the guest rootfs == "/". */
+		if (prefix_length == 1)
+			prefix_length = 0;
+
+		new_length = strlen(path) - prefix_length;
+		memmove(path, path + prefix_length, new_length);
+
+		path[new_length] = '\0';
+		break;
+
+	case PATHS_ARE_EQUAL:
+		/* Special case when path == root. */
+		new_length = 1;
+		strcpy(path, "/");
+		break;
+
+	default:
+		/* Ensure the path is within the new root.  */
+		if (sanity_check)
+			return -EPERM;
+		else
+			return 0;
+	}
+
+	return new_length + 1;
+}
+
+/**
+ * Check if the translated @host_path belongs to the guest rootfs,
+ * that is, isn't from a binding.
+ */
+bool belongs_to_guestfs(const Tracee *tracee, const char *host_path)
+{
+	Comparison comparison;
+
+	comparison = compare_paths(get_root(tracee), host_path);
+	return (comparison == PATHS_ARE_EQUAL || comparison == PATH1_IS_PREFIX);
+}
+
+/**
+ * Compare @path1 with @path2, which are respectively @length1 and
+ * @length2 long.
+ *
+ * This function works only with paths canonicalized in the same
+ * namespace (host/guest)!
+ */
+Comparison compare_paths2(const char *path1, size_t length1, const char *path2, size_t length2)
+{
+	size_t length_min;
+	bool is_prefix;
+	char sentinel;
+
+#if defined DEBUG_OPATH
+	assert(length(path1) == length1);
+	assert(length(path2) == length2);
+#endif
+	assert(length1 > 0);
+	assert(length2 > 0);
+
+	if (!length1 || !length2) {
+		return PATHS_ARE_NOT_COMPARABLE;
+	}
+
+	/* Remove potential trailing '/' for the comparison.  */
+	if (path1[length1 - 1] == '/')
+		length1--;
+
+	if (path2[length2 - 1] == '/')
+		length2--;
+
+	if (length1 < length2) {
+		length_min = length1;
+		sentinel = path2[length_min];
+	}
+	else {
+		length_min = length2;
+		sentinel = path1[length_min];
+	}
+
+	/* Optimize obvious cases.  */
+	if (sentinel != '/' && sentinel != '\0')
+		return PATHS_ARE_NOT_COMPARABLE;
+
+	is_prefix = (strncmp(path1, path2, length_min) == 0);
+
+	if (!is_prefix)
+		return PATHS_ARE_NOT_COMPARABLE;
+
+	if (length1 == length2)
+		return PATHS_ARE_EQUAL;
+	else if (length1 < length2)
+		return PATH1_IS_PREFIX;
+	else if (length1 > length2)
+		return PATH2_IS_PREFIX;
+
+	assert(0);
+	return PATHS_ARE_NOT_COMPARABLE;
+}
+
+Comparison compare_paths(const char *path1, const char *path2)
+{
+	return compare_paths2(path1, strlen(path1), path2, strlen(path2));
+}
+
+typedef int (*foreach_fd_t)(const Tracee *tracee, int fd, char path[PATH_MAX]);
+
+/**
+ * Call @callback on each open file descriptors of @pid. It returns
+ * the status of the first failure, that is, if @callback returned
+ * seomthing lesser than 0, otherwise 0.
+ */
+static int foreach_fd(const Tracee *tracee, foreach_fd_t callback)
+{
+	struct dirent *dirent;
+	char path[PATH_MAX];
+	char proc_fd[32]; /* 32 > sizeof("/proc//fd") + sizeof(#ULONG_MAX) */
+	int status;
+	DIR *dirp;
+
+	/* Format the path to the "virtual" directory. */
+	status = snprintf(proc_fd, sizeof(proc_fd), "/proc/%d/fd", tracee->pid);
+	if (status < 0 || (size_t) status >= sizeof(proc_fd))
+		return 0;
+
+	/* Open the virtual directory "/proc/$pid/fd". */
+	dirp = opendir(proc_fd);
+	if (dirp == NULL)
+		return 0;
+
+	while ((dirent = readdir(dirp)) != NULL) {
+		/* Read the value of this "virtual" link.  Don't use
+		 * readlinkat(2) here since it would require Linux >=
+		 * 2.6.16 and Glibc >= 2.4, whereas PRoot is supposed
+		 * to work on any Linux 2.6 systems.  */
+
+		char tmp[PATH_MAX];
+		if (strlen(proc_fd) + strlen(dirent->d_name) + 1 >= PATH_MAX)
+			continue;
+
+		strcpy(tmp, proc_fd);
+		strcat(tmp, "/");
+		strcat(tmp, dirent->d_name);
+
+		status = readlink(tmp, path, PATH_MAX);
+		if (status < 0 || status >= PATH_MAX)
+			continue;
+		path[status] = '\0';
+
+		/* Ensure it points to a path (not a socket or somethink like that). */
+		if (path[0] != '/')
+			continue;
+
+		status = callback(tracee, atoi(dirent->d_name), path);
+		if (status < 0)
+			goto end;
+	}
+	status = 0;
+
+end:
+	closedir(dirp);
+	return status;
+}
+
+/**
+ * Helper for list_open_fd().
+ */
+static int list_open_fd_callback(const Tracee *tracee, int fd, char path[PATH_MAX])
+{
+	VERBOSE(tracee, 1, "pid %d: access to \"%s\" (fd %d) won't be translated until closed",
+		tracee->pid, path, fd);
+	return 0;
+}
+
+/**
+ * Warn for files that are open. It is useful right after PRoot has
+ * attached a process.
+ */
+int list_open_fd(const Tracee *tracee)
+{
+	return foreach_fd(tracee, list_open_fd_callback);
+}
+
+/**
+ * Substitute the first @old_prefix_length bytes of @path with
+ * @new_prefix (the caller has to provides a correct
+ * @new_prefix_length).  This function returns the new length of
+ * @path.  Note: this function takes care about special cases (like
+ * "/").
+ */
+size_t substitute_path_prefix(char path[PATH_MAX], size_t old_prefix_length,
+			const char *new_prefix, size_t new_prefix_length)
+{
+	size_t path_length;
+	size_t new_length;
+
+	path_length = strlen(path);
+
+	assert(old_prefix_length < PATH_MAX);
+	assert(new_prefix_length < PATH_MAX);
+
+	if (new_prefix_length == 1) {
+		/* Special case: "/foo" -> "/".  Substitute "/foo/bin"
+		 * with "/bin" not "//bin".  */
+
+		new_length = path_length - old_prefix_length;
+		if (new_length != 0)
+			memmove(path, path + old_prefix_length, new_length);
+		else {
+			/* Special case: "/".  */
+			path[0] = '/';
+			new_length = 1;
+		}
+	}
+	else if (old_prefix_length == 1) {
+		/* Special case: "/" -> "/foo". Substitute "/bin" with
+		 * "/foo/bin" not "/foobin".  */
+
+		new_length = new_prefix_length + path_length;
+		if (new_length >= PATH_MAX)
+			return -ENAMETOOLONG;
+
+		if (path_length > 1) {
+			memmove(path + new_prefix_length, path, path_length);
+			memcpy(path, new_prefix, new_prefix_length);
+		}
+		else {
+			/* Special case: "/".  */
+			memcpy(path, new_prefix, new_prefix_length);
+			new_length = new_prefix_length;
+		}
+	}
+	else {
+		/* Generic case.  */
+
+		new_length = path_length - old_prefix_length + new_prefix_length;
+		if (new_length >= PATH_MAX)
+			return -ENAMETOOLONG;
+
+		memmove(path + new_prefix_length,
+			path + old_prefix_length,
+			path_length - old_prefix_length);
+		memcpy(path, new_prefix, new_prefix_length);
+	}
+
+	assert(new_length < PATH_MAX);
+	path[new_length] = '\0';
+
+	return new_length;
+}
diff --git a/5.1.0/src/path/path.h b/5.1.0/src/path/path.h
new file mode 100644
index 0000000..1676056
--- /dev/null
+++ b/5.1.0/src/path/path.h
@@ -0,0 +1,99 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef PATH_H
+#define PATH_H
+
+#include <sys/types.h> /* pid_t, */
+#include <fcntl.h> /* AT_FDCWD, */
+#include <limits.h> /* PATH_MAX, */
+#include <stdbool.h>
+
+#include "tracee/tracee.h"
+
+/* File type.  */
+typedef enum {
+	REGULAR,
+	SYMLINK,
+} Type;
+
+/* Path point-of-view.  */
+typedef enum {
+	GUEST,
+	HOST,
+
+	/* Used for bindings as specified by the user but not
+	 * canonicalized yet (new_binding, initialize_binding).  */
+	PENDING,
+} Side;
+
+/* Path with cached attributes.  */
+typedef struct {
+	char path[PATH_MAX];
+	size_t length;
+	Side side;
+} Path;
+
+/* Path ending type.  */
+typedef enum {
+	NOT_FINAL,
+	FINAL_NORMAL,
+	FINAL_SLASH,
+	FINAL_DOT
+} Finality;
+
+#define IS_FINAL(a) ((a) != NOT_FINAL)
+
+/* Comparison between two paths.  */
+typedef enum Comparison {
+	PATHS_ARE_EQUAL,
+	PATH1_IS_PREFIX,
+	PATH2_IS_PREFIX,
+	PATHS_ARE_NOT_COMPARABLE,
+} Comparison;
+
+extern int which(Tracee *tracee, const char *paths, char host_path[PATH_MAX], const char *command);
+extern int realpath2(Tracee *tracee, char host_path[PATH_MAX], const char *path, bool deref_final);
+extern int getcwd2(Tracee *tracee, char guest_path[PATH_MAX]);
+extern void chop_finality(char *path);
+
+extern int translate_path(Tracee *tracee, char host_path[PATH_MAX],
+			int dir_fd, const char *guest_path, bool deref_final);
+
+extern int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[PATH_MAX]);
+extern bool belongs_to_guestfs(const Tracee *tracee, const char *path);
+
+extern int join_paths(int number_paths, char result[PATH_MAX], ...);
+extern int list_open_fd(const Tracee *tracee);
+
+extern Comparison compare_paths(const char *path1, const char *path2);
+extern Comparison compare_paths2(const char *path1, size_t length1, const char *path2, size_t length2);
+
+extern size_t substitute_path_prefix(char path[PATH_MAX], size_t old_prefix_length,
+				const char *new_prefix, size_t new_prefix_length);
+
+extern int readlink_proc_pid_fd(pid_t pid, int fd, char path[PATH_MAX]);
+
+/* Check if path interpretable relatively to dirfd, see openat(2) for details. */
+#define AT_FD(dirfd, path) ((dirfd) != AT_FDCWD && ((path) != NULL && (path)[0] != '/'))
+
+#endif /* PATH_H */
diff --git a/5.1.0/src/path/proc.c b/5.1.0/src/path/proc.c
new file mode 100644
index 0000000..08d705b
--- /dev/null
+++ b/5.1.0/src/path/proc.c
@@ -0,0 +1,195 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdio.h>   /* snprintf(3), */
+#include <string.h>  /* strcmp(3), */
+#include <stdlib.h>  /* atoi(3), strtol(3), */
+#include <errno.h>   /* E*, */
+#include <assert.h>  /* assert(3), */
+
+#include "path/proc.h"
+#include "tracee/tracee.h"
+#include "path/path.h"
+#include "path/binding.h"
+
+/**
+ * This function emulates the @result of readlink("@base/@component")
+ * with respect to @tracee, where @base belongs to "/proc" (according
+ * to @comparison).  This function returns -errno on error, an enum
+ * @action otherwise (c.f. above).
+ *
+ * Unlike readlink(), this function includes the nul terminating byte
+ * to @result.
+ */
+Action readlink_proc(const Tracee *tracee, char result[PATH_MAX],
+			const char base[PATH_MAX], const char component[NAME_MAX],
+			Comparison comparison)
+{
+	const Tracee *known_tracee;
+	char proc_path[64]; /* 64 > sizeof("/proc//fd/") + 2 * sizeof(#ULONG_MAX) */
+	int status;
+	pid_t pid;
+
+	assert(comparison == compare_paths("/proc", base));
+
+	/* Remember: comparison = compare_paths("/proc", base)  */
+	switch (comparison) {
+	case PATHS_ARE_EQUAL:
+		/* Substitute "/proc/self" with "/proc/<PID>".  */
+		if (strcmp(component, "self") != 0)
+			return DEFAULT;
+
+		status = snprintf(result, PATH_MAX, "/proc/%d", tracee->pid);
+		if (status < 0 || status >= PATH_MAX)
+			return -EPERM;
+
+		return CANONICALIZE;
+
+	case PATH1_IS_PREFIX:
+		/* Handle "/proc/<PID>" below, where <PID> is process
+		 * monitored by PRoot.  */
+		break;
+
+	default:
+		return DEFAULT;
+	}
+
+	pid = atoi(base + strlen("/proc/"));
+	if (pid == 0)
+		return DEFAULT;
+
+	/* Handle links in "/proc/<PID>/".  */
+	status = snprintf(proc_path, sizeof(proc_path), "/proc/%d", pid);
+	if (status < 0 || (size_t) status >= sizeof(proc_path))
+		return -EPERM;
+
+	comparison = compare_paths(proc_path, base);
+	switch (comparison) {
+	case PATHS_ARE_EQUAL:
+		known_tracee = get_tracee(tracee, pid, false);
+		if (known_tracee == NULL)
+			return DEFAULT;
+
+#define SUBSTITUTE(name, string)				\
+		do {						\
+			if (strcmp(component, #name) != 0)	\
+				break;				\
+								\
+			status = strlen(string);		\
+			if (status >= PATH_MAX)			\
+				return -EPERM;			\
+								\
+			strncpy(result, string, status + 1);	\
+			return CANONICALIZE;			\
+		} while (0)
+
+		/* Substitute link "/proc/<PID>/???" with the content
+		 * of tracee->???.  */
+		SUBSTITUTE(exe, known_tracee->exe);
+		SUBSTITUTE(cwd, known_tracee->fs->cwd);
+		SUBSTITUTE(root, get_root(known_tracee));
+#undef SUBSTITUTE
+		return DEFAULT;
+
+	case PATH1_IS_PREFIX:
+		/* Handle "/proc/<PID>/???" below.  */
+		break;
+
+	default:
+		return DEFAULT;
+	}
+
+	/* Handle links in "/proc/<PID>/fd/".  */
+	status = snprintf(proc_path, sizeof(proc_path), "/proc/%d/fd", pid);
+	if (status < 0 || (size_t) status >= sizeof(proc_path))
+		return -EPERM;
+
+	comparison = compare_paths(proc_path, base);
+	switch (comparison) {
+		char *end_ptr;
+
+	case PATHS_ARE_EQUAL:
+		/* Sanity check: a number is expected.  */
+		errno = 0;
+		(void) strtol(component, &end_ptr, 10);
+		if (errno != 0 || end_ptr == component)
+			return -EPERM;
+
+		/* Don't dereference "/proc/<PID>/fd/???" now: they
+		 * can point to anonymous pipe, socket, ...  otherwise
+		 * they point to a path already canonicalized by the
+		 * kernel.
+		 *
+		 * Note they are still correctly detranslated in
+		 * syscall/exit.c if a monitored process uses
+		 * readlink() against any of them.  */
+		status = snprintf(result, PATH_MAX, "%s/%s", base, component);
+		if (status < 0 || status >= PATH_MAX)
+			return -EPERM;
+
+		return DONT_CANONICALIZE;
+
+	default:
+		break;
+	}
+
+	return DEFAULT;
+}
+
+/**
+ * This function emulates the @result of readlink("@referer") with
+ * respect to @tracee, where @referer is a strict subpath of "/proc".
+ * This function returns -errno if an error occured, the length of
+ * @result if the readlink was emulated, 0 otherwise.
+ *
+ * Unlike readlink(), this function includes the nul terminating byte
+ * to @result (but this byte is not counted in the returned value).
+ */
+ssize_t readlink_proc2(const Tracee *tracee, char result[PATH_MAX], const char referer[PATH_MAX])
+{
+	Action action;
+	char base[PATH_MAX];
+	char *component;
+
+	/* Sanity check.  */
+	if (strnlen(referer, PATH_MAX) >= PATH_MAX)
+		return -ENAMETOOLONG;
+
+	assert(compare_paths("/proc", referer) == PATH1_IS_PREFIX);
+
+	/* It's safe to use strrchr() here since @referer was
+	 * previously canonicalized.  */
+	strcpy(base, referer);
+	component = strrchr(base, '/');
+
+	/* These cases are not possible: @referer is supposed to be a
+	 * canonicalized subpath of "/proc".  */
+	assert(component != NULL && component != base);
+
+	component[0] = '\0';
+	component++;
+	if (component[0] == '\0')
+		return 0;
+
+	action = readlink_proc(tracee, result, base, component, PATH1_IS_PREFIX);
+	return (action == CANONICALIZE ? strlen(result) : 0);
+}
diff --git a/5.1.0/src/path/proc.h b/5.1.0/src/path/proc.h
new file mode 100644
index 0000000..55d26cc
--- /dev/null
+++ b/5.1.0/src/path/proc.h
@@ -0,0 +1,44 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef PROC_H
+#define PROC_H
+
+#include <limits.h>
+
+#include "tracee/tracee.h"
+#include "path/path.h"
+
+/* Action to do after a call to readlink_proc().  */
+typedef enum {
+	DEFAULT,           /* Nothing special to do, treat it as a regular link.  */
+	CANONICALIZE,      /* The symlink was dereferenced, now canonicalize it.  */
+	DONT_CANONICALIZE, /* The symlink shouldn't be dereferenced nor canonicalized.  */
+} Action;
+
+
+extern Action readlink_proc(const Tracee *tracee, char result[PATH_MAX], const char path[PATH_MAX],
+			const char component[NAME_MAX],	Comparison comparison);
+
+extern ssize_t readlink_proc2(const Tracee *tracee, char result[PATH_MAX], const char path[PATH_MAX]);
+
+#endif /* PROC_H */
diff --git a/5.1.0/src/path/temp.c b/5.1.0/src/path/temp.c
new file mode 100644
index 0000000..bbcfb5f
--- /dev/null
+++ b/5.1.0/src/path/temp.c
@@ -0,0 +1,305 @@
+#include <sys/types.h>  /* stat(2), opendir(3), */
+#include <sys/stat.h>   /* stat(2), chmod(2), */
+#include <unistd.h>     /* stat(2), rmdir(2), unlink(2), readlink(2), */
+#include <errno.h>      /* errno(2), */
+#include <dirent.h>     /* readdir(3), opendir(3), */
+#include <string.h>     /* strcmp(3), */
+#include <stdlib.h>     /* free(3), */
+#include <stdio.h>      /* P_tmpdir, */
+#include <talloc.h>     /* talloc(3), */
+
+#include "cli/note.h"
+
+/**
+ * Remove recursively the content of the current working directory.
+ * This latter has to lie in P_tmpdir (ie. "/tmp" on most systems).
+ * This function returns -1 if a fatal error occured (ie. the
+ * recursion must be stopped), the number of non-fatal errors
+ * otherwise.
+ *
+ * WARNING: this function changes the current working directory for
+ * the calling process.
+ */
+static int clean_temp_cwd()
+{
+	const size_t length_tmpdir = strlen(P_tmpdir);
+	char prefix[length_tmpdir];
+	int nb_errors = 0;
+	int status;
+	DIR *dir;
+
+	/* Sanity check: ensure the current directory lies in
+	 * "/tmp".  */
+	status = readlink("/proc/self/cwd", prefix, length_tmpdir);
+	if (status < 0) {
+		note(NULL, WARNING, SYSTEM, "can't readlink '/proc/self/cwd'");
+		return ++nb_errors;
+	}
+	if (strncmp(prefix, P_tmpdir, length_tmpdir) != 0) {
+		note(NULL, ERROR, INTERNAL,
+			"trying to remove a directory outside of '%s', "
+			"please report this error.\n", P_tmpdir);
+		return ++nb_errors;
+	}
+
+	dir = opendir(".");
+	if (dir == NULL) {
+		note(NULL, WARNING, SYSTEM, "can't open '.'");
+		return ++nb_errors;
+	}
+
+	while (1) {
+		struct dirent *entry;
+
+		errno = 0;
+		entry = readdir(dir);
+		if (entry == NULL)
+			break;
+
+		if (   strcmp(entry->d_name, ".")  == 0
+		    || strcmp(entry->d_name, "..") == 0)
+			continue;
+
+		status = chmod(entry->d_name, 0700);
+		if (status < 0) {
+			note(NULL, WARNING, SYSTEM, "cant chmod '%s'", entry->d_name);
+			nb_errors++;
+			continue;
+		}
+
+		if (entry->d_type == DT_DIR) {
+			status = chdir(entry->d_name);
+			if (status < 0) {
+				note(NULL, WARNING, SYSTEM, "can't chdir '%s'", entry->d_name);
+				nb_errors++;
+				continue;
+			}
+
+			/* Recurse.  */
+			status = clean_temp_cwd();
+			if (status < 0) {
+				nb_errors = -1;
+				goto end;
+			}
+			nb_errors += status;
+
+			status = chdir("..");
+			if (status < 0) {
+				note(NULL, ERROR, SYSTEM, "can't chdir to '..'");
+				nb_errors = -1;
+				goto end;
+			}
+
+			status = rmdir(entry->d_name);
+		}
+		else {
+			status = unlink(entry->d_name);
+		}
+		if (status < 0) {
+			note(NULL, WARNING, SYSTEM, "can't remove '%s'", entry->d_name);
+			nb_errors++;
+			continue;
+		}
+	}
+	if (errno != 0) {
+		note(NULL, WARNING, SYSTEM, "can't readdir '.'");
+		nb_errors++;
+	}
+
+end:
+	(void) closedir(dir);
+	return nb_errors;
+}
+
+/**
+ * Remove recursively @path.  This latter has to be a directory lying
+ * in P_tmpdir (ie. "/tmp" on most systems).  This function returns -1
+ * on error, otherwise 0.
+ */
+static int remove_temp_directory2(const char *path)
+{
+	int result;
+	int status;
+	char *cwd;
+
+	cwd = get_current_dir_name();
+
+	status = chmod(path, 0700);
+	if (status < 0) {
+		note(NULL, ERROR, SYSTEM, "can't chmod '%s'", path);
+		result = -1;
+		goto end;
+	}
+
+	status = chdir(path);
+	if (status < 0) {
+		note(NULL, ERROR, SYSTEM, "can't chdir to '%s'", path);
+		result = -1;
+		goto end;
+	}
+
+	status = clean_temp_cwd();
+	result = (status == 0 ? 0 : -1);
+
+	/* Try to remove path even if something went wrong.  */
+	status = chdir("..");
+	if (status < 0) {
+		note(NULL, ERROR, SYSTEM, "can't chdir to '..'");
+		result = -1;
+		goto end;
+	}
+
+	status = rmdir(path);
+	if (status < 0) {
+		note(NULL, ERROR, SYSTEM, "cant remove '%s'", path);
+		result = -1;
+		goto end;
+	}
+
+end:
+	if (cwd != NULL) {
+		status = chdir(cwd);
+		if (status < 0) {
+			result = -1;
+			note(NULL, ERROR, SYSTEM, "can't chdir to '%s'", cwd);
+		}
+		free(cwd);
+	}
+
+	return result;
+}
+
+/**
+ * Like remove_temp_directory2() but always return 0.
+ *
+ * Note: this is a talloc destructor.
+ */
+static int remove_temp_directory(char *path)
+{
+	(void) remove_temp_directory2(path);
+	return 0;
+}
+
+/**
+ * Remove the file @path.  This function always returns 0.
+ *
+ * Note: this is a talloc destructor.
+ */
+static int remove_temp_file(char *path)
+{
+	int status;
+
+	status = unlink(path);
+	if (status < 0)
+		note(NULL, ERROR, SYSTEM, "can't remove '%s'", path);
+
+	return 0;
+}
+
+/**
+ * Create a path name with the following format:
+ * "/tmp/@prefix-$PID-XXXXXX".  The returned C string is either
+ * auto-freed if @context is NULL.  This function returns NULL if an
+ * error occurred.
+ */
+char *create_temp_name(TALLOC_CTX *context, const char *prefix)
+{
+	char *name;
+
+	if (context == NULL)
+		context = talloc_autofree_context();
+
+	name = talloc_asprintf(context, "%s/%s-%d-XXXXXX", P_tmpdir, prefix, getpid());
+	if (name == NULL) {
+		note(NULL, ERROR, INTERNAL, "can't allocate memory");
+		return NULL;
+	}
+
+	return name;
+}
+
+/**
+ * Create a directory that will be automatically removed either on
+ * PRoot termination if @context is NULL, or once its path name
+ * (attached to @context) is freed.  This function returns NULL on
+ * error, otherwise the absolute path name to the created directory
+ * (@prefix-ed).
+ */
+const char *create_temp_directory(TALLOC_CTX *context, const char *prefix)
+{
+	char *name;
+
+	name = create_temp_name(context, prefix);
+	if (name == NULL)
+		return NULL;
+
+	name = mkdtemp(name);
+	if (name == NULL) {
+		note(NULL, ERROR, SYSTEM, "can't create temporary directory");
+		return NULL;
+	}
+
+	talloc_set_destructor(name, remove_temp_directory);
+
+	return name;
+}
+
+/**
+ * Create a file that will be automatically removed either on PRoot
+ * termination if @context is NULL, or once its path name (attached to
+ * @context) is freed.  This function returns NULL on error,
+ * otherwise the absolute path name to the created file (@prefix-ed).
+ */
+const char *create_temp_file(TALLOC_CTX *context, const char *prefix)
+{
+	char *name;
+	int fd;
+
+	name = create_temp_name(context, prefix);
+	if (name == NULL)
+		return NULL;
+
+	fd = mkstemp(name);
+	if (fd < 0) {
+		note(NULL, ERROR, SYSTEM, "can't create temporary file");
+		return NULL;
+	}
+	close(fd);
+
+	talloc_set_destructor(name, remove_temp_file);
+
+	return name;
+}
+
+/**
+ * Like create_temp_file() but returns an open file stream to the
+ * created file.  It's up to the caller to close returned stream.
+ */
+FILE* open_temp_file(TALLOC_CTX *context, const char *prefix)
+{
+	char *name;
+	FILE *file;
+	int fd;
+
+	name = create_temp_name(context, prefix);
+	if (name == NULL)
+		return NULL;
+
+	fd = mkstemp(name);
+	if (fd < 0)
+		goto error;
+
+	talloc_set_destructor(name, remove_temp_file);
+
+	file = fdopen(fd, "w");
+	if (file == NULL)
+		goto error;
+
+	return file;
+
+error:
+	if (fd >= 0)
+		close(fd);
+	note(NULL, ERROR, SYSTEM, "can't create temporary file");
+	return NULL;
+}
diff --git a/5.1.0/src/path/temp.h b/5.1.0/src/path/temp.h
new file mode 100644
index 0000000..faa9341
--- /dev/null
+++ b/5.1.0/src/path/temp.h
@@ -0,0 +1,33 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef TEMP_H
+#define TEMP_H
+
+#include <talloc.h>
+
+extern char *create_temp_name(TALLOC_CTX *context, const char *prefix);
+extern const char *create_temp_directory(TALLOC_CTX *context, const char *prefix);
+extern const char *create_temp_file(TALLOC_CTX *context, const char *prefix);
+extern FILE* open_temp_file(TALLOC_CTX *context, const char *prefix);
+
+#endif /* TEMP_H */
diff --git a/5.1.0/src/ptrace/ptrace.c b/5.1.0/src/ptrace/ptrace.c
new file mode 100644
index 0000000..ef69cf5
--- /dev/null
+++ b/5.1.0/src/ptrace/ptrace.c
@@ -0,0 +1,656 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/ptrace.h> /* PTRACE_*,  */
+#include <errno.h>      /* E*, */
+#include <assert.h>     /* assert(3), */
+#include <stdbool.h>    /* bool, true, false, */
+#include <signal.h>     /* siginfo_t, */
+#include <sys/uio.h>    /* struct iovec, */
+#include <sys/param.h>  /* MIN(), MAX(), */
+#include <string.h>     /* memcpy(3), */
+
+#include "ptrace/ptrace.h"
+#include "ptrace/user.h"
+#include "tracee/tracee.h"
+#include "syscall/sysnum.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+#include "tracee/abi.h"
+#include "tracee/event.h"
+#include "cli/note.h"
+#include "arch.h"
+
+#include "compat.h"
+
+#if defined(ARCH_X86_64) || defined(ARCH_X86)
+#include <asm/ldt.h>    /* struct user_desc, */
+#endif
+
+#if defined(ARCH_X86_64)
+#include <asm/prctl.h>    /* ARCH_{G,S}ET_{F,G}S, */
+#endif
+
+#if defined(ARCH_ARM_EABI)
+#define user_fpregs_struct user_fpregs
+#endif
+
+#if defined(ARCH_ARM64)
+#define user_fpregs_struct user_fpsimd_struct
+#endif
+
+static const char *stringify_ptrace(enum __ptrace_request request)
+{
+#define CASE_STR(a) case a: return #a; break;
+	switch ((int) request) {
+	CASE_STR(PTRACE_TRACEME)	CASE_STR(PTRACE_PEEKTEXT)	CASE_STR(PTRACE_PEEKDATA)
+	CASE_STR(PTRACE_PEEKUSER)	CASE_STR(PTRACE_POKETEXT)	CASE_STR(PTRACE_POKEDATA)
+	CASE_STR(PTRACE_POKEUSER)	CASE_STR(PTRACE_CONT)		CASE_STR(PTRACE_KILL)
+	CASE_STR(PTRACE_SINGLESTEP)	CASE_STR(PTRACE_GETREGS)	CASE_STR(PTRACE_SETREGS)
+	CASE_STR(PTRACE_GETFPREGS)	CASE_STR(PTRACE_SETFPREGS)	CASE_STR(PTRACE_ATTACH)
+	CASE_STR(PTRACE_DETACH)		CASE_STR(PTRACE_GETFPXREGS)	CASE_STR(PTRACE_SETFPXREGS)
+	CASE_STR(PTRACE_SYSCALL)	CASE_STR(PTRACE_SETOPTIONS)	CASE_STR(PTRACE_GETEVENTMSG)
+	CASE_STR(PTRACE_GETSIGINFO)	CASE_STR(PTRACE_SETSIGINFO)	CASE_STR(PTRACE_GETREGSET)
+	CASE_STR(PTRACE_SETREGSET)	CASE_STR(PTRACE_SEIZE)		CASE_STR(PTRACE_INTERRUPT)
+	CASE_STR(PTRACE_LISTEN)		CASE_STR(PTRACE_SET_SYSCALL)
+	CASE_STR(PTRACE_GET_THREAD_AREA)	CASE_STR(PTRACE_SET_THREAD_AREA)
+	CASE_STR(PTRACE_GETVFPREGS)	CASE_STR(PTRACE_SINGLEBLOCK)	CASE_STR(PTRACE_ARCH_PRCTL)
+	default: return "PTRACE_???"; }
+}
+
+/**
+ * Translate the ptrace syscall made by @tracee into a "void" syscall
+ * in order to emulate the ptrace mechanism within PRoot.  This
+ * function returns -errno if an error occured (unsupported request),
+ * otherwise 0.
+ */
+int translate_ptrace_enter(Tracee *tracee)
+{
+	/* The ptrace syscall have to be emulated since it can't be nested.  */
+	set_sysnum(tracee, PR_void);
+	return 0;
+}
+
+/**
+ * Set @ptracee's tracer to @ptracer, and increment ptracees counter
+ * of this later.
+ */
+void attach_to_ptracer(Tracee *ptracee, Tracee *ptracer)
+{
+	bzero(&(PTRACEE), sizeof(PTRACEE));
+	PTRACEE.ptracer = ptracer;
+
+	PTRACER.nb_ptracees++;
+}
+
+/**
+ * Unset @ptracee's tracer, and decrement ptracees counter of this
+ * later.
+ */
+void detach_from_ptracer(Tracee *ptracee)
+{
+	Tracee *ptracer = PTRACEE.ptracer;
+
+	PTRACEE.ptracer = NULL;
+
+	assert(PTRACER.nb_ptracees > 0);
+	PTRACER.nb_ptracees--;
+}
+
+/**
+ * Emulate the ptrace syscall made by @tracee.  This function returns
+ * -errno if an error occured (unsupported request), otherwise 0.
+ */
+int translate_ptrace_exit(Tracee *tracee)
+{
+	word_t request, pid, address, data, result;
+	Tracee *ptracee, *ptracer;
+	int forced_signal = -1;
+	int signal;
+	int status;
+
+	/* Read ptrace parameters.  */
+	request = peek_reg(tracee, ORIGINAL, SYSARG_1);
+	pid     = peek_reg(tracee, ORIGINAL, SYSARG_2);
+	address = peek_reg(tracee, ORIGINAL, SYSARG_3);
+	data    = peek_reg(tracee, ORIGINAL, SYSARG_4);
+
+	/* Propagate signedness for this special value.  */
+	if (is_32on64_mode(tracee) && pid == 0xFFFFFFFF)
+		pid = (word_t) -1;
+
+	/* The TRACEME request is the only one used by a tracee.  */
+	if (request == PTRACE_TRACEME) {
+		ptracer = tracee->parent;
+		ptracee = tracee;
+
+		/* The emulated ptrace in PRoot has the same
+		 * limitation as the real ptrace in the Linux kernel:
+		 * only one tracer per process.  */
+		if (PTRACEE.ptracer != NULL || ptracee == ptracer)
+			return -EPERM;
+
+		attach_to_ptracer(ptracee, ptracer);
+
+		/* Detect when the ptracer has gone to wait before the
+		 * ptracee did the ptrace(ATTACHME) request.  */
+		if (PTRACER.waits_in == WAITS_IN_KERNEL) {
+			status = kill(ptracer->pid, SIGSTOP);
+			if (status < 0)
+				note(tracee, WARNING, INTERNAL,
+					"can't wake ptracer %d", ptracer->pid);
+			else {
+				ptracer->sigstop = SIGSTOP_IGNORED;
+				PTRACER.waits_in = WAITS_IN_PROOT;
+			}
+		}
+
+		/* Disable seccomp acceleration for this tracee and
+		 * all its children since we can't assume what are the
+		 * syscalls its tracer is interested with.  */
+		if (tracee->seccomp == ENABLED)
+			tracee->seccomp = DISABLING;
+
+		return 0;
+	}
+
+	/* The ATTACH, SEIZE, and INTERRUPT requests are the only ones
+	 * where the ptracee is in an unknown state.  */
+	if (request == PTRACE_ATTACH) {
+		ptracer = tracee;
+		ptracee = get_tracee(ptracer, pid, false);
+		if (ptracee == NULL)
+			return -ESRCH;
+
+		/* The emulated ptrace in PRoot has the same
+		 * limitation as the real ptrace in the Linux kernel:
+		 * only one tracer per process.  */
+		if (PTRACEE.ptracer != NULL || ptracee == ptracer)
+			return -EPERM;
+
+		attach_to_ptracer(ptracee, ptracer);
+
+		/* The tracee is sent a SIGSTOP, but will not
+		 * necessarily have stopped by the completion of this
+		 * call.
+		 *
+		 * -- man 2 ptrace.  */
+		kill(pid, SIGSTOP);
+
+		return 0;
+	}
+
+	/* Here, the tracee is a ptracer.  Also, the requested ptracee
+	 * has to be in the "stopped for ptracer" state.  */
+	ptracer = tracee;
+	ptracee = get_stopped_ptracee(ptracer, pid, false, __WALL);
+	if (ptracee == NULL) {
+		static bool warned = false;
+
+		/* Ensure we didn't get there only because inheritance
+		 * mechanism has missed this one.  */
+		ptracee = get_tracee(tracee, pid, false);
+		if (ptracee != NULL && ptracee->exe == NULL && !warned) {
+			warned = true;
+			note(ptracer, WARNING, INTERNAL, "ptrace request to an unexpected ptracee");
+		}
+
+		return -ESRCH;
+	}
+
+	/* Sanity checks.  */
+	if (   PTRACEE.is_zombie
+	    || PTRACEE.ptracer != ptracer
+	    || pid == (word_t) -1)
+		return -ESRCH;
+
+	switch (request) {
+	case PTRACE_SYSCALL:
+		PTRACEE.ignore_syscalls = false;
+		forced_signal = (int) data;
+		status = 0;
+		break;  /* Restart the ptracee.  */
+
+	case PTRACE_CONT:
+		PTRACEE.ignore_syscalls = true;
+		forced_signal = (int) data;
+		status = 0;
+		break;  /* Restart the ptracee.  */
+
+	case PTRACE_SINGLESTEP:
+		ptracee->restart_how = PTRACE_SINGLESTEP;
+		forced_signal = (int) data;
+		status = 0;
+		break;  /* Restart the ptracee.  */
+
+	case PTRACE_SINGLEBLOCK:
+		ptracee->restart_how = PTRACE_SINGLEBLOCK;
+		forced_signal = (int) data;
+		status = 0;
+		break;  /* Restart the ptracee.  */
+
+	case PTRACE_DETACH:
+		detach_from_ptracer(ptracee);
+		status = 0;
+		break;  /* Restart the ptracee.  */
+
+	case PTRACE_KILL:
+		status = ptrace(request, pid, NULL, NULL);
+		break;  /* Restart the ptracee.  */
+
+	case PTRACE_SETOPTIONS:
+		PTRACEE.options = data;
+		return 0;  /* Don't restart the ptracee.  */
+
+	case PTRACE_GETEVENTMSG: {
+		status = ptrace(request, pid, NULL, &result);
+		if (status < 0)
+			return -errno;
+
+		poke_word(ptracer, data, result);
+		if (errno != 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_PEEKUSER:
+		if (is_32on64_mode(ptracer)) {
+			address = convert_user_offset(address);
+			if (address == (word_t) -1)
+				return -EIO;
+		}
+		/* Fall through.  */
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKDATA:
+		errno = 0;
+		result = (word_t) ptrace(request, pid, address, NULL);
+		if (errno != 0)
+			return -errno;
+
+		poke_word(ptracer, data, result);
+		if (errno != 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+
+	case PTRACE_POKEUSER:
+		if (is_32on64_mode(ptracer)) {
+			address = convert_user_offset(address);
+			if (address == (word_t) -1)
+				return -EIO;
+		}
+
+		status = ptrace(request, pid, address, data);
+		if (status < 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEDATA:
+		if (is_32on64_mode(ptracer)) {
+			word_t tmp;
+
+			errno = 0;
+			tmp = (word_t) ptrace(PTRACE_PEEKDATA, ptracee->pid, address, NULL);
+			if (errno != 0)
+				return -errno;
+
+			data |= (tmp & 0xFFFFFFFF00000000ULL);
+		}
+
+		status = ptrace(request, pid, address, data);
+		if (status < 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+
+	case PTRACE_GETSIGINFO: {
+		siginfo_t siginfo;
+
+		status = ptrace(request, pid, NULL, &siginfo);
+		if (status < 0)
+			return -errno;
+
+		status = write_data(ptracer, data, &siginfo, sizeof(siginfo));
+		if (status < 0)
+			return status;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_SETSIGINFO: {
+		siginfo_t siginfo;
+
+		status = read_data(ptracer, &siginfo, data, sizeof(siginfo));
+		if (status < 0)
+			return status;
+
+		status = ptrace(request, pid, NULL, &siginfo);
+		if (status < 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_GETREGS: {
+		size_t size;
+		union {
+			struct user_regs_struct regs;
+			uint32_t regs32[USER32_NB_REGS];
+		} buffer;
+
+		status = ptrace(request, pid, NULL, &buffer);
+		if (status < 0)
+			return -errno;
+
+		if (is_32on64_mode(tracee)) {
+			struct user_regs_struct regs64;
+
+			memcpy(&regs64, &buffer.regs, sizeof(struct user_regs_struct));
+			convert_user_regs_struct(false,	(uint64_t *) &regs64, buffer.regs32);
+
+			size = sizeof(buffer.regs32);
+		}
+		else
+			size = sizeof(buffer.regs);
+
+		status = write_data(ptracer, data, &buffer, size);
+		if (status < 0)
+			return status;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_SETREGS: {
+		size_t size;
+		union {
+			struct user_regs_struct regs;
+			uint32_t regs32[USER32_NB_REGS];
+		} buffer;
+
+		size = (is_32on64_mode(ptracer)
+			? sizeof(buffer.regs32)
+			: sizeof(buffer.regs));
+
+		status = read_data(ptracer, &buffer, data, size);
+		if (status < 0)
+			return status;
+
+		if (is_32on64_mode(ptracer)) {
+			uint32_t regs32[USER32_NB_REGS];
+
+			memcpy(regs32, buffer.regs32, sizeof(regs32));
+			convert_user_regs_struct(true, (uint64_t *) &buffer.regs, regs32);
+		}
+
+		status = ptrace(request, pid, NULL, &buffer);
+		if (status < 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_GETFPREGS: {
+		size_t size;
+		union {
+			struct user_fpregs_struct fpregs;
+			uint32_t fpregs32[USER32_NB_FPREGS];
+		} buffer;
+
+		status = ptrace(request, pid, NULL, &buffer);
+		if (status < 0)
+			return -errno;
+
+		if (is_32on64_mode(tracee)) {
+#if 0 /* TODO */
+			struct user_fpregs_struct fpregs64;
+
+			memcpy(&fpregs64, &buffer.fpregs, sizeof(struct user_fpregs_struct));
+			convert_user_fpregs_struct(false, (uint64_t *) &fpregs64, buffer.fpregs32);
+#else
+			static bool warned = false;
+			if (!warned)
+				note(ptracer, WARNING, INTERNAL,
+					"ptrace 32-bit request '%s' not supported on 64-bit yet",
+					stringify_ptrace(request));
+			warned = true;
+			bzero(&buffer, sizeof(buffer));
+#endif
+			size = sizeof(buffer.fpregs32);
+		}
+		else
+			size = sizeof(buffer.fpregs);
+
+		status = write_data(ptracer, data, &buffer, size);
+		if (status < 0)
+			return status;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_SETFPREGS: {
+		size_t size;
+		union {
+			struct user_fpregs_struct fpregs;
+			uint32_t fpregs32[USER32_NB_FPREGS];
+		} buffer;
+
+		size = (is_32on64_mode(ptracer)
+			? sizeof(buffer.fpregs32)
+			: sizeof(buffer.fpregs));
+
+		status = read_data(ptracer, &buffer, data, size);
+		if (status < 0)
+			return status;
+
+		if (is_32on64_mode(ptracer)) {
+#if 0 /* TODO */
+			uint32_t fpregs32[USER32_NB_FPREGS];
+
+			memcpy(fpregs32, buffer.fpregs32, sizeof(fpregs32));
+			convert_user_fpregs_struct(true, (uint64_t *) &buffer.fpregs, fpregs32);
+#else
+			static bool warned = false;
+			if (!warned)
+				note(ptracer, WARNING, INTERNAL,
+					"ptrace 32-bit request '%s' not supported on 64-bit yet",
+					stringify_ptrace(request));
+			warned = true;
+			return -ENOTSUP;
+#endif
+		}
+
+		status = ptrace(request, pid, NULL, &buffer);
+		if (status < 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+#if defined(ARCH_X86_64) || defined(ARCH_X86)
+	case PTRACE_GET_THREAD_AREA: {
+		struct user_desc user_desc;
+
+		status = ptrace(request, pid, address, &user_desc);
+		if (status < 0)
+			return -errno;
+
+		status = write_data(ptracer, data, &user_desc, sizeof(user_desc));
+		if (status < 0)
+			return status;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_SET_THREAD_AREA: {
+		struct user_desc user_desc;
+
+		status = read_data(ptracer, &user_desc, data, sizeof(user_desc));
+		if (status < 0)
+			return status;
+
+		status = ptrace(request, pid, address, &user_desc);
+		if (status < 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+#endif
+
+	case PTRACE_GETREGSET: {
+		struct iovec local_iovec;
+		word_t remote_iovec_base;
+		word_t remote_iovec_len;
+
+		remote_iovec_base = peek_word(ptracer, data);
+		if (errno != 0)
+			return -errno;
+
+		remote_iovec_len = peek_word(ptracer, data + sizeof_word(ptracer));
+		if (errno != 0)
+			return -errno;
+
+		/* Sanity check.  */
+		assert(sizeof(local_iovec.iov_len) == sizeof(word_t));
+
+		local_iovec.iov_len  = remote_iovec_len;
+		local_iovec.iov_base = talloc_zero_size(ptracer->ctx, remote_iovec_len);
+		if (local_iovec.iov_base == NULL)
+			return -ENOMEM;
+
+		status = ptrace(PTRACE_GETREGSET, pid, address, &local_iovec);
+		if (status < 0)
+			return status;
+
+		remote_iovec_len = local_iovec.iov_len =
+			MIN(remote_iovec_len, local_iovec.iov_len);
+
+		/* Update remote vector content.  */
+		status = writev_data(ptracer, remote_iovec_base, &local_iovec, 1);
+		if (status < 0)
+			return status;
+
+		/* Update remote vector length.  */
+		poke_word(ptracer, data + sizeof_word(ptracer), remote_iovec_len);
+		if (errno != 0)
+			return -errno;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_SETREGSET: {
+		struct iovec local_iovec;
+		word_t remote_iovec_base;
+		word_t remote_iovec_len;
+
+		remote_iovec_base = peek_word(ptracer, data);
+		if (errno != 0)
+			return -errno;
+
+		remote_iovec_len = peek_word(ptracer, data + sizeof_word(ptracer));
+		if (errno != 0)
+			return -errno;
+
+		/* Sanity check.  */
+		assert(sizeof(local_iovec.iov_len) == sizeof(word_t));
+
+		local_iovec.iov_len  = remote_iovec_len;
+		local_iovec.iov_base = talloc_zero_size(ptracer->ctx, remote_iovec_len);
+		if (local_iovec.iov_base == NULL)
+			return -ENOMEM;
+
+		/* Copy remote content into the local vector.  */
+		status = read_data(ptracer, local_iovec.iov_base,
+				remote_iovec_base, local_iovec.iov_len);
+		if (status < 0)
+			return status;
+
+		status = ptrace(PTRACE_SETREGSET, pid, address, &local_iovec);
+		if (status < 0)
+			return status;
+
+		return 0;  /* Don't restart the ptracee.  */
+	}
+
+	case PTRACE_GETVFPREGS:
+	case PTRACE_GETFPXREGS: {
+		static bool warned = false;
+		if (!warned)
+			note(ptracer, WARNING, INTERNAL, "ptrace request '%s' not supported yet",
+				stringify_ptrace(request));
+		warned = true;
+		return -ENOTSUP;
+	}
+
+#if defined(ARCH_X86_64)
+	case PTRACE_ARCH_PRCTL:
+		switch (data) {
+		case ARCH_GET_GS:
+		case ARCH_GET_FS:
+			status = ptrace(request, pid, &result, data);
+			if (status < 0)
+				return -errno;
+
+			poke_word(ptracer, address, result);
+			if (errno != 0)
+				return -errno;
+			break;
+
+		case ARCH_SET_GS:
+		case ARCH_SET_FS: {
+			static bool warned = false;
+			if (!warned)
+				note(ptracer, WARNING, INTERNAL,
+					"ptrace request '%s' ARCH_SET_{G,F}S not supported yet",
+					stringify_ptrace(request));
+			return -ENOTSUP;
+		}
+
+		default:
+			return -ENOTSUP;
+		}
+
+		return 0;  /* Don't restart the ptracee.  */
+#endif
+
+	default:
+		note(ptracer, WARNING, INTERNAL, "ptrace request '%s' not supported yet",
+			stringify_ptrace(request));
+		return -ENOTSUP;
+	}
+
+	/* Now, the initial tracee's event can be handled.  */
+	signal = PTRACEE.event4.proot.pending
+		? handle_tracee_event(ptracee, PTRACEE.event4.proot.value)
+		: PTRACEE.event4.proot.value;
+
+	/* The restarting signal from the ptracer overrides the
+	 * restarting signal from PRoot.  */
+	if (forced_signal != -1)
+		signal = forced_signal;
+
+	(void) restart_tracee(ptracee, signal);
+
+	return status;
+}
diff --git a/5.1.0/src/ptrace/ptrace.h b/5.1.0/src/ptrace/ptrace.h
new file mode 100644
index 0000000..a5ad170
--- /dev/null
+++ b/5.1.0/src/ptrace/ptrace.h
@@ -0,0 +1,36 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef PTRACE_H
+#define PTRACE_H
+
+#include "tracee/tracee.h"
+
+extern int translate_ptrace_enter(Tracee *tracee);
+extern int translate_ptrace_exit(Tracee *tracee);
+extern void attach_to_ptracer(Tracee *ptracee, Tracee *ptracer);
+extern void detach_from_ptracer(Tracee *ptracee);
+
+#define PTRACEE (ptracee->as_ptracee)
+#define PTRACER (ptracer->as_ptracer)
+
+#endif /* PTRACE_H */
diff --git a/5.1.0/src/ptrace/user.c b/5.1.0/src/ptrace/user.c
new file mode 100644
index 0000000..4a27fba
--- /dev/null
+++ b/5.1.0/src/ptrace/user.c
@@ -0,0 +1,166 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <stddef.h>
+
+#include "ptrace/user.h"
+#include "cli/note.h"
+
+#if defined(ARCH_X86_64)
+
+/**
+ * Return the index in the "regs" field of a 64-bit "user" area that
+ * corresponds to the specified @index in the "regs" field of a 32-bit
+ * "user" area.
+ */
+static inline size_t convert_user_regs_index(size_t index)
+{
+	static size_t mapping[USER32_NB_REGS] = {
+		05, /* ?bx */	11, /* ?cx */	12, /* ?dx */
+		13, /* ?si */	14, /* ?di */	04, /* ?bp */
+		10, /* ?ax */	23, /* ds */	24, /* es */
+		25, /* fs */	26, /* gs */	15, /* orig_?ax */
+		16, /* ?ip */	17, /* cs */	18, /* eflags */
+		19, /* ?sp */	20, /* ss */ };
+
+	/* Sanity check.  */
+	assert(index < USER32_NB_REGS);
+
+	return mapping[index];
+}
+
+/* Layout of a 32-bit "user" area.  */
+#define USER32_REGS_OFFSET	0
+#define USER32_REGS_SIZE	(USER32_NB_REGS * sizeof(uint32_t))
+#define USER32_FPVALID_OFFSET	(USER32_REGS_OFFSET	+ USER32_REGS_SIZE)
+#define USER32_I387_OFFSET	(USER32_FPVALID_OFFSET	+ sizeof(uint32_t))
+#define USER32_I387_SIZE	(USER32_NB_FPREGS * sizeof(uint32_t))
+#define USER32_TSIZE_OFFSET	(USER32_I387_OFFSET	+ USER32_I387_SIZE)
+#define USER32_DSIZE_OFFSET	(USER32_TSIZE_OFFSET	+ sizeof(uint32_t))
+#define USER32_SSIZE_OFFSET	(USER32_DSIZE_OFFSET	+ sizeof(uint32_t))
+#define USER32_START_CODE_OFFSET  (USER32_SSIZE_OFFSET	+ sizeof(uint32_t))
+#define USER32_START_STACK_OFFSET (USER32_START_CODE_OFFSET	+ sizeof(uint32_t))
+#define USER32_SIGNAL_OFFSET	(USER32_START_STACK_OFFSET	+ sizeof(uint32_t))
+#define USER32_RESERVED_OFFSET	(USER32_SIGNAL_OFFSET	+ sizeof(uint32_t))
+#define USER32_AR0_OFFSET	(USER32_RESERVED_OFFSET	+ sizeof(uint32_t))
+#define USER32_FPSTATE_OFFSET	(USER32_AR0_OFFSET	+ sizeof(uint32_t))
+#define USER32_MAGIC_OFFSET	(USER32_FPSTATE_OFFSET	+ sizeof(uint32_t))
+#define USER32_COMM_OFFSET	(USER32_MAGIC_OFFSET	+ sizeof(uint32_t))
+#define USER32_COMM_SIZE	(32 * sizeof(uint8_t))
+#define USER32_DEBUGREG_OFFSET	(USER32_COMM_OFFSET	+ USER32_COMM_SIZE)
+#define USER32_DEBUGREG_SIZE	(8 * sizeof(uint32_t))
+
+/**
+ * Return the offset in the "debugreg" field of a 64-bit "user" area
+ * that corresponds to the specified @offset in the "debugreg" field
+ * of a 32-bit "user" area.
+ */
+static inline size_t convert_user_debugreg_offset(size_t offset)
+{
+	size_t index;
+
+	/* Sanity check.  */
+	assert(offset >= USER32_DEBUGREG_OFFSET
+	    && offset < USER32_DEBUGREG_OFFSET + USER32_DEBUGREG_SIZE);
+
+	index = (offset - USER32_DEBUGREG_OFFSET) / sizeof(uint32_t);
+	return offsetof(struct user, u_debugreg) + index * sizeof(uint64_t);
+}
+
+/**
+ * Return the offset in a 64-bit "user" area that corresponds to the
+ * specified @offset in a 32-bit "user" area.  This function returns
+ * "(word_t) -1" if the specified @offset is invalid.
+ */
+word_t convert_user_offset(word_t offset)
+{
+	const char *area_name = NULL;
+
+	if (/* offset >= 0 && */ offset < USER32_REGS_OFFSET + USER32_REGS_SIZE) {
+		/* Sanity checks.  */
+		if ((offset % sizeof(uint32_t)) != 0)
+			return (word_t) -1;
+
+		return convert_user_regs_index(offset / sizeof(uint32_t)) * sizeof(uint64_t);
+	}
+	else if (offset == USER32_FPVALID_OFFSET)
+		area_name = "fpvalid"; /* Not yet supported.  */
+	else if (offset >= USER32_I387_OFFSET && offset < USER32_I387_OFFSET + USER32_I387_SIZE)
+		area_name = "i387"; /* Not yet supported.  */
+	else if (offset == USER32_TSIZE_OFFSET)
+		area_name = "tsize"; /* Not yet supported.  */
+	else if (offset == USER32_DSIZE_OFFSET)
+		area_name = "dsize"; /* Not yet supported.  */
+	else if (offset == USER32_SSIZE_OFFSET)
+		area_name = "ssize"; /* Not yet supported.  */
+	else if (offset == USER32_START_CODE_OFFSET)
+		area_name = "start_code"; /* Not yet supported.  */
+	else if (offset == USER32_START_STACK_OFFSET)
+		area_name = "start_stack"; /* Not yet supported.  */
+	else if (offset == USER32_SIGNAL_OFFSET)
+		area_name = "signal"; /* Not yet supported.  */
+	else if (offset == USER32_RESERVED_OFFSET)
+		area_name = "reserved"; /* Not yet supported.  */
+	else if (offset == USER32_AR0_OFFSET)
+		area_name = "ar0"; /* Not yet supported.  */
+	else if (offset == USER32_FPSTATE_OFFSET)
+		area_name = "fpstate"; /* Not yet supported.  */
+	else if (offset == USER32_MAGIC_OFFSET)
+		area_name = "magic"; /* Not yet supported.  */
+	else if (offset >= USER32_COMM_OFFSET && offset < USER32_COMM_OFFSET + USER32_COMM_SIZE)
+		area_name = "comm"; /* Not yet supported.  */
+	else if (offset >= USER32_DEBUGREG_OFFSET && offset < USER32_DEBUGREG_OFFSET + USER32_DEBUGREG_SIZE)
+		return convert_user_debugreg_offset(offset);
+	else
+		area_name = "<unknown>";
+
+	note(NULL, WARNING, INTERNAL, "ptrace user area '%s' not supported yet", area_name);
+	return (word_t) -1;  /* Unknown offset.  */
+}
+
+/**
+ * Convert the "regs" field from a 64-bit "user" area into a "regs"
+ * field from a 32-bit "user" area, or vice versa according to
+ * @reverse.
+ */
+void convert_user_regs_struct(bool reverse, uint64_t *user_regs64,
+			uint32_t user_regs32[USER32_NB_REGS])
+{
+	size_t index32;
+
+	for (index32 = 0; index32 < USER32_NB_REGS; index32++) {
+		size_t index64 = convert_user_regs_index(index32);
+		assert(index64 != (size_t) -1);
+
+		if (reverse)
+			user_regs64[index64] = (uint64_t) user_regs32[index32];
+		else
+			user_regs32[index32] = (uint32_t) user_regs64[index64];
+	}
+}
+
+#endif /* ARCH_X86_64 */
diff --git a/5.1.0/src/ptrace/user.h b/5.1.0/src/ptrace/user.h
new file mode 100644
index 0000000..152f355
--- /dev/null
+++ b/5.1.0/src/ptrace/user.h
@@ -0,0 +1,56 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "arch.h"
+#include "attribute.h"
+
+#if defined(ARCH_X86_64)
+
+#define USER32_NB_REGS   17
+#define USER32_NB_FPREGS 27
+
+extern word_t convert_user_offset(word_t offset);
+extern void convert_user_regs_struct(bool reverse, uint64_t *user_regs64,
+				uint32_t user_regs32[USER32_NB_REGS]);
+
+#else
+
+#define USER32_NB_REGS   0
+#define USER32_NB_FPREGS 0
+
+static inline word_t convert_user_offset(word_t offset UNUSED)
+{
+	assert(0);
+}
+
+static inline void convert_user_regs_struct(bool reverse UNUSED,
+					uint64_t *user_regs64 UNUSED,
+					uint32_t user_regs32[USER32_NB_REGS] UNUSED)
+{
+	assert(0);
+}
+
+#endif
diff --git a/5.1.0/src/ptrace/wait.c b/5.1.0/src/ptrace/wait.c
new file mode 100644
index 0000000..1b172ce
--- /dev/null
+++ b/5.1.0/src/ptrace/wait.c
@@ -0,0 +1,360 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/ptrace.h> /* PTRACE_*,  */
+#include <errno.h>      /* E*, */
+#include <assert.h>     /* assert(3), */
+#include <stdbool.h>    /* bool, true, false, */
+#include <signal.h>     /* SIG*, */
+#include <talloc.h>     /* talloc*, */
+
+#include "ptrace/wait.h"
+#include "ptrace/ptrace.h"
+#include "syscall/sysnum.h"
+#include "syscall/chain.h"
+#include "tracee/tracee.h"
+#include "tracee/event.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+
+#include "attribute.h"
+
+static const char *stringify_event(int event) UNUSED;
+static const char *stringify_event(int event)
+{
+	if (WIFEXITED(event))
+		return "exited";
+	else if (WIFSIGNALED(event))
+		return "signaled";
+	else if (WIFCONTINUED(event))
+		return "continued";
+	else if (WIFSTOPPED(event)) {
+		switch ((event & 0xfff00) >> 8) {
+		case SIGTRAP:
+			return "stopped: SIGTRAP";
+		case SIGTRAP | 0x80:
+			return "stopped: SIGTRAP: 0x80";
+		case SIGTRAP | PTRACE_EVENT_VFORK << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_VFORK";
+		case SIGTRAP | PTRACE_EVENT_FORK  << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_FORK";
+		case SIGTRAP | PTRACE_EVENT_VFORK_DONE  << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_VFORK_DONE";
+		case SIGTRAP | PTRACE_EVENT_CLONE << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_CLONE";
+		case SIGTRAP | PTRACE_EVENT_EXEC  << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_EXEC";
+		case SIGTRAP | PTRACE_EVENT_EXIT  << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_EXIT";
+		case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_SECCOMP2";
+		case SIGTRAP | PTRACE_EVENT_SECCOMP << 8:
+			return "stopped: SIGTRAP: PTRACE_EVENT_SECCOMP";
+		case SIGSTOP:
+			return "stopped: SIGSTOP";
+		default:
+			return "stopped: unknown";
+		}
+	}
+	return "unknown";
+}
+
+/**
+ * Translate the wait syscall made by @ptracer into a "void" syscall
+ * if the expected pid is one of its ptracees, in order to emulate the
+ * ptrace mechanism within PRoot.  This function returns -errno if an
+ * error occured (unsupported request), otherwise 0.
+ */
+int translate_wait_enter(Tracee *ptracer)
+{
+	Tracee *ptracee;
+	pid_t pid;
+
+	PTRACER.waits_in = WAITS_IN_KERNEL;
+
+	/* Don't emulate the ptrace mechanism if it's not a ptracer.  */
+	if (PTRACER.nb_ptracees == 0)
+		return 0;
+
+	/* Don't emulate the ptrace mechanism if the requested pid is
+	 * not a ptracee.  */
+	pid = (pid_t) peek_reg(ptracer, ORIGINAL, SYSARG_1);
+	if (pid != -1) {
+		ptracee = get_tracee(ptracer, pid, false);
+		if (ptracee == NULL || PTRACEE.ptracer != ptracer)
+			return 0;
+	}
+
+	/* This syscall is canceled at the enter stage in order to be
+	 * handled at the exit stage.  */
+	set_sysnum(ptracer, PR_void);
+	PTRACER.waits_in = WAITS_IN_PROOT;
+
+	return 0;
+}
+
+/**
+ * Update pid & wait status of @ptracer's wait(2) for the given
+ * @ptracee.  This function returns -errno if an error occurred, 0 if
+ * the wait syscall will be restarted (ie. the event is discarded),
+ * otherwise @ptracee's pid.
+ */
+static int update_wait_status(Tracee *ptracer, Tracee *ptracee)
+{
+	word_t address;
+	int result;
+
+	/* Special case: the Linux kernel reports the terminating
+	 * event issued by a process to both its parent and its
+	 * tracer, except when they are the same.  In this case the
+	 * Linux kernel reports the terminating event only once to the
+	 * tracing parent ...  */
+	if (PTRACEE.ptracer == ptracee->parent
+	    && (WIFEXITED(PTRACEE.event4.ptracer.value)
+	     || WIFSIGNALED(PTRACEE.event4.ptracer.value))) {
+		/* ... So hide this terminating event (toward its
+		 * tracer, ie. PRoot) and make the second one appear
+		 * (towards its parent, ie. the ptracer).  This will
+		 * ensure its exit status is collected from a kernel
+		 * point-of-view (ie. it doesn't stay a zombie
+		 * forever).  */
+		restart_original_syscall(ptracer);
+
+		/* Detach this ptracee from its ptracer, PRoot doesn't
+		 * have anything else to emulate.  */
+		detach_from_ptracer(ptracee);
+
+		/* Zombies can rest in peace once the ptracer is
+		 * notified.  */
+		if (PTRACEE.is_zombie)
+			TALLOC_FREE(ptracee);
+
+		return 0;
+	}
+
+	address = peek_reg(ptracer, ORIGINAL, SYSARG_2);
+	if (address != 0) {
+		poke_int32(ptracer, address, PTRACEE.event4.ptracer.value);
+		if (errno != 0)
+			return -errno;
+	}
+
+	PTRACEE.event4.ptracer.pending = false;
+
+	/* Be careful; ptracee might get freed before its pid is
+	 * returned.  */
+	result = ptracee->pid;
+
+	/* Zombies can rest in peace once the ptracer is notified.  */
+	if (PTRACEE.is_zombie) {
+		detach_from_ptracer(ptracee);
+		TALLOC_FREE(ptracee);
+	}
+
+	return result;
+}
+
+/**
+ * Emulate the wait* syscall made by @ptracer if it was in the context
+ * of the ptrace mechanism. This function returns -errno if an error
+ * occured, otherwise the pid of the expected tracee.
+ */
+int translate_wait_exit(Tracee *ptracer)
+{
+	Tracee *ptracee;
+	word_t options;
+	int status;
+	pid_t pid;
+
+	assert(PTRACER.waits_in == WAITS_IN_PROOT);
+	PTRACER.waits_in = DOESNT_WAIT;
+
+	pid = (pid_t) peek_reg(ptracer, ORIGINAL, SYSARG_1);
+	options = peek_reg(ptracer, ORIGINAL, SYSARG_3);
+
+	/* Is there such a stopped ptracee with an event not yet
+	 * passed to its ptracer?  */
+	ptracee = get_stopped_ptracee(ptracer, pid, true, options);
+	if (ptracee == NULL) {
+		/* Is there still living ptracees?  */
+		if (PTRACER.nb_ptracees == 0)
+			return -ECHILD;
+
+		/* Non blocking wait(2) ?  */
+		if ((options & WNOHANG) != 0) {
+			/* if WNOHANG was specified and one or more
+			 * child(ren) specified by pid exist, but have
+			 * not yet changed state, then 0 is returned.
+			 * On error, -1 is returned.
+			 *
+			 * -- man 2 waitpid  */
+			return (has_ptracees(ptracer, pid, options) ? 0 : -ECHILD);
+		}
+
+		/* Otherwise put this ptracer in the "waiting for
+		 * ptracee" state, it will be woken up in
+		 * handle_ptracee_event() later.  */
+		PTRACER.wait_pid = pid;
+		PTRACER.wait_options = options;
+
+		return 0;
+	}
+
+	status = update_wait_status(ptracer, ptracee);
+	if (status < 0)
+		return status;
+
+	return status;
+}
+
+/**
+ * For the given @ptracee, pass its current @event to its ptracer if
+ * this latter is waiting for it, otherwise put the @ptracee in the
+ * "waiting for ptracer" state.  This function returns whether
+ * @ptracee shall be kept in the stop state or not.
+ */
+bool handle_ptracee_event(Tracee *ptracee, int event)
+{
+	bool handled_by_proot_first = false;
+	Tracee *ptracer = PTRACEE.ptracer;
+	bool keep_stopped;
+
+	assert(ptracer != NULL);
+
+	/* Remember what the event initially was, this will be
+	 * required by PRoot to handle this event later.  */
+	PTRACEE.event4.proot.value   = event;
+	PTRACEE.event4.proot.pending = true;
+
+	/* By default, this ptracee should be kept stopped until its
+	 * ptracer restarts it.  */
+	keep_stopped = true;
+
+	/* Not all events are expected for this ptracee.  */
+	if (WIFSTOPPED(event)) {
+		switch ((event & 0xfff00) >> 8) {
+		case SIGTRAP | 0x80:
+			if (PTRACEE.ignore_syscalls || PTRACEE.ignore_loader_syscalls)
+				return false;
+
+			if ((PTRACEE.options & PTRACE_O_TRACESYSGOOD) == 0)
+				event &= ~(0x80 << 8);
+
+			handled_by_proot_first = IS_IN_SYSEXIT(ptracee);
+			break;
+
+#define PTRACE_EVENT_VFORKDONE PTRACE_EVENT_VFORK_DONE
+#define CASE_FILTER_EVENT(name) \
+		case SIGTRAP | PTRACE_EVENT_ ##name << 8:			\
+			if ((PTRACEE.options & PTRACE_O_TRACE ##name) == 0)	\
+				return false;					\
+			PTRACEE.tracing_started = true;				\
+			handled_by_proot_first = true;				\
+			break;
+
+		CASE_FILTER_EVENT(FORK);
+		CASE_FILTER_EVENT(VFORK);
+		CASE_FILTER_EVENT(VFORKDONE);
+		CASE_FILTER_EVENT(CLONE);
+		CASE_FILTER_EVENT(EXIT);
+		CASE_FILTER_EVENT(EXEC);
+
+			/* Never reached.  */
+			assert(0);
+
+		case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
+		case SIGTRAP | PTRACE_EVENT_SECCOMP << 8:
+			/* These events are not supported [yet?] under
+			 * ptrace emulation.  */
+			return false;
+
+		default:
+			PTRACEE.tracing_started = true;
+			break;
+		}
+	}
+	/* In these cases, the ptracee isn't really alive anymore.  To
+	 * ensure it will not be in limbo, PRoot restarts it whether
+	 * its ptracer is waiting for it or not.  */
+	else if (WIFEXITED(event) || WIFSIGNALED(event)) {
+		PTRACEE.tracing_started = true;
+		keep_stopped = false;
+	}
+
+	/* A process is not traced right from the TRACEME request; it
+	 * is traced from the first received signal, whether it was
+	 * raised by the process itself (implicitly or explicitly), or
+	 * it was induced by a PTRACE_EVENT_*.  */
+	if (!PTRACEE.tracing_started)
+		return false;
+
+	/* Under some circumstances, the event must be handled by
+	 * PRoot first.  */
+	if (handled_by_proot_first) {
+		int signal;
+		signal = handle_tracee_event(ptracee, PTRACEE.event4.proot.value);
+		PTRACEE.event4.proot.value = signal;
+
+		/* The computed signal is always 0 since we can come
+		 * in this block only on sysexit and special events
+		 * (as for now).  */
+		assert(signal == 0);
+	}
+
+	/* Remember what the new event is, this will be required by
+	   the ptracer in translate_ptrace_exit() in order to restart
+	   this ptracee.  */
+	PTRACEE.event4.ptracer.value   = event;
+	PTRACEE.event4.ptracer.pending = true;
+
+	/* Notify asynchronously the ptracer about this event, as the
+	 * kernel does.  */
+	kill(ptracer->pid, SIGCHLD);
+
+	/* Note: wait_pid is set in translate_wait_exit() if no
+	 * ptracee event was pending when the ptracer started to
+	 * wait.  */
+	if (   (PTRACER.wait_pid == -1 || PTRACER.wait_pid == ptracee->pid)
+	    && EXPECTED_WAIT_CLONE(PTRACER.wait_options, ptracee)) {
+		bool restarted;
+		int status;
+
+		status = update_wait_status(ptracer, ptracee);
+		if (status == 0)
+			chain_next_syscall(ptracer);
+		else
+			poke_reg(ptracer, SYSARG_RESULT, (word_t) status);
+
+		/* Write ptracer's register cache back.  */
+		(void) push_regs(ptracer);
+
+		/* Restart the ptracer.  */
+		PTRACER.wait_pid = 0;
+		restarted = restart_tracee(ptracer, 0);
+		if (!restarted)
+			keep_stopped = false;
+
+		return keep_stopped;
+	}
+
+	return keep_stopped;
+}
diff --git a/5.1.0/src/ptrace/wait.h b/5.1.0/src/ptrace/wait.h
new file mode 100644
index 0000000..7f94303
--- /dev/null
+++ b/5.1.0/src/ptrace/wait.h
@@ -0,0 +1,47 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef PTRACE_WAIT_H
+#define PTRACE_WAIT_H
+
+#include "tracee/tracee.h"
+
+extern int translate_wait_enter(Tracee *ptracer);
+extern int translate_wait_exit(Tracee *ptracer);
+extern bool handle_ptracee_event(Tracee *ptracee, int wait_status);
+
+/* __WCLONE: Wait for "clone" children only.  If omitted then wait for
+ * "non-clone" children only.  (A "clone" child is one which delivers
+ * no signal, or a signal other than SIGCHLD to its parent upon
+ * termination.)  This option is ignored if __WALL is also specified.
+ *
+ * __WALL: Wait for all children, regardless of type ("clone" or
+ * "non-clone").
+ *
+ * -- wait(2) man-page
+ */
+#define EXPECTED_WAIT_CLONE(wait_options, tracee)		\
+	((((wait_options) & __WALL) != 0)			\
+      || ((((wait_options) & __WCLONE) != 0) && (tracee)->clone) \
+      || ((((wait_options) & __WCLONE) == 0) && !(tracee)->clone))
+
+#endif /* PTRACE_WAIT_H */
diff --git a/5.1.0/src/syscall/chain.c b/5.1.0/src/syscall/chain.c
new file mode 100644
index 0000000..b2d28bc
--- /dev/null
+++ b/5.1.0/src/syscall/chain.c
@@ -0,0 +1,156 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <talloc.h>     /* talloc*, */
+#include <sys/queue.h>  /* STAILQ_*, */
+#include <errno.h>      /* E*, */
+#include <assert.h>     /* assert(3), */
+
+#include "syscall/chain.h"
+#include "syscall/sysnum.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "arch.h"
+
+struct chained_syscall {
+	Sysnum sysnum;
+	word_t sysargs[6];
+	STAILQ_ENTRY(chained_syscall) link;
+};
+
+STAILQ_HEAD(chained_syscalls, chained_syscall);
+
+/**
+ * Append a new syscall (@sysnum, @sysarg_*) to the list of
+ * "unrequested" syscalls for the given @tracee.  These new syscalls
+ * will be triggered in order once the current syscall is done.  The
+ * caller is free to force the last result of this syscall chain in
+ * @tracee->chain.final_result.  This function returns -errno if an
+ * error occurred, otherwise 0.
+ */
+int register_chained_syscall(Tracee *tracee, Sysnum sysnum,
+			word_t sysarg_1, word_t sysarg_2, word_t sysarg_3,
+			word_t sysarg_4, word_t sysarg_5, word_t sysarg_6)
+{
+	struct chained_syscall *syscall;
+
+	if (tracee->chain.syscalls == NULL) {
+		tracee->chain.syscalls = talloc_zero(tracee, struct chained_syscalls);
+		if (tracee->chain.syscalls == NULL)
+			return -ENOMEM;
+
+		STAILQ_INIT(tracee->chain.syscalls);
+	}
+
+	syscall = talloc_zero(tracee->chain.syscalls, struct chained_syscall);
+	if (syscall == NULL)
+		return -ENOMEM;
+
+	syscall->sysnum     = sysnum;
+	syscall->sysargs[0] = sysarg_1;
+	syscall->sysargs[1] = sysarg_2;
+	syscall->sysargs[2] = sysarg_3;
+	syscall->sysargs[3] = sysarg_4;
+	syscall->sysargs[4] = sysarg_5;
+	syscall->sysargs[5] = sysarg_6;
+
+	STAILQ_INSERT_TAIL(tracee->chain.syscalls, syscall, link);
+
+	return 0;
+}
+
+/**
+ * Use/remove the first element of @tracee->chain.syscalls to forge a
+ * new syscall.  This function should be called only at the end of in
+ * the sysexit stage.
+ */
+void chain_next_syscall(Tracee *tracee)
+{
+	struct chained_syscall *syscall;
+	word_t instr_pointer;
+	word_t sysnum;
+
+	assert(tracee->chain.syscalls != NULL);
+
+	/* No more chained syscalls: force the result of the initial
+	 * syscall (the one explicitly requested by the tracee).  */
+	if (STAILQ_EMPTY(tracee->chain.syscalls)) {
+		TALLOC_FREE(tracee->chain.syscalls);
+
+		if (tracee->chain.force_final_result)
+			poke_reg(tracee, SYSARG_RESULT, tracee->chain.final_result);
+
+		tracee->chain.force_final_result = false;
+		tracee->chain.final_result = 0;
+
+		return;
+	}
+
+	/* Original register values will be restored right after the
+	 * last chained syscall.  */
+	tracee->restore_original_regs = false;
+
+	/* The list of chained syscalls is a FIFO.  */
+	syscall = STAILQ_FIRST(tracee->chain.syscalls);
+	STAILQ_REMOVE_HEAD(tracee->chain.syscalls, link);
+
+	poke_reg(tracee, SYSARG_1, syscall->sysargs[0]);
+	poke_reg(tracee, SYSARG_2, syscall->sysargs[1]);
+	poke_reg(tracee, SYSARG_3, syscall->sysargs[2]);
+	poke_reg(tracee, SYSARG_4, syscall->sysargs[3]);
+	poke_reg(tracee, SYSARG_5, syscall->sysargs[4]);
+	poke_reg(tracee, SYSARG_6, syscall->sysargs[5]);
+
+	sysnum = detranslate_sysnum(get_abi(tracee), syscall->sysnum);
+	poke_reg(tracee, SYSTRAP_NUM, sysnum);
+
+	/* Move the instruction pointer back to the original trap.  */
+	instr_pointer = peek_reg(tracee, CURRENT, INSTR_POINTER);
+	poke_reg(tracee, INSTR_POINTER, instr_pointer - SYSTRAP_SIZE);
+}
+
+/**
+ * Force the last result of the @tracee's current syscall chain to be
+ * @forced_result.
+ */
+void force_chain_final_result(Tracee *tracee, word_t forced_result)
+{
+	tracee->chain.force_final_result = true;
+	tracee->chain.final_result = forced_result;
+}
+
+/**
+ * Restart the original syscall of the given @tracee.  The result of
+ * the current syscall will be overwritten.  This function returns the
+ * same status as register_chained_syscall().
+ */
+int restart_original_syscall(Tracee *tracee)
+{
+	return register_chained_syscall(tracee,
+					get_sysnum(tracee, ORIGINAL),
+					peek_reg(tracee, ORIGINAL, SYSARG_1),
+					peek_reg(tracee, ORIGINAL, SYSARG_2),
+					peek_reg(tracee, ORIGINAL, SYSARG_3),
+					peek_reg(tracee, ORIGINAL, SYSARG_4),
+					peek_reg(tracee, ORIGINAL, SYSARG_5),
+					peek_reg(tracee, ORIGINAL, SYSARG_6));
+}
diff --git a/5.1.0/src/syscall/chain.h b/5.1.0/src/syscall/chain.h
new file mode 100644
index 0000000..7c4f056
--- /dev/null
+++ b/5.1.0/src/syscall/chain.h
@@ -0,0 +1,41 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef CHAIN_H
+#define CHAIN_H
+
+#include "tracee/tracee.h"
+#include "syscall/sysnum.h"
+#include "arch.h"
+
+extern int register_chained_syscall(Tracee *tracee, Sysnum sysnum,
+			word_t sysarg_1, word_t sysarg_2, word_t sysarg_3,
+			word_t sysarg_4, word_t sysarg_5, word_t sysarg_6);
+
+extern void force_chain_final_result(Tracee *tracee, word_t forced_result);
+
+extern int restart_original_syscall(Tracee *tracee);
+
+extern void chain_next_syscall(Tracee *tracee);
+
+
+#endif /* CHAIN_H */
diff --git a/5.1.0/src/syscall/enter.c b/5.1.0/src/syscall/enter.c
new file mode 100644
index 0000000..2c5ad92
--- /dev/null
+++ b/5.1.0/src/syscall/enter.c
@@ -0,0 +1,576 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <errno.h>       /* errno(3), E* */
+#include <talloc.h>      /* talloc_*, */
+#include <sys/un.h>      /* struct sockaddr_un, */
+#include <linux/net.h>   /* SYS_*, */
+#include <fcntl.h>       /* AT_FDCWD, */
+#include <limits.h>      /* PATH_MAX, */
+
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "syscall/socket.h"
+#include "ptrace/ptrace.h"
+#include "ptrace/wait.h"
+#include "syscall/heap.h"
+#include "extension/extension.h"
+#include "execve/execve.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+#include "tracee/abi.h"
+#include "path/path.h"
+#include "path/canon.h"
+#include "arch.h"
+
+/**
+ * Translate @path and put the result in the @tracee's memory address
+ * space pointed to by the @reg argument of the current syscall. See
+ * the documentation of translate_path() about the meaning of
+ * @type. This function returns -errno if an error occured, otherwise
+ * 0.
+ */
+static int translate_path2(Tracee *tracee, int dir_fd, char path[PATH_MAX], Reg reg, Type type)
+{
+	char new_path[PATH_MAX];
+	int status;
+
+	/* Special case where the argument was NULL. */
+	if (path[0] == '\0')
+		return 0;
+
+	/* Translate the original path. */
+	status = translate_path(tracee, new_path, dir_fd, path, type != SYMLINK);
+	if (status < 0)
+		return status;
+
+	return set_sysarg_path(tracee, new_path, reg);
+}
+
+/**
+ * A helper, see the comment of the function above.
+ */
+static int translate_sysarg(Tracee *tracee, Reg reg, Type type)
+{
+	char old_path[PATH_MAX];
+	int status;
+
+	/* Extract the original path. */
+	status = get_sysarg_path(tracee, old_path, reg);
+	if (status < 0)
+		return status;
+
+	return translate_path2(tracee, AT_FDCWD, old_path, reg, type);
+}
+
+/**
+ * Translate the input arguments of the current @tracee's syscall in the
+ * @tracee->pid process area. This function sets @tracee->status to
+ * -errno if an error occured from the tracee's point-of-view (EFAULT
+ * for instance), otherwise 0.
+ */
+int translate_syscall_enter(Tracee *tracee)
+{
+	int flags;
+	int dirfd;
+	int olddirfd;
+	int newdirfd;
+
+	int status;
+	int status2;
+
+	char path[PATH_MAX];
+	char oldpath[PATH_MAX];
+	char newpath[PATH_MAX];
+
+	word_t syscall_number;
+	bool special = false;
+
+	status = notify_extensions(tracee, SYSCALL_ENTER_START, 0, 0);
+	if (status < 0)
+		goto end;
+	if (status > 0)
+		return 0;
+
+	/* Translate input arguments. */
+	syscall_number = get_sysnum(tracee, ORIGINAL);
+	switch (syscall_number) {
+	default:
+		/* Nothing to do. */
+		status = 0;
+		break;
+
+	case PR_execve:
+		status = translate_execve_enter(tracee);
+		break;
+
+	case PR_ptrace:
+		status = translate_ptrace_enter(tracee);
+		break;
+
+	case PR_wait4:
+	case PR_waitpid:
+		status = translate_wait_enter(tracee);
+		break;
+
+	case PR_brk:
+		status = translate_brk_enter(tracee);
+		break;
+
+	case PR_getcwd:
+		set_sysnum(tracee, PR_void);
+		status = 0;
+		break;
+
+	case PR_fchdir:
+	case PR_chdir: {
+		struct stat statl;
+		char *tmp;
+
+		/* The ending "." ensures an error will be reported if
+		 * path does not exist or if it is not a directory.  */
+		if (syscall_number == PR_chdir) {
+			status = get_sysarg_path(tracee, path, SYSARG_1);
+			if (status < 0)
+				break;
+
+			status = join_paths(2, oldpath, path, ".");
+			if (status < 0)
+				break;
+
+			dirfd = AT_FDCWD;
+		}
+		else {
+			strcpy(oldpath, ".");
+			dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		}
+
+		status = translate_path(tracee, path, dirfd, oldpath, true);
+		if (status < 0)
+			break;
+
+		status = lstat(path, &statl);
+		if (status < 0)
+			break;
+
+		/* Check this directory is accessible.  */
+		if ((statl.st_mode & S_IXUSR) == 0)
+			return -EACCES;
+
+		/* Sadly this method doesn't detranslate statefully,
+		 * this means that there's an ambiguity when several
+		 * bindings are from the same host path:
+		 *
+		 *    $ proot -m /tmp:/a -m /tmp:/b fchdir_getcwd /a
+		 *    /b
+		 *
+		 *    $ proot -m /tmp:/b -m /tmp:/a fchdir_getcwd /a
+		 *    /a
+		 *
+		 * A solution would be to follow each file descriptor
+		 * just like it is done for cwd.
+		 */
+
+		status = detranslate_path(tracee, path, NULL);
+		if (status < 0)
+			break;
+
+		/* Remove the trailing "/" or "/.".  */
+		chop_finality(path);
+
+		tmp = talloc_strdup(tracee->fs, path);
+		if (tmp == NULL) {
+			status = -ENOMEM;
+			break;
+		}
+		TALLOC_FREE(tracee->fs->cwd);
+
+		tracee->fs->cwd = tmp;
+		talloc_set_name_const(tracee->fs->cwd, "$cwd");
+
+		set_sysnum(tracee, PR_void);
+		status = 0;
+		break;
+	}
+
+	case PR_bind:
+	case PR_connect: {
+		word_t address;
+		word_t size;
+
+		address = peek_reg(tracee, CURRENT, SYSARG_2);
+		size    = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		status = translate_socketcall_enter(tracee, &address, size);
+		if (status <= 0)
+			break;
+
+		poke_reg(tracee, SYSARG_2, address);
+		poke_reg(tracee, SYSARG_3, sizeof(struct sockaddr_un));
+
+		status = 0;
+		break;
+	}
+
+#define SYSARG_ADDR(n) (args_addr + ((n) - 1) * sizeof_word(tracee))
+
+#define PEEK_WORD(addr, forced_errno)		\
+	peek_word(tracee, addr);		\
+	if (errno != 0) {			\
+		status = forced_errno ?: -errno; \
+		break;				\
+	}
+
+#define POKE_WORD(addr, value)			\
+	poke_word(tracee, addr, value);		\
+	if (errno != 0) {			\
+		status = -errno;		\
+		break;				\
+	}
+
+	case PR_accept:
+	case PR_accept4:
+		/* Nothing special to do if no sockaddr was specified.  */
+		if (peek_reg(tracee, ORIGINAL, SYSARG_2) == 0) {
+			status = 0;
+			break;
+		}
+		special = true;
+		/* Fall through.  */
+	case PR_getsockname:
+	case PR_getpeername:{
+		int size;
+
+		/* Remember: PEEK_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		size = (int) PEEK_WORD(peek_reg(tracee, ORIGINAL, SYSARG_3), special ? -EINVAL : 0);
+
+		/* The "size" argument is both used as an input parameter
+		 * (max. size) and as an output parameter (actual size).  The
+		 * exit stage needs to know the max. size to not overwrite
+		 * anything, that's why it is copied in the 6th argument
+		 * (unused) before the kernel updates it.  */
+		poke_reg(tracee, SYSARG_6, size);
+
+		status = 0;
+		break;
+	}
+
+	case PR_socketcall: {
+		word_t args_addr;
+		word_t sock_addr_saved;
+		word_t sock_addr;
+		word_t size_addr;
+		word_t size;
+
+		args_addr = peek_reg(tracee, CURRENT, SYSARG_2);
+
+		switch (peek_reg(tracee, CURRENT, SYSARG_1)) {
+		case SYS_BIND:
+		case SYS_CONNECT:
+			/* Handle these cases below.  */
+			status = 1;
+			break;
+
+		case SYS_ACCEPT:
+		case SYS_ACCEPT4:
+			/* Nothing special to do if no sockaddr was specified.  */
+			sock_addr = PEEK_WORD(SYSARG_ADDR(2), 0);
+			if (sock_addr == 0) {
+				status = 0;
+				break;
+			}
+			special = true;
+			/* Fall through.  */
+		case SYS_GETSOCKNAME:
+		case SYS_GETPEERNAME:
+			/* Remember: PEEK_WORD puts -errno in status and breaks
+			 * if an error occured.  */
+			size_addr =  PEEK_WORD(SYSARG_ADDR(3), 0);
+			size = (int) PEEK_WORD(size_addr, special ? -EINVAL : 0);
+
+			/* See case PR_accept for explanation.  */
+			poke_reg(tracee, SYSARG_6, size);
+			status = 0;
+			break;
+
+		default:
+			status = 0;
+			break;
+		}
+
+		/* An error occured or there's nothing else to do.  */
+		if (status <= 0)
+			break;
+
+		/* Remember: PEEK_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		sock_addr = PEEK_WORD(SYSARG_ADDR(2), 0);
+		size      = PEEK_WORD(SYSARG_ADDR(3), 0);
+
+		sock_addr_saved = sock_addr;
+		status = translate_socketcall_enter(tracee, &sock_addr, size);
+		if (status <= 0)
+			break;
+
+		/* These parameters are used/restored at the exit stage.  */
+		poke_reg(tracee, SYSARG_5, sock_addr_saved);
+		poke_reg(tracee, SYSARG_6, size);
+
+		/* Remember: POKE_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		POKE_WORD(SYSARG_ADDR(2), sock_addr);
+		POKE_WORD(SYSARG_ADDR(3), sizeof(struct sockaddr_un));
+
+		status = 0;
+		break;
+	}
+
+#undef SYSARG_ADDR
+#undef PEEK_WORD
+#undef POKE_WORD
+
+	case PR_access:
+	case PR_acct:
+	case PR_chmod:
+	case PR_chown:
+	case PR_chown32:
+	case PR_chroot:
+	case PR_getxattr:
+	case PR_listxattr:
+	case PR_mknod:
+	case PR_oldstat:
+	case PR_creat:
+	case PR_removexattr:
+	case PR_setxattr:
+	case PR_stat:
+	case PR_stat64:
+	case PR_statfs:
+	case PR_statfs64:
+	case PR_swapoff:
+	case PR_swapon:
+	case PR_truncate:
+	case PR_truncate64:
+	case PR_umount:
+	case PR_umount2:
+	case PR_uselib:
+	case PR_utime:
+	case PR_utimes:
+		status = translate_sysarg(tracee, SYSARG_1, REGULAR);
+		break;
+
+	case PR_open:
+		flags = peek_reg(tracee, CURRENT, SYSARG_2);
+
+		if (   ((flags & O_NOFOLLOW) != 0)
+		    || ((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0))
+			status = translate_sysarg(tracee, SYSARG_1, SYMLINK);
+		else
+			status = translate_sysarg(tracee, SYSARG_1, REGULAR);
+		break;
+
+	case PR_fchownat:
+	case PR_fstatat64:
+	case PR_newfstatat:
+	case PR_utimensat:
+	case PR_name_to_handle_at:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		flags = (  syscall_number == PR_fchownat
+			|| syscall_number == PR_name_to_handle_at)
+			? peek_reg(tracee, CURRENT, SYSARG_5)
+			: peek_reg(tracee, CURRENT, SYSARG_4);
+
+		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, SYMLINK);
+		else
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, REGULAR);
+		break;
+
+	case PR_fchmodat:
+	case PR_faccessat:
+	case PR_futimesat:
+	case PR_mknodat:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, dirfd, path, SYSARG_2, REGULAR);
+		break;
+
+	case PR_inotify_add_watch:
+		flags = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		if ((flags & IN_DONT_FOLLOW) != 0)
+			status = translate_sysarg(tracee, SYSARG_2, SYMLINK);
+		else
+			status = translate_sysarg(tracee, SYSARG_2, REGULAR);
+		break;
+
+	case PR_readlink:
+	case PR_lchown:
+	case PR_lchown32:
+	case PR_lgetxattr:
+	case PR_llistxattr:
+	case PR_lremovexattr:
+	case PR_lsetxattr:
+	case PR_lstat:
+	case PR_lstat64:
+	case PR_oldlstat:
+	case PR_unlink:
+	case PR_rmdir:
+	case PR_mkdir:
+		status = translate_sysarg(tracee, SYSARG_1, SYMLINK);
+		break;
+
+	case PR_pivot_root:
+		status = translate_sysarg(tracee, SYSARG_1, REGULAR);
+		if (status < 0)
+			break;
+
+		status = translate_sysarg(tracee, SYSARG_2, REGULAR);
+		break;
+
+	case PR_linkat:
+		olddirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		newdirfd = peek_reg(tracee, CURRENT, SYSARG_3);
+		flags    = peek_reg(tracee, CURRENT, SYSARG_5);
+
+		status = get_sysarg_path(tracee, oldpath, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = get_sysarg_path(tracee, newpath, SYSARG_4);
+		if (status < 0)
+			break;
+
+		if ((flags & AT_SYMLINK_FOLLOW) != 0)
+			status = translate_path2(tracee, olddirfd, oldpath, SYSARG_2, REGULAR);
+		else
+			status = translate_path2(tracee, olddirfd, oldpath, SYSARG_2, SYMLINK);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, newdirfd, newpath, SYSARG_4, SYMLINK);
+		break;
+
+	case PR_mount:
+		status = get_sysarg_path(tracee, path, SYSARG_1);
+		if (status < 0)
+			break;
+
+		/* The following check covers only 90% of the cases. */
+		if (path[0] == '/' || path[0] == '.') {
+			status = translate_path2(tracee, AT_FDCWD, path, SYSARG_1, REGULAR);
+			if (status < 0)
+				break;
+		}
+
+		status = translate_sysarg(tracee, SYSARG_2, REGULAR);
+		break;
+
+	case PR_openat:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		flags = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		if (   ((flags & O_NOFOLLOW) != 0)
+			|| ((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0))
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, SYMLINK);
+		else
+			status = translate_path2(tracee, dirfd, path, SYSARG_2, REGULAR);
+		break;
+
+	case PR_readlinkat:
+	case PR_unlinkat:
+	case PR_mkdirat:
+		dirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+
+		status = get_sysarg_path(tracee, path, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, dirfd, path, SYSARG_2, SYMLINK);
+		break;
+
+	case PR_link:
+	case PR_rename:
+		status = translate_sysarg(tracee, SYSARG_1, SYMLINK);
+		if (status < 0)
+			break;
+
+		status = translate_sysarg(tracee, SYSARG_2, SYMLINK);
+		break;
+
+	case PR_renameat:
+	case PR_renameat2:
+		olddirfd = peek_reg(tracee, CURRENT, SYSARG_1);
+		newdirfd = peek_reg(tracee, CURRENT, SYSARG_3);
+
+		status = get_sysarg_path(tracee, oldpath, SYSARG_2);
+		if (status < 0)
+			break;
+
+		status = get_sysarg_path(tracee, newpath, SYSARG_4);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, olddirfd, oldpath, SYSARG_2, SYMLINK);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, newdirfd, newpath, SYSARG_4, SYMLINK);
+		break;
+
+	case PR_symlink:
+		status = translate_sysarg(tracee, SYSARG_2, SYMLINK);
+		break;
+
+	case PR_symlinkat:
+		newdirfd = peek_reg(tracee, CURRENT, SYSARG_2);
+
+		status = get_sysarg_path(tracee, newpath, SYSARG_3);
+		if (status < 0)
+			break;
+
+		status = translate_path2(tracee, newdirfd, newpath, SYSARG_3, SYMLINK);
+		break;
+	}
+
+end:
+	status2 = notify_extensions(tracee, SYSCALL_ENTER_END, status, 0);
+	if (status2 < 0)
+		status = status2;
+
+	return status;
+}
+
diff --git a/5.1.0/src/syscall/exit.c b/5.1.0/src/syscall/exit.c
new file mode 100644
index 0000000..81937bd
--- /dev/null
+++ b/5.1.0/src/syscall/exit.c
@@ -0,0 +1,455 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <errno.h>       /* errno(3), E* */
+#include <sys/utsname.h> /* struct utsname, */
+#include <linux/net.h>   /* SYS_*, */
+#include <string.h>      /* strlen(3), */
+
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "syscall/socket.h"
+#include "syscall/chain.h"
+#include "syscall/heap.h"
+#include "execve/execve.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+#include "tracee/abi.h"
+#include "path/path.h"
+#include "ptrace/ptrace.h"
+#include "ptrace/wait.h"
+#include "extension/extension.h"
+#include "arch.h"
+
+/**
+ * Translate the output arguments of the current @tracee's syscall in
+ * the @tracee->pid process area. This function sets the result of
+ * this syscall to @tracee->status if an error occured previously
+ * during the translation, that is, if @tracee->status is less than 0.
+ */
+void translate_syscall_exit(Tracee *tracee)
+{
+	word_t syscall_number;
+	word_t syscall_result;
+	int status;
+
+	status = notify_extensions(tracee, SYSCALL_EXIT_START, 0, 0);
+	if (status < 0) {
+		poke_reg(tracee, SYSARG_RESULT, (word_t) status);
+		goto end;
+	}
+	if (status > 0)
+		return;
+
+	/* Set the tracee's errno if an error occured previously during
+	 * the translation. */
+	if (tracee->status < 0) {
+		poke_reg(tracee, SYSARG_RESULT, (word_t) tracee->status);
+		goto end;
+	}
+
+	/* Translate output arguments:
+	 * - break: update the syscall result register with "status"
+	 * - goto end: nothing else to do.
+	 */
+	syscall_number = get_sysnum(tracee, ORIGINAL);
+	syscall_result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+	switch (syscall_number) {
+	case PR_brk:
+		translate_brk_exit(tracee);
+		goto end;
+
+	case PR_getcwd: {
+		char path[PATH_MAX];
+		size_t new_size;
+		size_t size;
+		word_t output;
+
+		size = (size_t) peek_reg(tracee, ORIGINAL, SYSARG_2);
+		if (size == 0) {
+			status = -EINVAL;
+			break;
+		}
+
+		/* Ensure cwd still exists.  */
+		status = translate_path(tracee, path, AT_FDCWD, ".", false);
+		if (status < 0)
+			break;
+
+		new_size = strlen(tracee->fs->cwd) + 1;
+		if (size < new_size) {
+			status = -ERANGE;
+			break;
+		}
+
+		/* Overwrite the path.  */
+		output = peek_reg(tracee, ORIGINAL, SYSARG_1);
+		status = write_data(tracee, output, tracee->fs->cwd, new_size);
+		if (status < 0)
+			break;
+
+		/* The value of "status" is used to update the returned value
+		 * in translate_syscall_exit().  */
+		status = new_size;
+		break;
+	}
+
+	case PR_accept:
+	case PR_accept4:
+		/* Nothing special to do if no sockaddr was specified.  */
+		if (peek_reg(tracee, ORIGINAL, SYSARG_2) == 0)
+			goto end;
+		/* Fall through.  */
+	case PR_getsockname:
+	case PR_getpeername: {
+		word_t sock_addr;
+		word_t size_addr;
+		word_t max_size;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		sock_addr = peek_reg(tracee, ORIGINAL, SYSARG_2);
+		size_addr = peek_reg(tracee, MODIFIED, SYSARG_3);
+		max_size  = peek_reg(tracee, MODIFIED, SYSARG_6);
+
+		status = translate_socketcall_exit(tracee, sock_addr, size_addr, max_size);
+		if (status < 0)
+			break;
+
+		/* Don't overwrite the syscall result.  */
+		goto end;
+	}
+
+#define SYSARG_ADDR(n) (args_addr + ((n) - 1) * sizeof_word(tracee))
+
+#define POKE_WORD(addr, value)			\
+	poke_word(tracee, addr, value);		\
+	if (errno != 0)	{			\
+		status = -errno;		\
+		break;				\
+	}
+
+#define PEEK_WORD(addr)				\
+	peek_word(tracee, addr);		\
+	if (errno != 0) {			\
+		status = -errno;		\
+		break;				\
+	}
+
+	case PR_socketcall: {
+		word_t args_addr;
+		word_t sock_addr;
+		word_t size_addr;
+		word_t max_size;
+
+		args_addr = peek_reg(tracee, ORIGINAL, SYSARG_2);
+
+		switch (peek_reg(tracee, ORIGINAL, SYSARG_1)) {
+		case SYS_ACCEPT:
+		case SYS_ACCEPT4:
+			/* Nothing special to do if no sockaddr was specified.  */
+			sock_addr = PEEK_WORD(SYSARG_ADDR(2));
+			if (sock_addr == 0)
+				goto end;
+			/* Fall through.  */
+		case SYS_GETSOCKNAME:
+		case SYS_GETPEERNAME:
+			/* Handle these cases below.  */
+			status = 1;
+			break;
+
+		case SYS_BIND:
+		case SYS_CONNECT:
+			/* Restore the initial parameters: this memory was
+			 * overwritten at the enter stage.  Remember: POKE_WORD
+			 * puts -errno in status and breaks if an error
+			 * occured.  */
+			POKE_WORD(SYSARG_ADDR(2), peek_reg(tracee, MODIFIED, SYSARG_5));
+			POKE_WORD(SYSARG_ADDR(3), peek_reg(tracee, MODIFIED, SYSARG_6));
+
+			status = 0;
+			break;
+
+		default:
+			status = 0;
+			break;
+		}
+
+		/* Error reported by the kernel or there's nothing else to do.  */
+		if ((int) syscall_result < 0 || status == 0)
+			goto end;
+
+		/* An error occured in SYS_BIND or SYS_CONNECT.  */
+		if (status < 0)
+			break;
+
+		/* Remember: PEEK_WORD puts -errno in status and breaks if an
+		 * error occured.  */
+		sock_addr = PEEK_WORD(SYSARG_ADDR(2));
+		size_addr = PEEK_WORD(SYSARG_ADDR(3));
+		max_size  = peek_reg(tracee, MODIFIED, SYSARG_6);
+
+		status = translate_socketcall_exit(tracee, sock_addr, size_addr, max_size);
+		if (status < 0)
+			break;
+
+		/* Don't overwrite the syscall result.  */
+		goto end;
+	}
+
+#undef SYSARG_ADDR
+#undef PEEK_WORD
+#undef POKE_WORD
+
+	case PR_fchdir:
+	case PR_chdir:
+		/* These syscalls are fully emulated, see enter.c for details
+		 * (like errors).  */
+		status = 0;
+		break;
+
+	case PR_rename:
+	case PR_renameat:
+	case PR_renameat2: {
+		char old_path[PATH_MAX];
+		char new_path[PATH_MAX];
+		ssize_t old_length;
+		ssize_t new_length;
+		Comparison comparison;
+		Reg old_reg;
+		Reg new_reg;
+		char *tmp;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		if (syscall_number == PR_rename) {
+			old_reg = SYSARG_1;
+			new_reg = SYSARG_2;
+		}
+		else {
+			old_reg = SYSARG_2;
+			new_reg = SYSARG_4;
+		}
+
+		/* Get the old path, then convert it to the same
+		 * "point-of-view" as tracee->fs->cwd (guest).  */
+		status = read_path(tracee, old_path, peek_reg(tracee, MODIFIED, old_reg));
+		if (status < 0)
+			break;
+
+		status = detranslate_path(tracee, old_path, NULL);
+		if (status < 0)
+			break;
+		old_length = (status > 0 ? status - 1 : (ssize_t) strlen(old_path));
+
+		/* Nothing special to do if the moved path is not the
+		 * current working directory.  */
+		comparison = compare_paths(old_path, tracee->fs->cwd);
+		if (comparison != PATH1_IS_PREFIX && comparison != PATHS_ARE_EQUAL) {
+			status = 0;
+			break;
+		}
+
+		/* Get the new path, then convert it to the same
+		 * "point-of-view" as tracee->fs->cwd (guest).  */
+		status = read_path(tracee, new_path, peek_reg(tracee, MODIFIED, new_reg));
+		if (status < 0)
+			break;
+
+		status = detranslate_path(tracee, new_path, NULL);
+		if (status < 0)
+			break;
+		new_length = (status > 0 ? status - 1 : (ssize_t) strlen(new_path));
+
+		/* Sanity check.  */
+		if (strlen(tracee->fs->cwd) >= PATH_MAX) {
+			status = 0;
+			break;
+		}
+		strcpy(old_path, tracee->fs->cwd);
+
+		/* Update the virtual current working directory.  */
+		substitute_path_prefix(old_path, old_length, new_path, new_length);
+
+		tmp = talloc_strdup(tracee->fs, old_path);
+		if (tmp == NULL) {
+			status = -ENOMEM;
+			break;
+		}
+
+		TALLOC_FREE(tracee->fs->cwd);
+		tracee->fs->cwd = tmp;
+
+		status = 0;
+		break;
+	}
+
+	case PR_readlink:
+	case PR_readlinkat: {
+		char referee[PATH_MAX];
+		char referer[PATH_MAX];
+		size_t old_size;
+		size_t new_size;
+		size_t max_size;
+		word_t input;
+		word_t output;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		old_size = syscall_result;
+
+		if (syscall_number == PR_readlink) {
+			output   = peek_reg(tracee, ORIGINAL, SYSARG_2);
+			max_size = peek_reg(tracee, ORIGINAL, SYSARG_3);
+			input    = peek_reg(tracee, MODIFIED, SYSARG_1);
+		}
+		else {
+			output   = peek_reg(tracee, ORIGINAL,  SYSARG_3);
+			max_size = peek_reg(tracee, ORIGINAL, SYSARG_4);
+			input    = peek_reg(tracee, MODIFIED, SYSARG_2);
+		}
+
+		if (max_size > PATH_MAX)
+			max_size = PATH_MAX;
+
+		if (max_size == 0) {
+			status = -EINVAL;
+			break;
+		}
+
+		/* The kernel does NOT put the NULL terminating byte for
+		 * readlink(2).  */
+		status = read_data(tracee, referee, output, old_size);
+		if (status < 0)
+			break;
+		referee[old_size] = '\0';
+
+		/* Not optimal but safe (path is fully translated).  */
+		status = read_path(tracee, referer, input);
+		if (status < 0)
+			break;
+
+		if (status >= PATH_MAX) {
+			status = -ENAMETOOLONG;
+			break;
+		}
+
+		status = detranslate_path(tracee, referee, referer);
+		if (status < 0)
+			break;
+
+		/* The original path doesn't require any transformation, i.e
+		 * it is a symetric binding.  */
+		if (status == 0)
+			goto end;
+
+		/* Overwrite the path.  Note: the output buffer might be
+		 * initialized with zeros but it was updated with the kernel
+		 * result, and then with the detranslated result.  This later
+		 * might be shorter than the former, so it's safier to add a
+		 * NULL terminating byte when possible.  This problem was
+		 * exposed by IDA Demo 6.3.  */
+		if ((size_t) status < max_size) {
+			new_size = status - 1;
+			status = write_data(tracee, output, referee, status);
+		}
+		else {
+			new_size = max_size;
+			status = write_data(tracee, output, referee, max_size);
+		}
+		if (status < 0)
+			break;
+
+		/* The value of "status" is used to update the returned value
+		 * in translate_syscall_exit().  */
+		status = new_size;
+		break;
+	}
+
+#if defined(ARCH_X86_64)
+	case PR_uname: {
+		struct utsname utsname;
+		word_t address;
+		size_t size;
+
+		if (get_abi(tracee) != ABI_2)
+			goto end;
+
+		/* Error reported by the kernel.  */
+		if ((int) syscall_result < 0)
+			goto end;
+
+		address = peek_reg(tracee, ORIGINAL, SYSARG_1);
+
+		status = read_data(tracee, &utsname, address, sizeof(utsname));
+		if (status < 0)
+			break;
+
+		/* Some 32-bit programs like package managers can be
+		 * confused when the kernel reports "x86_64".  */
+		size = sizeof(utsname.machine);
+		strncpy(utsname.machine, "i686", size);
+		utsname.machine[size - 1] = '\0';
+
+		status = write_data(tracee, address, &utsname, sizeof(utsname));
+		if (status < 0)
+			break;
+
+		status = 0;
+		break;
+	}
+#endif
+
+	case PR_execve:
+		translate_execve_exit(tracee);
+		goto end;
+
+	case PR_ptrace:
+		status = translate_ptrace_exit(tracee);
+		break;
+
+	case PR_wait4:
+	case PR_waitpid:
+		if (tracee->as_ptracer.waits_in != WAITS_IN_PROOT)
+			goto end;
+
+		status = translate_wait_exit(tracee);
+		break;
+
+	default:
+		goto end;
+	}
+
+	poke_reg(tracee, SYSARG_RESULT, (word_t) status);
+
+end:
+	status = notify_extensions(tracee, SYSCALL_EXIT_END, 0, 0);
+	if (status < 0)
+		poke_reg(tracee, SYSARG_RESULT, (word_t) status);
+}
diff --git a/5.1.0/src/syscall/heap.c b/5.1.0/src/syscall/heap.c
new file mode 100644
index 0000000..d96196b
--- /dev/null
+++ b/5.1.0/src/syscall/heap.c
@@ -0,0 +1,226 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/mman.h>	/* PROT_*, MAP_*, */
+#include <assert.h>	/* assert(3),  */
+#include <string.h>     /* strerror(3), */
+#include <unistd.h>     /* sysconf(3), */
+#include <sys/param.h>  /* MIN(), MAX(), */
+
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+#include "syscall/sysnum.h"
+#include "cli/note.h"
+
+#include "compat.h"
+
+#define DEBUG_BRK(...) /* fprintf(stderr, __VA_ARGS__) */
+
+/* The size of the heap can be zero, unlike the size of a memory
+ * mapping.  As a consequence, the first page of the "heap" memory
+ * mapping is discarded in order to emulate an empty heap.  */
+static word_t heap_offset = 0;
+
+#define PREALLOCATED_HEAP_SIZE (16 * 1024 * 1024)
+
+/**
+ * Emulate the brk(2) syscall with mmap(2) and/or mremap(2); this is
+ * required to ensure a minimal heap size [1].  This function always
+ * returns 0.
+ *
+ * [1] With some versions of the Linux kernel and some versions of the
+ *     GNU ELF interpreter (ld.so), the heap can't grow at all because
+ *     the kernel has put a memory mapping right after the heap.  This
+ *     issue can be reproduced when using a Ubuntu 12.04 x86_64 rootfs
+ *     on RHEL 5 x86_64.
+ */
+word_t translate_brk_enter(Tracee *tracee)
+{
+	word_t new_brk_address;
+	size_t old_heap_size;
+	size_t new_heap_size;
+
+	if (tracee->heap->disabled)
+		return 0;
+
+	if (heap_offset == 0) {
+		heap_offset = sysconf(_SC_PAGE_SIZE);
+		if ((int) heap_offset <= 0)
+			heap_offset = 0x1000;
+	}
+
+	/* Non-fixed mmap pages might be placed right after the
+	 * emulated heap on some architectures.  A solution is to
+	 * preallocate some space to ensure a minimal heap size.  */
+	if (tracee->heap->prealloc_size == 0)
+		tracee->heap->prealloc_size = MAX(PREALLOCATED_HEAP_SIZE, heap_offset);
+
+	new_brk_address = peek_reg(tracee, CURRENT, SYSARG_1);
+	DEBUG_BRK("brk(0x%lx)\n", new_brk_address);
+
+	/* Allocate a new mapping for the emulated heap.  */
+	if (tracee->heap->base == 0) {
+		Sysnum sysnum;
+
+		/* From PRoot's point-of-view this is the first time this
+		 * tracee calls brk(2), although an address was specified.
+		 * This is not supposed to happen the first time.  It is
+		 * likely because this tracee is the very first child of PRoot
+		 * but the first execve(2) didn't happen yet (so this is not
+		 * its first call to brk(2)).  For instance, the installation
+		 * of seccomp filters is made after this very first process is
+		 * traced, and might call malloc(3) before the first
+		 * execve(2).  */
+		if (new_brk_address != 0) {
+			if (tracee->verbose > 0)
+				note(tracee, WARNING, INTERNAL,
+					"process %d is doing suspicious brk()",	tracee->pid);
+			return 0;
+		}
+
+		/* I don't understand yet why mmap(2) fails (EFAULT)
+		 * on architectures that also have mmap2(2).  Maybe
+		 * this former implies MAP_FIXED in such cases.  */
+		sysnum = detranslate_sysnum(get_abi(tracee), PR_mmap2) != SYSCALL_AVOIDER
+			? PR_mmap2
+			: PR_mmap;
+
+		set_sysnum(tracee, sysnum);
+		poke_reg(tracee, SYSARG_1 /* address */, 0);
+		poke_reg(tracee, SYSARG_2 /* length  */, heap_offset + tracee->heap->prealloc_size);
+		poke_reg(tracee, SYSARG_3 /* prot    */, PROT_READ | PROT_WRITE);
+		poke_reg(tracee, SYSARG_4 /* flags   */, MAP_PRIVATE | MAP_ANONYMOUS);
+		poke_reg(tracee, SYSARG_5 /* fd      */, -1);
+		poke_reg(tracee, SYSARG_6 /* offset  */, 0);
+
+		return 0;
+	}
+
+	/* The size of the heap can't be negative.  */
+	if (new_brk_address < tracee->heap->base) {
+		set_sysnum(tracee, PR_void);
+		return 0;
+	}
+
+	new_heap_size = new_brk_address - tracee->heap->base;
+	old_heap_size = tracee->heap->size;
+
+	/* Clear the released memory in preallocated space, so it will be
+	 * in the expected state next time it will be reallocated.  */
+	if (new_heap_size < old_heap_size && new_heap_size < tracee->heap->prealloc_size) {
+		(void) clear_mem(tracee,
+				tracee->heap->base + new_heap_size,
+				MIN(old_heap_size, tracee->heap->prealloc_size) - new_heap_size);
+	}
+
+	/* No need to use mremap when both old size and new size are
+	 * in the preallocated space.  */
+	if (   new_heap_size <= tracee->heap->prealloc_size
+	    && old_heap_size <= tracee->heap->prealloc_size) {
+		tracee->heap->size = new_heap_size;
+		set_sysnum(tracee, PR_void);
+		return 0;
+	}
+
+	/* Ensure the preallocated space will never be released.  */
+	new_heap_size = MAX(new_heap_size, tracee->heap->prealloc_size);
+	old_heap_size = MAX(old_heap_size, tracee->heap->prealloc_size);
+
+	/* Actually resizing.  */
+	set_sysnum(tracee, PR_mremap);
+	poke_reg(tracee, SYSARG_1 /* old_address */, tracee->heap->base - heap_offset);
+	poke_reg(tracee, SYSARG_2 /* old_size    */, old_heap_size + heap_offset);
+	poke_reg(tracee, SYSARG_3 /* new_size    */, new_heap_size + heap_offset);
+	poke_reg(tracee, SYSARG_4 /* flags       */, 0);
+	poke_reg(tracee, SYSARG_5 /* new_address */, 0);
+
+	return 0;
+}
+
+/**
+ * c.f. function above.
+ */
+void translate_brk_exit(Tracee *tracee)
+{
+	word_t result;
+	word_t sysnum;
+	int tracee_errno;
+
+	if (tracee->heap->disabled)
+		return;
+
+	assert(heap_offset > 0);
+
+	sysnum = get_sysnum(tracee, MODIFIED);
+	result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
+	tracee_errno = (int) result;
+
+	switch (sysnum) {
+	case PR_void:
+		poke_reg(tracee, SYSARG_RESULT, tracee->heap->base + tracee->heap->size);
+		break;
+
+	case PR_mmap:
+	case PR_mmap2:
+		/* On error, mmap(2) returns -errno (the last 4k is
+		 * reserved for this), whereas brk(2) returns the
+		 * previous value.  */
+		if (tracee_errno < 0 && tracee_errno > -4096) {
+			poke_reg(tracee, SYSARG_RESULT, 0);
+			break;
+		}
+
+		tracee->heap->base = result + heap_offset;
+		tracee->heap->size = 0;
+
+		poke_reg(tracee, SYSARG_RESULT, tracee->heap->base + tracee->heap->size);
+		break;
+
+	case PR_mremap:
+		/* On error, mremap(2) returns -errno (the last 4k is
+		 * reserved this), whereas brk(2) returns the previous
+		 * value.  */
+		if (   (tracee_errno < 0 && tracee_errno > -4096)
+		    || (tracee->heap->base != result + heap_offset)) {
+			poke_reg(tracee, SYSARG_RESULT, tracee->heap->base + tracee->heap->size);
+			break;
+		}
+
+		tracee->heap->size = peek_reg(tracee, MODIFIED, SYSARG_3) - heap_offset;
+
+		poke_reg(tracee, SYSARG_RESULT, tracee->heap->base + tracee->heap->size);
+		break;
+
+	case PR_brk:
+		/* Is it confirmed that this suspicious call to brk(2)
+		 * is actually legit?  */
+		if (result == peek_reg(tracee, ORIGINAL, SYSARG_1))
+			tracee->heap->disabled = true;
+		break;
+
+	default:
+		assert(0);
+	}
+
+	DEBUG_BRK("brk() = 0x%lx\n", peek_reg(tracee, CURRENT, SYSARG_RESULT));
+}
diff --git a/5.1.0/src/syscall/heap.h b/5.1.0/src/syscall/heap.h
new file mode 100644
index 0000000..15230cd
--- /dev/null
+++ b/5.1.0/src/syscall/heap.h
@@ -0,0 +1,42 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef HEAP_H
+#define HEAP_H
+
+#include "tracee/tracee.h"
+
+extern int translate_brk_enter(Tracee *tracee);
+extern void translate_brk_exit(Tracee *tracee);
+
+/**
+ * Check if the @address is in the @tracee's preallocated heap space.
+ * This space is not supposed to be accessible.
+ */
+static inline bool belongs_to_heap_prealloc(const Tracee *tracee, word_t address)
+{
+	return (tracee->heap != NULL && !tracee->heap->disabled
+		&& address >= tracee->heap->base + tracee->heap->size
+		&& address < tracee->heap->base + tracee->heap->prealloc_size);
+}
+
+#endif /* HEAP_H */
diff --git a/5.1.0/src/syscall/seccomp.c b/5.1.0/src/syscall/seccomp.c
new file mode 100644
index 0000000..b548b69
--- /dev/null
+++ b/5.1.0/src/syscall/seccomp.c
@@ -0,0 +1,512 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include "build.h"
+#include "arch.h"
+
+#if defined(HAVE_SECCOMP_FILTER)
+
+#include <sys/prctl.h>     /* prctl(2), PR_* */
+#include <linux/filter.h>  /* struct sock_*, */
+#include <linux/seccomp.h> /* SECCOMP_MODE_FILTER, */
+#include <linux/filter.h>  /* struct sock_*, */
+#include <linux/audit.h>   /* AUDIT_, */
+#include <sys/queue.h>     /* LIST_FOREACH, */
+#include <sys/types.h>     /* size_t, */
+#include <talloc.h>        /* talloc_*, */
+#include <errno.h>         /* E*, */
+#include <string.h>        /* memcpy(3), */
+#include <stddef.h>        /* offsetof(3), */
+#include <stdint.h>        /* uint*_t, UINT*_MAX, */
+#include <assert.h>        /* assert(3), */
+
+#include "syscall/seccomp.h"
+#include "tracee/tracee.h"
+#include "syscall/syscall.h"
+#include "syscall/sysnum.h"
+#include "extension/extension.h"
+#include "cli/note.h"
+
+#include "compat.h"
+#include "attribute.h"
+
+#define DEBUG_FILTER(...) /* fprintf(stderr, __VA_ARGS__) */
+
+/**
+ * Allocate an empty @program->filter.  This function returns -errno
+ * if an error occurred, otherwise 0.
+ */
+static int new_program_filter(struct sock_fprog *program)
+{
+	program->filter = talloc_array(NULL, struct sock_filter, 0);
+	if (program->filter == NULL)
+		return -ENOMEM;
+
+	program->len = 0;
+	return 0;
+}
+
+/**
+ * Append to @program->filter the given @statements (@nb_statements
+ * items).  This function returns -errno if an error occurred,
+ * otherwise 0.
+ */
+static int add_statements(struct sock_fprog *program, size_t nb_statements,
+			struct sock_filter *statements)
+{
+	size_t length;
+	void *tmp;
+	size_t i;
+
+	length = talloc_array_length(program->filter);
+	tmp  = talloc_realloc(NULL, program->filter, struct sock_filter, length + nb_statements);
+	if (tmp == NULL)
+		return -ENOMEM;
+	program->filter = tmp;
+
+	for (i = 0; i < nb_statements; i++, length++)
+		memcpy(&program->filter[length], &statements[i], sizeof(struct sock_filter));
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements required to notify PRoot
+ * about the given @syscall made by a tracee, with the given @flag.
+ * This function returns -errno if an error occurred, otherwise 0.
+ */
+static int add_trace_syscall(struct sock_fprog *program, word_t syscall, int flag)
+{
+	int status;
+
+	/* Sanity check.  */
+	if (syscall > UINT32_MAX)
+		return -ERANGE;
+
+	#define LENGTH_TRACE_SYSCALL 2
+	struct sock_filter statements[LENGTH_TRACE_SYSCALL] = {
+		/* Compare the accumulator with the expected syscall:
+		 * skip the next statement if not equal.  */
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, syscall, 0, 1),
+
+		/* Notify the tracer.  */
+		BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE + flag)
+	};
+
+	DEBUG_FILTER("FILTER:     trace if syscall == %ld\n", syscall);
+
+	status = add_statements(program, LENGTH_TRACE_SYSCALL, statements);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements that allow anything (if
+ * unfiltered).  Note that @nb_traced_syscalls is used to make a
+ * sanity check.  This function returns -errno if an error occurred,
+ * otherwise 0.
+ */
+static int end_arch_section(struct sock_fprog *program, size_t nb_traced_syscalls)
+{
+	int status;
+
+	#define LENGTH_END_SECTION 1
+	struct sock_filter statements[LENGTH_END_SECTION] = {
+		BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW)
+	};
+
+	DEBUG_FILTER("FILTER:     allow\n");
+
+	status = add_statements(program, LENGTH_END_SECTION, statements);
+	if (status < 0)
+		return status;
+
+	/* Sanity check, see start_arch_section().  */
+	if (   talloc_array_length(program->filter) - program->len
+	    != LENGTH_END_SECTION + nb_traced_syscalls * LENGTH_TRACE_SYSCALL)
+		return -ERANGE;
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements that check the current
+ * @architecture.  Note that @nb_traced_syscalls is used to make a
+ * sanity check.  This function returns -errno if an error occurred,
+ * otherwise 0.
+ */
+static int start_arch_section(struct sock_fprog *program, uint32_t arch, size_t nb_traced_syscalls)
+{
+	const size_t arch_offset    = offsetof(struct seccomp_data, arch);
+	const size_t syscall_offset = offsetof(struct seccomp_data, nr);
+	const size_t section_length = LENGTH_END_SECTION +
+					nb_traced_syscalls * LENGTH_TRACE_SYSCALL;
+	int status;
+
+	/* Sanity checks.  */
+	if (   arch_offset    > UINT32_MAX
+	    || syscall_offset > UINT32_MAX
+	    || section_length > UINT32_MAX - 1)
+		return -ERANGE;
+
+	#define LENGTH_START_SECTION 4
+	struct sock_filter statements[LENGTH_START_SECTION] = {
+		/* Load the current architecture into the
+		 * accumulator.  */
+		BPF_STMT(BPF_LD + BPF_W + BPF_ABS, arch_offset),
+
+		/* Compare the accumulator with the expected
+		 * architecture: skip the following statement if
+		 * equal.  */
+		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 1, 0),
+
+		/* This is not the expected architecture, so jump
+		 * unconditionally to the end of this section.  */
+		BPF_STMT(BPF_JMP + BPF_JA + BPF_K, section_length + 1),
+
+		/* This is the expected architecture, so load the
+		 * current syscall into the accumulator.  */
+		BPF_STMT(BPF_LD + BPF_W + BPF_ABS, syscall_offset)
+	};
+
+	DEBUG_FILTER("FILTER: if arch == %ld, up to %zdth statement\n",
+		arch, nb_traced_syscalls);
+
+	status = add_statements(program, LENGTH_START_SECTION, statements);
+	if (status < 0)
+		return status;
+
+	/* See the sanity check in end_arch_section().  */
+	program->len = talloc_array_length(program->filter);
+
+	return 0;
+}
+
+/**
+ * Append to @program->filter the statements that forbid anything (if
+ * unfiltered) and update @program->len.  This function returns -errno
+ * if an error occurred, otherwise 0.
+ */
+static int finalize_program_filter(struct sock_fprog *program)
+{
+	int status;
+
+	#define LENGTH_FINALIZE 1
+	struct sock_filter statements[LENGTH_FINALIZE] = {
+		BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL)
+	};
+
+	DEBUG_FILTER("FILTER: kill\n");
+
+	status = add_statements(program, LENGTH_FINALIZE, statements);
+	if (status < 0)
+		return status;
+
+	program->len = talloc_array_length(program->filter);
+
+	return 0;
+}
+
+/**
+ * Free @program->filter and set @program->len to 0.
+ */
+static void free_program_filter(struct sock_fprog *program)
+{
+	TALLOC_FREE(program->filter);
+	program->len = 0;
+}
+
+/**
+ * Convert the given @sysnums into BPF filters according to the
+ * following pseudo-code, then enabled them for the given @tracee and
+ * all of its future children:
+ *
+ *     for each handled architectures
+ *         for each filtered syscall
+ *             trace
+ *         allow
+ *     kill
+ *
+ * This function returns -errno if an error occurred, otherwise 0.
+ */
+static int set_seccomp_filters(const FilteredSysnum *sysnums)
+{
+	SeccompArch seccomp_archs[] = SECCOMP_ARCHS;
+	size_t nb_archs = sizeof(seccomp_archs) / sizeof(SeccompArch);
+
+	struct sock_fprog program = { .len = 0, .filter = NULL };
+	size_t nb_traced_syscalls;
+	size_t i, j, k;
+	int status;
+
+	status = new_program_filter(&program);
+	if (status < 0)
+		goto end;
+
+	/* For each handled architectures */
+	for (i = 0; i < nb_archs; i++) {
+		word_t syscall;
+
+		nb_traced_syscalls = 0;
+
+		/* Pre-compute the number of traced syscalls for this architecture.  */
+		for (j = 0; j < seccomp_archs[i].nb_abis; j++) {
+			for (k = 0; sysnums[k].value != PR_void; k++) {
+				syscall = detranslate_sysnum(seccomp_archs[i].abis[j], sysnums[k].value);
+				if (syscall != SYSCALL_AVOIDER)
+					nb_traced_syscalls++;
+			}
+		}
+
+		/* Filter: if handled architecture */
+		status = start_arch_section(&program, seccomp_archs[i].value, nb_traced_syscalls);
+		if (status < 0)
+			goto end;
+
+		for (j = 0; j < seccomp_archs[i].nb_abis; j++) {
+			for (k = 0; sysnums[k].value != PR_void; k++) {
+				/* Get the architecture specific syscall number.  */
+				syscall = detranslate_sysnum(seccomp_archs[i].abis[j], sysnums[k].value);
+				if (syscall == SYSCALL_AVOIDER)
+					continue;
+
+				/* Filter: trace if handled syscall */
+				status = add_trace_syscall(&program, syscall, sysnums[k].flags);
+				if (status < 0)
+					goto end;
+			}
+		}
+
+		/* Filter: allow untraced syscalls for this architecture */
+		status = end_arch_section(&program, nb_traced_syscalls);
+		if (status < 0)
+			goto end;
+	}
+
+	status = finalize_program_filter(&program);
+	if (status < 0)
+		goto end;
+
+	status = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+	if (status < 0)
+		goto end;
+
+	/* To output this BPF program for debug purpose:
+	 *
+	 *     write(2, program.filter, program.len * sizeof(struct sock_filter));
+	 */
+
+	status = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &program);
+	if (status < 0)
+		goto end;
+
+	status = 0;
+end:
+	free_program_filter(&program);
+	return status;
+}
+
+/* List of sysnums handled by PRoot.  */
+static FilteredSysnum proot_sysnums[] = {
+	{ PR_accept,		FILTER_SYSEXIT },
+	{ PR_accept4,		FILTER_SYSEXIT },
+	{ PR_access,		0 },
+	{ PR_acct,		0 },
+	{ PR_bind,		0 },
+	{ PR_brk,		FILTER_SYSEXIT },
+	{ PR_chdir,		FILTER_SYSEXIT },
+	{ PR_chmod,		0 },
+	{ PR_chown,		0 },
+	{ PR_chown32,		0 },
+	{ PR_chroot,		0 },
+	{ PR_connect,		0 },
+	{ PR_creat,		0 },
+	{ PR_execve,		FILTER_SYSEXIT },
+	{ PR_faccessat,		0 },
+	{ PR_fchdir,		FILTER_SYSEXIT },
+	{ PR_fchmodat,		0 },
+	{ PR_fchownat,		0 },
+	{ PR_fstatat64,		0 },
+	{ PR_futimesat,		0 },
+	{ PR_getcwd,		FILTER_SYSEXIT },
+	{ PR_getpeername,	FILTER_SYSEXIT },
+	{ PR_getsockname,	FILTER_SYSEXIT },
+	{ PR_getxattr,		0 },
+	{ PR_inotify_add_watch,	0 },
+	{ PR_lchown,		0 },
+	{ PR_lchown32,		0 },
+	{ PR_lgetxattr,		0 },
+	{ PR_link,		0 },
+	{ PR_linkat,		0 },
+	{ PR_listxattr,		0 },
+	{ PR_llistxattr,	0 },
+	{ PR_lremovexattr,	0 },
+	{ PR_lsetxattr,		0 },
+	{ PR_lstat,		0 },
+	{ PR_lstat64,		0 },
+	{ PR_mkdir,		0 },
+	{ PR_mkdirat,		0 },
+	{ PR_mknod,		0 },
+	{ PR_mknodat,		0 },
+	{ PR_mount,		0 },
+	{ PR_name_to_handle_at,	0 },
+	{ PR_newfstatat,	0 },
+	{ PR_oldlstat,		0 },
+	{ PR_oldstat,		0 },
+	{ PR_open,		0 },
+	{ PR_openat,		0 },
+	{ PR_pivot_root,	0 },
+	{ PR_ptrace,		FILTER_SYSEXIT },
+	{ PR_readlink,		FILTER_SYSEXIT },
+	{ PR_readlinkat,	FILTER_SYSEXIT },
+	{ PR_removexattr,	0 },
+	{ PR_rename,		FILTER_SYSEXIT },
+	{ PR_renameat,		FILTER_SYSEXIT },
+	{ PR_renameat2,		FILTER_SYSEXIT },
+	{ PR_rmdir,		0 },
+	{ PR_setxattr,		0 },
+	{ PR_socketcall,	FILTER_SYSEXIT },
+	{ PR_stat,		0 },
+	{ PR_stat64,		0 },
+	{ PR_statfs,		0 },
+	{ PR_statfs64,		0 },
+	{ PR_swapoff,		0 },
+	{ PR_swapon,		0 },
+	{ PR_symlink,		0 },
+	{ PR_symlinkat,		0 },
+	{ PR_truncate,		0 },
+	{ PR_truncate64,	0 },
+	{ PR_umount,		0 },
+	{ PR_umount2,		0 },
+	{ PR_uname,		FILTER_SYSEXIT },
+	{ PR_unlink,		0 },
+	{ PR_unlinkat,		0 },
+	{ PR_uselib,		0 },
+	{ PR_utime,		0 },
+	{ PR_utimensat,		0 },
+	{ PR_utimes,		0 },
+	{ PR_wait4,		FILTER_SYSEXIT },
+	{ PR_waitpid,		FILTER_SYSEXIT },
+	FILTERED_SYSNUM_END,
+};
+
+/**
+ * Add the @new_sysnums to the list of filtered @sysnums, using the
+ * given Talloc @context.  This function returns -errno if an error
+ * occurred, otherwise 0.
+ */
+static int merge_filtered_sysnums(TALLOC_CTX *context, FilteredSysnum **sysnums,
+				const FilteredSysnum *new_sysnums)
+{
+	size_t i, j;
+
+	assert(sysnums != NULL);
+
+	if (*sysnums == NULL) {
+		/* Start with no sysnums but the terminator.  */
+		*sysnums = talloc_array(context, FilteredSysnum, 1);
+		if (*sysnums == NULL)
+			return -ENOMEM;
+
+		(*sysnums)[0].value = PR_void;
+	}
+
+	for (i = 0; new_sysnums[i].value != PR_void; i++) {
+		/* Search for the given sysnum.  */
+		for (j = 0; (*sysnums)[j].value != PR_void
+			 && (*sysnums)[j].value != new_sysnums[i].value; j++)
+			;
+
+		if ((*sysnums)[j].value == PR_void) {
+			/* No such sysnum, allocate a new entry.  */
+			(*sysnums) = talloc_realloc(context, (*sysnums), FilteredSysnum, j + 2);
+			if ((*sysnums) == NULL)
+				return -ENOMEM;
+
+			(*sysnums)[j] = new_sysnums[i];
+
+			/* The last item is the terminator.  */
+			(*sysnums)[j + 1].value = PR_void;
+		}
+		else
+			/* The sysnum is already filtered, merge the
+			 * flags.  */
+			(*sysnums)[j].flags |= new_sysnums[i].flags;
+	}
+
+	return 0;
+}
+
+/**
+ * Tell the kernel to trace only syscalls handled by PRoot and its
+ * extensions.  This filter will be enabled for the given @tracee and
+ * all of its future children.  This function returns -errno if an
+ * error occurred, otherwise 0.
+ */
+int enable_syscall_filtering(const Tracee *tracee)
+{
+	FilteredSysnum *filtered_sysnums = NULL;
+	Extension *extension;
+	int status;
+
+	assert(tracee != NULL && tracee->ctx != NULL);
+
+	/* Add the sysnums required by PRoot to the list of filtered
+	 * sysnums.  TODO: only if path translation is required.  */
+	status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums, proot_sysnums);
+	if (status < 0)
+		return status;
+
+	/* Merge the sysnums required by the extensions to the list
+	 * of filtered sysnums.  */
+	if (tracee->extensions != NULL) {
+		LIST_FOREACH(extension, tracee->extensions, link) {
+			if (extension->filtered_sysnums == NULL)
+				continue;
+
+			status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums,
+							extension->filtered_sysnums);
+			if (status < 0)
+				return status;
+		}
+	}
+
+	status = set_seccomp_filters(filtered_sysnums);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+#else
+
+#include "tracee/tracee.h"
+#include "attribute.h"
+
+int enable_syscall_filtering(const Tracee *tracee UNUSED)
+{
+	return 0;
+}
+
+#endif /* defined(HAVE_SECCOMP_FILTER) */
diff --git a/5.1.0/src/syscall/seccomp.h b/5.1.0/src/syscall/seccomp.h
new file mode 100644
index 0000000..1e8a1e7
--- /dev/null
+++ b/5.1.0/src/syscall/seccomp.h
@@ -0,0 +1,48 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef SECCOMP_H
+#define SECCOMP_H
+
+#include "syscall/sysnum.h"
+#include "tracee/tracee.h"
+#include "attribute.h"
+#include "arch.h"
+
+typedef struct {
+	Sysnum value;
+	word_t flags;
+} FilteredSysnum;
+
+typedef struct {
+	unsigned int value;
+	size_t nb_abis;
+	Abi abis[NB_MAX_ABIS];
+} SeccompArch;
+
+#define FILTERED_SYSNUM_END { PR_void, 0 }
+
+#define FILTER_SYSEXIT  0x1
+
+extern int enable_syscall_filtering(const Tracee *tracee);
+
+#endif /* SECCOMP_H */
diff --git a/5.1.0/src/syscall/socket.c b/5.1.0/src/syscall/socket.c
new file mode 100644
index 0000000..381ae64
--- /dev/null
+++ b/5.1.0/src/syscall/socket.c
@@ -0,0 +1,216 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <stddef.h>      /* offsetof(3), */
+#include <strings.h>     /* bzero(3), */
+#include <string.h>      /* strncpy(3), strlen(3), */
+#include <assert.h>      /* assert(3), */
+#include <errno.h>       /* E*, */
+#include <sys/socket.h>  /* struct sockaddr_un, AF_UNIX, */
+#include <sys/un.h>      /* struct sockaddr_un, */
+#include <sys/param.h>   /* MIN(), MAX(), */
+
+#include "syscall/socket.h"
+#include "tracee/tracee.h"
+#include "tracee/mem.h"
+#include "path/binding.h"
+#include "path/temp.h"
+#include "path/path.h"
+#include "arch.h"
+
+#include "compat.h"
+
+/* The sockaddr_un structure has exactly the same layout on all
+ * architectures.  */
+static const off_t offsetof_path = offsetof(struct sockaddr_un, sun_path);
+extern struct sockaddr_un sockaddr_un__;
+static const size_t sizeof_path  = sizeof(sockaddr_un__.sun_path);
+
+/**
+ * Copy in @sockaddr the struct sockaddr_un stored in the @tracee
+ * memory at the given @address.  Also, its pathname is copied to the
+ * null-terminated @path.  Only @size bytes are read from the @tracee
+ * memory (should be <= @max_size <= sizeof(struct sockaddr_un)).
+ * This function returns -errno if an error occurred, 0 if the
+ * structure was not found (not a sockaddr_un or @size > @max_size),
+ * otherwise 1.
+ */
+static int read_sockaddr_un(Tracee *tracee, struct sockaddr_un *sockaddr, word_t max_size,
+			char path[PATH_MAX], word_t address, int size)
+{
+	int status;
+
+	assert(max_size <= sizeof(struct sockaddr_un));
+
+	/* Nothing to do if the sockaddr has an unexpected size.  */
+	if (size <= offsetof_path || (word_t) size > max_size)
+		return 0;
+
+	bzero(sockaddr, sizeof(struct sockaddr_un));
+	status = read_data(tracee, sockaddr, address, size);
+	if (status < 0)
+		return status;
+
+	/* Nothing to do if it's not a named Unix domain socket.  */
+	if ((sockaddr->sun_family != AF_UNIX)
+	    || sockaddr->sun_path[0] == '\0')
+		return 0;
+
+	/* Be careful: sun_path doesn't have to be null-terminated.  */
+	assert(sizeof_path < PATH_MAX - 1);
+	strncpy(path, sockaddr->sun_path, sizeof_path);
+	path[sizeof_path] = '\0';
+
+	return 1;
+}
+
+/**
+ * Translate the pathname of the struct sockaddr_un currently stored
+ * in the @tracee memory at the given @address.  See the documentation
+ * of read_sockaddr_un() for the meaning of the @size parameter.
+ * Also, the new address of the translated sockaddr_un is put in the
+ * @address parameter.  This function returns -errno if an error
+ * occurred, otherwise 0.
+ */
+int translate_socketcall_enter(Tracee *tracee, word_t *address, int size)
+{
+	struct sockaddr_un sockaddr;
+	char user_path[PATH_MAX];
+	char host_path[PATH_MAX];
+	int status;
+
+	if (*address == 0)
+		return 0;
+
+	status = read_sockaddr_un(tracee, &sockaddr, sizeof(sockaddr), user_path, *address, size);
+	if (status <= 0)
+		return status;
+
+	status = translate_path(tracee, host_path, AT_FDCWD, user_path, true);
+	if (status < 0)
+		return status;
+
+	/* Be careful: sun_path doesn't have to be null-terminated.  */
+	if (strlen(host_path) > sizeof_path) {
+		char *shorter_host_path;
+		Binding *binding;
+
+		/* The translated path is too long to fit the sun_path
+		 * array, so let's bind it to a shorter path.  */
+		shorter_host_path = create_temp_name(tracee->ctx, "proot");
+		if (shorter_host_path == NULL || strlen(shorter_host_path) > sizeof_path)
+			return -EINVAL;
+
+		(void) mktemp(shorter_host_path);
+
+		if (strlen(shorter_host_path) > sizeof_path)
+			return -EINVAL;
+
+		/* Ensure the guest path of this new binding is
+		 * canonicalized, as it is always assumed.  */
+		strcpy(user_path, host_path);
+		status = detranslate_path(tracee, user_path, NULL);
+		if (status < 0)
+			return -EINVAL;
+
+		/* Bing the guest path to a shorter host path.  */
+		binding = insort_binding3(tracee, tracee->ctx, shorter_host_path, user_path);
+		if (binding == NULL)
+			return -EINVAL;
+
+		/* This temporary file (shorter_host_path) will be removed once the
+		 * binding is destroyed.  */
+		talloc_reparent(tracee->ctx, binding, shorter_host_path);
+
+		/* Let's use this shorter path now.  */
+		strcpy(host_path, shorter_host_path);
+	}
+	strncpy(sockaddr.sun_path, host_path, sizeof_path);
+
+	/* Push the updated sockaddr to a newly allocated space.  */
+	*address = alloc_mem(tracee, sizeof(sockaddr));
+	if (*address == 0)
+		return -EFAULT;
+
+	status = write_data(tracee, *address, &sockaddr, sizeof(sockaddr));
+	if (status < 0)
+		return status;
+
+	return 1;
+}
+
+/**
+ * Detranslate the pathname of the struct sockaddr_un currently stored
+ * in the @tracee memory at the given @sock_addr.  See the
+ * documentation of read_sockaddr_un() for the meaning of the
+ * @size_addr and @max_size parameters.  This function returns -errno
+ * if an error occurred, otherwise 0.
+ */
+int translate_socketcall_exit(Tracee *tracee, word_t sock_addr, word_t size_addr, word_t max_size)
+{
+	struct sockaddr_un sockaddr;
+	bool is_truncated = false;
+	char path[PATH_MAX];
+	int status;
+	int size;
+
+	if (sock_addr == 0)
+		return 0;
+
+	size = peek_int32(tracee, size_addr);
+	if (errno != 0)
+		return -errno;
+
+	max_size = MIN(max_size, sizeof(sockaddr));
+	status = read_sockaddr_un(tracee, &sockaddr, max_size, path, sock_addr, size);
+	if (status <= 0)
+		return status;
+
+	status = detranslate_path(tracee, path, NULL);
+	if (status < 0)
+		return status;
+
+	/* Be careful: sun_path doesn't have to be null-terminated.  */
+	size = offsetof_path + strlen(path) + 1;
+	if (size < 0 || (word_t) size > max_size) {
+		size = max_size;
+		is_truncated = true;
+	}
+	strncpy(sockaddr.sun_path, path, sizeof_path);
+
+	/* Overwrite the sockaddr and socklen parameters.  */
+	status = write_data(tracee, sock_addr, &sockaddr, size);
+	if (status < 0)
+		return status;
+
+	/* If sockaddr is truncated (because the buffer provided is
+	 * too small), addrlen will return a value greater than was
+	 * supplied to the call.  See man 2 accept. */
+	if (is_truncated)
+		size = max_size + 1;
+
+	poke_int32(tracee, size_addr, size);
+	if (errno != 0)
+		return -errno;
+
+	return 0;
+}
diff --git a/5.1.0/src/syscall/socket.h b/5.1.0/src/syscall/socket.h
new file mode 100644
index 0000000..0a41932
--- /dev/null
+++ b/5.1.0/src/syscall/socket.h
@@ -0,0 +1,32 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef SOCKET_H
+#define SOCKET_H
+
+#include "arch.h" /* word_t */
+#include "tracee/tracee.h"
+
+int translate_socketcall_enter(Tracee *tracee, word_t *sock_addr, int size);
+int translate_socketcall_exit(Tracee *tracee, word_t sock_addr, word_t size_addr, word_t max_size);
+
+#endif /* SOCKET_H */
diff --git a/5.1.0/src/syscall/syscall.c b/5.1.0/src/syscall/syscall.c
new file mode 100644
index 0000000..c5ca734
--- /dev/null
+++ b/5.1.0/src/syscall/syscall.c
@@ -0,0 +1,181 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <assert.h>      /* assert(3), */
+#include <limits.h>      /* PATH_MAX, */
+#include <string.h>      /* strlen(3), */
+#include <errno.h>       /* errno(3), E* */
+
+#include "syscall/syscall.h"
+#include "syscall/chain.h"
+#include "extension/extension.h"
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "tracee/mem.h"
+
+/**
+ * Copy in @path a C string (PATH_MAX bytes max.) from the @tracee's
+ * memory address space pointed to by the @reg argument of the
+ * current syscall.  This function returns -errno if an error occured,
+ * otherwise it returns the size in bytes put into the @path.
+ */
+int get_sysarg_path(const Tracee *tracee, char path[PATH_MAX], Reg reg)
+{
+	int size;
+	word_t src;
+
+	src = peek_reg(tracee, CURRENT, reg);
+
+	/* Check if the parameter is not NULL. Technically we should
+	 * not return an -EFAULT for this special value since it is
+	 * allowed for some syscall, utimensat(2) for instance. */
+	if (src == 0) {
+		path[0] = '\0';
+		return 0;
+	}
+
+	/* Get the path from the tracee's memory space. */
+	size = read_path(tracee, path, src);
+	if (size < 0)
+		return size;
+
+	path[size] = '\0';
+	return size;
+}
+
+/**
+ * Copy @size bytes of the data pointed to by @tracer_ptr into a
+ * @tracee's memory block and make the @reg argument of the current
+ * syscall points to this new block.  This function returns -errno if
+ * an error occured, otherwise 0.
+ */
+static int set_sysarg_data(Tracee *tracee, const void *tracer_ptr, word_t size, Reg reg)
+{
+	word_t tracee_ptr;
+	int status;
+
+	/* Allocate space into the tracee's memory to host the new data. */
+	tracee_ptr = alloc_mem(tracee, size);
+	if (tracee_ptr == 0)
+		return -EFAULT;
+
+	/* Copy the new data into the previously allocated space. */
+	status = write_data(tracee, tracee_ptr, tracer_ptr, size);
+	if (status < 0)
+		return status;
+
+	/* Make this argument point to the new data. */
+	poke_reg(tracee, reg, tracee_ptr);
+
+	return 0;
+}
+
+/**
+ * Copy @path to a @tracee's memory block and make the @reg argument
+ * of the current syscall points to this new block.  This function
+ * returns -errno if an error occured, otherwise 0.
+ */
+int set_sysarg_path(Tracee *tracee, const char path[PATH_MAX], Reg reg)
+{
+	return set_sysarg_data(tracee, path, strlen(path) + 1, reg);
+}
+
+void translate_syscall(Tracee *tracee)
+{
+	const bool is_enter_stage = IS_IN_SYSENTER(tracee);
+	int status;
+
+	assert(tracee->exe != NULL);
+
+	status = fetch_regs(tracee);
+	if (status < 0)
+		return;
+
+	if (is_enter_stage) {
+		/* Never restore original register values at the end
+		 * of this stage.  */
+		tracee->restore_original_regs = false;
+
+		print_current_regs(tracee, 3, "sysenter start");
+
+		/* Translate the syscall only if it was actually
+		 * requested by the tracee, it is not a syscall
+		 * chained by PRoot.  */
+		if (tracee->chain.syscalls == NULL) {
+			save_current_regs(tracee, ORIGINAL);
+			status = translate_syscall_enter(tracee);
+			save_current_regs(tracee, MODIFIED);
+		}
+		else {
+			status = notify_extensions(tracee, SYSCALL_CHAINED_ENTER, 0, 0);
+			tracee->restart_how = PTRACE_SYSCALL;
+		}
+
+		/* Remember the tracee status for the "exit" stage and
+		 * avoid the actual syscall if an error was reported
+		 * by the translation/extension. */
+		if (status < 0) {
+			set_sysnum(tracee, PR_void);
+			poke_reg(tracee, SYSARG_RESULT, (word_t) status);
+			tracee->status = status;
+		}
+		else
+			tracee->status = 1;
+
+		/* Restore tracee's stack pointer now if it won't hit
+		 * the sysexit stage (i.e. when seccomp is enabled and
+		 * there's nothing else to do).  */
+		if (tracee->restart_how == PTRACE_CONT) {
+			tracee->status = 0;
+			poke_reg(tracee, STACK_POINTER, peek_reg(tracee, ORIGINAL, STACK_POINTER));
+		}
+	}
+	else {
+		/* By default, restore original register values at the
+		 * end of this stage.  */
+		tracee->restore_original_regs = true;
+
+		print_current_regs(tracee, 5, "sysexit start");
+
+		/* Translate the syscall only if it was actually
+		 * requested by the tracee, it is not a syscall
+		 * chained by PRoot.  */
+		if (tracee->chain.syscalls == NULL)
+			translate_syscall_exit(tracee);
+		else
+			(void) notify_extensions(tracee, SYSCALL_CHAINED_EXIT, 0, 0);
+
+		/* Reset the tracee's status. */
+		tracee->status = 0;
+
+		/* Insert the next chained syscall, if any.  */
+		if (tracee->chain.syscalls != NULL)
+			chain_next_syscall(tracee);
+	}
+
+	(void) push_regs(tracee);
+
+	if (is_enter_stage)
+		print_current_regs(tracee, 5, "sysenter end" );
+	else
+		print_current_regs(tracee, 4, "sysexit end");
+}
diff --git a/5.1.0/src/syscall/syscall.h b/5.1.0/src/syscall/syscall.h
new file mode 100644
index 0000000..98f59b2
--- /dev/null
+++ b/5.1.0/src/syscall/syscall.h
@@ -0,0 +1,38 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef SYSCALL_H
+#define SYSCALL_H
+
+#include <limits.h>     /* PATH_MAX, */
+
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+
+extern int get_sysarg_path(const Tracee *tracee, char path[PATH_MAX], Reg reg);
+extern int set_sysarg_path(Tracee *tracee, const char path[PATH_MAX], Reg reg);
+
+extern void translate_syscall(Tracee *tracee);
+extern int  translate_syscall_enter(Tracee *tracee);
+extern void translate_syscall_exit(Tracee *tracee);
+
+#endif /* SYSCALL_H */
diff --git a/5.1.0/src/syscall/sysnum.c b/5.1.0/src/syscall/sysnum.c
new file mode 100644
index 0000000..5802a34
--- /dev/null
+++ b/5.1.0/src/syscall/sysnum.c
@@ -0,0 +1,161 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <assert.h>
+
+#include "syscall/sysnum.h"
+#include "tracee/tracee.h"
+#include "tracee/abi.h"
+#include "tracee/reg.h"
+#include "arch.h"
+#include "cli/note.h"
+
+#include SYSNUMS_HEADER1
+
+#ifdef SYSNUMS_HEADER2
+#include SYSNUMS_HEADER2
+#endif
+
+#ifdef SYSNUMS_HEADER3
+#include SYSNUMS_HEADER3
+#endif
+
+typedef struct {
+	const Sysnum *table;
+	word_t offset;
+	word_t length;
+} Sysnums;
+
+/**
+ * Update @sysnums' fields with the sysnum table for the given @abi.
+ */
+static void get_sysnums(Abi abi, Sysnums *sysnums)
+{
+	switch (abi) {
+	case ABI_DEFAULT:
+		sysnums->table  = SYSNUMS_ABI1;
+		sysnums->length = sizeof(SYSNUMS_ABI1) / sizeof(Sysnum);
+		sysnums->offset = 0;
+		return;
+#ifdef SYSNUMS_ABI2
+	case ABI_2:
+		sysnums->table  = SYSNUMS_ABI2;
+		sysnums->length = sizeof(SYSNUMS_ABI2) / sizeof(Sysnum);
+		sysnums->offset = 0;
+		return;
+#endif
+#ifdef SYSNUMS_ABI3
+	case ABI_3:
+		sysnums->table  = SYSNUMS_ABI3;
+		sysnums->length = sizeof(SYSNUMS_ABI3) / sizeof(Sysnum);
+		sysnums->offset = 0x40000000; /* x32 */
+		return;
+#endif
+	default:
+		assert(0);
+	}
+}
+
+/**
+ * Return the neutral value of @sysnum from the given @abi.
+ */
+static Sysnum translate_sysnum(Abi abi, word_t sysnum)
+{
+	Sysnums sysnums;
+	word_t index;
+
+	get_sysnums(abi, &sysnums);
+
+	/* Sanity checks.  */
+	if (sysnum < sysnums.offset)
+		return PR_void;
+
+	index = sysnum - sysnums.offset;
+
+	/* Sanity checks.  */
+	if (index > sysnums.length)
+		return PR_void;
+
+	return sysnums.table[index];
+}
+
+/**
+ * Return the architecture value of @sysnum for the given @abi.
+ */
+word_t detranslate_sysnum(Abi abi, Sysnum sysnum)
+{
+	Sysnums sysnums;
+	size_t i;
+
+	/* Very special case.  */
+	if (sysnum == PR_void)
+		return SYSCALL_AVOIDER;
+
+	get_sysnums(abi, &sysnums);
+
+	for (i = 0; i < sysnums.length; i++) {
+		if (sysnums.table[i] != sysnum)
+			continue;
+
+		return i + sysnums.offset;
+	}
+
+	return SYSCALL_AVOIDER;
+}
+
+/**
+ * Return the neutral value of the @tracee's current syscall number.
+ */
+Sysnum get_sysnum(const Tracee *tracee, RegVersion version)
+{
+	return translate_sysnum(get_abi(tracee), peek_reg(tracee, version, SYSARG_NUM));
+}
+
+/**
+ * Overwrite the @tracee's current syscall number with @sysnum.  Note:
+ * this neutral value is automatically converted into the architecture
+ * value.
+ */
+void set_sysnum(Tracee *tracee, Sysnum sysnum)
+{
+	poke_reg(tracee, SYSARG_NUM, detranslate_sysnum(get_abi(tracee), sysnum));
+}
+
+/**
+ * Return the human readable name of @sysnum.
+ */
+const char *stringify_sysnum(Sysnum sysnum)
+{
+	#define SYSNUM(item) [ PR_ ## item ] = #item,
+	static const char *names[] = {
+		#include "syscall/sysnums.list"
+	};
+	#undef SYSNUM
+
+	if (sysnum == 0)
+		return "void";
+
+	if (sysnum >= PR_NB_SYSNUM)
+		return "";
+
+	return names[sysnum];
+}
diff --git a/5.1.0/src/syscall/sysnum.h b/5.1.0/src/syscall/sysnum.h
new file mode 100644
index 0000000..2deb69a
--- /dev/null
+++ b/5.1.0/src/syscall/sysnum.h
@@ -0,0 +1,45 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef SYSNUM_H
+#define SYSNUM_H
+
+#include <stdbool.h>
+
+#include "tracee/tracee.h"
+#include "tracee/abi.h"
+#include "tracee/reg.h"
+
+#define SYSNUM(item) PR_ ## item,
+typedef enum {
+	PR_void = 0,
+	#include "syscall/sysnums.list"
+	PR_NB_SYSNUM
+} Sysnum;
+#undef SYSNUM
+
+extern Sysnum get_sysnum(const Tracee *tracee, RegVersion version);
+extern void set_sysnum(Tracee *tracee, Sysnum sysnum);
+extern word_t detranslate_sysnum(Abi abi, Sysnum sysnum);
+extern const char *stringify_sysnum(Sysnum sysnum);
+
+#endif /* SYSNUM_H */
diff --git a/5.1.0/src/syscall/sysnums-arm.h b/5.1.0/src/syscall/sysnums-arm.h
new file mode 100644
index 0000000..42d3540
--- /dev/null
+++ b/5.1.0/src/syscall/sysnums-arm.h
@@ -0,0 +1,343 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_arm[] = {
+	[ 0 ] = PR_restart_syscall,
+	[ 1 ] = PR_exit,
+	[ 2 ] = PR_fork,
+	[ 3 ] = PR_read,
+	[ 4 ] = PR_write,
+	[ 5 ] = PR_open,
+	[ 6 ] = PR_close,
+	[ 8 ] = PR_creat,
+	[ 9 ] = PR_link,
+	[ 10 ] = PR_unlink,
+	[ 11 ] = PR_execve,
+	[ 12 ] = PR_chdir,
+	[ 14 ] = PR_mknod,
+	[ 15 ] = PR_chmod,
+	[ 16 ] = PR_lchown,
+	[ 19 ] = PR_lseek,
+	[ 20 ] = PR_getpid,
+	[ 21 ] = PR_mount,
+	[ 23 ] = PR_setuid,
+	[ 24 ] = PR_getuid,
+	[ 26 ] = PR_ptrace,
+	[ 29 ] = PR_pause,
+	[ 33 ] = PR_access,
+	[ 34 ] = PR_nice,
+	[ 36 ] = PR_sync,
+	[ 37 ] = PR_kill,
+	[ 38 ] = PR_rename,
+	[ 39 ] = PR_mkdir,
+	[ 40 ] = PR_rmdir,
+	[ 41 ] = PR_dup,
+	[ 42 ] = PR_pipe,
+	[ 43 ] = PR_times,
+	[ 45 ] = PR_brk,
+	[ 46 ] = PR_setgid,
+	[ 47 ] = PR_getgid,
+	[ 49 ] = PR_geteuid,
+	[ 50 ] = PR_getegid,
+	[ 51 ] = PR_acct,
+	[ 52 ] = PR_umount2,
+	[ 54 ] = PR_ioctl,
+	[ 55 ] = PR_fcntl,
+	[ 57 ] = PR_setpgid,
+	[ 60 ] = PR_umask,
+	[ 61 ] = PR_chroot,
+	[ 62 ] = PR_ustat,
+	[ 63 ] = PR_dup2,
+	[ 64 ] = PR_getppid,
+	[ 65 ] = PR_getpgrp,
+	[ 66 ] = PR_setsid,
+	[ 67 ] = PR_sigaction,
+	[ 70 ] = PR_setreuid,
+	[ 71 ] = PR_setregid,
+	[ 72 ] = PR_sigsuspend,
+	[ 73 ] = PR_sigpending,
+	[ 74 ] = PR_sethostname,
+	[ 75 ] = PR_setrlimit,
+	[ 77 ] = PR_getrusage,
+	[ 78 ] = PR_gettimeofday,
+	[ 79 ] = PR_settimeofday,
+	[ 80 ] = PR_getgroups,
+	[ 81 ] = PR_setgroups,
+	[ 83 ] = PR_symlink,
+	[ 85 ] = PR_readlink,
+	[ 86 ] = PR_uselib,
+	[ 87 ] = PR_swapon,
+	[ 88 ] = PR_reboot,
+	[ 91 ] = PR_munmap,
+	[ 92 ] = PR_truncate,
+	[ 93 ] = PR_ftruncate,
+	[ 94 ] = PR_fchmod,
+	[ 95 ] = PR_fchown,
+	[ 96 ] = PR_getpriority,
+	[ 97 ] = PR_setpriority,
+	[ 99 ] = PR_statfs,
+	[ 100 ] = PR_fstatfs,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_setitimer,
+	[ 105 ] = PR_getitimer,
+	[ 106 ] = PR_stat,
+	[ 107 ] = PR_lstat,
+	[ 108 ] = PR_fstat,
+	[ 111 ] = PR_vhangup,
+	[ 114 ] = PR_wait4,
+	[ 115 ] = PR_swapoff,
+	[ 116 ] = PR_sysinfo,
+	[ 118 ] = PR_fsync,
+	[ 119 ] = PR_sigreturn,
+	[ 120 ] = PR_clone,
+	[ 121 ] = PR_setdomainname,
+	[ 122 ] = PR_uname,
+	[ 124 ] = PR_adjtimex,
+	[ 125 ] = PR_mprotect,
+	[ 126 ] = PR_sigprocmask,
+	[ 128 ] = PR_init_module,
+	[ 129 ] = PR_delete_module,
+	[ 131 ] = PR_quotactl,
+	[ 132 ] = PR_getpgid,
+	[ 133 ] = PR_fchdir,
+	[ 134 ] = PR_bdflush,
+	[ 135 ] = PR_sysfs,
+	[ 136 ] = PR_personality,
+	[ 138 ] = PR_setfsuid,
+	[ 139 ] = PR_setfsgid,
+	[ 140 ] = PR__llseek,
+	[ 141 ] = PR_getdents,
+	[ 142 ] = PR__newselect,
+	[ 143 ] = PR_flock,
+	[ 144 ] = PR_msync,
+	[ 145 ] = PR_readv,
+	[ 146 ] = PR_writev,
+	[ 147 ] = PR_getsid,
+	[ 148 ] = PR_fdatasync,
+	[ 149 ] = PR__sysctl,
+	[ 150 ] = PR_mlock,
+	[ 151 ] = PR_munlock,
+	[ 152 ] = PR_mlockall,
+	[ 153 ] = PR_munlockall,
+	[ 154 ] = PR_sched_setparam,
+	[ 155 ] = PR_sched_getparam,
+	[ 156 ] = PR_sched_setscheduler,
+	[ 157 ] = PR_sched_getscheduler,
+	[ 158 ] = PR_sched_yield,
+	[ 159 ] = PR_sched_get_priority_max,
+	[ 160 ] = PR_sched_get_priority_min,
+	[ 161 ] = PR_sched_rr_get_interval,
+	[ 162 ] = PR_nanosleep,
+	[ 163 ] = PR_mremap,
+	[ 164 ] = PR_setresuid,
+	[ 165 ] = PR_getresuid,
+	[ 168 ] = PR_poll,
+	[ 169 ] = PR_nfsservctl,
+	[ 170 ] = PR_setresgid,
+	[ 171 ] = PR_getresgid,
+	[ 172 ] = PR_prctl,
+	[ 173 ] = PR_rt_sigreturn,
+	[ 174 ] = PR_rt_sigaction,
+	[ 175 ] = PR_rt_sigprocmask,
+	[ 176 ] = PR_rt_sigpending,
+	[ 177 ] = PR_rt_sigtimedwait,
+	[ 178 ] = PR_rt_sigqueueinfo,
+	[ 179 ] = PR_rt_sigsuspend,
+	[ 180 ] = PR_pread64,
+	[ 181 ] = PR_pwrite64,
+	[ 182 ] = PR_chown,
+	[ 183 ] = PR_getcwd,
+	[ 184 ] = PR_capget,
+	[ 185 ] = PR_capset,
+	[ 186 ] = PR_sigaltstack,
+	[ 187 ] = PR_sendfile,
+	[ 190 ] = PR_vfork,
+	[ 191 ] = PR_ugetrlimit,
+	[ 192 ] = PR_mmap2,
+	[ 193 ] = PR_truncate64,
+	[ 194 ] = PR_ftruncate64,
+	[ 195 ] = PR_stat64,
+	[ 196 ] = PR_lstat64,
+	[ 197 ] = PR_fstat64,
+	[ 198 ] = PR_lchown32,
+	[ 199 ] = PR_getuid32,
+	[ 200 ] = PR_getgid32,
+	[ 201 ] = PR_geteuid32,
+	[ 202 ] = PR_getegid32,
+	[ 203 ] = PR_setreuid32,
+	[ 204 ] = PR_setregid32,
+	[ 205 ] = PR_getgroups32,
+	[ 206 ] = PR_setgroups32,
+	[ 207 ] = PR_fchown32,
+	[ 208 ] = PR_setresuid32,
+	[ 209 ] = PR_getresuid32,
+	[ 210 ] = PR_setresgid32,
+	[ 211 ] = PR_getresgid32,
+	[ 212 ] = PR_chown32,
+	[ 213 ] = PR_setuid32,
+	[ 214 ] = PR_setgid32,
+	[ 215 ] = PR_setfsuid32,
+	[ 216 ] = PR_setfsgid32,
+	[ 217 ] = PR_getdents64,
+	[ 218 ] = PR_pivot_root,
+	[ 219 ] = PR_mincore,
+	[ 220 ] = PR_madvise,
+	[ 221 ] = PR_fcntl64,
+	[ 222 ] = PR_void,
+	[ 224 ] = PR_gettid,
+	[ 225 ] = PR_readahead,
+	[ 226 ] = PR_setxattr,
+	[ 227 ] = PR_lsetxattr,
+	[ 228 ] = PR_fsetxattr,
+	[ 229 ] = PR_getxattr,
+	[ 230 ] = PR_lgetxattr,
+	[ 231 ] = PR_fgetxattr,
+	[ 232 ] = PR_listxattr,
+	[ 233 ] = PR_llistxattr,
+	[ 234 ] = PR_flistxattr,
+	[ 235 ] = PR_removexattr,
+	[ 236 ] = PR_lremovexattr,
+	[ 237 ] = PR_fremovexattr,
+	[ 238 ] = PR_tkill,
+	[ 239 ] = PR_sendfile64,
+	[ 240 ] = PR_futex,
+	[ 241 ] = PR_sched_setaffinity,
+	[ 242 ] = PR_sched_getaffinity,
+	[ 243 ] = PR_io_setup,
+	[ 244 ] = PR_io_destroy,
+	[ 245 ] = PR_io_getevents,
+	[ 246 ] = PR_io_submit,
+	[ 247 ] = PR_io_cancel,
+	[ 248 ] = PR_exit_group,
+	[ 249 ] = PR_lookup_dcookie,
+	[ 250 ] = PR_epoll_create,
+	[ 251 ] = PR_epoll_ctl,
+	[ 252 ] = PR_epoll_wait,
+	[ 253 ] = PR_remap_file_pages,
+	[ 256 ] = PR_set_tid_address,
+	[ 257 ] = PR_timer_create,
+	[ 258 ] = PR_timer_settime,
+	[ 259 ] = PR_timer_gettime,
+	[ 260 ] = PR_timer_getoverrun,
+	[ 261 ] = PR_timer_delete,
+	[ 262 ] = PR_clock_settime,
+	[ 263 ] = PR_clock_gettime,
+	[ 264 ] = PR_clock_getres,
+	[ 265 ] = PR_clock_nanosleep,
+	[ 266 ] = PR_statfs64,
+	[ 267 ] = PR_fstatfs64,
+	[ 268 ] = PR_tgkill,
+	[ 269 ] = PR_utimes,
+	[ 270 ] = PR_arm_fadvise64_64,
+	[ 271 ] = PR_pciconfig_iobase,
+	[ 272 ] = PR_pciconfig_read,
+	[ 273 ] = PR_pciconfig_write,
+	[ 274 ] = PR_mq_open,
+	[ 275 ] = PR_mq_unlink,
+	[ 276 ] = PR_mq_timedsend,
+	[ 277 ] = PR_mq_timedreceive,
+	[ 278 ] = PR_mq_notify,
+	[ 279 ] = PR_mq_getsetattr,
+	[ 280 ] = PR_waitid,
+	[ 281 ] = PR_socket,
+	[ 282 ] = PR_bind,
+	[ 283 ] = PR_connect,
+	[ 284 ] = PR_listen,
+	[ 285 ] = PR_accept,
+	[ 286 ] = PR_getsockname,
+	[ 287 ] = PR_getpeername,
+	[ 288 ] = PR_socketpair,
+	[ 289 ] = PR_send,
+	[ 290 ] = PR_sendto,
+	[ 291 ] = PR_recv,
+	[ 292 ] = PR_recvfrom,
+	[ 293 ] = PR_shutdown,
+	[ 294 ] = PR_setsockopt,
+	[ 295 ] = PR_getsockopt,
+	[ 296 ] = PR_sendmsg,
+	[ 297 ] = PR_recvmsg,
+	[ 298 ] = PR_semop,
+	[ 299 ] = PR_semget,
+	[ 300 ] = PR_semctl,
+	[ 301 ] = PR_msgsnd,
+	[ 302 ] = PR_msgrcv,
+	[ 303 ] = PR_msgget,
+	[ 304 ] = PR_msgctl,
+	[ 305 ] = PR_shmat,
+	[ 306 ] = PR_shmdt,
+	[ 307 ] = PR_shmget,
+	[ 308 ] = PR_shmctl,
+	[ 309 ] = PR_add_key,
+	[ 310 ] = PR_request_key,
+	[ 311 ] = PR_keyctl,
+	[ 312 ] = PR_semtimedop,
+	[ 313 ] = PR_vserver,
+	[ 314 ] = PR_ioprio_set,
+	[ 315 ] = PR_ioprio_get,
+	[ 316 ] = PR_inotify_init,
+	[ 317 ] = PR_inotify_add_watch,
+	[ 318 ] = PR_inotify_rm_watch,
+	[ 319 ] = PR_mbind,
+	[ 320 ] = PR_get_mempolicy,
+	[ 321 ] = PR_set_mempolicy,
+	[ 322 ] = PR_openat,
+	[ 323 ] = PR_mkdirat,
+	[ 324 ] = PR_mknodat,
+	[ 325 ] = PR_fchownat,
+	[ 326 ] = PR_futimesat,
+	[ 327 ] = PR_fstatat64,
+	[ 328 ] = PR_unlinkat,
+	[ 329 ] = PR_renameat,
+	[ 330 ] = PR_linkat,
+	[ 331 ] = PR_symlinkat,
+	[ 332 ] = PR_readlinkat,
+	[ 333 ] = PR_fchmodat,
+	[ 334 ] = PR_faccessat,
+	[ 335 ] = PR_pselect6,
+	[ 336 ] = PR_ppoll,
+	[ 337 ] = PR_unshare,
+	[ 338 ] = PR_set_robust_list,
+	[ 339 ] = PR_get_robust_list,
+	[ 340 ] = PR_splice,
+	[ 341 ] = PR_arm_sync_file_range,
+	[ 342 ] = PR_tee,
+	[ 343 ] = PR_vmsplice,
+	[ 344 ] = PR_move_pages,
+	[ 345 ] = PR_getcpu,
+	[ 346 ] = PR_epoll_pwait,
+	[ 347 ] = PR_kexec_load,
+	[ 348 ] = PR_utimensat,
+	[ 349 ] = PR_signalfd,
+	[ 350 ] = PR_timerfd_create,
+	[ 351 ] = PR_eventfd,
+	[ 352 ] = PR_fallocate,
+	[ 353 ] = PR_timerfd_settime,
+	[ 354 ] = PR_timerfd_gettime,
+	[ 355 ] = PR_signalfd4,
+	[ 356 ] = PR_eventfd2,
+	[ 357 ] = PR_epoll_create1,
+	[ 358 ] = PR_dup3,
+	[ 359 ] = PR_pipe2,
+	[ 360 ] = PR_inotify_init1,
+	[ 361 ] = PR_preadv,
+	[ 362 ] = PR_pwritev,
+	[ 363 ] = PR_rt_tgsigqueueinfo,
+	[ 364 ] = PR_perf_event_open,
+	[ 365 ] = PR_recvmmsg,
+	[ 366 ] = PR_accept4,
+	[ 367 ] = PR_fanotify_init,
+	[ 368 ] = PR_fanotify_mark,
+	[ 369 ] = PR_prlimit64,
+	[ 370 ] = PR_name_to_handle_at,
+	[ 371 ] = PR_open_by_handle_at,
+	[ 372 ] = PR_clock_adjtime,
+	[ 373 ] = PR_syncfs,
+	[ 374 ] = PR_sendmmsg,
+	[ 375 ] = PR_setns,
+	[ 376 ] = PR_process_vm_readv,
+	[ 377 ] = PR_process_vm_writev,
+	[ 378 ] = PR_kcmp,
+	[ 379 ] = PR_finit_module,
+	[ 380 ] = PR_sched_setattr,
+	[ 381 ] = PR_sched_getattr,
+	[ 382 ] = PR_renameat2,
+};
diff --git a/5.1.0/src/syscall/sysnums-arm64.h b/5.1.0/src/syscall/sysnums-arm64.h
new file mode 100644
index 0000000..f7d7a5e
--- /dev/null
+++ b/5.1.0/src/syscall/sysnums-arm64.h
@@ -0,0 +1,266 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_arm64[] = {
+	[ 0 ] = PR_io_setup,
+	[ 1 ] = PR_io_destroy,
+	[ 2 ] = PR_io_submit,
+	[ 3 ] = PR_io_cancel,
+	[ 4 ] = PR_io_getevents,
+	[ 5 ] = PR_setxattr,
+	[ 6 ] = PR_lsetxattr,
+	[ 7 ] = PR_fsetxattr,
+	[ 8 ] = PR_getxattr,
+	[ 9 ] = PR_lgetxattr,
+	[ 10 ] = PR_fgetxattr,
+	[ 11 ] = PR_listxattr,
+	[ 12 ] = PR_llistxattr,
+	[ 13 ] = PR_flistxattr,
+	[ 14 ] = PR_removexattr,
+	[ 15 ] = PR_lremovexattr,
+	[ 16 ] = PR_fremovexattr,
+	[ 17 ] = PR_getcwd,
+	[ 18 ] = PR_lookup_dcookie,
+	[ 19 ] = PR_eventfd2,
+	[ 20 ] = PR_epoll_create1,
+	[ 21 ] = PR_epoll_ctl,
+	[ 22 ] = PR_epoll_pwait,
+	[ 23 ] = PR_dup,
+	[ 24 ] = PR_dup3,
+	[ 25 ] = PR_fcntl,
+	[ 26 ] = PR_inotify_init1,
+	[ 27 ] = PR_inotify_add_watch,
+	[ 28 ] = PR_inotify_rm_watch,
+	[ 29 ] = PR_ioctl,
+	[ 30 ] = PR_ioprio_set,
+	[ 31 ] = PR_ioprio_get,
+	[ 32 ] = PR_flock,
+	[ 33 ] = PR_mknodat,
+	[ 34 ] = PR_mkdirat,
+	[ 35 ] = PR_unlinkat,
+	[ 36 ] = PR_symlinkat,
+	[ 37 ] = PR_linkat,
+	[ 38 ] = PR_renameat,
+	[ 39 ] = PR_umount2,
+	[ 40 ] = PR_mount,
+	[ 41 ] = PR_pivot_root,
+	[ 42 ] = PR_nfsservctl,
+	[ 43 ] = PR_statfs,
+	[ 44 ] = PR_fstatfs,
+	[ 45 ] = PR_truncate,
+	[ 46 ] = PR_ftruncate,
+	[ 47 ] = PR_fallocate,
+	[ 48 ] = PR_faccessat,
+	[ 49 ] = PR_chdir,
+	[ 50 ] = PR_fchdir,
+	[ 51 ] = PR_chroot,
+	[ 52 ] = PR_fchmod,
+	[ 53 ] = PR_fchmodat,
+	[ 54 ] = PR_fchownat,
+	[ 55 ] = PR_fchown,
+	[ 56 ] = PR_openat,
+	[ 57 ] = PR_close,
+	[ 58 ] = PR_vhangup,
+	[ 59 ] = PR_pipe2,
+	[ 60 ] = PR_quotactl,
+	[ 61 ] = PR_getdents64,
+	[ 62 ] = PR_lseek,
+	[ 63 ] = PR_read,
+	[ 64 ] = PR_write,
+	[ 65 ] = PR_readv,
+	[ 66 ] = PR_writev,
+	[ 67 ] = PR_pread64,
+	[ 68 ] = PR_pwrite64,
+	[ 69 ] = PR_preadv,
+	[ 70 ] = PR_pwritev,
+	[ 71 ] = PR_sendfile,
+	[ 72 ] = PR_pselect6,
+	[ 73 ] = PR_ppoll,
+	[ 74 ] = PR_signalfd4,
+	[ 75 ] = PR_vmsplice,
+	[ 76 ] = PR_splice,
+	[ 77 ] = PR_tee,
+	[ 78 ] = PR_readlinkat,
+	[ 79 ] = PR_fstatat64,
+	[ 80 ] = PR_fstat,
+	[ 81 ] = PR_sync,
+	[ 82 ] = PR_fsync,
+	[ 83 ] = PR_fdatasync,
+	[ 84 ] = PR_sync_file_range,
+	[ 85 ] = PR_timerfd_create,
+	[ 86 ] = PR_timerfd_settime,
+	[ 87 ] = PR_timerfd_gettime,
+	[ 88 ] = PR_utimensat,
+	[ 89 ] = PR_acct,
+	[ 90 ] = PR_capget,
+	[ 91 ] = PR_capset,
+	[ 92 ] = PR_personality,
+	[ 93 ] = PR_exit,
+	[ 94 ] = PR_exit_group,
+	[ 95 ] = PR_waitid,
+	[ 96 ] = PR_set_tid_address,
+	[ 97 ] = PR_unshare,
+	[ 98 ] = PR_futex,
+	[ 99 ] = PR_set_robust_list,
+	[ 100 ] = PR_get_robust_list,
+	[ 101 ] = PR_nanosleep,
+	[ 102 ] = PR_getitimer,
+	[ 103 ] = PR_setitimer,
+	[ 104 ] = PR_kexec_load,
+	[ 105 ] = PR_init_module,
+	[ 106 ] = PR_delete_module,
+	[ 107 ] = PR_timer_create,
+	[ 108 ] = PR_timer_gettime,
+	[ 109 ] = PR_timer_getoverrun,
+	[ 110 ] = PR_timer_settime,
+	[ 111 ] = PR_timer_delete,
+	[ 112 ] = PR_clock_settime,
+	[ 113 ] = PR_clock_gettime,
+	[ 114 ] = PR_clock_getres,
+	[ 115 ] = PR_clock_nanosleep,
+	[ 116 ] = PR_syslog,
+	[ 117 ] = PR_ptrace,
+	[ 118 ] = PR_sched_setparam,
+	[ 119 ] = PR_sched_setscheduler,
+	[ 120 ] = PR_sched_getscheduler,
+	[ 121 ] = PR_sched_getparam,
+	[ 122 ] = PR_sched_setaffinity,
+	[ 123 ] = PR_sched_getaffinity,
+	[ 124 ] = PR_sched_yield,
+	[ 125 ] = PR_sched_get_priority_max,
+	[ 126 ] = PR_sched_get_priority_min,
+	[ 127 ] = PR_sched_rr_get_interval,
+	[ 128 ] = PR_restart_syscall,
+	[ 129 ] = PR_kill,
+	[ 130 ] = PR_tkill,
+	[ 131 ] = PR_tgkill,
+	[ 132 ] = PR_sigaltstack,
+	[ 133 ] = PR_rt_sigsuspend,
+	[ 134 ] = PR_rt_sigaction,
+	[ 135 ] = PR_rt_sigprocmask,
+	[ 136 ] = PR_rt_sigpending,
+	[ 137 ] = PR_rt_sigtimedwait,
+	[ 138 ] = PR_rt_sigqueueinfo,
+	[ 139 ] = PR_rt_sigreturn,
+	[ 140 ] = PR_setpriority,
+	[ 141 ] = PR_getpriority,
+	[ 142 ] = PR_reboot,
+	[ 143 ] = PR_setregid,
+	[ 144 ] = PR_setgid,
+	[ 145 ] = PR_setreuid,
+	[ 146 ] = PR_setuid,
+	[ 147 ] = PR_setresuid,
+	[ 148 ] = PR_getresuid,
+	[ 149 ] = PR_setresgid,
+	[ 150 ] = PR_getresgid,
+	[ 151 ] = PR_setfsuid,
+	[ 152 ] = PR_setfsgid,
+	[ 153 ] = PR_times,
+	[ 154 ] = PR_setpgid,
+	[ 155 ] = PR_getpgid,
+	[ 156 ] = PR_getsid,
+	[ 157 ] = PR_setsid,
+	[ 158 ] = PR_getgroups,
+	[ 159 ] = PR_setgroups,
+	[ 160 ] = PR_uname,
+	[ 161 ] = PR_sethostname,
+	[ 162 ] = PR_setdomainname,
+	[ 163 ] = PR_getrlimit,
+	[ 164 ] = PR_setrlimit,
+	[ 165 ] = PR_getrusage,
+	[ 166 ] = PR_umask,
+	[ 167 ] = PR_prctl,
+	[ 168 ] = PR_getcpu,
+	[ 169 ] = PR_gettimeofday,
+	[ 170 ] = PR_settimeofday,
+	[ 171 ] = PR_adjtimex,
+	[ 172 ] = PR_getpid,
+	[ 173 ] = PR_getppid,
+	[ 174 ] = PR_getuid,
+	[ 175 ] = PR_geteuid,
+	[ 176 ] = PR_getgid,
+	[ 177 ] = PR_getegid,
+	[ 178 ] = PR_gettid,
+	[ 179 ] = PR_sysinfo,
+	[ 180 ] = PR_mq_open,
+	[ 181 ] = PR_mq_unlink,
+	[ 182 ] = PR_mq_timedsend,
+	[ 183 ] = PR_mq_timedreceive,
+	[ 184 ] = PR_mq_notify,
+	[ 185 ] = PR_mq_getsetattr,
+	[ 186 ] = PR_msgget,
+	[ 187 ] = PR_msgctl,
+	[ 188 ] = PR_msgrcv,
+	[ 189 ] = PR_msgsnd,
+	[ 190 ] = PR_semget,
+	[ 191 ] = PR_semctl,
+	[ 192 ] = PR_semtimedop,
+	[ 193 ] = PR_semop,
+	[ 194 ] = PR_shmget,
+	[ 195 ] = PR_shmctl,
+	[ 196 ] = PR_shmat,
+	[ 197 ] = PR_shmdt,
+	[ 198 ] = PR_socket,
+	[ 199 ] = PR_socketpair,
+	[ 200 ] = PR_bind,
+	[ 201 ] = PR_listen,
+	[ 202 ] = PR_accept,
+	[ 203 ] = PR_connect,
+	[ 204 ] = PR_getsockname,
+	[ 205 ] = PR_getpeername,
+	[ 206 ] = PR_sendto,
+	[ 207 ] = PR_recvfrom,
+	[ 208 ] = PR_setsockopt,
+	[ 209 ] = PR_getsockopt,
+	[ 210 ] = PR_shutdown,
+	[ 211 ] = PR_sendmsg,
+	[ 212 ] = PR_recvmsg,
+	[ 213 ] = PR_readahead,
+	[ 214 ] = PR_brk,
+	[ 215 ] = PR_munmap,
+	[ 216 ] = PR_mremap,
+	[ 217 ] = PR_add_key,
+	[ 218 ] = PR_request_key,
+	[ 219 ] = PR_keyctl,
+	[ 220 ] = PR_clone,
+	[ 221 ] = PR_execve,
+	[ 222 ] = PR_mmap,
+	[ 223 ] = PR_fadvise64,
+	[ 224 ] = PR_swapon,
+	[ 225 ] = PR_swapoff,
+	[ 226 ] = PR_mprotect,
+	[ 227 ] = PR_msync,
+	[ 228 ] = PR_mlock,
+	[ 229 ] = PR_munlock,
+	[ 230 ] = PR_mlockall,
+	[ 231 ] = PR_munlockall,
+	[ 232 ] = PR_mincore,
+	[ 233 ] = PR_madvise,
+	[ 234 ] = PR_remap_file_pages,
+	[ 235 ] = PR_mbind,
+	[ 236 ] = PR_get_mempolicy,
+	[ 237 ] = PR_set_mempolicy,
+	[ 238 ] = PR_migrate_pages,
+	[ 239 ] = PR_move_pages,
+	[ 240 ] = PR_rt_tgsigqueueinfo,
+	[ 241 ] = PR_perf_event_open,
+	[ 242 ] = PR_accept4,
+	[ 243 ] = PR_recvmmsg,
+	[ 244 ] = PR_arch_specific_syscall,
+	[ 260 ] = PR_wait4,
+	[ 261 ] = PR_prlimit64,
+	[ 262 ] = PR_fanotify_init,
+	[ 263 ] = PR_fanotify_mark,
+	[ 264 ] = PR_name_to_handle_at,
+	[ 265 ] = PR_open_by_handle_at,
+	[ 266 ] = PR_clock_adjtime,
+	[ 267 ] = PR_syncfs,
+	[ 268 ] = PR_setns,
+	[ 269 ] = PR_sendmmsg,
+	[ 270 ] = PR_process_vm_readv,
+	[ 271 ] = PR_process_vm_writev,
+	[ 272 ] = PR_kcmp,
+	[ 273 ] = PR_finit_module,
+	[ 274 ] = PR_sched_setattr,
+	[ 275 ] = PR_sched_getattr,
+	[ 276 ] = PR_renameat2,
+};
diff --git a/5.1.0/src/syscall/sysnums-i386.h b/5.1.0/src/syscall/sysnums-i386.h
new file mode 100644
index 0000000..dff8919
--- /dev/null
+++ b/5.1.0/src/syscall/sysnums-i386.h
@@ -0,0 +1,354 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_i386[] = {
+	[ 0 ] = PR_restart_syscall,
+	[ 1 ] = PR_exit,
+	[ 2 ] = PR_fork,
+	[ 3 ] = PR_read,
+	[ 4 ] = PR_write,
+	[ 5 ] = PR_open,
+	[ 6 ] = PR_close,
+	[ 7 ] = PR_waitpid,
+	[ 8 ] = PR_creat,
+	[ 9 ] = PR_link,
+	[ 10 ] = PR_unlink,
+	[ 11 ] = PR_execve,
+	[ 12 ] = PR_chdir,
+	[ 13 ] = PR_time,
+	[ 14 ] = PR_mknod,
+	[ 15 ] = PR_chmod,
+	[ 16 ] = PR_lchown,
+	[ 17 ] = PR_break,
+	[ 18 ] = PR_oldstat,
+	[ 19 ] = PR_lseek,
+	[ 20 ] = PR_getpid,
+	[ 21 ] = PR_mount,
+	[ 22 ] = PR_umount,
+	[ 23 ] = PR_setuid,
+	[ 24 ] = PR_getuid,
+	[ 25 ] = PR_stime,
+	[ 26 ] = PR_ptrace,
+	[ 27 ] = PR_alarm,
+	[ 28 ] = PR_oldfstat,
+	[ 29 ] = PR_pause,
+	[ 30 ] = PR_utime,
+	[ 31 ] = PR_stty,
+	[ 32 ] = PR_gtty,
+	[ 33 ] = PR_access,
+	[ 34 ] = PR_nice,
+	[ 35 ] = PR_ftime,
+	[ 36 ] = PR_sync,
+	[ 37 ] = PR_kill,
+	[ 38 ] = PR_rename,
+	[ 39 ] = PR_mkdir,
+	[ 40 ] = PR_rmdir,
+	[ 41 ] = PR_dup,
+	[ 42 ] = PR_pipe,
+	[ 43 ] = PR_times,
+	[ 44 ] = PR_prof,
+	[ 45 ] = PR_brk,
+	[ 46 ] = PR_setgid,
+	[ 47 ] = PR_getgid,
+	[ 48 ] = PR_signal,
+	[ 49 ] = PR_geteuid,
+	[ 50 ] = PR_getegid,
+	[ 51 ] = PR_acct,
+	[ 52 ] = PR_umount2,
+	[ 53 ] = PR_lock,
+	[ 54 ] = PR_ioctl,
+	[ 55 ] = PR_fcntl,
+	[ 56 ] = PR_mpx,
+	[ 57 ] = PR_setpgid,
+	[ 58 ] = PR_ulimit,
+	[ 59 ] = PR_oldolduname,
+	[ 60 ] = PR_umask,
+	[ 61 ] = PR_chroot,
+	[ 62 ] = PR_ustat,
+	[ 63 ] = PR_dup2,
+	[ 64 ] = PR_getppid,
+	[ 65 ] = PR_getpgrp,
+	[ 66 ] = PR_setsid,
+	[ 67 ] = PR_sigaction,
+	[ 68 ] = PR_sgetmask,
+	[ 69 ] = PR_ssetmask,
+	[ 70 ] = PR_setreuid,
+	[ 71 ] = PR_setregid,
+	[ 72 ] = PR_sigsuspend,
+	[ 73 ] = PR_sigpending,
+	[ 74 ] = PR_sethostname,
+	[ 75 ] = PR_setrlimit,
+	[ 76 ] = PR_getrlimit,
+	[ 77 ] = PR_getrusage,
+	[ 78 ] = PR_gettimeofday,
+	[ 79 ] = PR_settimeofday,
+	[ 80 ] = PR_getgroups,
+	[ 81 ] = PR_setgroups,
+	[ 82 ] = PR_select,
+	[ 83 ] = PR_symlink,
+	[ 84 ] = PR_oldlstat,
+	[ 85 ] = PR_readlink,
+	[ 86 ] = PR_uselib,
+	[ 87 ] = PR_swapon,
+	[ 88 ] = PR_reboot,
+	[ 89 ] = PR_readdir,
+	[ 90 ] = PR_mmap,
+	[ 91 ] = PR_munmap,
+	[ 92 ] = PR_truncate,
+	[ 93 ] = PR_ftruncate,
+	[ 94 ] = PR_fchmod,
+	[ 95 ] = PR_fchown,
+	[ 96 ] = PR_getpriority,
+	[ 97 ] = PR_setpriority,
+	[ 98 ] = PR_profil,
+	[ 99 ] = PR_statfs,
+	[ 100 ] = PR_fstatfs,
+	[ 101 ] = PR_ioperm,
+	[ 102 ] = PR_socketcall,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_setitimer,
+	[ 105 ] = PR_getitimer,
+	[ 106 ] = PR_stat,
+	[ 107 ] = PR_lstat,
+	[ 108 ] = PR_fstat,
+	[ 109 ] = PR_olduname,
+	[ 110 ] = PR_iopl,
+	[ 111 ] = PR_vhangup,
+	[ 112 ] = PR_idle,
+	[ 113 ] = PR_vm86old,
+	[ 114 ] = PR_wait4,
+	[ 115 ] = PR_swapoff,
+	[ 116 ] = PR_sysinfo,
+	[ 117 ] = PR_ipc,
+	[ 118 ] = PR_fsync,
+	[ 119 ] = PR_sigreturn,
+	[ 120 ] = PR_clone,
+	[ 121 ] = PR_setdomainname,
+	[ 122 ] = PR_uname,
+	[ 123 ] = PR_modify_ldt,
+	[ 124 ] = PR_adjtimex,
+	[ 125 ] = PR_mprotect,
+	[ 126 ] = PR_sigprocmask,
+	[ 127 ] = PR_create_module,
+	[ 128 ] = PR_init_module,
+	[ 129 ] = PR_delete_module,
+	[ 130 ] = PR_get_kernel_syms,
+	[ 131 ] = PR_quotactl,
+	[ 132 ] = PR_getpgid,
+	[ 133 ] = PR_fchdir,
+	[ 134 ] = PR_bdflush,
+	[ 135 ] = PR_sysfs,
+	[ 136 ] = PR_personality,
+	[ 137 ] = PR_afs_syscall,
+	[ 138 ] = PR_setfsuid,
+	[ 139 ] = PR_setfsgid,
+	[ 140 ] = PR__llseek,
+	[ 141 ] = PR_getdents,
+	[ 142 ] = PR__newselect,
+	[ 143 ] = PR_flock,
+	[ 144 ] = PR_msync,
+	[ 145 ] = PR_readv,
+	[ 146 ] = PR_writev,
+	[ 147 ] = PR_getsid,
+	[ 148 ] = PR_fdatasync,
+	[ 149 ] = PR__sysctl,
+	[ 150 ] = PR_mlock,
+	[ 151 ] = PR_munlock,
+	[ 152 ] = PR_mlockall,
+	[ 153 ] = PR_munlockall,
+	[ 154 ] = PR_sched_setparam,
+	[ 155 ] = PR_sched_getparam,
+	[ 156 ] = PR_sched_setscheduler,
+	[ 157 ] = PR_sched_getscheduler,
+	[ 158 ] = PR_sched_yield,
+	[ 159 ] = PR_sched_get_priority_max,
+	[ 160 ] = PR_sched_get_priority_min,
+	[ 161 ] = PR_sched_rr_get_interval,
+	[ 162 ] = PR_nanosleep,
+	[ 163 ] = PR_mremap,
+	[ 164 ] = PR_setresuid,
+	[ 165 ] = PR_getresuid,
+	[ 166 ] = PR_vm86,
+	[ 167 ] = PR_query_module,
+	[ 168 ] = PR_poll,
+	[ 169 ] = PR_nfsservctl,
+	[ 170 ] = PR_setresgid,
+	[ 171 ] = PR_getresgid,
+	[ 172 ] = PR_prctl,
+	[ 173 ] = PR_rt_sigreturn,
+	[ 174 ] = PR_rt_sigaction,
+	[ 175 ] = PR_rt_sigprocmask,
+	[ 176 ] = PR_rt_sigpending,
+	[ 177 ] = PR_rt_sigtimedwait,
+	[ 178 ] = PR_rt_sigqueueinfo,
+	[ 179 ] = PR_rt_sigsuspend,
+	[ 180 ] = PR_pread64,
+	[ 181 ] = PR_pwrite64,
+	[ 182 ] = PR_chown,
+	[ 183 ] = PR_getcwd,
+	[ 184 ] = PR_capget,
+	[ 185 ] = PR_capset,
+	[ 186 ] = PR_sigaltstack,
+	[ 187 ] = PR_sendfile,
+	[ 188 ] = PR_getpmsg,
+	[ 189 ] = PR_putpmsg,
+	[ 190 ] = PR_vfork,
+	[ 191 ] = PR_ugetrlimit,
+	[ 192 ] = PR_mmap2,
+	[ 193 ] = PR_truncate64,
+	[ 194 ] = PR_ftruncate64,
+	[ 195 ] = PR_stat64,
+	[ 196 ] = PR_lstat64,
+	[ 197 ] = PR_fstat64,
+	[ 198 ] = PR_lchown32,
+	[ 199 ] = PR_getuid32,
+	[ 200 ] = PR_getgid32,
+	[ 201 ] = PR_geteuid32,
+	[ 202 ] = PR_getegid32,
+	[ 203 ] = PR_setreuid32,
+	[ 204 ] = PR_setregid32,
+	[ 205 ] = PR_getgroups32,
+	[ 206 ] = PR_setgroups32,
+	[ 207 ] = PR_fchown32,
+	[ 208 ] = PR_setresuid32,
+	[ 209 ] = PR_getresuid32,
+	[ 210 ] = PR_setresgid32,
+	[ 211 ] = PR_getresgid32,
+	[ 212 ] = PR_chown32,
+	[ 213 ] = PR_setuid32,
+	[ 214 ] = PR_setgid32,
+	[ 215 ] = PR_setfsuid32,
+	[ 216 ] = PR_setfsgid32,
+	[ 217 ] = PR_pivot_root,
+	[ 218 ] = PR_mincore,
+	[ 219 ] = PR_madvise,
+	[ 220 ] = PR_getdents64,
+	[ 221 ] = PR_fcntl64,
+	[ 224 ] = PR_gettid,
+	[ 225 ] = PR_readahead,
+	[ 226 ] = PR_setxattr,
+	[ 227 ] = PR_lsetxattr,
+	[ 228 ] = PR_fsetxattr,
+	[ 229 ] = PR_getxattr,
+	[ 230 ] = PR_lgetxattr,
+	[ 231 ] = PR_fgetxattr,
+	[ 232 ] = PR_listxattr,
+	[ 233 ] = PR_llistxattr,
+	[ 234 ] = PR_flistxattr,
+	[ 235 ] = PR_removexattr,
+	[ 236 ] = PR_lremovexattr,
+	[ 237 ] = PR_fremovexattr,
+	[ 238 ] = PR_tkill,
+	[ 239 ] = PR_sendfile64,
+	[ 240 ] = PR_futex,
+	[ 241 ] = PR_sched_setaffinity,
+	[ 242 ] = PR_sched_getaffinity,
+	[ 243 ] = PR_set_thread_area,
+	[ 244 ] = PR_get_thread_area,
+	[ 245 ] = PR_io_setup,
+	[ 246 ] = PR_io_destroy,
+	[ 247 ] = PR_io_getevents,
+	[ 248 ] = PR_io_submit,
+	[ 249 ] = PR_io_cancel,
+	[ 250 ] = PR_fadvise64,
+	[ 252 ] = PR_exit_group,
+	[ 253 ] = PR_lookup_dcookie,
+	[ 254 ] = PR_epoll_create,
+	[ 255 ] = PR_epoll_ctl,
+	[ 256 ] = PR_epoll_wait,
+	[ 257 ] = PR_remap_file_pages,
+	[ 258 ] = PR_set_tid_address,
+	[ 259 ] = PR_timer_create,
+	[ 260 ] = PR_timer_settime,
+	[ 261 ] = PR_timer_gettime,
+	[ 262 ] = PR_timer_getoverrun,
+	[ 263 ] = PR_timer_delete,
+	[ 264 ] = PR_clock_settime,
+	[ 265 ] = PR_clock_gettime,
+	[ 266 ] = PR_clock_getres,
+	[ 267 ] = PR_clock_nanosleep,
+	[ 268 ] = PR_statfs64,
+	[ 269 ] = PR_fstatfs64,
+	[ 270 ] = PR_tgkill,
+	[ 271 ] = PR_utimes,
+	[ 272 ] = PR_fadvise64_64,
+	[ 273 ] = PR_vserver,
+	[ 274 ] = PR_mbind,
+	[ 275 ] = PR_get_mempolicy,
+	[ 276 ] = PR_set_mempolicy,
+	[ 277 ] = PR_mq_open,
+	[ 278 ] = PR_mq_unlink,
+	[ 279 ] = PR_mq_timedsend,
+	[ 280 ] = PR_mq_timedreceive,
+	[ 281 ] = PR_mq_notify,
+	[ 282 ] = PR_mq_getsetattr,
+	[ 283 ] = PR_kexec_load,
+	[ 284 ] = PR_waitid,
+	[ 286 ] = PR_add_key,
+	[ 287 ] = PR_request_key,
+	[ 288 ] = PR_keyctl,
+	[ 289 ] = PR_ioprio_set,
+	[ 290 ] = PR_ioprio_get,
+	[ 291 ] = PR_inotify_init,
+	[ 292 ] = PR_inotify_add_watch,
+	[ 293 ] = PR_inotify_rm_watch,
+	[ 294 ] = PR_migrate_pages,
+	[ 295 ] = PR_openat,
+	[ 296 ] = PR_mkdirat,
+	[ 297 ] = PR_mknodat,
+	[ 298 ] = PR_fchownat,
+	[ 299 ] = PR_futimesat,
+	[ 300 ] = PR_fstatat64,
+	[ 301 ] = PR_unlinkat,
+	[ 302 ] = PR_renameat,
+	[ 303 ] = PR_linkat,
+	[ 304 ] = PR_symlinkat,
+	[ 305 ] = PR_readlinkat,
+	[ 306 ] = PR_fchmodat,
+	[ 307 ] = PR_faccessat,
+	[ 308 ] = PR_pselect6,
+	[ 309 ] = PR_ppoll,
+	[ 310 ] = PR_unshare,
+	[ 311 ] = PR_set_robust_list,
+	[ 312 ] = PR_get_robust_list,
+	[ 313 ] = PR_splice,
+	[ 314 ] = PR_sync_file_range,
+	[ 315 ] = PR_tee,
+	[ 316 ] = PR_vmsplice,
+	[ 317 ] = PR_move_pages,
+	[ 318 ] = PR_getcpu,
+	[ 319 ] = PR_epoll_pwait,
+	[ 320 ] = PR_utimensat,
+	[ 321 ] = PR_signalfd,
+	[ 322 ] = PR_timerfd_create,
+	[ 323 ] = PR_eventfd,
+	[ 324 ] = PR_fallocate,
+	[ 325 ] = PR_timerfd_settime,
+	[ 326 ] = PR_timerfd_gettime,
+	[ 327 ] = PR_signalfd4,
+	[ 328 ] = PR_eventfd2,
+	[ 329 ] = PR_epoll_create1,
+	[ 330 ] = PR_dup3,
+	[ 331 ] = PR_pipe2,
+	[ 332 ] = PR_inotify_init1,
+	[ 333 ] = PR_preadv,
+	[ 334 ] = PR_pwritev,
+	[ 335 ] = PR_rt_tgsigqueueinfo,
+	[ 336 ] = PR_perf_event_open,
+	[ 337 ] = PR_recvmmsg,
+	[ 338 ] = PR_fanotify_init,
+	[ 339 ] = PR_fanotify_mark,
+	[ 340 ] = PR_prlimit64,
+	[ 341 ] = PR_name_to_handle_at,
+	[ 342 ] = PR_open_by_handle_at,
+	[ 343 ] = PR_clock_adjtime,
+	[ 344 ] = PR_syncfs,
+	[ 345 ] = PR_sendmmsg,
+	[ 346 ] = PR_setns,
+	[ 347 ] = PR_process_vm_readv,
+	[ 348 ] = PR_process_vm_writev,
+	[ 349 ] = PR_kcmp,
+	[ 350 ] = PR_finit_module,
+	[ 351 ] = PR_sched_setattr,
+	[ 352 ] = PR_sched_getattr,
+	[ 353 ] = PR_renameat2,
+};
diff --git a/5.1.0/src/syscall/sysnums-sh4.h b/5.1.0/src/syscall/sysnums-sh4.h
new file mode 100644
index 0000000..1d3758c
--- /dev/null
+++ b/5.1.0/src/syscall/sysnums-sh4.h
@@ -0,0 +1,347 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_sh4[] = {
+	[ 0 ] = PR_restart_syscall,
+	[ 1 ] = PR_exit,
+	[ 2 ] = PR_fork,
+	[ 3 ] = PR_read,
+	[ 4 ] = PR_write,
+	[ 5 ] = PR_open,
+	[ 6 ] = PR_close,
+	[ 7 ] = PR_waitpid,
+	[ 8 ] = PR_creat,
+	[ 9 ] = PR_link,
+	[ 10 ] = PR_unlink,
+	[ 11 ] = PR_execve,
+	[ 12 ] = PR_chdir,
+	[ 13 ] = PR_time,
+	[ 14 ] = PR_mknod,
+	[ 15 ] = PR_chmod,
+	[ 16 ] = PR_lchown,
+	[ 18 ] = PR_oldstat,
+	[ 19 ] = PR_lseek,
+	[ 20 ] = PR_getpid,
+	[ 21 ] = PR_mount,
+	[ 22 ] = PR_umount,
+	[ 23 ] = PR_setuid,
+	[ 24 ] = PR_getuid,
+	[ 25 ] = PR_stime,
+	[ 26 ] = PR_ptrace,
+	[ 27 ] = PR_alarm,
+	[ 28 ] = PR_oldfstat,
+	[ 29 ] = PR_pause,
+	[ 30 ] = PR_utime,
+	[ 33 ] = PR_access,
+	[ 34 ] = PR_nice,
+	[ 36 ] = PR_sync,
+	[ 37 ] = PR_kill,
+	[ 38 ] = PR_rename,
+	[ 39 ] = PR_mkdir,
+	[ 40 ] = PR_rmdir,
+	[ 41 ] = PR_dup,
+	[ 42 ] = PR_pipe,
+	[ 43 ] = PR_times,
+	[ 45 ] = PR_brk,
+	[ 46 ] = PR_setgid,
+	[ 47 ] = PR_getgid,
+	[ 48 ] = PR_signal,
+	[ 49 ] = PR_geteuid,
+	[ 50 ] = PR_getegid,
+	[ 51 ] = PR_acct,
+	[ 52 ] = PR_umount2,
+	[ 54 ] = PR_ioctl,
+	[ 55 ] = PR_fcntl,
+	[ 57 ] = PR_setpgid,
+	[ 60 ] = PR_umask,
+	[ 61 ] = PR_chroot,
+	[ 62 ] = PR_ustat,
+	[ 63 ] = PR_dup2,
+	[ 64 ] = PR_getppid,
+	[ 65 ] = PR_getpgrp,
+	[ 66 ] = PR_setsid,
+	[ 67 ] = PR_sigaction,
+	[ 68 ] = PR_sgetmask,
+	[ 69 ] = PR_ssetmask,
+	[ 70 ] = PR_setreuid,
+	[ 71 ] = PR_setregid,
+	[ 72 ] = PR_sigsuspend,
+	[ 73 ] = PR_sigpending,
+	[ 74 ] = PR_sethostname,
+	[ 75 ] = PR_setrlimit,
+	[ 76 ] = PR_getrlimit,
+	[ 77 ] = PR_getrusage,
+	[ 78 ] = PR_gettimeofday,
+	[ 79 ] = PR_settimeofday,
+	[ 80 ] = PR_getgroups,
+	[ 81 ] = PR_setgroups,
+	[ 83 ] = PR_symlink,
+	[ 84 ] = PR_oldlstat,
+	[ 85 ] = PR_readlink,
+	[ 86 ] = PR_uselib,
+	[ 87 ] = PR_swapon,
+	[ 88 ] = PR_reboot,
+	[ 89 ] = PR_readdir,
+	[ 90 ] = PR_mmap,
+	[ 91 ] = PR_munmap,
+	[ 92 ] = PR_truncate,
+	[ 93 ] = PR_ftruncate,
+	[ 94 ] = PR_fchmod,
+	[ 95 ] = PR_fchown,
+	[ 96 ] = PR_getpriority,
+	[ 97 ] = PR_setpriority,
+	[ 99 ] = PR_statfs,
+	[ 100 ] = PR_fstatfs,
+	[ 102 ] = PR_socketcall,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_setitimer,
+	[ 105 ] = PR_getitimer,
+	[ 106 ] = PR_stat,
+	[ 107 ] = PR_lstat,
+	[ 108 ] = PR_fstat,
+	[ 109 ] = PR_olduname,
+	[ 111 ] = PR_vhangup,
+	[ 114 ] = PR_wait4,
+	[ 115 ] = PR_swapoff,
+	[ 116 ] = PR_sysinfo,
+	[ 117 ] = PR_ipc,
+	[ 118 ] = PR_fsync,
+	[ 119 ] = PR_sigreturn,
+	[ 120 ] = PR_clone,
+	[ 121 ] = PR_setdomainname,
+	[ 122 ] = PR_uname,
+	[ 123 ] = PR_cacheflush,
+	[ 124 ] = PR_adjtimex,
+	[ 125 ] = PR_mprotect,
+	[ 126 ] = PR_sigprocmask,
+	[ 128 ] = PR_init_module,
+	[ 129 ] = PR_delete_module,
+	[ 131 ] = PR_quotactl,
+	[ 132 ] = PR_getpgid,
+	[ 133 ] = PR_fchdir,
+	[ 134 ] = PR_bdflush,
+	[ 135 ] = PR_sysfs,
+	[ 136 ] = PR_personality,
+	[ 138 ] = PR_setfsuid,
+	[ 139 ] = PR_setfsgid,
+	[ 140 ] = PR__llseek,
+	[ 141 ] = PR_getdents,
+	[ 142 ] = PR__newselect,
+	[ 143 ] = PR_flock,
+	[ 144 ] = PR_msync,
+	[ 145 ] = PR_readv,
+	[ 146 ] = PR_writev,
+	[ 147 ] = PR_getsid,
+	[ 148 ] = PR_fdatasync,
+	[ 149 ] = PR__sysctl,
+	[ 150 ] = PR_mlock,
+	[ 151 ] = PR_munlock,
+	[ 152 ] = PR_mlockall,
+	[ 153 ] = PR_munlockall,
+	[ 154 ] = PR_sched_setparam,
+	[ 155 ] = PR_sched_getparam,
+	[ 156 ] = PR_sched_setscheduler,
+	[ 157 ] = PR_sched_getscheduler,
+	[ 158 ] = PR_sched_yield,
+	[ 159 ] = PR_sched_get_priority_max,
+	[ 160 ] = PR_sched_get_priority_min,
+	[ 161 ] = PR_sched_rr_get_interval,
+	[ 162 ] = PR_nanosleep,
+	[ 163 ] = PR_mremap,
+	[ 164 ] = PR_setresuid,
+	[ 165 ] = PR_getresuid,
+	[ 168 ] = PR_poll,
+	[ 169 ] = PR_nfsservctl,
+	[ 170 ] = PR_setresgid,
+	[ 171 ] = PR_getresgid,
+	[ 172 ] = PR_prctl,
+	[ 173 ] = PR_rt_sigreturn,
+	[ 174 ] = PR_rt_sigaction,
+	[ 175 ] = PR_rt_sigprocmask,
+	[ 176 ] = PR_rt_sigpending,
+	[ 177 ] = PR_rt_sigtimedwait,
+	[ 178 ] = PR_rt_sigqueueinfo,
+	[ 179 ] = PR_rt_sigsuspend,
+	[ 180 ] = PR_pread64,
+	[ 181 ] = PR_pwrite64,
+	[ 182 ] = PR_chown,
+	[ 183 ] = PR_getcwd,
+	[ 184 ] = PR_capget,
+	[ 185 ] = PR_capset,
+	[ 186 ] = PR_sigaltstack,
+	[ 187 ] = PR_sendfile,
+	[ 190 ] = PR_vfork,
+	[ 191 ] = PR_ugetrlimit,
+	[ 192 ] = PR_mmap2,
+	[ 193 ] = PR_truncate64,
+	[ 194 ] = PR_ftruncate64,
+	[ 195 ] = PR_stat64,
+	[ 196 ] = PR_lstat64,
+	[ 197 ] = PR_fstat64,
+	[ 198 ] = PR_lchown32,
+	[ 199 ] = PR_getuid32,
+	[ 200 ] = PR_getgid32,
+	[ 201 ] = PR_geteuid32,
+	[ 202 ] = PR_getegid32,
+	[ 203 ] = PR_setreuid32,
+	[ 204 ] = PR_setregid32,
+	[ 205 ] = PR_getgroups32,
+	[ 206 ] = PR_setgroups32,
+	[ 207 ] = PR_fchown32,
+	[ 208 ] = PR_setresuid32,
+	[ 209 ] = PR_getresuid32,
+	[ 210 ] = PR_setresgid32,
+	[ 211 ] = PR_getresgid32,
+	[ 212 ] = PR_chown32,
+	[ 213 ] = PR_setuid32,
+	[ 214 ] = PR_setgid32,
+	[ 215 ] = PR_setfsuid32,
+	[ 216 ] = PR_setfsgid32,
+	[ 217 ] = PR_pivot_root,
+	[ 218 ] = PR_mincore,
+	[ 219 ] = PR_madvise,
+	[ 220 ] = PR_getdents64,
+	[ 221 ] = PR_fcntl64,
+	[ 224 ] = PR_gettid,
+	[ 225 ] = PR_readahead,
+	[ 226 ] = PR_setxattr,
+	[ 227 ] = PR_lsetxattr,
+	[ 228 ] = PR_fsetxattr,
+	[ 229 ] = PR_getxattr,
+	[ 230 ] = PR_lgetxattr,
+	[ 231 ] = PR_fgetxattr,
+	[ 232 ] = PR_listxattr,
+	[ 233 ] = PR_llistxattr,
+	[ 234 ] = PR_flistxattr,
+	[ 235 ] = PR_removexattr,
+	[ 236 ] = PR_lremovexattr,
+	[ 237 ] = PR_fremovexattr,
+	[ 238 ] = PR_tkill,
+	[ 239 ] = PR_sendfile64,
+	[ 240 ] = PR_futex,
+	[ 241 ] = PR_sched_setaffinity,
+	[ 242 ] = PR_sched_getaffinity,
+	[ 245 ] = PR_io_setup,
+	[ 246 ] = PR_io_destroy,
+	[ 247 ] = PR_io_getevents,
+	[ 248 ] = PR_io_submit,
+	[ 249 ] = PR_io_cancel,
+	[ 250 ] = PR_fadvise64,
+	[ 252 ] = PR_exit_group,
+	[ 253 ] = PR_lookup_dcookie,
+	[ 254 ] = PR_epoll_create,
+	[ 255 ] = PR_epoll_ctl,
+	[ 256 ] = PR_epoll_wait,
+	[ 257 ] = PR_remap_file_pages,
+	[ 258 ] = PR_set_tid_address,
+	[ 259 ] = PR_timer_create,
+	[ 260 ] = PR_timer_settime,
+	[ 261 ] = PR_timer_gettime,
+	[ 262 ] = PR_timer_getoverrun,
+	[ 263 ] = PR_timer_delete,
+	[ 264 ] = PR_clock_settime,
+	[ 265 ] = PR_clock_gettime,
+	[ 266 ] = PR_clock_getres,
+	[ 267 ] = PR_clock_nanosleep,
+	[ 268 ] = PR_statfs64,
+	[ 269 ] = PR_fstatfs64,
+	[ 270 ] = PR_tgkill,
+	[ 271 ] = PR_utimes,
+	[ 272 ] = PR_fadvise64_64,
+	[ 274 ] = PR_mbind,
+	[ 275 ] = PR_get_mempolicy,
+	[ 276 ] = PR_set_mempolicy,
+	[ 277 ] = PR_mq_open,
+	[ 278 ] = PR_mq_unlink,
+	[ 279 ] = PR_mq_timedsend,
+	[ 280 ] = PR_mq_timedreceive,
+	[ 281 ] = PR_mq_notify,
+	[ 282 ] = PR_mq_getsetattr,
+	[ 283 ] = PR_kexec_load,
+	[ 284 ] = PR_waitid,
+	[ 285 ] = PR_add_key,
+	[ 286 ] = PR_request_key,
+	[ 287 ] = PR_keyctl,
+	[ 288 ] = PR_ioprio_set,
+	[ 289 ] = PR_ioprio_get,
+	[ 290 ] = PR_inotify_init,
+	[ 291 ] = PR_inotify_add_watch,
+	[ 292 ] = PR_inotify_rm_watch,
+	[ 294 ] = PR_migrate_pages,
+	[ 295 ] = PR_openat,
+	[ 296 ] = PR_mkdirat,
+	[ 297 ] = PR_mknodat,
+	[ 298 ] = PR_fchownat,
+	[ 299 ] = PR_futimesat,
+	[ 300 ] = PR_fstatat64,
+	[ 301 ] = PR_unlinkat,
+	[ 302 ] = PR_renameat,
+	[ 303 ] = PR_linkat,
+	[ 304 ] = PR_symlinkat,
+	[ 305 ] = PR_readlinkat,
+	[ 306 ] = PR_fchmodat,
+	[ 307 ] = PR_faccessat,
+	[ 308 ] = PR_pselect6,
+	[ 309 ] = PR_ppoll,
+	[ 310 ] = PR_unshare,
+	[ 311 ] = PR_set_robust_list,
+	[ 312 ] = PR_get_robust_list,
+	[ 313 ] = PR_splice,
+	[ 314 ] = PR_sync_file_range,
+	[ 315 ] = PR_tee,
+	[ 316 ] = PR_vmsplice,
+	[ 317 ] = PR_move_pages,
+	[ 318 ] = PR_getcpu,
+	[ 319 ] = PR_epoll_pwait,
+	[ 320 ] = PR_utimensat,
+	[ 321 ] = PR_signalfd,
+	[ 322 ] = PR_timerfd_create,
+	[ 323 ] = PR_eventfd,
+	[ 324 ] = PR_fallocate,
+	[ 325 ] = PR_timerfd_settime,
+	[ 326 ] = PR_timerfd_gettime,
+	[ 327 ] = PR_signalfd4,
+	[ 328 ] = PR_eventfd2,
+	[ 329 ] = PR_epoll_create1,
+	[ 330 ] = PR_dup3,
+	[ 331 ] = PR_pipe2,
+	[ 332 ] = PR_inotify_init1,
+	[ 333 ] = PR_preadv,
+	[ 334 ] = PR_pwritev,
+	[ 335 ] = PR_rt_tgsigqueueinfo,
+	[ 336 ] = PR_perf_event_open,
+	[ 337 ] = PR_fanotify_init,
+	[ 338 ] = PR_fanotify_mark,
+	[ 339 ] = PR_prlimit64,
+	[ 340 ] = PR_socket,
+	[ 341 ] = PR_bind,
+	[ 342 ] = PR_connect,
+	[ 343 ] = PR_listen,
+	[ 344 ] = PR_accept,
+	[ 345 ] = PR_getsockname,
+	[ 346 ] = PR_getpeername,
+	[ 347 ] = PR_socketpair,
+	[ 348 ] = PR_send,
+	[ 349 ] = PR_sendto,
+	[ 350 ] = PR_recv,
+	[ 351 ] = PR_recvfrom,
+	[ 352 ] = PR_shutdown,
+	[ 353 ] = PR_setsockopt,
+	[ 354 ] = PR_getsockopt,
+	[ 355 ] = PR_sendmsg,
+	[ 356 ] = PR_recvmsg,
+	[ 357 ] = PR_recvmmsg,
+	[ 358 ] = PR_accept4,
+	[ 359 ] = PR_name_to_handle_at,
+	[ 360 ] = PR_open_by_handle_at,
+	[ 361 ] = PR_clock_adjtime,
+	[ 362 ] = PR_syncfs,
+	[ 363 ] = PR_sendmmsg,
+	[ 364 ] = PR_setns,
+	[ 365 ] = PR_process_vm_readv,
+	[ 366 ] = PR_process_vm_writev,
+	[ 367 ] = PR_kcmp,
+	[ 368 ] = PR_finit_module,
+	[ 369 ] = PR_sched_setattr,
+	[ 370 ] = PR_sched_getattr,
+	[ 371 ] = PR_renameat2,
+};
diff --git a/5.1.0/src/syscall/sysnums-x32.h b/5.1.0/src/syscall/sysnums-x32.h
new file mode 100644
index 0000000..0c3405b
--- /dev/null
+++ b/5.1.0/src/syscall/sysnums-x32.h
@@ -0,0 +1,310 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_x32[] = {
+	[ 0 ] = PR_read,
+	[ 1 ] = PR_write,
+	[ 2 ] = PR_open,
+	[ 3 ] = PR_close,
+	[ 4 ] = PR_stat,
+	[ 5 ] = PR_fstat,
+	[ 6 ] = PR_lstat,
+	[ 7 ] = PR_poll,
+	[ 8 ] = PR_lseek,
+	[ 9 ] = PR_mmap,
+	[ 10 ] = PR_mprotect,
+	[ 11 ] = PR_munmap,
+	[ 12 ] = PR_brk,
+	[ 14 ] = PR_rt_sigprocmask,
+	[ 17 ] = PR_pread64,
+	[ 18 ] = PR_pwrite64,
+	[ 21 ] = PR_access,
+	[ 22 ] = PR_pipe,
+	[ 23 ] = PR_select,
+	[ 24 ] = PR_sched_yield,
+	[ 25 ] = PR_mremap,
+	[ 26 ] = PR_msync,
+	[ 27 ] = PR_mincore,
+	[ 28 ] = PR_madvise,
+	[ 29 ] = PR_shmget,
+	[ 30 ] = PR_shmat,
+	[ 31 ] = PR_shmctl,
+	[ 32 ] = PR_dup,
+	[ 33 ] = PR_dup2,
+	[ 34 ] = PR_pause,
+	[ 35 ] = PR_nanosleep,
+	[ 36 ] = PR_getitimer,
+	[ 37 ] = PR_alarm,
+	[ 38 ] = PR_setitimer,
+	[ 39 ] = PR_getpid,
+	[ 40 ] = PR_sendfile,
+	[ 41 ] = PR_socket,
+	[ 42 ] = PR_connect,
+	[ 43 ] = PR_accept,
+	[ 44 ] = PR_sendto,
+	[ 48 ] = PR_shutdown,
+	[ 49 ] = PR_bind,
+	[ 50 ] = PR_listen,
+	[ 51 ] = PR_getsockname,
+	[ 52 ] = PR_getpeername,
+	[ 53 ] = PR_socketpair,
+	[ 56 ] = PR_clone,
+	[ 57 ] = PR_fork,
+	[ 58 ] = PR_vfork,
+	[ 60 ] = PR_exit,
+	[ 61 ] = PR_wait4,
+	[ 62 ] = PR_kill,
+	[ 63 ] = PR_uname,
+	[ 64 ] = PR_semget,
+	[ 65 ] = PR_semop,
+	[ 66 ] = PR_semctl,
+	[ 67 ] = PR_shmdt,
+	[ 68 ] = PR_msgget,
+	[ 69 ] = PR_msgsnd,
+	[ 70 ] = PR_msgrcv,
+	[ 71 ] = PR_msgctl,
+	[ 72 ] = PR_fcntl,
+	[ 73 ] = PR_flock,
+	[ 74 ] = PR_fsync,
+	[ 75 ] = PR_fdatasync,
+	[ 76 ] = PR_truncate,
+	[ 77 ] = PR_ftruncate,
+	[ 78 ] = PR_getdents,
+	[ 79 ] = PR_getcwd,
+	[ 80 ] = PR_chdir,
+	[ 81 ] = PR_fchdir,
+	[ 82 ] = PR_rename,
+	[ 83 ] = PR_mkdir,
+	[ 84 ] = PR_rmdir,
+	[ 85 ] = PR_creat,
+	[ 86 ] = PR_link,
+	[ 87 ] = PR_unlink,
+	[ 88 ] = PR_symlink,
+	[ 89 ] = PR_readlink,
+	[ 90 ] = PR_chmod,
+	[ 91 ] = PR_fchmod,
+	[ 92 ] = PR_chown,
+	[ 93 ] = PR_fchown,
+	[ 94 ] = PR_lchown,
+	[ 95 ] = PR_umask,
+	[ 96 ] = PR_gettimeofday,
+	[ 97 ] = PR_getrlimit,
+	[ 98 ] = PR_getrusage,
+	[ 99 ] = PR_sysinfo,
+	[ 100 ] = PR_times,
+	[ 102 ] = PR_getuid,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_getgid,
+	[ 105 ] = PR_setuid,
+	[ 106 ] = PR_setgid,
+	[ 107 ] = PR_geteuid,
+	[ 108 ] = PR_getegid,
+	[ 109 ] = PR_setpgid,
+	[ 110 ] = PR_getppid,
+	[ 111 ] = PR_getpgrp,
+	[ 112 ] = PR_setsid,
+	[ 113 ] = PR_setreuid,
+	[ 114 ] = PR_setregid,
+	[ 115 ] = PR_getgroups,
+	[ 116 ] = PR_setgroups,
+	[ 117 ] = PR_setresuid,
+	[ 118 ] = PR_getresuid,
+	[ 119 ] = PR_setresgid,
+	[ 120 ] = PR_getresgid,
+	[ 121 ] = PR_getpgid,
+	[ 122 ] = PR_setfsuid,
+	[ 123 ] = PR_setfsgid,
+	[ 124 ] = PR_getsid,
+	[ 125 ] = PR_capget,
+	[ 126 ] = PR_capset,
+	[ 130 ] = PR_rt_sigsuspend,
+	[ 132 ] = PR_utime,
+	[ 133 ] = PR_mknod,
+	[ 135 ] = PR_personality,
+	[ 136 ] = PR_ustat,
+	[ 137 ] = PR_statfs,
+	[ 138 ] = PR_fstatfs,
+	[ 139 ] = PR_sysfs,
+	[ 140 ] = PR_getpriority,
+	[ 141 ] = PR_setpriority,
+	[ 142 ] = PR_sched_setparam,
+	[ 143 ] = PR_sched_getparam,
+	[ 144 ] = PR_sched_setscheduler,
+	[ 145 ] = PR_sched_getscheduler,
+	[ 146 ] = PR_sched_get_priority_max,
+	[ 147 ] = PR_sched_get_priority_min,
+	[ 148 ] = PR_sched_rr_get_interval,
+	[ 149 ] = PR_mlock,
+	[ 150 ] = PR_munlock,
+	[ 151 ] = PR_mlockall,
+	[ 152 ] = PR_munlockall,
+	[ 153 ] = PR_vhangup,
+	[ 154 ] = PR_modify_ldt,
+	[ 155 ] = PR_pivot_root,
+	[ 157 ] = PR_prctl,
+	[ 158 ] = PR_arch_prctl,
+	[ 159 ] = PR_adjtimex,
+	[ 160 ] = PR_setrlimit,
+	[ 161 ] = PR_chroot,
+	[ 162 ] = PR_sync,
+	[ 163 ] = PR_acct,
+	[ 164 ] = PR_settimeofday,
+	[ 165 ] = PR_mount,
+	[ 166 ] = PR_umount2,
+	[ 167 ] = PR_swapon,
+	[ 168 ] = PR_swapoff,
+	[ 169 ] = PR_reboot,
+	[ 170 ] = PR_sethostname,
+	[ 171 ] = PR_setdomainname,
+	[ 172 ] = PR_iopl,
+	[ 173 ] = PR_ioperm,
+	[ 175 ] = PR_init_module,
+	[ 176 ] = PR_delete_module,
+	[ 179 ] = PR_quotactl,
+	[ 181 ] = PR_getpmsg,
+	[ 182 ] = PR_putpmsg,
+	[ 183 ] = PR_afs_syscall,
+	[ 184 ] = PR_tuxcall,
+	[ 185 ] = PR_security,
+	[ 186 ] = PR_gettid,
+	[ 187 ] = PR_readahead,
+	[ 188 ] = PR_setxattr,
+	[ 189 ] = PR_lsetxattr,
+	[ 190 ] = PR_fsetxattr,
+	[ 191 ] = PR_getxattr,
+	[ 192 ] = PR_lgetxattr,
+	[ 193 ] = PR_fgetxattr,
+	[ 194 ] = PR_listxattr,
+	[ 195 ] = PR_llistxattr,
+	[ 196 ] = PR_flistxattr,
+	[ 197 ] = PR_removexattr,
+	[ 198 ] = PR_lremovexattr,
+	[ 199 ] = PR_fremovexattr,
+	[ 200 ] = PR_tkill,
+	[ 201 ] = PR_time,
+	[ 202 ] = PR_futex,
+	[ 203 ] = PR_sched_setaffinity,
+	[ 204 ] = PR_sched_getaffinity,
+	[ 206 ] = PR_io_setup,
+	[ 207 ] = PR_io_destroy,
+	[ 208 ] = PR_io_getevents,
+	[ 209 ] = PR_io_submit,
+	[ 210 ] = PR_io_cancel,
+	[ 212 ] = PR_lookup_dcookie,
+	[ 213 ] = PR_epoll_create,
+	[ 216 ] = PR_remap_file_pages,
+	[ 217 ] = PR_getdents64,
+	[ 218 ] = PR_set_tid_address,
+	[ 219 ] = PR_restart_syscall,
+	[ 220 ] = PR_semtimedop,
+	[ 221 ] = PR_fadvise64,
+	[ 223 ] = PR_timer_settime,
+	[ 224 ] = PR_timer_gettime,
+	[ 225 ] = PR_timer_getoverrun,
+	[ 226 ] = PR_timer_delete,
+	[ 227 ] = PR_clock_settime,
+	[ 228 ] = PR_clock_gettime,
+	[ 229 ] = PR_clock_getres,
+	[ 230 ] = PR_clock_nanosleep,
+	[ 231 ] = PR_exit_group,
+	[ 232 ] = PR_epoll_wait,
+	[ 233 ] = PR_epoll_ctl,
+	[ 234 ] = PR_tgkill,
+	[ 235 ] = PR_utimes,
+	[ 237 ] = PR_mbind,
+	[ 238 ] = PR_set_mempolicy,
+	[ 239 ] = PR_get_mempolicy,
+	[ 240 ] = PR_mq_open,
+	[ 241 ] = PR_mq_unlink,
+	[ 242 ] = PR_mq_timedsend,
+	[ 243 ] = PR_mq_timedreceive,
+	[ 245 ] = PR_mq_getsetattr,
+	[ 248 ] = PR_add_key,
+	[ 249 ] = PR_request_key,
+	[ 250 ] = PR_keyctl,
+	[ 251 ] = PR_ioprio_set,
+	[ 252 ] = PR_ioprio_get,
+	[ 253 ] = PR_inotify_init,
+	[ 254 ] = PR_inotify_add_watch,
+	[ 255 ] = PR_inotify_rm_watch,
+	[ 256 ] = PR_migrate_pages,
+	[ 257 ] = PR_openat,
+	[ 258 ] = PR_mkdirat,
+	[ 259 ] = PR_mknodat,
+	[ 260 ] = PR_fchownat,
+	[ 261 ] = PR_futimesat,
+	[ 262 ] = PR_newfstatat,
+	[ 263 ] = PR_unlinkat,
+	[ 264 ] = PR_renameat,
+	[ 265 ] = PR_linkat,
+	[ 266 ] = PR_symlinkat,
+	[ 267 ] = PR_readlinkat,
+	[ 268 ] = PR_fchmodat,
+	[ 269 ] = PR_faccessat,
+	[ 270 ] = PR_pselect6,
+	[ 271 ] = PR_ppoll,
+	[ 272 ] = PR_unshare,
+	[ 275 ] = PR_splice,
+	[ 276 ] = PR_tee,
+	[ 277 ] = PR_sync_file_range,
+	[ 280 ] = PR_utimensat,
+	[ 281 ] = PR_epoll_pwait,
+	[ 282 ] = PR_signalfd,
+	[ 283 ] = PR_timerfd_create,
+	[ 284 ] = PR_eventfd,
+	[ 285 ] = PR_fallocate,
+	[ 286 ] = PR_timerfd_settime,
+	[ 287 ] = PR_timerfd_gettime,
+	[ 288 ] = PR_accept4,
+	[ 289 ] = PR_signalfd4,
+	[ 290 ] = PR_eventfd2,
+	[ 291 ] = PR_epoll_create1,
+	[ 292 ] = PR_dup3,
+	[ 293 ] = PR_pipe2,
+	[ 294 ] = PR_inotify_init1,
+	[ 298 ] = PR_perf_event_open,
+	[ 300 ] = PR_fanotify_init,
+	[ 301 ] = PR_fanotify_mark,
+	[ 302 ] = PR_prlimit64,
+	[ 303 ] = PR_name_to_handle_at,
+	[ 304 ] = PR_open_by_handle_at,
+	[ 305 ] = PR_clock_adjtime,
+	[ 306 ] = PR_syncfs,
+	[ 308 ] = PR_setns,
+	[ 309 ] = PR_getcpu,
+	[ 312 ] = PR_kcmp,
+	[ 313 ] = PR_finit_module,
+	[ 314 ] = PR_sched_setattr,
+	[ 315 ] = PR_sched_getattr,
+	[ 316 ] = PR_renameat2,
+	[ 512 ] = PR_rt_sigaction,
+	[ 513 ] = PR_rt_sigreturn,
+	[ 514 ] = PR_ioctl,
+	[ 515 ] = PR_readv,
+	[ 516 ] = PR_writev,
+	[ 517 ] = PR_recvfrom,
+	[ 518 ] = PR_sendmsg,
+	[ 519 ] = PR_recvmsg,
+	[ 520 ] = PR_execve,
+	[ 521 ] = PR_ptrace,
+	[ 522 ] = PR_rt_sigpending,
+	[ 523 ] = PR_rt_sigtimedwait,
+	[ 524 ] = PR_rt_sigqueueinfo,
+	[ 525 ] = PR_sigaltstack,
+	[ 526 ] = PR_timer_create,
+	[ 527 ] = PR_mq_notify,
+	[ 528 ] = PR_kexec_load,
+	[ 529 ] = PR_waitid,
+	[ 530 ] = PR_set_robust_list,
+	[ 531 ] = PR_get_robust_list,
+	[ 532 ] = PR_vmsplice,
+	[ 533 ] = PR_move_pages,
+	[ 534 ] = PR_preadv,
+	[ 535 ] = PR_pwritev,
+	[ 536 ] = PR_rt_tgsigqueueinfo,
+	[ 537 ] = PR_recvmmsg,
+	[ 538 ] = PR_sendmmsg,
+	[ 539 ] = PR_process_vm_readv,
+	[ 540 ] = PR_process_vm_writev,
+	[ 541 ] = PR_setsockopt,
+	[ 542 ] = PR_getsockopt,
+};
diff --git a/5.1.0/src/syscall/sysnums-x86_64.h b/5.1.0/src/syscall/sysnums-x86_64.h
new file mode 100644
index 0000000..eb44166
--- /dev/null
+++ b/5.1.0/src/syscall/sysnums-x86_64.h
@@ -0,0 +1,321 @@
+#include "syscall/sysnum.h"
+
+static const Sysnum sysnums_x86_64[] = {
+	[ 0 ] = PR_read,
+	[ 1 ] = PR_write,
+	[ 2 ] = PR_open,
+	[ 3 ] = PR_close,
+	[ 4 ] = PR_stat,
+	[ 5 ] = PR_fstat,
+	[ 6 ] = PR_lstat,
+	[ 7 ] = PR_poll,
+	[ 8 ] = PR_lseek,
+	[ 9 ] = PR_mmap,
+	[ 10 ] = PR_mprotect,
+	[ 11 ] = PR_munmap,
+	[ 12 ] = PR_brk,
+	[ 13 ] = PR_rt_sigaction,
+	[ 14 ] = PR_rt_sigprocmask,
+	[ 15 ] = PR_rt_sigreturn,
+	[ 16 ] = PR_ioctl,
+	[ 17 ] = PR_pread64,
+	[ 18 ] = PR_pwrite64,
+	[ 19 ] = PR_readv,
+	[ 20 ] = PR_writev,
+	[ 21 ] = PR_access,
+	[ 22 ] = PR_pipe,
+	[ 23 ] = PR_select,
+	[ 24 ] = PR_sched_yield,
+	[ 25 ] = PR_mremap,
+	[ 26 ] = PR_msync,
+	[ 27 ] = PR_mincore,
+	[ 28 ] = PR_madvise,
+	[ 29 ] = PR_shmget,
+	[ 30 ] = PR_shmat,
+	[ 31 ] = PR_shmctl,
+	[ 32 ] = PR_dup,
+	[ 33 ] = PR_dup2,
+	[ 34 ] = PR_pause,
+	[ 35 ] = PR_nanosleep,
+	[ 36 ] = PR_getitimer,
+	[ 37 ] = PR_alarm,
+	[ 38 ] = PR_setitimer,
+	[ 39 ] = PR_getpid,
+	[ 40 ] = PR_sendfile,
+	[ 41 ] = PR_socket,
+	[ 42 ] = PR_connect,
+	[ 43 ] = PR_accept,
+	[ 44 ] = PR_sendto,
+	[ 45 ] = PR_recvfrom,
+	[ 46 ] = PR_sendmsg,
+	[ 47 ] = PR_recvmsg,
+	[ 48 ] = PR_shutdown,
+	[ 49 ] = PR_bind,
+	[ 50 ] = PR_listen,
+	[ 51 ] = PR_getsockname,
+	[ 52 ] = PR_getpeername,
+	[ 53 ] = PR_socketpair,
+	[ 54 ] = PR_setsockopt,
+	[ 55 ] = PR_getsockopt,
+	[ 56 ] = PR_clone,
+	[ 57 ] = PR_fork,
+	[ 58 ] = PR_vfork,
+	[ 59 ] = PR_execve,
+	[ 60 ] = PR_exit,
+	[ 61 ] = PR_wait4,
+	[ 62 ] = PR_kill,
+	[ 63 ] = PR_uname,
+	[ 64 ] = PR_semget,
+	[ 65 ] = PR_semop,
+	[ 66 ] = PR_semctl,
+	[ 67 ] = PR_shmdt,
+	[ 68 ] = PR_msgget,
+	[ 69 ] = PR_msgsnd,
+	[ 70 ] = PR_msgrcv,
+	[ 71 ] = PR_msgctl,
+	[ 72 ] = PR_fcntl,
+	[ 73 ] = PR_flock,
+	[ 74 ] = PR_fsync,
+	[ 75 ] = PR_fdatasync,
+	[ 76 ] = PR_truncate,
+	[ 77 ] = PR_ftruncate,
+	[ 78 ] = PR_getdents,
+	[ 79 ] = PR_getcwd,
+	[ 80 ] = PR_chdir,
+	[ 81 ] = PR_fchdir,
+	[ 82 ] = PR_rename,
+	[ 83 ] = PR_mkdir,
+	[ 84 ] = PR_rmdir,
+	[ 85 ] = PR_creat,
+	[ 86 ] = PR_link,
+	[ 87 ] = PR_unlink,
+	[ 88 ] = PR_symlink,
+	[ 89 ] = PR_readlink,
+	[ 90 ] = PR_chmod,
+	[ 91 ] = PR_fchmod,
+	[ 92 ] = PR_chown,
+	[ 93 ] = PR_fchown,
+	[ 94 ] = PR_lchown,
+	[ 95 ] = PR_umask,
+	[ 96 ] = PR_gettimeofday,
+	[ 97 ] = PR_getrlimit,
+	[ 98 ] = PR_getrusage,
+	[ 99 ] = PR_sysinfo,
+	[ 100 ] = PR_times,
+	[ 101 ] = PR_ptrace,
+	[ 102 ] = PR_getuid,
+	[ 103 ] = PR_syslog,
+	[ 104 ] = PR_getgid,
+	[ 105 ] = PR_setuid,
+	[ 106 ] = PR_setgid,
+	[ 107 ] = PR_geteuid,
+	[ 108 ] = PR_getegid,
+	[ 109 ] = PR_setpgid,
+	[ 110 ] = PR_getppid,
+	[ 111 ] = PR_getpgrp,
+	[ 112 ] = PR_setsid,
+	[ 113 ] = PR_setreuid,
+	[ 114 ] = PR_setregid,
+	[ 115 ] = PR_getgroups,
+	[ 116 ] = PR_setgroups,
+	[ 117 ] = PR_setresuid,
+	[ 118 ] = PR_getresuid,
+	[ 119 ] = PR_setresgid,
+	[ 120 ] = PR_getresgid,
+	[ 121 ] = PR_getpgid,
+	[ 122 ] = PR_setfsuid,
+	[ 123 ] = PR_setfsgid,
+	[ 124 ] = PR_getsid,
+	[ 125 ] = PR_capget,
+	[ 126 ] = PR_capset,
+	[ 127 ] = PR_rt_sigpending,
+	[ 128 ] = PR_rt_sigtimedwait,
+	[ 129 ] = PR_rt_sigqueueinfo,
+	[ 130 ] = PR_rt_sigsuspend,
+	[ 131 ] = PR_sigaltstack,
+	[ 132 ] = PR_utime,
+	[ 133 ] = PR_mknod,
+	[ 134 ] = PR_uselib,
+	[ 135 ] = PR_personality,
+	[ 136 ] = PR_ustat,
+	[ 137 ] = PR_statfs,
+	[ 138 ] = PR_fstatfs,
+	[ 139 ] = PR_sysfs,
+	[ 140 ] = PR_getpriority,
+	[ 141 ] = PR_setpriority,
+	[ 142 ] = PR_sched_setparam,
+	[ 143 ] = PR_sched_getparam,
+	[ 144 ] = PR_sched_setscheduler,
+	[ 145 ] = PR_sched_getscheduler,
+	[ 146 ] = PR_sched_get_priority_max,
+	[ 147 ] = PR_sched_get_priority_min,
+	[ 148 ] = PR_sched_rr_get_interval,
+	[ 149 ] = PR_mlock,
+	[ 150 ] = PR_munlock,
+	[ 151 ] = PR_mlockall,
+	[ 152 ] = PR_munlockall,
+	[ 153 ] = PR_vhangup,
+	[ 154 ] = PR_modify_ldt,
+	[ 155 ] = PR_pivot_root,
+	[ 156 ] = PR__sysctl,
+	[ 157 ] = PR_prctl,
+	[ 158 ] = PR_arch_prctl,
+	[ 159 ] = PR_adjtimex,
+	[ 160 ] = PR_setrlimit,
+	[ 161 ] = PR_chroot,
+	[ 162 ] = PR_sync,
+	[ 163 ] = PR_acct,
+	[ 164 ] = PR_settimeofday,
+	[ 165 ] = PR_mount,
+	[ 166 ] = PR_umount2,
+	[ 167 ] = PR_swapon,
+	[ 168 ] = PR_swapoff,
+	[ 169 ] = PR_reboot,
+	[ 170 ] = PR_sethostname,
+	[ 171 ] = PR_setdomainname,
+	[ 172 ] = PR_iopl,
+	[ 173 ] = PR_ioperm,
+	[ 174 ] = PR_create_module,
+	[ 175 ] = PR_init_module,
+	[ 176 ] = PR_delete_module,
+	[ 177 ] = PR_get_kernel_syms,
+	[ 178 ] = PR_query_module,
+	[ 179 ] = PR_quotactl,
+	[ 180 ] = PR_nfsservctl,
+	[ 181 ] = PR_getpmsg,
+	[ 182 ] = PR_putpmsg,
+	[ 183 ] = PR_afs_syscall,
+	[ 184 ] = PR_tuxcall,
+	[ 185 ] = PR_security,
+	[ 186 ] = PR_gettid,
+	[ 187 ] = PR_readahead,
+	[ 188 ] = PR_setxattr,
+	[ 189 ] = PR_lsetxattr,
+	[ 190 ] = PR_fsetxattr,
+	[ 191 ] = PR_getxattr,
+	[ 192 ] = PR_lgetxattr,
+	[ 193 ] = PR_fgetxattr,
+	[ 194 ] = PR_listxattr,
+	[ 195 ] = PR_llistxattr,
+	[ 196 ] = PR_flistxattr,
+	[ 197 ] = PR_removexattr,
+	[ 198 ] = PR_lremovexattr,
+	[ 199 ] = PR_fremovexattr,
+	[ 200 ] = PR_tkill,
+	[ 201 ] = PR_time,
+	[ 202 ] = PR_futex,
+	[ 203 ] = PR_sched_setaffinity,
+	[ 204 ] = PR_sched_getaffinity,
+	[ 205 ] = PR_set_thread_area,
+	[ 206 ] = PR_io_setup,
+	[ 207 ] = PR_io_destroy,
+	[ 208 ] = PR_io_getevents,
+	[ 209 ] = PR_io_submit,
+	[ 210 ] = PR_io_cancel,
+	[ 211 ] = PR_get_thread_area,
+	[ 212 ] = PR_lookup_dcookie,
+	[ 213 ] = PR_epoll_create,
+	[ 214 ] = PR_epoll_ctl_old,
+	[ 215 ] = PR_epoll_wait_old,
+	[ 216 ] = PR_remap_file_pages,
+	[ 217 ] = PR_getdents64,
+	[ 218 ] = PR_set_tid_address,
+	[ 219 ] = PR_restart_syscall,
+	[ 220 ] = PR_semtimedop,
+	[ 221 ] = PR_fadvise64,
+	[ 222 ] = PR_timer_create,
+	[ 223 ] = PR_timer_settime,
+	[ 224 ] = PR_timer_gettime,
+	[ 225 ] = PR_timer_getoverrun,
+	[ 226 ] = PR_timer_delete,
+	[ 227 ] = PR_clock_settime,
+	[ 228 ] = PR_clock_gettime,
+	[ 229 ] = PR_clock_getres,
+	[ 230 ] = PR_clock_nanosleep,
+	[ 231 ] = PR_exit_group,
+	[ 232 ] = PR_epoll_wait,
+	[ 233 ] = PR_epoll_ctl,
+	[ 234 ] = PR_tgkill,
+	[ 235 ] = PR_utimes,
+	[ 236 ] = PR_vserver,
+	[ 237 ] = PR_mbind,
+	[ 238 ] = PR_set_mempolicy,
+	[ 239 ] = PR_get_mempolicy,
+	[ 240 ] = PR_mq_open,
+	[ 241 ] = PR_mq_unlink,
+	[ 242 ] = PR_mq_timedsend,
+	[ 243 ] = PR_mq_timedreceive,
+	[ 244 ] = PR_mq_notify,
+	[ 245 ] = PR_mq_getsetattr,
+	[ 246 ] = PR_kexec_load,
+	[ 247 ] = PR_waitid,
+	[ 248 ] = PR_add_key,
+	[ 249 ] = PR_request_key,
+	[ 250 ] = PR_keyctl,
+	[ 251 ] = PR_ioprio_set,
+	[ 252 ] = PR_ioprio_get,
+	[ 253 ] = PR_inotify_init,
+	[ 254 ] = PR_inotify_add_watch,
+	[ 255 ] = PR_inotify_rm_watch,
+	[ 256 ] = PR_migrate_pages,
+	[ 257 ] = PR_openat,
+	[ 258 ] = PR_mkdirat,
+	[ 259 ] = PR_mknodat,
+	[ 260 ] = PR_fchownat,
+	[ 261 ] = PR_futimesat,
+	[ 262 ] = PR_newfstatat,
+	[ 263 ] = PR_unlinkat,
+	[ 264 ] = PR_renameat,
+	[ 265 ] = PR_linkat,
+	[ 266 ] = PR_symlinkat,
+	[ 267 ] = PR_readlinkat,
+	[ 268 ] = PR_fchmodat,
+	[ 269 ] = PR_faccessat,
+	[ 270 ] = PR_pselect6,
+	[ 271 ] = PR_ppoll,
+	[ 272 ] = PR_unshare,
+	[ 273 ] = PR_set_robust_list,
+	[ 274 ] = PR_get_robust_list,
+	[ 275 ] = PR_splice,
+	[ 276 ] = PR_tee,
+	[ 277 ] = PR_sync_file_range,
+	[ 278 ] = PR_vmsplice,
+	[ 279 ] = PR_move_pages,
+	[ 280 ] = PR_utimensat,
+	[ 281 ] = PR_epoll_pwait,
+	[ 282 ] = PR_signalfd,
+	[ 283 ] = PR_timerfd_create,
+	[ 284 ] = PR_eventfd,
+	[ 285 ] = PR_fallocate,
+	[ 286 ] = PR_timerfd_settime,
+	[ 287 ] = PR_timerfd_gettime,
+	[ 288 ] = PR_accept4,
+	[ 289 ] = PR_signalfd4,
+	[ 290 ] = PR_eventfd2,
+	[ 291 ] = PR_epoll_create1,
+	[ 292 ] = PR_dup3,
+	[ 293 ] = PR_pipe2,
+	[ 294 ] = PR_inotify_init1,
+	[ 295 ] = PR_preadv,
+	[ 296 ] = PR_pwritev,
+	[ 297 ] = PR_rt_tgsigqueueinfo,
+	[ 298 ] = PR_perf_event_open,
+	[ 299 ] = PR_recvmmsg,
+	[ 300 ] = PR_fanotify_init,
+	[ 301 ] = PR_fanotify_mark,
+	[ 302 ] = PR_prlimit64,
+	[ 303 ] = PR_name_to_handle_at,
+	[ 304 ] = PR_open_by_handle_at,
+	[ 305 ] = PR_clock_adjtime,
+	[ 306 ] = PR_syncfs,
+	[ 307 ] = PR_sendmmsg,
+	[ 308 ] = PR_setns,
+	[ 309 ] = PR_getcpu,
+	[ 310 ] = PR_process_vm_readv,
+	[ 311 ] = PR_process_vm_writev,
+	[ 312 ] = PR_kcmp,
+	[ 313 ] = PR_finit_module,
+	[ 314 ] = PR_sched_setattr,
+	[ 315 ] = PR_sched_getattr,
+	[ 316 ] = PR_renameat2,
+};
diff --git a/5.1.0/src/syscall/sysnums.list b/5.1.0/src/syscall/sysnums.list
new file mode 100644
index 0000000..7bdc731
--- /dev/null
+++ b/5.1.0/src/syscall/sysnums.list
@@ -0,0 +1,430 @@
+SYSNUM(ARM_BASE)
+SYSNUM(ARM_breakpoint)
+SYSNUM(ARM_cacheflush)
+SYSNUM(ARM_set_tls)
+SYSNUM(ARM_usr26)
+SYSNUM(ARM_usr32)
+SYSNUM(X32_SYSCALL_BIT)
+SYSNUM(_llseek)
+SYSNUM(_newselect)
+SYSNUM(_sysctl)
+SYSNUM(accept)
+SYSNUM(accept4)
+SYSNUM(access)
+SYSNUM(acct)
+SYSNUM(add_key)
+SYSNUM(adjtimex)
+SYSNUM(afs_syscall)
+SYSNUM(alarm)
+SYSNUM(arch_prctl)
+SYSNUM(arch_specific_syscall)
+SYSNUM(arm_fadvise64_64)
+SYSNUM(arm_sync_file_range)
+SYSNUM(bdflush)
+SYSNUM(bind)
+SYSNUM(break)
+SYSNUM(brk)
+SYSNUM(cacheflush)
+SYSNUM(capget)
+SYSNUM(capset)
+SYSNUM(chdir)
+SYSNUM(chmod)
+SYSNUM(chown)
+SYSNUM(chown32)
+SYSNUM(chroot)
+SYSNUM(clock_adjtime)
+SYSNUM(clock_getres)
+SYSNUM(clock_gettime)
+SYSNUM(clock_nanosleep)
+SYSNUM(clock_settime)
+SYSNUM(clone)
+SYSNUM(close)
+SYSNUM(connect)
+SYSNUM(creat)
+SYSNUM(create_module)
+SYSNUM(delete_module)
+SYSNUM(dup)
+SYSNUM(dup2)
+SYSNUM(dup3)
+SYSNUM(epoll_create)
+SYSNUM(epoll_create1)
+SYSNUM(epoll_ctl)
+SYSNUM(epoll_ctl_old)
+SYSNUM(epoll_pwait)
+SYSNUM(epoll_wait)
+SYSNUM(epoll_wait_old)
+SYSNUM(eventfd)
+SYSNUM(eventfd2)
+SYSNUM(execve)
+SYSNUM(exit)
+SYSNUM(exit_group)
+SYSNUM(faccessat)
+SYSNUM(fadvise64)
+SYSNUM(fadvise64_64)
+SYSNUM(fallocate)
+SYSNUM(fanotify_init)
+SYSNUM(fanotify_mark)
+SYSNUM(fchdir)
+SYSNUM(fchmod)
+SYSNUM(fchmodat)
+SYSNUM(fchown)
+SYSNUM(fchown32)
+SYSNUM(fchownat)
+SYSNUM(fcntl)
+SYSNUM(fcntl64)
+SYSNUM(fdatasync)
+SYSNUM(fgetxattr)
+SYSNUM(finit_module)
+SYSNUM(flistxattr)
+SYSNUM(flock)
+SYSNUM(fork)
+SYSNUM(fremovexattr)
+SYSNUM(fsetxattr)
+SYSNUM(fstat)
+SYSNUM(fstat64)
+SYSNUM(fstatat64)
+SYSNUM(fstatfs)
+SYSNUM(fstatfs64)
+SYSNUM(fsync)
+SYSNUM(ftime)
+SYSNUM(ftruncate)
+SYSNUM(ftruncate64)
+SYSNUM(futex)
+SYSNUM(futimesat)
+SYSNUM(get_kernel_syms)
+SYSNUM(get_mempolicy)
+SYSNUM(get_robust_list)
+SYSNUM(get_thread_area)
+SYSNUM(getcpu)
+SYSNUM(getcwd)
+SYSNUM(getdents)
+SYSNUM(getdents64)
+SYSNUM(getegid)
+SYSNUM(getegid32)
+SYSNUM(geteuid)
+SYSNUM(geteuid32)
+SYSNUM(getgid)
+SYSNUM(getgid32)
+SYSNUM(getgroups)
+SYSNUM(getgroups32)
+SYSNUM(getitimer)
+SYSNUM(getpeername)
+SYSNUM(getpgid)
+SYSNUM(getpgrp)
+SYSNUM(getpid)
+SYSNUM(getpmsg)
+SYSNUM(getppid)
+SYSNUM(getpriority)
+SYSNUM(getresgid)
+SYSNUM(getresgid32)
+SYSNUM(getresuid)
+SYSNUM(getresuid32)
+SYSNUM(getrlimit)
+SYSNUM(getrusage)
+SYSNUM(getsid)
+SYSNUM(getsockname)
+SYSNUM(getsockopt)
+SYSNUM(gettid)
+SYSNUM(gettimeofday)
+SYSNUM(getuid)
+SYSNUM(getuid32)
+SYSNUM(getxattr)
+SYSNUM(gtty)
+SYSNUM(idle)
+SYSNUM(init_module)
+SYSNUM(inotify_add_watch)
+SYSNUM(inotify_init)
+SYSNUM(inotify_init1)
+SYSNUM(inotify_rm_watch)
+SYSNUM(io_cancel)
+SYSNUM(io_destroy)
+SYSNUM(io_getevents)
+SYSNUM(io_setup)
+SYSNUM(io_submit)
+SYSNUM(ioctl)
+SYSNUM(ioperm)
+SYSNUM(iopl)
+SYSNUM(ioprio_get)
+SYSNUM(ioprio_set)
+SYSNUM(ipc)
+SYSNUM(kcmp)
+SYSNUM(kexec_load)
+SYSNUM(keyctl)
+SYSNUM(kill)
+SYSNUM(lchown)
+SYSNUM(lchown32)
+SYSNUM(lgetxattr)
+SYSNUM(link)
+SYSNUM(linkat)
+SYSNUM(listen)
+SYSNUM(listxattr)
+SYSNUM(llistxattr)
+SYSNUM(lock)
+SYSNUM(lookup_dcookie)
+SYSNUM(lremovexattr)
+SYSNUM(lseek)
+SYSNUM(lsetxattr)
+SYSNUM(lstat)
+SYSNUM(lstat64)
+SYSNUM(madvise)
+SYSNUM(mbind)
+SYSNUM(migrate_pages)
+SYSNUM(mincore)
+SYSNUM(mkdir)
+SYSNUM(mkdirat)
+SYSNUM(mknod)
+SYSNUM(mknodat)
+SYSNUM(mlock)
+SYSNUM(mlockall)
+SYSNUM(mmap)
+SYSNUM(mmap2)
+SYSNUM(modify_ldt)
+SYSNUM(mount)
+SYSNUM(move_pages)
+SYSNUM(mprotect)
+SYSNUM(mpx)
+SYSNUM(mq_getsetattr)
+SYSNUM(mq_notify)
+SYSNUM(mq_open)
+SYSNUM(mq_timedreceive)
+SYSNUM(mq_timedsend)
+SYSNUM(mq_unlink)
+SYSNUM(mremap)
+SYSNUM(msgctl)
+SYSNUM(msgget)
+SYSNUM(msgrcv)
+SYSNUM(msgsnd)
+SYSNUM(msync)
+SYSNUM(munlock)
+SYSNUM(munlockall)
+SYSNUM(munmap)
+SYSNUM(name_to_handle_at)
+SYSNUM(nanosleep)
+SYSNUM(newfstatat)
+SYSNUM(nfsservctl)
+SYSNUM(nice)
+SYSNUM(oldfstat)
+SYSNUM(oldlstat)
+SYSNUM(oldolduname)
+SYSNUM(oldstat)
+SYSNUM(olduname)
+SYSNUM(open)
+SYSNUM(open_by_handle_at)
+SYSNUM(openat)
+SYSNUM(pause)
+SYSNUM(pciconfig_iobase)
+SYSNUM(pciconfig_read)
+SYSNUM(pciconfig_write)
+SYSNUM(perf_event_open)
+SYSNUM(personality)
+SYSNUM(pipe)
+SYSNUM(pipe2)
+SYSNUM(pivot_root)
+SYSNUM(poll)
+SYSNUM(ppoll)
+SYSNUM(prctl)
+SYSNUM(pread64)
+SYSNUM(preadv)
+SYSNUM(prlimit64)
+SYSNUM(process_vm_readv)
+SYSNUM(process_vm_writev)
+SYSNUM(prof)
+SYSNUM(profil)
+SYSNUM(pselect6)
+SYSNUM(ptrace)
+SYSNUM(putpmsg)
+SYSNUM(pwrite64)
+SYSNUM(pwritev)
+SYSNUM(query_module)
+SYSNUM(quotactl)
+SYSNUM(read)
+SYSNUM(readahead)
+SYSNUM(readdir)
+SYSNUM(readlink)
+SYSNUM(readlinkat)
+SYSNUM(readv)
+SYSNUM(reboot)
+SYSNUM(recv)
+SYSNUM(recvfrom)
+SYSNUM(recvmmsg)
+SYSNUM(recvmsg)
+SYSNUM(remap_file_pages)
+SYSNUM(removexattr)
+SYSNUM(rename)
+SYSNUM(renameat)
+SYSNUM(renameat2)
+SYSNUM(request_key)
+SYSNUM(restart_syscall)
+SYSNUM(rmdir)
+SYSNUM(rt_sigaction)
+SYSNUM(rt_sigpending)
+SYSNUM(rt_sigprocmask)
+SYSNUM(rt_sigqueueinfo)
+SYSNUM(rt_sigreturn)
+SYSNUM(rt_sigsuspend)
+SYSNUM(rt_sigtimedwait)
+SYSNUM(rt_tgsigqueueinfo)
+SYSNUM(sched_get_priority_max)
+SYSNUM(sched_get_priority_min)
+SYSNUM(sched_getaffinity)
+SYSNUM(sched_getattr)
+SYSNUM(sched_getparam)
+SYSNUM(sched_getscheduler)
+SYSNUM(sched_rr_get_interval)
+SYSNUM(sched_setaffinity)
+SYSNUM(sched_setattr)
+SYSNUM(sched_setparam)
+SYSNUM(sched_setscheduler)
+SYSNUM(sched_yield)
+SYSNUM(security)
+SYSNUM(select)
+SYSNUM(semctl)
+SYSNUM(semget)
+SYSNUM(semop)
+SYSNUM(semtimedop)
+SYSNUM(send)
+SYSNUM(sendfile)
+SYSNUM(sendfile64)
+SYSNUM(sendmmsg)
+SYSNUM(sendmsg)
+SYSNUM(sendto)
+SYSNUM(set_mempolicy)
+SYSNUM(set_robust_list)
+SYSNUM(set_thread_area)
+SYSNUM(set_tid_address)
+SYSNUM(setdomainname)
+SYSNUM(setfsgid)
+SYSNUM(setfsgid32)
+SYSNUM(setfsuid)
+SYSNUM(setfsuid32)
+SYSNUM(setgid)
+SYSNUM(setgid32)
+SYSNUM(setgroups)
+SYSNUM(setgroups32)
+SYSNUM(sethostname)
+SYSNUM(setitimer)
+SYSNUM(setns)
+SYSNUM(setpgid)
+SYSNUM(setpriority)
+SYSNUM(setregid)
+SYSNUM(setregid32)
+SYSNUM(setresgid)
+SYSNUM(setresgid32)
+SYSNUM(setresuid)
+SYSNUM(setresuid32)
+SYSNUM(setreuid)
+SYSNUM(setreuid32)
+SYSNUM(setrlimit)
+SYSNUM(setsid)
+SYSNUM(setsockopt)
+SYSNUM(settimeofday)
+SYSNUM(setuid)
+SYSNUM(setuid32)
+SYSNUM(setxattr)
+SYSNUM(sgetmask)
+SYSNUM(shmat)
+SYSNUM(shmctl)
+SYSNUM(shmdt)
+SYSNUM(shmget)
+SYSNUM(shutdown)
+SYSNUM(sigaction)
+SYSNUM(sigaltstack)
+SYSNUM(signal)
+SYSNUM(signalfd)
+SYSNUM(signalfd4)
+SYSNUM(sigpending)
+SYSNUM(sigprocmask)
+SYSNUM(sigreturn)
+SYSNUM(sigsuspend)
+SYSNUM(socket)
+SYSNUM(socketcall)
+SYSNUM(socketpair)
+SYSNUM(splice)
+SYSNUM(ssetmask)
+SYSNUM(stat)
+SYSNUM(stat64)
+SYSNUM(statfs)
+SYSNUM(statfs64)
+SYSNUM(stime)
+SYSNUM(stty)
+SYSNUM(swapoff)
+SYSNUM(swapon)
+SYSNUM(symlink)
+SYSNUM(symlinkat)
+SYSNUM(sync)
+SYSNUM(sync_file_range)
+SYSNUM(sync_file_range2)
+SYSNUM(syncfs)
+SYSNUM(sysfs)
+SYSNUM(sysinfo)
+SYSNUM(syslog)
+SYSNUM(tee)
+SYSNUM(tgkill)
+SYSNUM(time)
+SYSNUM(timer_create)
+SYSNUM(timer_delete)
+SYSNUM(timer_getoverrun)
+SYSNUM(timer_gettime)
+SYSNUM(timer_settime)
+SYSNUM(timerfd_create)
+SYSNUM(timerfd_gettime)
+SYSNUM(timerfd_settime)
+SYSNUM(times)
+SYSNUM(tkill)
+SYSNUM(truncate)
+SYSNUM(truncate64)
+SYSNUM(tuxcall)
+SYSNUM(ugetrlimit)
+SYSNUM(ulimit)
+SYSNUM(umask)
+SYSNUM(umount)
+SYSNUM(umount2)
+SYSNUM(uname)
+SYSNUM(unlink)
+SYSNUM(unlinkat)
+SYSNUM(unshare)
+SYSNUM(uselib)
+SYSNUM(ustat)
+SYSNUM(utime)
+SYSNUM(utimensat)
+SYSNUM(utimes)
+SYSNUM(vfork)
+SYSNUM(vhangup)
+SYSNUM(vm86)
+SYSNUM(vm86old)
+SYSNUM(vmsplice)
+SYSNUM(vserver)
+SYSNUM(wait4)
+SYSNUM(waitid)
+SYSNUM(waitpid)
+SYSNUM(write)
+SYSNUM(writev)
+SYSNUM(x32_execve)
+SYSNUM(x32_get_robust_list)
+SYSNUM(x32_ioctl)
+SYSNUM(x32_kexec_load)
+SYSNUM(x32_move_pages)
+SYSNUM(x32_mq_notify)
+SYSNUM(x32_preadv)
+SYSNUM(x32_process_vm_readv)
+SYSNUM(x32_process_vm_writev)
+SYSNUM(x32_ptrace)
+SYSNUM(x32_pwritev)
+SYSNUM(x32_readv)
+SYSNUM(x32_recvfrom)
+SYSNUM(x32_recvmmsg)
+SYSNUM(x32_recvmsg)
+SYSNUM(x32_rt_sigaction)
+SYSNUM(x32_rt_sigpending)
+SYSNUM(x32_rt_sigqueueinfo)
+SYSNUM(x32_rt_sigreturn)
+SYSNUM(x32_rt_sigtimedwait)
+SYSNUM(x32_rt_tgsigqueueinfo)
+SYSNUM(x32_sendmmsg)
+SYSNUM(x32_sendmsg)
+SYSNUM(x32_set_robust_list)
+SYSNUM(x32_sigaltstack)
+SYSNUM(x32_timer_create)
+SYSNUM(x32_vmsplice)
+SYSNUM(x32_waitid)
+SYSNUM(x32_writev)
diff --git a/5.1.0/src/tracee/abi.h b/5.1.0/src/tracee/abi.h
new file mode 100644
index 0000000..51191e9
--- /dev/null
+++ b/5.1.0/src/tracee/abi.h
@@ -0,0 +1,131 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef TRACEE_ABI_H
+#define TRACEE_ABI_H
+
+#include <stdbool.h>
+#include <stddef.h> /* offsetof(),  */
+
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "arch.h"
+
+#include "attribute.h"
+
+typedef enum {
+	ABI_DEFAULT = 0,
+	ABI_2, /* x86_32 on x86_64.  */
+	ABI_3, /* x32 on x86_64.  */
+	NB_MAX_ABIS,
+} Abi;
+
+/**
+ * Return the ABI currently used by the given @tracee.
+ */
+#if defined(ARCH_X86_64)
+static inline Abi get_abi(const Tracee *tracee)
+{
+	/* The ABI can be changed by a syscall ("execve" typically),
+	 * however the change is only effective once the syscall has
+	 * *fully* returned, hence the use of _regs[ORIGINAL].  */
+	switch (tracee->_regs[ORIGINAL].cs) {
+	case 0x23:
+		return ABI_2;
+
+	case 0x33:
+		if (tracee->_regs[ORIGINAL].ds == 0x2B)
+			return ABI_3;
+		/* Fall through.  */
+	default:
+		return ABI_DEFAULT;
+	}
+}
+
+/**
+ * Return true if @tracee is a 32-bit process running on a 64-bit
+ * kernel.
+ */
+static inline bool is_32on64_mode(const Tracee *tracee)
+{
+	/* Unlike the ABI, 32-bit/64-bit mode change is effective
+	 * immediately, hence _regs[CURRENT].cs.  */
+	switch (tracee->_regs[CURRENT].cs) {
+	case 0x23:
+		return true;
+
+	case 0x33:
+		if (tracee->_regs[CURRENT].ds == 0x2B)
+			return true;
+		/* Fall through.  */
+	default:
+		return false;
+	}
+}
+#else
+static inline Abi get_abi(const Tracee *tracee UNUSED)
+{
+	return ABI_DEFAULT;
+}
+
+static inline bool is_32on64_mode(const Tracee *tracee UNUSED)
+{
+	return false;
+}
+#endif
+
+/**
+ * Return the size of a word according to the ABI currently used by
+ * the given @tracee.
+ */
+static inline size_t sizeof_word(const Tracee *tracee)
+{
+	return (is_32on64_mode(tracee)
+		? sizeof(word_t) / 2
+		: sizeof(word_t));
+}
+
+#include <sys/stat.h>
+
+/**
+ * Return the offset of the 'uid' field in a 'stat' structure
+ * according to the ABI currently used by the given @tracee.
+ */
+static inline off_t offsetof_stat_uid(const Tracee *tracee)
+{
+	return (is_32on64_mode(tracee)
+		? OFFSETOF_STAT_UID_32
+		: offsetof(struct stat, st_uid));
+}
+
+/**
+ * Return the offset of the 'gid' field in a 'stat' structure
+ * according to the ABI currently used by the given @tracee.
+ */
+static inline off_t offsetof_stat_gid(const Tracee *tracee)
+{
+	return (is_32on64_mode(tracee)
+		? OFFSETOF_STAT_GID_32
+		: offsetof(struct stat, st_gid));
+}
+
+#endif /* TRACEE_ABI_H */
diff --git a/5.1.0/src/tracee/event.c b/5.1.0/src/tracee/event.c
new file mode 100644
index 0000000..bafc3c5
--- /dev/null
+++ b/5.1.0/src/tracee/event.c
@@ -0,0 +1,602 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sched.h>      /* CLONE_*,  */
+#include <sys/types.h>  /* pid_t, */
+#include <sys/ptrace.h> /* ptrace(1), PTRACE_*, */
+#include <sys/types.h>  /* waitpid(2), */
+#include <sys/wait.h>   /* waitpid(2), */
+#include <sys/utsname.h> /* uname(2), */
+#include <unistd.h>     /* fork(2), chdir(2), getpid(2), */
+#include <string.h>     /* strcmp(3), */
+#include <errno.h>      /* errno(3), */
+#include <stdbool.h>    /* bool, true, false, */
+#include <assert.h>     /* assert(3), */
+#include <stdlib.h>     /* atexit(3), getenv(3), */
+#include <talloc.h>     /* talloc_*, */
+
+#include "tracee/event.h"
+#include "cli/note.h"
+#include "path/path.h"
+#include "path/binding.h"
+#include "syscall/syscall.h"
+#include "syscall/seccomp.h"
+#include "ptrace/wait.h"
+#include "extension/extension.h"
+#include "execve/elf.h"
+
+#include "attribute.h"
+#include "compat.h"
+
+/**
+ * Start @tracee->exe with the given @argv[].  This function
+ * returns -errno if an error occurred, otherwise 0.
+ */
+int launch_process(Tracee *tracee, char *const argv[])
+{
+	char *const default_argv[] = { "-sh", NULL };
+	long status;
+	pid_t pid;
+
+	/* Warn about open file descriptors. They won't be
+	 * translated until they are closed. */
+	if (tracee->verbose > 0)
+		list_open_fd(tracee);
+
+	pid = fork();
+	switch(pid) {
+	case -1:
+		note(tracee, ERROR, SYSTEM, "fork()");
+		return -errno;
+
+	case 0: /* child */
+		/* Declare myself as ptraceable before executing the
+		 * requested program. */
+		status = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+		if (status < 0) {
+			note(tracee, ERROR, SYSTEM, "ptrace(TRACEME)");
+			return -errno;
+		}
+
+		/* Synchronize with the tracer's event loop.  Without
+		 * this trick the tracer only sees the "return" from
+		 * the next execve(2) so PRoot wouldn't handle the
+		 * interpreter/runner.  I also verified that strace
+		 * does the same thing. */
+		kill(getpid(), SIGSTOP);
+
+		/* Improve performance by using seccomp mode 2, unless
+		 * this support is explicitly disabled.  */
+		if (getenv("PROOT_NO_SECCOMP") == NULL)
+			(void) enable_syscall_filtering(tracee);
+
+		/* Now process is ptraced, so the current rootfs is already the
+		 * guest rootfs.  Note: Valgrind can't handle execve(2) on
+		 * "foreign" binaries (ENOEXEC) but can handle execvp(3) on such
+		 * binaries.  */
+		execvp(tracee->exe, argv[0] != NULL ? argv : default_argv);
+		return -errno;
+
+	default: /* parent */
+		/* We know the pid of the first tracee now.  */
+		tracee->pid = pid;
+		return 0;
+	}
+
+	/* Never reached.  */
+	return -ENOSYS;
+}
+
+/* Send the KILL signal to all tracees when PRoot has received a fatal
+ * signal.  */
+static void kill_all_tracees2(int signum, siginfo_t *siginfo UNUSED, void *ucontext UNUSED)
+{
+	note(NULL, WARNING, INTERNAL, "signal %d received from process %d",
+		signum, siginfo->si_pid);
+	kill_all_tracees();
+
+	/* Exit immediately for system signals (segmentation fault,
+	 * illegal instruction, ...), otherwise exit cleanly through
+	 * the event loop.  */
+	if (signum != SIGQUIT)
+		_exit(EXIT_FAILURE);
+}
+
+/**
+ * Helper for print_talloc_hierarchy().
+ */
+static void print_talloc_chunk(const void *ptr, int depth, int max_depth UNUSED,
+			int is_ref, void *data UNUSED)
+{
+	const char *name;
+	size_t count;
+	size_t size;
+
+	name = talloc_get_name(ptr);
+	size = talloc_get_size(ptr);
+	count = talloc_reference_count(ptr);
+
+	if (depth == 0)
+		return;
+
+	while (depth-- > 1)
+		fprintf(stderr, "\t");
+
+	fprintf(stderr, "%-16s ", name);
+
+	if (is_ref)
+		fprintf(stderr, "-> %-8p", ptr);
+	else {
+		fprintf(stderr, "%-8p  %zd bytes  %zd ref'", ptr, size, count);
+
+		if (name[0] == '$') {
+			fprintf(stderr, "\t(\"%s\")", (char *)ptr);
+		}
+		if (name[0] == '@') {
+			char **argv;
+			int i;
+
+			fprintf(stderr, "\t(");
+			for (i = 0, argv = (char **)ptr; argv[i] != NULL; i++)
+				fprintf(stderr, "\"%s\", ", argv[i]);
+			fprintf(stderr, ")");
+		}
+		else if (strcmp(name, "Tracee") == 0) {
+			fprintf(stderr, "\t(pid = %d, parent = %p)",
+				((Tracee *)ptr)->pid, ((Tracee *)ptr)->parent);
+		}
+		else if (strcmp(name, "Bindings") == 0) {
+			Tracee *tracee;
+
+			tracee = TRACEE(ptr);
+
+			if (ptr == tracee->fs->bindings.pending)
+				fprintf(stderr, "\t(pending)");
+			else if (ptr == tracee->fs->bindings.guest)
+				fprintf(stderr, "\t(guest)");
+			else if (ptr == tracee->fs->bindings.host)
+				fprintf(stderr, "\t(host)");
+		}
+		else if (strcmp(name, "Binding") == 0) {
+			Binding *binding = (Binding *)ptr;
+			fprintf(stderr, "\t(%s:%s)", binding->host.path, binding->guest.path);
+		}
+	}
+
+	fprintf(stderr, "\n");
+}
+
+/* Print on stderr the complete talloc hierarchy.  */
+static void print_talloc_hierarchy(int signum, siginfo_t *siginfo UNUSED, void *ucontext UNUSED)
+{
+	switch (signum) {
+	case SIGUSR1:
+		talloc_report_depth_cb(NULL, 0, 100, print_talloc_chunk, NULL);
+		break;
+
+	case SIGUSR2:
+		talloc_report_depth_file(NULL, 0, 100, stderr);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int last_exit_status = -1;
+
+/**
+ * Check if this instance of PRoot can *technically* handle @tracee.
+ */
+static void check_architecture(Tracee *tracee)
+{
+	struct utsname utsname;
+	ElfHeader elf_header;
+	char path[PATH_MAX];
+	int status;
+
+	if (tracee->exe == NULL)
+		return;
+
+	status = translate_path(tracee, path, AT_FDCWD, tracee->exe, false);
+	if (status < 0)
+		return;
+
+	status = open_elf(path, &elf_header);
+	if (status < 0)
+		return;
+	close(status);
+
+	if (!IS_CLASS64(elf_header) || sizeof(word_t) == sizeof(uint64_t))
+		return;
+
+	note(tracee, ERROR, USER,
+		"'%s' is a 64-bit program whereas this version of "
+		"%s handles 32-bit programs only", path, tracee->tool_name);
+
+	status = uname(&utsname);
+	if (status < 0)
+		return;
+
+	if (strcmp(utsname.machine, "x86_64") != 0)
+		return;
+
+	note(tracee, INFO, USER,
+		"Get a 64-bit version that supports 32-bit binaries here: "
+		"http://static.proot.me/proot-x86_64");
+}
+
+/**
+ * Wait then handle any event from any tracee.  This function returns
+ * the exit status of the last terminated program.
+ */
+int event_loop()
+{
+	struct sigaction signal_action;
+	long status;
+	int signum;
+
+	/* Kill all tracees when exiting.  */
+	status = atexit(kill_all_tracees);
+	if (status != 0)
+		note(NULL, WARNING, INTERNAL, "atexit() failed");
+
+	/* All signals are blocked when the signal handler is called.
+	 * SIGINFO is used to know which process has signaled us and
+	 * RESTART is used to restart waitpid(2) seamlessly.  */
+	bzero(&signal_action, sizeof(signal_action));
+	signal_action.sa_flags = SA_SIGINFO | SA_RESTART;
+	status = sigfillset(&signal_action.sa_mask);
+	if (status < 0)
+		note(NULL, WARNING, SYSTEM, "sigfillset()");
+
+	/* Handle all signals.  */
+	for (signum = 0; signum < SIGRTMAX; signum++) {
+		switch (signum) {
+		case SIGQUIT:
+		case SIGILL:
+		case SIGABRT:
+		case SIGFPE:
+		case SIGSEGV:
+			/* Kill all tracees on abnormal termination
+			 * signals.  This ensures no process is left
+			 * untraced.  */
+			signal_action.sa_sigaction = kill_all_tracees2;
+			break;
+
+		case SIGUSR1:
+		case SIGUSR2:
+			/* Print on stderr the complete talloc
+			 * hierarchy, useful for debug purpose.  */
+			signal_action.sa_sigaction = print_talloc_hierarchy;
+			break;
+
+		case SIGCHLD:
+		case SIGCONT:
+		case SIGSTOP:
+		case SIGTSTP:
+		case SIGTTIN:
+		case SIGTTOU:
+			/* The default action is OK for these signals,
+			 * they are related to tty and job control.  */
+			continue;
+
+		default:
+			/* Ignore all other signals, including
+			 * terminating ones (^C for instance). */
+			signal_action.sa_sigaction = (void *)SIG_IGN;
+			break;
+		}
+
+		status = sigaction(signum, &signal_action, NULL);
+		if (status < 0 && errno != EINVAL)
+			note(NULL, WARNING, SYSTEM, "sigaction(%d)", signum);
+	}
+
+	while (1) {
+		int tracee_status;
+		Tracee *tracee;
+		int signal;
+		pid_t pid;
+
+		/* This is the only safe place to free tracees.  */
+		free_terminated_tracees();
+
+		/* Wait for the next tracee's stop. */
+		pid = waitpid(-1, &tracee_status, __WALL);
+		if (pid < 0) {
+			if (errno != ECHILD) {
+				note(NULL, ERROR, SYSTEM, "waitpid()");
+				return EXIT_FAILURE;
+			}
+			break;
+		}
+
+		/* Get information about this tracee. */
+		tracee = get_tracee(NULL, pid, true);
+		assert(tracee != NULL);
+
+		tracee->running = false;
+
+		status = notify_extensions(tracee, NEW_STATUS, tracee_status, 0);
+		if (status != 0)
+			continue;
+
+		if (tracee->as_ptracee.ptracer != NULL) {
+			bool keep_stopped = handle_ptracee_event(tracee, tracee_status);
+			if (keep_stopped)
+				continue;
+		}
+
+		signal = handle_tracee_event(tracee, tracee_status);
+		(void) restart_tracee(tracee, signal);
+	}
+
+	return last_exit_status;
+}
+
+/**
+ * Handle the current event (@tracee_status) of the given @tracee.
+ * This function returns the "computed" signal that should be used to
+ * restart the given @tracee.
+ */
+int handle_tracee_event(Tracee *tracee, int tracee_status)
+{
+	static bool seccomp_detected = false;
+	pid_t pid = tracee->pid;
+	long status;
+	int signal;
+
+	/* Don't overwrite restart_how if it is explicitly set
+	 * elsewhere, i.e in the ptrace emulation when single
+	 * stepping.  */
+	if (tracee->restart_how == 0) {
+		/* When seccomp is enabled, all events are restarted in
+		 * non-stop mode, but this default choice could be overwritten
+		 * later if necessary.  The check against "sysexit_pending"
+		 * ensures PTRACE_SYSCALL (used to hit the exit stage under
+		 * seccomp) is not cleared due to an event that would happen
+		 * before the exit stage, eg. PTRACE_EVENT_EXEC for the exit
+		 * stage of execve(2).  */
+		if (tracee->seccomp == ENABLED && !tracee->sysexit_pending)
+			tracee->restart_how = PTRACE_CONT;
+		else
+			tracee->restart_how = PTRACE_SYSCALL;
+	}
+
+	/* Not a signal-stop by default.  */
+	signal = 0;
+
+	if (WIFEXITED(tracee_status)) {
+		last_exit_status = WEXITSTATUS(tracee_status);
+		VERBOSE(tracee, 1, "pid %d: exited with status %d", pid, last_exit_status);
+		tracee->terminated = true;
+	}
+	else if (WIFSIGNALED(tracee_status)) {
+		check_architecture(tracee);
+		VERBOSE(tracee, (int) (last_exit_status != -1),
+			"pid %d: terminated with signal %d", pid, WTERMSIG(tracee_status));
+		tracee->terminated = true;
+	}
+	else if (WIFSTOPPED(tracee_status)) {
+		/* Don't use WSTOPSIG() to extract the signal
+		 * since it clears the PTRACE_EVENT_* bits. */
+		signal = (tracee_status & 0xfff00) >> 8;
+
+		switch (signal) {
+			static bool deliver_sigtrap = false;
+
+		case SIGTRAP: {
+			const unsigned long default_ptrace_options = (
+				PTRACE_O_TRACESYSGOOD	|
+				PTRACE_O_TRACEFORK	|
+				PTRACE_O_TRACEVFORK	|
+				PTRACE_O_TRACEVFORKDONE	|
+				PTRACE_O_TRACEEXEC	|
+				PTRACE_O_TRACECLONE	|
+				PTRACE_O_TRACEEXIT);
+
+			/* Distinguish some events from others and
+			 * automatically trace each new process with
+			 * the same options.
+			 *
+			 * Note that only the first bare SIGTRAP is
+			 * related to the tracing loop, others SIGTRAP
+			 * carry tracing information because of
+			 * TRACE*FORK/CLONE/EXEC.  */
+			if (deliver_sigtrap)
+				break;  /* Deliver this signal as-is.  */
+
+			deliver_sigtrap = true;
+
+			/* Try to enable seccomp mode 2...  */
+			status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
+					default_ptrace_options | PTRACE_O_TRACESECCOMP);
+			if (status < 0) {
+				/* ... otherwise use default options only.  */
+				status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
+						default_ptrace_options);
+				if (status < 0) {
+					note(tracee, ERROR, SYSTEM, "ptrace(PTRACE_SETOPTIONS)");
+					exit(EXIT_FAILURE);
+				}
+			}
+		}
+			/* Fall through. */
+		case SIGTRAP | 0x80:
+			signal = 0;
+
+			/* This tracee got signaled then freed during the
+			   sysenter stage but the kernel reports the sysexit
+			   stage; just discard this spurious tracee/event.  */
+			if (tracee->exe == NULL) {
+				tracee->restart_how = PTRACE_CONT;
+				return 0;
+			}
+
+			switch (tracee->seccomp) {
+			case ENABLED:
+				if (IS_IN_SYSENTER(tracee)) {
+					/* sysenter: ensure the sysexit
+					 * stage will be hit under seccomp.  */
+					tracee->restart_how = PTRACE_SYSCALL;
+					tracee->sysexit_pending = true;
+				}
+				else {
+					/* sysexit: the next sysenter
+					 * will be notified by seccomp.  */
+					tracee->restart_how = PTRACE_CONT;
+					tracee->sysexit_pending = false;
+				}
+				/* Fall through.  */
+			case DISABLED:
+				translate_syscall(tracee);
+
+				/* This syscall has disabled seccomp.  */
+				if (tracee->seccomp == DISABLING) {
+					tracee->restart_how = PTRACE_SYSCALL;
+					tracee->seccomp = DISABLED;
+				}
+
+				break;
+
+			case DISABLING:
+				/* Seccomp was disabled by the
+				 * previous syscall, but its sysenter
+				 * stage was already handled.  */
+				tracee->seccomp = DISABLED;
+				if (IS_IN_SYSENTER(tracee))
+					tracee->status = 1;
+				break;
+			}
+			break;
+
+		case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
+		case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: {
+			unsigned long flags = 0;
+
+			signal = 0;
+
+			if (!seccomp_detected) {
+				VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
+				tracee->seccomp = ENABLED;
+				seccomp_detected = true;
+			}
+
+			/* Use the common ptrace flow if seccomp was
+			 * explicitely disabled for this tracee.  */
+			if (tracee->seccomp != ENABLED)
+				break;
+
+			status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
+			if (status < 0)
+				break;
+
+			/* Use the common ptrace flow when
+			 * sysexit has to be handled.  */
+			if ((flags & FILTER_SYSEXIT) != 0) {
+				tracee->restart_how = PTRACE_SYSCALL;
+				break;
+			}
+
+			/* Otherwise, handle the sysenter
+			 * stage right now.  */
+			tracee->restart_how = PTRACE_CONT;
+			translate_syscall(tracee);
+
+			/* This syscall has disabled seccomp, so move
+			 * the ptrace flow back to the common path to
+			 * ensure its sysexit will be handled.  */
+			if (tracee->seccomp == DISABLING)
+				tracee->restart_how = PTRACE_SYSCALL;
+			break;
+		}
+
+		case SIGTRAP | PTRACE_EVENT_VFORK << 8:
+			signal = 0;
+			(void) new_child(tracee, CLONE_VFORK);
+			break;
+
+		case SIGTRAP | PTRACE_EVENT_FORK  << 8:
+		case SIGTRAP | PTRACE_EVENT_CLONE << 8:
+			signal = 0;
+			(void) new_child(tracee, 0);
+			break;
+
+		case SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8:
+		case SIGTRAP | PTRACE_EVENT_EXEC  << 8:
+		case SIGTRAP | PTRACE_EVENT_EXIT  << 8:
+			signal = 0;
+			break;
+
+		case SIGSTOP:
+			/* Stop this tracee until PRoot has received
+			 * the EVENT_*FORK|CLONE notification.  */
+			if (tracee->exe == NULL) {
+				tracee->sigstop = SIGSTOP_PENDING;
+				signal = -1;
+			}
+
+			/* For each tracee, the first SIGSTOP
+			 * is only used to notify the tracer.  */
+			if (tracee->sigstop == SIGSTOP_IGNORED) {
+				tracee->sigstop = SIGSTOP_ALLOWED;
+				signal = 0;
+			}
+			break;
+
+		default:
+			/* Deliver this signal as-is.  */
+			break;
+		}
+	}
+
+	/* Clear the pending event, if any.  */
+	tracee->as_ptracee.event4.proot.pending = false;
+
+	return signal;
+}
+
+/**
+ * Restart the given @tracee with the specified @signal.  This
+ * function returns false if the tracee was not restarted (error or
+ * put in the "waiting for ptracee" state), otherwise true.
+ */
+bool restart_tracee(Tracee *tracee, int signal)
+{
+	int status;
+
+	/* Put in the "stopped"/"waiting for ptracee" state?.  */
+	if (tracee->as_ptracer.wait_pid != 0 || signal == -1)
+		return false;
+
+	/* Restart the tracee and stop it at the next instruction, or
+	 * at the next entry or exit of a system call. */
+	status = ptrace(tracee->restart_how, tracee->pid, NULL, signal);
+	if (status < 0)
+		return false; /* The process likely died in a syscall.  */
+
+	tracee->restart_how = 0;
+	tracee->running = true;
+
+	return true;
+}
diff --git a/5.1.0/src/tracee/event.h b/5.1.0/src/tracee/event.h
new file mode 100644
index 0000000..3ff3602
--- /dev/null
+++ b/5.1.0/src/tracee/event.h
@@ -0,0 +1,35 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef TRACEE_EVENT_H
+#define TRACEE_EVENT_H
+
+#include <stdbool.h>
+
+#include "tracee/tracee.h"
+
+extern int launch_process(Tracee *tracee, char *const argv[]);
+extern int event_loop();
+extern int handle_tracee_event(Tracee *tracee, int tracee_status);
+extern bool restart_tracee(Tracee *tracee, int signal);
+
+#endif /* TRACEE_EVENT_H */
diff --git a/5.1.0/src/tracee/mem.c b/5.1.0/src/tracee/mem.c
new file mode 100644
index 0000000..6f6c1bd
--- /dev/null
+++ b/5.1.0/src/tracee/mem.c
@@ -0,0 +1,570 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/ptrace.h> /* ptrace(2), PTRACE_*, */
+#include <sys/types.h>  /* pid_t, size_t, */
+#include <stdlib.h>     /* NULL, */
+#include <stddef.h>     /* offsetof(), */
+#include <sys/user.h>   /* struct user*, */
+#include <errno.h>      /* errno, */
+#include <assert.h>     /* assert(3), */
+#include <sys/wait.h>   /* waitpid(2), */
+#include <string.h>     /* memcpy(3), */
+#include <stdint.h>     /* uint*_t, */
+#include <sys/uio.h>    /* process_vm_*, struct iovec, */
+#include <unistd.h>     /* sysconf(3), */
+#include <sys/mman.h>   /* mmap(2), munmap(2), MAP_*, */
+
+#include "tracee/mem.h"
+#include "tracee/abi.h"
+#include "syscall/heap.h"
+#include "arch.h"            /* word_t, NO_MISALIGNED_ACCESS */
+#include "build.h"           /* HAVE_PROCESS_VM,  */
+#include "cli/note.h"
+
+/**
+ * Load the word at the given @address, potentially *not* aligned.
+ */
+static inline word_t load_word(const void *address)
+{
+#ifdef NO_MISALIGNED_ACCESS
+	if (((word_t)address) % sizeof(word_t) == 0)
+		return *(word_t *)address;
+	else {
+		word_t value;
+		memcpy(&value, address, sizeof(word_t));
+		return value;
+	}
+#else
+	return *(word_t *)address;
+#endif
+}
+
+/**
+ * Store the word with the given @value to the given @address,
+ * potentially *not* aligned.
+ */
+static inline void store_word(void *address, word_t value)
+{
+#ifdef NO_MISALIGNED_ACCESS
+	if (((word_t)address) % sizeof(word_t) == 0)
+		*((word_t *)address) = value;
+	else
+		memcpy(address, &value, sizeof(word_t));
+#else
+	*((word_t *)address) = value;
+#endif
+}
+
+/**
+ * Copy @size bytes from the buffer @src_tracer to the address
+ * @dest_tracee within the memory space of the @tracee process. It
+ * returns -errno if an error occured, otherwise 0.
+ */
+int write_data(const Tracee *tracee, word_t dest_tracee, const void *src_tracer, word_t size)
+{
+	word_t *src  = (word_t *)src_tracer;
+	word_t *dest = (word_t *)dest_tracee;
+
+	long   status;
+	word_t word, i, j;
+	word_t nb_trailing_bytes;
+	word_t nb_full_words;
+
+	uint8_t *last_dest_word;
+	uint8_t *last_src_word;
+
+	if (belongs_to_heap_prealloc(tracee, dest_tracee))
+		return -EFAULT;
+
+#if defined(HAVE_PROCESS_VM)
+	struct iovec local;
+	struct iovec remote;
+
+	local.iov_base = src;
+	local.iov_len  = size;
+
+	remote.iov_base = dest;
+	remote.iov_len  = size;
+
+	status = process_vm_writev(tracee->pid, &local, 1, &remote, 1, 0);
+	if ((size_t) status == size)
+		return 0;
+	/* Fallback to ptrace if something went wrong.  */
+
+#endif /* HAVE_PROCESS_VM */
+
+	nb_trailing_bytes = size % sizeof(word_t);
+	nb_full_words     = (size - nb_trailing_bytes) / sizeof(word_t);
+
+	/* Copy one word by one word, except for the last one. */
+	for (i = 0; i < nb_full_words; i++) {
+		status = ptrace(PTRACE_POKEDATA, tracee->pid, dest + i, load_word(&src[i]));
+		if (status < 0) {
+			note(tracee, WARNING, SYSTEM, "ptrace(POKEDATA)");
+			return -EFAULT;
+		}
+	}
+
+	if (nb_trailing_bytes == 0)
+		return 0;
+
+	/* Copy the bytes in the last word carefully since we have to
+	 * overwrite only the relevant ones. */
+
+	word = ptrace(PTRACE_PEEKDATA, tracee->pid, dest + i, NULL);
+	if (errno != 0) {
+		note(tracee, WARNING, SYSTEM, "ptrace(PEEKDATA)");
+		return -EFAULT;
+	}
+
+	last_dest_word = (uint8_t *)&word;
+	last_src_word  = (uint8_t *)&src[i];
+
+	for (j = 0; j < nb_trailing_bytes; j++)
+		last_dest_word[j] = last_src_word[j];
+
+	status = ptrace(PTRACE_POKEDATA, tracee->pid, dest + i, word);
+	if (status < 0) {
+		note(tracee, WARNING, SYSTEM, "ptrace(POKEDATA)");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * Gather the @src_tracer_count buffers pointed to by @src_tracer to
+ * the address @dest_tracee within the memory space of the @tracee
+ * process.  This function returns -errno if an error occured,
+ * otherwise 0.
+ */
+int writev_data(const Tracee *tracee, word_t dest_tracee, const struct iovec *src_tracer, int src_tracer_count)
+{
+	size_t size;
+	int status;
+	int i;
+
+	if (belongs_to_heap_prealloc(tracee, dest_tracee))
+		return -EFAULT;
+
+#if defined(HAVE_PROCESS_VM)
+	struct iovec remote;
+
+	for (i = 0, size = 0; i < src_tracer_count; i++)
+		size += src_tracer[i].iov_len;
+
+	remote.iov_base = (word_t *)dest_tracee;
+	remote.iov_len  = size;
+
+	status = process_vm_writev(tracee->pid, src_tracer, src_tracer_count, &remote, 1, 0);
+	if ((size_t) status == size)
+		return 0;
+	/* Fallback to iterative-write if something went wrong.  */
+
+#endif /* HAVE_PROCESS_VM */
+
+	for (i = 0, size = 0; i < src_tracer_count; i++) {
+		status = write_data(tracee, dest_tracee + size,
+				src_tracer[i].iov_base, src_tracer[i].iov_len);
+		if (status < 0)
+			return status;
+
+		size += src_tracer[i].iov_len;
+	}
+
+	return 0;
+}
+
+/**
+ * Copy @size bytes to the buffer @dest_tracer from the address
+ * @src_tracee within the memory space of the @tracee process. It
+ * returns -errno if an error occured, otherwise 0.
+ */
+int read_data(const Tracee *tracee, void *dest_tracer, word_t src_tracee, word_t size)
+{
+	word_t *src  = (word_t *)src_tracee;
+	word_t *dest = (word_t *)dest_tracer;
+
+	word_t nb_trailing_bytes;
+	word_t nb_full_words;
+	word_t word, i, j;
+
+	uint8_t *last_src_word;
+	uint8_t *last_dest_word;
+
+	if (belongs_to_heap_prealloc(tracee, src_tracee))
+		return -EFAULT;
+
+#if defined(HAVE_PROCESS_VM)
+	long status;
+	struct iovec local;
+	struct iovec remote;
+
+	local.iov_base = dest;
+	local.iov_len  = size;
+
+	remote.iov_base = src;
+	remote.iov_len  = size;
+
+	status = process_vm_readv(tracee->pid, &local, 1, &remote, 1, 0);
+	if ((size_t) status == size)
+		return 0;
+	/* Fallback to ptrace if something went wrong.  */
+
+#endif /* HAVE_PROCESS_VM */
+
+	nb_trailing_bytes = size % sizeof(word_t);
+	nb_full_words     = (size - nb_trailing_bytes) / sizeof(word_t);
+
+	/* Copy one word by one word, except for the last one. */
+	for (i = 0; i < nb_full_words; i++) {
+		word = ptrace(PTRACE_PEEKDATA, tracee->pid, src + i, NULL);
+		if (errno != 0) {
+			note(tracee, WARNING, SYSTEM, "ptrace(PEEKDATA)");
+			return -EFAULT;
+		}
+		store_word(&dest[i], word);
+	}
+
+	if (nb_trailing_bytes == 0)
+		return 0;
+
+	/* Copy the bytes from the last word carefully since we have
+	 * to not overwrite the bytes lying beyond @dest_tracer. */
+
+	word = ptrace(PTRACE_PEEKDATA, tracee->pid, src + i, NULL);
+	if (errno != 0) {
+		note(tracee, WARNING, SYSTEM, "ptrace(PEEKDATA)");
+		return -EFAULT;
+	}
+
+	last_dest_word = (uint8_t *)&dest[i];
+	last_src_word  = (uint8_t *)&word;
+
+	for (j = 0; j < nb_trailing_bytes; j++)
+		last_dest_word[j] = last_src_word[j];
+
+	return 0;
+}
+
+/**
+ * Copy to @dest_tracer at most @max_size bytes from the string
+ * pointed to by @src_tracee within the memory space of the @tracee
+ * process. This function returns -errno on error, otherwise
+ * it returns the number in bytes of the string, including the
+ * end-of-string terminator.
+ */
+int read_string(const Tracee *tracee, char *dest_tracer, word_t src_tracee, word_t max_size)
+{
+	word_t *src  = (word_t *)src_tracee;
+	word_t *dest = (word_t *)dest_tracer;
+
+	word_t nb_trailing_bytes;
+	word_t nb_full_words;
+	word_t word, i, j;
+
+	uint8_t *src_word;
+	uint8_t *dest_word;
+
+	if (belongs_to_heap_prealloc(tracee, src_tracee))
+		return -EFAULT;
+
+#if defined(HAVE_PROCESS_VM)
+	/* [process_vm] system calls do not check the memory regions
+	 * in the remote process until just before doing the
+	 * read/write.  Consequently, a partial read/write [1] may
+	 * result if one of the remote_iov elements points to an
+	 * invalid memory region in the remote process.  No further
+	 * reads/writes will be attempted beyond that point.  Keep
+	 * this in mind when attempting to read data of unknown length
+	 * (such as C strings that are null-terminated) from a remote
+	 * process, by avoiding spanning memory pages (typically 4KiB)
+	 * in a single remote iovec element.  (Instead, split the
+	 * remote read into two remote_iov elements and have them
+	 * merge back into a single write local_iov entry.  The first
+	 * read entry goes up to the page boundary, while the second
+	 * starts on the next page boundary.).
+	 *
+	 * [1] Partial transfers apply at the granularity of iovec
+	 * elements. These system calls won't perform a partial
+	 * transfer that splits a single iovec element.
+	 *
+	 * -- man 2 process_vm_readv
+	 */
+	long status;
+	size_t size;
+	size_t offset;
+	struct iovec local;
+	struct iovec remote;
+
+	static size_t chunk_size = 0;
+	static uintptr_t chunk_mask;
+
+	/* A chunk shall not cross a page boundary.  */
+	if (chunk_size == 0) {
+		chunk_size = sysconf(_SC_PAGESIZE);
+		chunk_size = (chunk_size > 0 && chunk_size < 1024 ? chunk_size : 1024);
+		chunk_mask = ~(chunk_size - 1);
+	}
+
+	/* Read the string by chunk.  */
+	offset = 0;
+	do {
+		uintptr_t current_chunk = (src_tracee + offset) & chunk_mask;
+		uintptr_t next_chunk    = current_chunk + chunk_size;
+
+		/* Compute the number of bytes available up to the
+		 * next chunk or up to max_size.  */
+		size = next_chunk - (src_tracee + offset);
+		size = (size < max_size - offset ? size : max_size - offset);
+
+		local.iov_base = (uint8_t *)dest + offset;
+		local.iov_len  = size;
+
+		remote.iov_base = (uint8_t *)src + offset;
+		remote.iov_len  = size;
+
+		status = process_vm_readv(tracee->pid, &local, 1, &remote, 1, 0);
+		if ((size_t) status != size)
+			goto fallback;
+
+		status = strnlen(local.iov_base, size);
+		if ((size_t) status < size) {
+			size = offset + status + 1;
+			assert(size <= max_size);
+			return size;
+		}
+
+		offset += size;
+	} while (offset < max_size);
+	assert(offset == max_size);
+
+	/* Fallback to ptrace if something went wrong.  */
+fallback:
+#endif /* HAVE_PROCESS_VM */
+
+	nb_trailing_bytes = max_size % sizeof(word_t);
+	nb_full_words     = (max_size - nb_trailing_bytes) / sizeof(word_t);
+
+	/* Copy one word by one word, except for the last one. */
+	for (i = 0; i < nb_full_words; i++) {
+		word = ptrace(PTRACE_PEEKDATA, tracee->pid, src + i, NULL);
+		if (errno != 0)
+			return -EFAULT;
+
+		store_word(&dest[i], word);
+
+		/* Stop once an end-of-string is detected. */
+		src_word = (uint8_t *)&word;
+		for (j = 0; j < sizeof(word_t); j++)
+			if (src_word[j] == '\0')
+				return i * sizeof(word_t) + j + 1;
+	}
+
+	/* Copy the bytes from the last word carefully since we have
+	 * to not overwrite the bytes lying beyond @dest_tracer. */
+
+	word = ptrace(PTRACE_PEEKDATA, tracee->pid, src + i, NULL);
+	if (errno != 0)
+		return -EFAULT;
+
+	dest_word = (uint8_t *)&dest[i];
+	src_word  = (uint8_t *)&word;
+
+	for (j = 0; j < nb_trailing_bytes; j++) {
+		dest_word[j] = src_word[j];
+		if (src_word[j] == '\0')
+			break;
+	}
+
+	return i * sizeof(word_t) + j + 1;
+}
+
+/**
+ * Return the value of the word at the given @address in the @tracee's
+ * memory space.  The caller must test errno to check if an error
+ * occured.
+ */
+word_t peek_word(const Tracee *tracee, word_t address)
+{
+	word_t result = 0;
+
+	if (belongs_to_heap_prealloc(tracee, address)) {
+		errno = EFAULT;
+		return 0;
+	}
+
+#if defined(HAVE_PROCESS_VM)
+	int status;
+	struct iovec local;
+	struct iovec remote;
+
+	local.iov_base = &result;
+	local.iov_len  = sizeof_word(tracee);
+
+	remote.iov_base = (void *)address;
+	remote.iov_len  = sizeof_word(tracee);
+
+	errno = 0;
+	status = process_vm_readv(tracee->pid, &local, 1, &remote, 1, 0);
+	if (status > 0)
+		return result;
+	/* Fallback to ptrace if something went wrong.  */
+#endif
+	errno = 0;
+	result = (word_t) ptrace(PTRACE_PEEKDATA, tracee->pid, address, NULL);
+
+	/* From ptrace(2) manual: "Unfortunately, under Linux,
+	 * different variations of this fault will return EIO or
+	 * EFAULT more or less arbitrarily."  */
+	if (errno == EIO)
+		errno = EFAULT;
+
+	/* Use only the 32 LSB when running a 32-bit process on a
+	 * 64-bit kernel. */
+	if (is_32on64_mode(tracee))
+		result &= 0xFFFFFFFF;
+
+	return result;
+}
+
+/**
+ * Set the word at the given @address in the @tracee's memory space to
+ * the given @value.  The caller must test errno to check if an error
+ * occured.
+ */
+void poke_word(const Tracee *tracee, word_t address, word_t value)
+{
+	word_t tmp;
+
+	if (belongs_to_heap_prealloc(tracee, address)) {
+		errno = EFAULT;
+		return;
+	}
+
+#if defined(HAVE_PROCESS_VM)
+	int status;
+	struct iovec local;
+	struct iovec remote;
+
+	/* Note: &value points to the 32 LSB on 64-bit little-endian
+	 * architecture.  */
+	local.iov_base = &value;
+	local.iov_len  = sizeof_word(tracee);
+
+	remote.iov_base = (void *)address;
+	remote.iov_len  = sizeof_word(tracee);
+
+	errno = 0;
+	status = process_vm_writev(tracee->pid, &local, 1, &remote, 1, 0);
+	if (status > 0)
+		return;
+	/* Fallback to ptrace if something went wrong.  */
+#endif
+	/* Don't overwrite the 32 MSB when running a 32-bit process on
+	 * a 64-bit kernel. */
+	if (is_32on64_mode(tracee)) {
+		errno = 0;
+		tmp = (word_t) ptrace(PTRACE_PEEKDATA, tracee->pid, address, NULL);
+		if (errno != 0)
+			return;
+
+		value |= (tmp & 0xFFFFFFFF00000000ULL);
+	}
+
+	errno = 0;
+	(void) ptrace(PTRACE_POKEDATA, tracee->pid, address, value);
+
+	/* From ptrace(2) manual: "Unfortunately, under Linux,
+	 * different variations of this fault will return EIO or
+	 * EFAULT more or less arbitrarily."  */
+	if (errno == EIO)
+		errno = EFAULT;
+
+	return;
+}
+
+/**
+ * Allocate @size bytes in the @tracee's memory space.  This function
+ * returns the address of the allocated memory in the @tracee's memory
+ * space, otherwise 0 if an error occured.
+ */
+word_t alloc_mem(Tracee *tracee, ssize_t size)
+{
+	word_t stack_pointer;
+
+	/* This function should be called in sysenter only since the
+	 * stack pointer is systematically restored at the end of
+	 * sysexit (except for execve, but in this case the stack
+	 * pointer should be handled with care since it is used by the
+	 * process to retrieve argc, argv, envp, and auxv).  */
+	assert(IS_IN_SYSENTER(tracee));
+
+	/* Get the current value of the stack pointer from the tracee's
+	 * USER area. */
+	stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER);
+
+	/* Some ABIs specify an amount of bytes after the stack
+	 * pointer that shall not be used by anything but the compiler
+	 * (for optimization purpose).  */
+	if (stack_pointer == peek_reg(tracee, ORIGINAL, STACK_POINTER))
+		size += RED_ZONE_SIZE;
+
+	/* Sanity check. */
+	if (   (size > 0 && stack_pointer <= (word_t) size)
+	    || (size < 0 && stack_pointer >= ULONG_MAX + size)) {
+		note(tracee, WARNING, INTERNAL, "integer under/overflow detected in %s",
+			__FUNCTION__);
+		return 0;
+	}
+
+	/* Remember the stack grows downward. */
+	stack_pointer -= size;
+
+	/* Set the new value of the stack pointer in the tracee's USER
+	 * area. */
+	poke_reg(tracee, STACK_POINTER, stack_pointer);
+	return stack_pointer;
+}
+
+/**
+ * Clear @size bytes at the given @address in the @tracee's memory
+ * space.  This function returns -errno if an error occured, otherwise
+ * 0.
+ */
+int clear_mem(const Tracee *tracee, word_t address, size_t size)
+{
+	int status;
+	void *zeros;
+
+	if (belongs_to_heap_prealloc(tracee, address))
+		return -EFAULT;
+
+	zeros = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (zeros == MAP_FAILED)
+		return -errno;
+
+	status = write_data(tracee, address, zeros, size);
+	munmap(zeros, size);
+	return status;
+}
diff --git a/5.1.0/src/tracee/mem.h b/5.1.0/src/tracee/mem.h
new file mode 100644
index 0000000..01853ec
--- /dev/null
+++ b/5.1.0/src/tracee/mem.h
@@ -0,0 +1,112 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef TRACEE_MEM_H
+#define TRACEE_MEM_H
+
+#include <limits.h>    /* PATH_MAX, */
+#include <sys/types.h> /* pid_t, size_t, */
+#include <stdint.h>    /* pid_t, size_t, */
+#include <sys/uio.h>   /* struct iovec, */
+#include <errno.h>     /* ENAMETOOLONG, */
+
+#include "arch.h" /* word_t, */
+#include "tracee/tracee.h"
+
+extern int write_data(const Tracee *tracee, word_t dest_tracee, const void *src_tracer, word_t size);
+extern int writev_data(const Tracee *tracee, word_t dest_tracee, const struct iovec *src_tracer, int src_tracer_count);
+extern int read_data(const Tracee *tracee, void *dest_tracer, word_t src_tracee, word_t size);
+extern int read_string(const Tracee *tracee, char *dest_tracer, word_t src_tracee, word_t max_size);
+extern word_t peek_word(const Tracee *tracee, word_t address);
+extern void poke_word(const Tracee *tracee, word_t address, word_t value);
+extern word_t alloc_mem(Tracee *tracee, ssize_t size);
+extern int clear_mem(const Tracee *tracee, word_t address, size_t size);
+
+/**
+ * Copy to @dest_tracer at most PATH_MAX bytes -- including the
+ * end-of-string terminator -- from the string pointed to by
+ * @src_tracee within the memory space of the @tracee process.  This
+ * function returns -errno on error, otherwise it returns the number
+ * in bytes of the string, including the end-of-string terminator.
+ */
+static inline int read_path(const Tracee *tracee, char dest_tracer[PATH_MAX], word_t src_tracee)
+{
+	int status;
+
+	status = read_string(tracee, dest_tracer, src_tracee, PATH_MAX);
+	if (status < 0)
+		return status;
+	if (status >= PATH_MAX)
+		return -ENAMETOOLONG;
+
+	return status;
+}
+
+/**
+ * Generate a function that returns the value of the @type at the
+ * given @address in the @tracee's memory space.  The caller must test
+ * errno to check if an error occured.
+ */
+#define GENERATE_peek(type)							\
+static inline type ## _t peek_ ## type(const Tracee *tracee, word_t address) 	\
+{										\
+	type ## _t result;							\
+	errno = -read_data(tracee, &result, address, sizeof(type ## _t));	\
+	return result;								\
+}
+
+GENERATE_peek(uint8);
+GENERATE_peek(uint16);
+GENERATE_peek(uint32);
+GENERATE_peek(uint64);
+
+GENERATE_peek(int8);
+GENERATE_peek(int16);
+GENERATE_peek(int32);
+GENERATE_peek(int64);
+
+#undef GENERATE_peek
+
+/**
+ * Generate a function that set the @type at the given @address in the
+ * @tracee's memory space to the given @value.  The caller must test
+ * errno to check if an error occured.
+ */
+#define GENERATE_poke(type)							\
+static inline void poke_ ## type(const Tracee *tracee, word_t address, type ## _t value) \
+{										\
+	errno = -write_data(tracee, address, &value, sizeof(type ## _t));	\
+}
+
+GENERATE_poke(uint8);
+GENERATE_poke(uint16);
+GENERATE_poke(uint32);
+GENERATE_poke(uint64);
+
+GENERATE_poke(int8);
+GENERATE_poke(int16);
+GENERATE_poke(int32);
+GENERATE_poke(int64);
+
+#undef GENERATE_poke
+
+#endif /* TRACEE_MEM_H */
diff --git a/5.1.0/src/tracee/reg.c b/5.1.0/src/tracee/reg.c
new file mode 100644
index 0000000..78dc5a5
--- /dev/null
+++ b/5.1.0/src/tracee/reg.c
@@ -0,0 +1,327 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>  /* off_t */
+#include <sys/user.h>   /* struct user*, */
+#include <sys/ptrace.h> /* ptrace(2), PTRACE*, */
+#include <assert.h>     /* assert(3), */
+#include <errno.h>      /* errno(3), */
+#include <stddef.h>     /* offsetof(), */
+#include <stdint.h>     /* *int*_t(), */
+#include <limits.h>     /* ULONG_MAX, */
+#include <string.h>     /* memcpy(3), */
+#include <sys/uio.h>    /* struct iovec, */
+
+#include "arch.h"
+
+#if defined(ARCH_ARM64)
+#include <linux/elf.h>  /* NT_PRSTATUS */
+#endif
+
+#include "syscall/sysnum.h"
+#include "tracee/reg.h"
+#include "tracee/abi.h"
+#include "cli/note.h"
+#include "compat.h"
+
+/**
+ * Compute the offset of the register @reg_name in the USER area.
+ */
+#define USER_REGS_OFFSET(reg_name)			\
+	(offsetof(struct user, regs)			\
+	 + offsetof(struct user_regs_struct, reg_name))
+
+#define REG(tracee, version, index)			\
+	(*(word_t*) (((uint8_t *) &tracee->_regs[version]) + reg_offset[index]))
+
+/* Specify the ABI registers (syscall argument passing, stack pointer).
+ * See sysdeps/unix/sysv/linux/${ARCH}/syscall.S from the GNU C Library. */
+#if defined(ARCH_X86_64)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(orig_rax),
+	[SYSARG_1]      = USER_REGS_OFFSET(rdi),
+	[SYSARG_2]      = USER_REGS_OFFSET(rsi),
+	[SYSARG_3]      = USER_REGS_OFFSET(rdx),
+	[SYSARG_4]      = USER_REGS_OFFSET(r10),
+	[SYSARG_5]      = USER_REGS_OFFSET(r8),
+	[SYSARG_6]      = USER_REGS_OFFSET(r9),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(rax),
+	[STACK_POINTER] = USER_REGS_OFFSET(rsp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(rip),
+	[RTLD_FINI]     = USER_REGS_OFFSET(rdx),
+	[STATE_FLAGS]   = USER_REGS_OFFSET(eflags),
+	[USERARG_1]     = USER_REGS_OFFSET(rdi),
+    };
+
+    static off_t reg_offset_x86[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(orig_rax),
+	[SYSARG_1]      = USER_REGS_OFFSET(rbx),
+	[SYSARG_2]      = USER_REGS_OFFSET(rcx),
+	[SYSARG_3]      = USER_REGS_OFFSET(rdx),
+	[SYSARG_4]      = USER_REGS_OFFSET(rsi),
+	[SYSARG_5]      = USER_REGS_OFFSET(rdi),
+	[SYSARG_6]      = USER_REGS_OFFSET(rbp),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(rax),
+	[STACK_POINTER] = USER_REGS_OFFSET(rsp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(rip),
+	[RTLD_FINI]     = USER_REGS_OFFSET(rdx),
+	[STATE_FLAGS]   = USER_REGS_OFFSET(eflags),
+	[USERARG_1]     = USER_REGS_OFFSET(rax),
+    };
+
+    #undef  REG
+    #define REG(tracee, version, index)					\
+	(*(word_t*) (tracee->_regs[version].cs == 0x23			\
+		? (((uint8_t *) &tracee->_regs[version]) + reg_offset_x86[index]) \
+		: (((uint8_t *) &tracee->_regs[version]) + reg_offset[index])))
+
+#elif defined(ARCH_ARM_EABI)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(uregs[7]),
+	[SYSARG_1]      = USER_REGS_OFFSET(uregs[0]),
+	[SYSARG_2]      = USER_REGS_OFFSET(uregs[1]),
+	[SYSARG_3]      = USER_REGS_OFFSET(uregs[2]),
+	[SYSARG_4]      = USER_REGS_OFFSET(uregs[3]),
+	[SYSARG_5]      = USER_REGS_OFFSET(uregs[4]),
+	[SYSARG_6]      = USER_REGS_OFFSET(uregs[5]),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(uregs[0]),
+	[STACK_POINTER] = USER_REGS_OFFSET(uregs[13]),
+	[INSTR_POINTER] = USER_REGS_OFFSET(uregs[15]),
+	[USERARG_1]     = USER_REGS_OFFSET(uregs[0]),
+    };
+
+#elif defined(ARCH_ARM64)
+
+    #undef  USER_REGS_OFFSET
+    #define USER_REGS_OFFSET(reg_name) offsetof(struct user_regs_struct, reg_name)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(regs[8]),
+	[SYSARG_1]      = USER_REGS_OFFSET(regs[0]),
+	[SYSARG_2]      = USER_REGS_OFFSET(regs[1]),
+	[SYSARG_3]      = USER_REGS_OFFSET(regs[2]),
+	[SYSARG_4]      = USER_REGS_OFFSET(regs[3]),
+	[SYSARG_5]      = USER_REGS_OFFSET(regs[4]),
+	[SYSARG_6]      = USER_REGS_OFFSET(regs[5]),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(regs[0]),
+	[STACK_POINTER] = USER_REGS_OFFSET(sp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(pc),
+    };
+
+#elif defined(ARCH_X86)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(orig_eax),
+	[SYSARG_1]      = USER_REGS_OFFSET(ebx),
+	[SYSARG_2]      = USER_REGS_OFFSET(ecx),
+	[SYSARG_3]      = USER_REGS_OFFSET(edx),
+	[SYSARG_4]      = USER_REGS_OFFSET(esi),
+	[SYSARG_5]      = USER_REGS_OFFSET(edi),
+	[SYSARG_6]      = USER_REGS_OFFSET(ebp),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(eax),
+	[STACK_POINTER] = USER_REGS_OFFSET(esp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(eip),
+	[RTLD_FINI]     = USER_REGS_OFFSET(edx),
+	[STATE_FLAGS]   = USER_REGS_OFFSET(eflags),
+	[USERARG_1]     = USER_REGS_OFFSET(eax),
+    };
+
+#elif defined(ARCH_SH4)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(regs[3]),
+	[SYSARG_1]      = USER_REGS_OFFSET(regs[4]),
+	[SYSARG_2]      = USER_REGS_OFFSET(regs[5]),
+	[SYSARG_3]      = USER_REGS_OFFSET(regs[6]),
+	[SYSARG_4]      = USER_REGS_OFFSET(regs[7]),
+	[SYSARG_5]      = USER_REGS_OFFSET(regs[0]),
+	[SYSARG_6]      = USER_REGS_OFFSET(regs[1]),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(regs[0]),
+	[STACK_POINTER] = USER_REGS_OFFSET(regs[15]),
+	[INSTR_POINTER] = USER_REGS_OFFSET(pc),
+	[RTLD_FINI]     = USER_REGS_OFFSET(r4),
+    };
+
+#else
+
+    #error "Unsupported architecture"
+
+#endif
+
+/**
+ * Return the *cached* value of the given @tracees' @reg.
+ */
+word_t peek_reg(const Tracee *tracee, RegVersion version, Reg reg)
+{
+	word_t result;
+
+	assert(version < NB_REG_VERSION);
+
+	result = REG(tracee, version, reg);
+
+	/* Use only the 32 least significant bits (LSB) when running
+	 * 32-bit processes on a 64-bit kernel.  */
+	if (is_32on64_mode(tracee))
+		result &= 0xFFFFFFFF;
+
+	return result;
+}
+
+/**
+ * Set the *cached* value of the given @tracees' @reg.
+ */
+void poke_reg(Tracee *tracee, Reg reg, word_t value)
+{
+	if (peek_reg(tracee, CURRENT, reg) == value)
+		return;
+
+	REG(tracee, CURRENT, reg) = value;
+	tracee->_regs_were_changed = true;
+}
+
+/**
+ * Print the value of the current @tracee's registers according
+ * to the @verbose_level.  Note: @message is mixed to the output.
+ */
+void print_current_regs(Tracee *tracee, int verbose_level, const char *message)
+{
+	if (tracee->verbose < verbose_level)
+		return;
+
+	note(tracee, INFO, INTERNAL,
+		"pid %d: %s: %s(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx) = 0x%lx [0x%lx, %d]",
+		tracee->pid, message,
+		stringify_sysnum(get_sysnum(tracee, CURRENT)),
+		peek_reg(tracee, CURRENT, SYSARG_1), peek_reg(tracee, CURRENT, SYSARG_2),
+		peek_reg(tracee, CURRENT, SYSARG_3), peek_reg(tracee, CURRENT, SYSARG_4),
+		peek_reg(tracee, CURRENT, SYSARG_5), peek_reg(tracee, CURRENT, SYSARG_6),
+		peek_reg(tracee, CURRENT, SYSARG_RESULT),
+		peek_reg(tracee, CURRENT, STACK_POINTER),
+		get_abi(tracee));
+}
+
+/**
+ * Save the @tracee's current register bank into the @version register
+ * bank.
+ */
+void save_current_regs(Tracee *tracee, RegVersion version)
+{
+	/* Optimization: don't restore original register values if
+	 * they were never changed.  */
+	if (version == ORIGINAL)
+		tracee->_regs_were_changed = false;
+
+	memcpy(&tracee->_regs[version], &tracee->_regs[CURRENT], sizeof(tracee->_regs[CURRENT]));
+}
+
+/**
+ * Copy all @tracee's general purpose registers into a dedicated
+ * cache.  This function returns -errno if an error occured, 0
+ * otherwise.
+ */
+int fetch_regs(Tracee *tracee)
+{
+	int status;
+
+#if defined(ARCH_ARM64)
+	struct iovec regs;
+
+	regs.iov_base = &tracee->_regs[CURRENT];
+	regs.iov_len  = sizeof(tracee->_regs[CURRENT]);
+
+	status = ptrace(PTRACE_GETREGSET, tracee->pid, NT_PRSTATUS, &regs);
+#else
+	status = ptrace(PTRACE_GETREGS, tracee->pid, NULL, &tracee->_regs[CURRENT]);
+#endif
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+/**
+ * Copy the cached values of all @tracee's general purpose registers
+ * back to the process, if necessary.  This function returns -errno if
+ * an error occured, 0 otherwise.
+ */
+int push_regs(Tracee *tracee)
+{
+	int status;
+
+	if (tracee->_regs_were_changed) {
+		/* At the very end of a syscall, with regard to the
+		 * entry, only the result register can be modified by
+		 * PRoot.  */
+		if (tracee->restore_original_regs) {
+			/* Restore the sysarg register only if it is
+			 * not the same as the result register.  Note:
+			 * it's never the case on x86 architectures,
+			 * so don't make this check, otherwise it
+			 * would introduce useless complexity because
+			 * of the multiple ABI support.  */
+#if defined(ARCH_X86) || defined(ARCH_X86_64)
+#    define		RESTORE(sysarg)	(REG(tracee, CURRENT, sysarg) = REG(tracee, ORIGINAL, sysarg))
+#else
+#    define	 	RESTORE(sysarg) (void) (reg_offset[SYSARG_RESULT] != reg_offset[sysarg] && \
+				(REG(tracee, CURRENT, sysarg) = REG(tracee, ORIGINAL, sysarg)))
+#endif
+
+			RESTORE(SYSARG_NUM);
+			RESTORE(SYSARG_1);
+			RESTORE(SYSARG_2);
+			RESTORE(SYSARG_3);
+			RESTORE(SYSARG_4);
+			RESTORE(SYSARG_5);
+			RESTORE(SYSARG_6);
+			RESTORE(STACK_POINTER);
+		}
+
+#if defined(ARCH_ARM64)
+		struct iovec regs;
+
+		regs.iov_base = &tracee->_regs[CURRENT];
+		regs.iov_len  = sizeof(tracee->_regs[CURRENT]);
+
+		status = ptrace(PTRACE_SETREGSET, tracee->pid, NT_PRSTATUS, &regs);
+#else
+#    if defined(ARCH_ARM_EABI)
+		/* On ARM, a special ptrace request is required to
+		 * change effectively the syscall number during a
+		 * ptrace-stop.  */
+		word_t current_sysnum = REG(tracee, CURRENT, SYSARG_NUM);
+		if (current_sysnum != REG(tracee, ORIGINAL, SYSARG_NUM)) {
+			status = ptrace(PTRACE_SET_SYSCALL, tracee->pid, 0, current_sysnum);
+			if (status < 0)
+				note(tracee, WARNING, SYSTEM, "can't set the syscall number");
+		}
+#    endif
+
+		status = ptrace(PTRACE_SETREGS, tracee->pid, NULL, &tracee->_regs[CURRENT]);
+#endif
+		if (status < 0)
+			return status;
+	}
+
+	return 0;
+}
diff --git a/5.1.0/src/tracee/reg.h b/5.1.0/src/tracee/reg.h
new file mode 100644
index 0000000..47f6d4e
--- /dev/null
+++ b/5.1.0/src/tracee/reg.h
@@ -0,0 +1,54 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef TRACEE_REG_H
+#define TRACEE_REG_H
+
+#include "tracee/tracee.h"
+#include "arch.h"
+
+typedef enum {
+	SYSARG_NUM = 0,
+	SYSARG_1,
+	SYSARG_2,
+	SYSARG_3,
+	SYSARG_4,
+	SYSARG_5,
+	SYSARG_6,
+	SYSARG_RESULT,
+	STACK_POINTER,
+	INSTR_POINTER,
+	RTLD_FINI,
+	STATE_FLAGS,
+	USERARG_1,
+} Reg;
+
+extern int fetch_regs(Tracee *tracee);
+extern int push_regs(Tracee *tracee);
+
+extern word_t peek_reg(const Tracee *tracee, RegVersion version, Reg reg);
+extern void poke_reg(Tracee *tracee, Reg reg, word_t value);
+
+extern void print_current_regs(Tracee *tracee, int verbose_level, const char *message);
+extern void save_current_regs(Tracee *tracee, RegVersion version);
+
+#endif /* TRACEE_REG_H */
diff --git a/5.1.0/src/tracee/tracee.c b/5.1.0/src/tracee/tracee.c
new file mode 100644
index 0000000..aa17294
--- /dev/null
+++ b/5.1.0/src/tracee/tracee.c
@@ -0,0 +1,603 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sched.h>      /* CLONE_*,  */
+#include <sys/types.h>  /* pid_t, size_t, */
+#include <stdlib.h>     /* NULL, */
+#include <assert.h>     /* assert(3), */
+#include <string.h>     /* bzero(3), */
+#include <stdbool.h>    /* bool, true, false, */
+#include <sys/queue.h>  /* LIST_*,  */
+#include <talloc.h>     /* talloc_*, */
+#include <signal.h>     /* kill(2), SIGKILL, */
+#include <sys/ptrace.h> /* ptrace(2), PTRACE_*, */
+#include <errno.h>      /* E*, */
+
+#include "tracee/tracee.h"
+#include "tracee/reg.h"
+#include "path/binding.h"
+#include "syscall/sysnum.h"
+#include "tracee/event.h"
+#include "ptrace/ptrace.h"
+#include "ptrace/wait.h"
+#include "extension/extension.h"
+#include "cli/note.h"
+
+#include "compat.h"
+
+typedef LIST_HEAD(tracees, tracee) Tracees;
+static Tracees tracees;
+
+
+/**
+ * Remove @zombie from its parent's list of zombies.  Note: this is a
+ * talloc destructor.
+ */
+static int remove_zombie(Tracee *zombie)
+{
+	LIST_REMOVE(zombie, link);
+	return 0;
+}
+
+/**
+ * Perform some specific treatments against @pointer according to its
+ * type, before it gets unlinked from @tracee_->life_context.
+ */
+static void clean_life_span_object(const void *pointer, int depth UNUSED,
+				int max_depth UNUSED, int is_ref UNUSED, void *tracee_)
+{
+	Binding *binding;
+	Tracee *tracee;
+
+	tracee = talloc_get_type_abort(tracee_, Tracee);
+
+	/* So far, only bindings need a special treatment.  */
+	binding = talloc_get_type(pointer, Binding);
+	if (binding != NULL)
+		remove_binding_from_all_lists(tracee, binding);
+}
+
+/**
+ * Remove @tracee from the list of tracees and update all of its
+ * children & ptracees, and its ptracer.  Note: this is a talloc
+ * destructor.
+ */
+static int remove_tracee(Tracee *tracee)
+{
+	Tracee *relative;
+	Tracee *ptracer;
+	int event;
+
+	LIST_REMOVE(tracee, link);
+
+	/* Clean objects that are linked to this tracee's life
+	 * span.  */
+	talloc_report_depth_cb(tracee->life_context, 0, 100, clean_life_span_object, tracee);
+
+	/* This could be optimize by using a dedicated list of
+	 * children and ptracees.  */
+	LIST_FOREACH(relative, &tracees, link) {
+		/* Its children are now orphan.  */
+		if (relative->parent == tracee)
+			relative->parent = NULL;
+
+		/* Its tracees are now free.  */
+		if (relative->as_ptracee.ptracer == tracee) {
+			/* Release the pending event, if any.  */
+			relative->as_ptracee.ptracer = NULL;
+
+			if (relative->as_ptracee.event4.proot.pending) {
+				event = handle_tracee_event(relative,
+							relative->as_ptracee.event4.proot.value);
+				(void) restart_tracee(relative, event);
+			}
+			else if (relative->as_ptracee.event4.ptracer.pending) {
+				event = relative->as_ptracee.event4.proot.value;
+				(void) restart_tracee(relative, event);
+			}
+
+			bzero(&relative->as_ptracee, sizeof(relative->as_ptracee));
+		}
+	}
+
+	/* Nothing else to do if it's not a ptracee.  */
+	ptracer = tracee->as_ptracee.ptracer;
+	if (ptracer == NULL)
+		return 0;
+
+	/* Zombify this ptracee until its ptracer is notified about
+	 * its death.  */
+	event = tracee->as_ptracee.event4.ptracer.value;
+	if (tracee->as_ptracee.event4.ptracer.pending
+	    && (WIFEXITED(event) || WIFSIGNALED(event))) {
+		Tracee *zombie;
+
+		zombie = new_dummy_tracee(ptracer);
+		if (zombie != NULL) {
+			LIST_INSERT_HEAD(&PTRACER.zombies, zombie, link);
+			talloc_set_destructor(zombie, remove_zombie);
+
+			zombie->parent = tracee->parent;
+			zombie->clone = tracee->clone;
+			zombie->pid = tracee->pid;
+
+			detach_from_ptracer(tracee);
+			attach_to_ptracer(zombie, ptracer);
+
+			zombie->as_ptracee.event4.ptracer.pending = true;
+			zombie->as_ptracee.event4.ptracer.value = event;
+			zombie->as_ptracee.is_zombie = true;
+
+			return 0;
+		}
+		/* Fallback to the common path.  */
+	}
+
+	detach_from_ptracer(tracee);
+
+	/* Wake its ptracer if there's nothing else to wait for.  */
+	if (PTRACER.nb_ptracees == 0 && PTRACER.wait_pid != 0) {
+		/* Update the return value of ptracer's wait(2).  */
+		poke_reg(ptracer, SYSARG_RESULT, -ECHILD);
+
+		/* Don't forget to write its register cache back.  */
+		(void) push_regs(ptracer);
+
+		PTRACER.wait_pid = 0;
+		(void) restart_tracee(ptracer, 0);
+	}
+
+	return 0;
+}
+
+/**
+ * Allocate a new entry for a dummy tracee (no pid, no destructor, not
+ * in the list of tracees, ...).  The new allocated memory is attached
+ * to the given @context.  This function returns NULL if an error
+ * occurred (ENOMEM), otherwise it returns the newly allocated
+ * structure.
+ */
+Tracee *new_dummy_tracee(TALLOC_CTX *context)
+{
+	Tracee *tracee;
+
+	tracee = talloc_zero(context, Tracee);
+	if (tracee == NULL)
+		return NULL;
+
+	/* Allocate a memory collector.  */
+	tracee->ctx = talloc_new(tracee);
+	if (tracee->ctx == NULL)
+		goto no_mem;
+
+	/* By default new tracees have an empty file-system
+	 * name-space and heap.  */
+	tracee->fs = talloc_zero(tracee, FileSystemNameSpace);
+	tracee->heap = talloc_zero(tracee, Heap);
+	if (tracee->fs == NULL || tracee->heap == NULL)
+		goto no_mem;
+
+	return tracee;
+
+no_mem:
+	TALLOC_FREE(tracee);
+	return NULL;
+}
+
+/**
+ * Allocate a new entry for the tracee @pid, then set its destructor
+ * and add it to the list of tracees.  This function returns NULL if
+ * an error occurred (ENOMEM), otherwise it returns the newly
+ * allocated structure.
+ */
+static Tracee *new_tracee(pid_t pid)
+{
+	Tracee *tracee;
+
+	tracee = new_dummy_tracee(NULL);
+	if (tracee == NULL)
+		return NULL;
+
+	talloc_set_destructor(tracee, remove_tracee);
+
+	tracee->pid = pid;
+	LIST_INSERT_HEAD(&tracees, tracee, link);
+
+	tracee->life_context = talloc_new(tracee);
+
+	return tracee;
+}
+
+/**
+ * Return the first [stopped?] tracee with the given
+ * @pid (-1 for any) which has the given @ptracer, and which has a
+ * pending event for its ptracer if @only_with_pevent is true.  See
+ * wait(2) manual for the meaning of @wait_options.  This function
+ * returns NULL if there's no such ptracee.
+ */
+static Tracee *get_ptracee(const Tracee *ptracer, pid_t pid, bool only_stopped,
+			bool only_with_pevent, word_t wait_options)
+{
+	Tracee *ptracee;
+
+	/* Return zombies first.  */
+	LIST_FOREACH(ptracee, &PTRACER.zombies, link) {
+		/* Not the ptracee you're looking for?  */
+		if (pid != ptracee->pid && pid != -1)
+			continue;
+
+		/* Not the expected kind of cloned process?  */
+		if (!EXPECTED_WAIT_CLONE(wait_options, ptracee))
+			continue;
+
+		return ptracee;
+	}
+
+	LIST_FOREACH(ptracee, &tracees, link) {
+		/* Discard tracees that don't have this ptracer.  */
+		if (PTRACEE.ptracer != ptracer)
+			continue;
+
+		/* Not the ptracee you're looking for?  */
+		if (pid != ptracee->pid && pid != -1)
+			continue;
+
+		/* Not the expected kind of cloned process?  */
+		if (!EXPECTED_WAIT_CLONE(wait_options, ptracee))
+			continue;
+
+		/* No need to do more checks if its stopped state
+		 * doesn't matter.  Be careful when using such
+		 * maybe-running tracee.  */
+		if (!only_stopped)
+			return ptracee;
+
+		/* Is this tracee in the stopped state?  */
+		if (ptracee->running)
+			continue;
+
+		/* Has a pending event for its ptracer?  */
+		if (PTRACEE.event4.ptracer.pending || !only_with_pevent)
+			return ptracee;
+
+		/* No need to go further if the specific tracee isn't
+		 * in the expected state?  */
+		if (pid == ptracee->pid)
+			return NULL;
+	}
+
+	return NULL;
+}
+
+/**
+ * Wrapper for get_ptracee(), this ensures only a stopped tracee is
+ * returned (or NULL).
+ */
+Tracee *get_stopped_ptracee(const Tracee *ptracer, pid_t pid,
+			bool only_with_pevent, word_t wait_options)
+{
+	return get_ptracee(ptracer, pid, true, only_with_pevent, wait_options);
+}
+
+/**
+ * Wrapper for get_ptracee(), this ensures no running tracee is
+ * returned.
+ */
+bool has_ptracees(const Tracee *ptracer, pid_t pid, word_t wait_options)
+{
+	return (get_ptracee(ptracer, pid, false, false, wait_options) != NULL);
+}
+
+/**
+ * Return the entry related to the tracee @pid.  If no entry were
+ * found, a new one is created if @create is true, otherwise NULL is
+ * returned.
+ */
+Tracee *get_tracee(const Tracee *current_tracee, pid_t pid, bool create)
+{
+	Tracee *tracee;
+
+	/* Don't reset the memory collector if the searched tracee is
+	 * the current one: there's likely pointers to the
+	 * sub-allocated data in the caller.  */
+	if (current_tracee != NULL && current_tracee->pid == pid)
+		return (Tracee *)current_tracee;
+
+	LIST_FOREACH(tracee, &tracees, link) {
+		if (tracee->pid == pid) {
+			/* Flush then allocate a new memory collector.  */
+			TALLOC_FREE(tracee->ctx);
+			tracee->ctx = talloc_new(tracee);
+
+			return tracee;
+		}
+	}
+
+	return (create ? new_tracee(pid) : NULL);
+}
+
+/**
+ * Free all tracees marked as terminated.
+ */
+void free_terminated_tracees()
+{
+	Tracee *next;
+
+	/* Items can't be deleted when using LIST_FOREACH.  */
+	next = tracees.lh_first;
+	while (next != NULL) {
+		Tracee *tracee = next;
+		next = tracee->link.le_next;
+
+		if (tracee->terminated)
+			TALLOC_FREE(tracee);
+	}
+}
+
+/**
+ * Make new @parent's child inherit from it.  Depending on
+ * @clone_flags, some information are copied or shared.  This function
+ * returns -errno if an error occured, otherwise 0.
+ */
+int new_child(Tracee *parent, word_t clone_flags)
+{
+	int ptrace_options;
+	unsigned long pid;
+	Tracee *child;
+	int status;
+
+	/* If the tracee calls clone(2) with the CLONE_VFORK flag,
+	 * PTRACE_EVENT_VFORK will be delivered instead [...];
+	 * otherwise if the tracee calls clone(2) with the exit signal
+	 * set to SIGCHLD, PTRACE_EVENT_FORK will be delivered [...]
+	 *
+	 * -- ptrace(2) man-page
+	 *
+	 * That means we have to check if it's actually a clone(2) in
+	 * order to get the right flags.
+	 */
+	status = fetch_regs(parent);
+	if (status >= 0 && get_sysnum(parent, CURRENT) == PR_clone)
+		clone_flags = peek_reg(parent, CURRENT, SYSARG_1);
+
+	/* Get the pid of the parent's new child.  */
+	status = ptrace(PTRACE_GETEVENTMSG, parent->pid, NULL, &pid);
+	if (status < 0 || pid == 0) {
+		note(parent, WARNING, SYSTEM, "ptrace(GETEVENTMSG)");
+		return status;
+	}
+
+	child = get_tracee(parent, (pid_t) pid, true);
+	if (child == NULL) {
+		note(parent, WARNING, SYSTEM, "running out of memory");
+		return -ENOMEM;
+	}
+
+	/* Sanity checks.  */
+	assert(child != NULL
+	    && child->exe == NULL
+	    && child->fs->cwd == NULL
+	    && child->fs->bindings.pending == NULL
+	    && child->fs->bindings.guest == NULL
+	    && child->fs->bindings.host == NULL
+	    && child->qemu == NULL
+	    && child->glue == NULL
+	    && child->parent == NULL
+	    && child->as_ptracee.ptracer == NULL);
+
+	child->verbose = parent->verbose;
+	child->seccomp = parent->seccomp;
+	child->sysexit_pending = parent->sysexit_pending;
+
+	/* If CLONE_VM is set, the calling process and the child
+	 * process run in the same memory space [...] any memory
+	 * mapping or unmapping performed with mmap(2) or munmap(2) by
+	 * the child or calling process also affects the other
+	 * process.
+	 *
+	 * If CLONE_VM is not set, the child process runs in a
+	 * separate copy of the memory space of the calling process at
+	 * the time of clone().  Memory writes or file
+	 * mappings/unmappings performed by one of the processes do
+	 * not affect the other, as with fork(2).
+	 *
+	 * -- clone(2) man-page
+	 */
+	TALLOC_FREE(child->heap);
+	child->heap = ((clone_flags & CLONE_VM) != 0)
+		? talloc_reference(child, parent->heap)
+		: talloc_memdup(child, parent->heap, sizeof(Heap));
+	if (child->heap == NULL)
+		return -ENOMEM;
+
+	/* If CLONE_PARENT is set, then the parent of the new child
+	 * (as returned by getppid(2)) will be the same as that of the
+	 * calling process.
+	 *
+	 * If CLONE_PARENT is not set, then (as with fork(2)) the
+	 * child's parent is the calling process.
+	 *
+	 * -- clone(2) man-page
+	 */
+	if ((clone_flags & CLONE_PARENT) != 0)
+		child->parent = parent->parent;
+	else
+		child->parent = parent;
+
+	/* Remember if this child belongs to the same thread group as
+	 * its parent.  This is currently useful for ptrace emulation
+	 * only but it deserves to be extended to support execve(2)
+	 * specificity (ie. when a thread calls execve(2), its pid
+	 * gets replaced by the pid of its thread group leader).  */
+	child->clone = ((clone_flags & CLONE_THREAD) != 0);
+
+	/* Depending on how the new process is created, it may be
+	 * automatically traced by the parent's tracer.  */
+	ptrace_options = ( clone_flags == 0			? PTRACE_O_TRACEFORK
+			: (clone_flags & 0xFF) == SIGCHLD	? PTRACE_O_TRACEFORK
+			: (clone_flags & CLONE_VFORK) != 0	? PTRACE_O_TRACEVFORK
+			: 					  PTRACE_O_TRACECLONE);
+	if (parent->as_ptracee.ptracer != NULL
+	    && (   (ptrace_options & parent->as_ptracee.options) != 0
+		|| (clone_flags & CLONE_PTRACE) != 0)) {
+		attach_to_ptracer(child, parent->as_ptracee.ptracer);
+
+		/* All these flags are inheritable, no matter why this
+		 * child is being traced.  */
+		child->as_ptracee.options |= (parent->as_ptracee.options
+					      & ( PTRACE_O_TRACECLONE
+						| PTRACE_O_TRACEEXEC
+						| PTRACE_O_TRACEEXIT
+						| PTRACE_O_TRACEFORK
+						| PTRACE_O_TRACESYSGOOD
+						| PTRACE_O_TRACEVFORK
+						| PTRACE_O_TRACEVFORKDONE));
+	}
+
+	/* If CLONE_FS is set, the parent and the child process share
+	 * the same file system information.  This includes the root
+	 * of the file system, the current working directory, and the
+	 * umask.  Any call to chroot(2), chdir(2), or umask(2)
+	 * performed by the parent process or the child process also
+	 * affects the other process.
+	 *
+	 * If CLONE_FS is not set, the child process works on a copy
+	 * of the file system information of the parent process at the
+	 * time of the clone() call.  Calls to chroot(2), chdir(2),
+	 * umask(2) performed later by one of the processes do not
+	 * affect the other process.
+	 *
+	 * -- clone(2) man-page
+	 */
+	TALLOC_FREE(child->fs);
+	if ((clone_flags & CLONE_FS) != 0) {
+		/* File-system name-space is shared.  */
+		child->fs = talloc_reference(child, parent->fs);
+	}
+	else {
+		/* File-system name-space is copied.  */
+		child->fs = talloc_zero(child, FileSystemNameSpace);
+		if (child->fs == NULL)
+			return -ENOMEM;
+
+		child->fs->cwd = talloc_strdup(child->fs, parent->fs->cwd);
+		if (child->fs->cwd == NULL)
+			return -ENOMEM;
+		talloc_set_name_const(child->fs->cwd, "$cwd");
+
+		/* Bindings are shared across file-system name-spaces since a
+		 * "mount --bind" made by a process affects all other processes
+		 * under Linux.  Actually they are copied when a sub
+		 * reconfiguration occured (nested proot or chroot(2)).  */
+		child->fs->bindings.guest = talloc_reference(child->fs, parent->fs->bindings.guest);
+		child->fs->bindings.host  = talloc_reference(child->fs, parent->fs->bindings.host);
+	}
+
+	/* The path to the executable is unshared only once the child
+	 * process does a call to execve(2).  */
+	child->exe = talloc_reference(child, parent->exe);
+
+	child->qemu = talloc_reference(child, parent->qemu);
+	child->glue = talloc_reference(child, parent->glue);
+
+	child->host_ldso_paths  = talloc_reference(child, parent->host_ldso_paths);
+	child->guest_ldso_paths = talloc_reference(child, parent->guest_ldso_paths);
+
+	child->tool_name = parent->tool_name;
+
+	inherit_extensions(child, parent, clone_flags);
+
+	/* Restart the child tracee if it was already alive but
+	 * stopped until that moment.  */
+	if (child->sigstop == SIGSTOP_PENDING) {
+		bool keep_stopped = false;
+
+		child->sigstop = SIGSTOP_ALLOWED;
+
+		/* Notify its ptracer if it is ready to be traced.  */
+		if (child->as_ptracee.ptracer != NULL) {
+			/* Sanity check.  */
+			assert(!child->as_ptracee.tracing_started);
+
+			keep_stopped = handle_ptracee_event(child, __W_STOPCODE(SIGSTOP));
+
+			/* Note that this event was already handled by
+			 * PRoot since child->as_ptracee.ptracer was
+			 * NULL up to now.  */
+			child->as_ptracee.event4.proot.pending = false;
+			child->as_ptracee.event4.proot.value   = 0;
+		}
+
+		if (!keep_stopped)
+			(void) restart_tracee(child, 0);
+	}
+
+	return 0;
+}
+
+/**
+ * Helper for swap_config().
+ */
+static void reparent_config(Tracee *new_parent, Tracee *old_parent)
+{
+	new_parent->verbose = old_parent->verbose;
+
+#define REPARENT(field) do {							\
+		talloc_reparent(old_parent, new_parent, old_parent->field);	\
+		new_parent->field = old_parent->field;				\
+	} while(0);
+
+	REPARENT(fs);
+	REPARENT(exe);
+	REPARENT(qemu);
+	REPARENT(glue);
+	REPARENT(extensions);
+
+#undef REPARENT
+}
+
+/**
+ * Swap configuration (pointers and parentality) between @tracee1 and @tracee2.
+ */
+int swap_config(Tracee *tracee1, Tracee *tracee2)
+{
+	Tracee *tmp;
+
+	tmp = talloc_zero(tracee1->ctx, Tracee);
+	if (tmp == NULL)
+		return -ENOMEM;
+
+	reparent_config(tmp,     tracee1);
+	reparent_config(tracee1, tracee2);
+	reparent_config(tracee2, tmp);
+
+	return 0;
+}
+
+/* Send the KILL signal to all tracees.  */
+void kill_all_tracees()
+{
+	Tracee *tracee;
+
+	LIST_FOREACH(tracee, &tracees, link)
+		kill(tracee->pid, SIGKILL);
+}
diff --git a/5.1.0/src/tracee/tracee.h b/5.1.0/src/tracee/tracee.h
new file mode 100644
index 0000000..f4c3a23
--- /dev/null
+++ b/5.1.0/src/tracee/tracee.h
@@ -0,0 +1,273 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef TRACEE_H
+#define TRACEE_H
+
+#include <sys/types.h> /* pid_t, size_t, */
+#include <sys/user.h>  /* struct user*, */
+#include <stdbool.h>   /* bool,  */
+#include <sys/queue.h> /* LIST_*, */
+#include <sys/ptrace.h>/* enum __ptrace_request */
+#include <talloc.h>    /* talloc_*, */
+
+#include "arch.h" /* word_t, user_regs_struct, */
+#include "compat.h"
+
+typedef enum {
+	CURRENT  = 0,
+	ORIGINAL = 1,
+	MODIFIED = 2,
+	NB_REG_VERSION
+} RegVersion;
+
+struct bindings;
+struct load_info;
+struct extensions;
+struct chained_syscalls;
+
+/* Information related to a file-system name-space.  */
+typedef struct {
+	struct {
+		/* List of bindings as specified by the user but not canonicalized yet.  */
+		struct bindings *pending;
+
+		/* List of bindings canonicalized and sorted in the "guest" order.  */
+		struct bindings *guest;
+
+		/* List of bindings canonicalized and sorted in the "host" order.  */
+		struct bindings *host;
+	} bindings;
+
+	/* Current working directory, à la /proc/self/pwd.  */
+	char *cwd;
+} FileSystemNameSpace;
+
+/* Virtual heap, emulated with a regular memory mapping.  */
+typedef struct {
+	word_t base;
+	size_t size;
+	size_t prealloc_size;
+	bool disabled;
+} Heap;
+
+/* Information related to a tracee process. */
+typedef struct tracee {
+	/**********************************************************************
+	 * Private resources                                                  *
+	 **********************************************************************/
+
+	/* Link for the list of all tracees.  */
+	LIST_ENTRY(tracee) link;
+
+	/* Process identifier. */
+	pid_t pid;
+
+	/* Is it currently running or not?  */
+	bool running;
+
+	/* Is this tracee ready to be freed?  TODO: move to a list
+	 * dedicated to terminated tracees instead.  */
+	bool terminated;
+
+	/* Parent of this tracee, NULL if none.  */
+	struct tracee *parent;
+
+	/* Is it a "clone", i.e has the same parent as its creator.  */
+	bool clone;
+
+	/* Support for ptrace emulation (tracer side).  */
+	struct {
+		size_t nb_ptracees;
+		LIST_HEAD(zombies, tracee) zombies;
+
+		pid_t wait_pid;
+		word_t wait_options;
+
+		enum {
+			DOESNT_WAIT = 0,
+			WAITS_IN_KERNEL,
+			WAITS_IN_PROOT
+		} waits_in;
+	} as_ptracer;
+
+	/* Support for ptrace emulation (tracee side).  */
+	struct {
+		struct tracee *ptracer;
+
+		struct {
+			#define STRUCT_EVENT struct { int value; bool pending; }
+
+			STRUCT_EVENT proot;
+			STRUCT_EVENT ptracer;
+		} event4;
+
+		bool tracing_started;
+		bool ignore_loader_syscalls;
+		bool ignore_syscalls;
+		word_t options;
+		bool is_zombie;
+	} as_ptracee;
+
+	/* Current status:
+	 *        0: enter syscall
+	 *        1: exit syscall no error
+	 *   -errno: exit syscall with error.  */
+	int status;
+
+#define IS_IN_SYSENTER(tracee) ((tracee)->status == 0)
+#define IS_IN_SYSEXIT(tracee) (!IS_IN_SYSENTER(tracee))
+#define IS_IN_SYSEXIT2(tracee, sysnum) (IS_IN_SYSEXIT(tracee) \
+				     && get_sysnum((tracee), ORIGINAL) == sysnum)
+
+	/* How this tracee is restarted.  */
+	enum __ptrace_request restart_how;
+
+	/* Value of the tracee's general purpose registers.  */
+	struct user_regs_struct _regs[NB_REG_VERSION];
+	bool _regs_were_changed;
+	bool restore_original_regs;
+
+	/* State for the special handling of SIGSTOP.  */
+	enum {
+		SIGSTOP_IGNORED = 0,  /* Ignore SIGSTOP (once the parent is known).  */
+		SIGSTOP_ALLOWED,      /* Allow SIGSTOP (once the parent is known).   */
+		SIGSTOP_PENDING,      /* Block SIGSTOP until the parent is unknown.  */
+	} sigstop;
+
+	/* Context used to collect all the temporary dynamic memory
+	 * allocations.  */
+	TALLOC_CTX *ctx;
+
+	/* Context used to collect all dynamic memory allocations that
+	 * should be released once this tracee is freed.  */
+	TALLOC_CTX *life_context;
+
+	/* Note: I could rename "ctx" in "event_span" and
+	 * "life_context" in "life_span".  */
+
+	/* Specify the type of the final component during the
+	 * initialization of a binding.  This variable is first
+	 * defined in bind_path() then used in build_glue().  */
+	mode_t glue_type;
+
+	/* During a sub-reconfiguration, the new setup is relatively
+	 * to @tracee's file-system name-space.  Also, @paths holds
+	 * its $PATH environment variable in order to emulate the
+	 * execvp(3) behavior.  */
+	struct {
+		struct tracee *tracee;
+		const char *paths;
+	} reconf;
+
+	/* Unrequested syscalls inserted by PRoot after an actual
+	 * syscall.  */
+	struct {
+		struct chained_syscalls *syscalls;
+		bool force_final_result;
+		word_t final_result;
+	} chain;
+
+	/* Load info generated during execve sysenter and used during
+	 * execve sysexit.  */
+	struct load_info *load_info;
+
+
+	/**********************************************************************
+	 * Private but inherited resources                                    *
+	 **********************************************************************/
+
+	/* Verbose level.  */
+	int verbose;
+
+	/* State of the seccomp acceleration for this tracee.  */
+	enum { DISABLED = 0, DISABLING, ENABLED } seccomp;
+
+	/* Ensure the sysexit stage is always hit under seccomp.  */
+	bool sysexit_pending;
+
+
+	/**********************************************************************
+	 * Shared or private resources, depending on the CLONE_FS/VM flags.   *
+	 **********************************************************************/
+
+	/* Information related to a file-system name-space.  */
+	FileSystemNameSpace *fs;
+
+	/* Virtual heap, emulated with a regular memory mapping.  */
+	Heap *heap;
+
+
+	/**********************************************************************
+	 * Shared resources until the tracee makes a call to execve().        *
+	 **********************************************************************/
+
+	/* Path to the executable, à la /proc/self/exe.  */
+	char *exe;
+	char *new_exe;
+
+
+	/**********************************************************************
+	 * Shared or private resources, depending on the (re-)configuration   *
+	 **********************************************************************/
+
+	/* Runner command-line.  */
+	char **qemu;
+
+	/* Path to glue between the guest rootfs and the host rootfs.  */
+	const char *glue;
+
+	/* List of extensions enabled for this tracee.  */
+	struct extensions *extensions;
+
+
+	/**********************************************************************
+	 * Shared but read-only resources                                     *
+	 **********************************************************************/
+
+	/* For the mixed-mode, the guest LD_LIBRARY_PATH is saved
+	 * during the "guest -> host" transition, in order to be
+	 * restored during the "host -> guest" transition (only if the
+	 * host LD_LIBRARY_PATH hasn't changed).  */
+	const char *host_ldso_paths;
+	const char *guest_ldso_paths;
+
+	/* For diagnostic purpose.  */
+	const char *tool_name;
+
+} Tracee;
+
+#define HOST_ROOTFS "/host-rootfs"
+
+#define TRACEE(a) talloc_get_type_abort(talloc_parent(talloc_parent(a)), Tracee)
+
+extern Tracee *get_tracee(const Tracee *tracee, pid_t pid, bool create);
+extern Tracee *get_stopped_ptracee(const Tracee *ptracer, pid_t pid,
+				bool only_with_pevent, word_t wait_options);
+extern bool has_ptracees(const Tracee *ptracer, pid_t pid, word_t wait_options);
+extern int new_child(Tracee *parent, word_t clone_flags);
+extern Tracee *new_dummy_tracee(TALLOC_CTX *context);
+extern void free_terminated_tracees();
+extern int swap_config(Tracee *tracee1, Tracee *tracee2);
+extern void kill_all_tracees();
+
+#endif /* TRACEE_H */
diff --git a/5.1.0/tests/GNUmakefile b/5.1.0/tests/GNUmakefile
new file mode 100644
index 0000000..d0eae50
--- /dev/null
+++ b/5.1.0/tests/GNUmakefile
@@ -0,0 +1,201 @@
+DIR    = $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
+ROOTFS = $(DIR)/rootfs
+PROOT  = $(DIR)/../src/proot
+CARE   = $(DIR)/../src/care
+CC     = gcc
+PROOT_RAW = $(PROOT)
+
+CHECK_TESTS = $(patsubst %,check-%, $(wildcard test-*.sh) $(wildcard test-*.c))
+
+.PHONY: check clean_failure check_failure setup check-%
+
+check: | clean_failure check_failure
+
+memcheck: PROOT_RAW := $(PROOT)
+memcheck: PROOT := $(shell which valgrind) -q --error-exitcode=1 $(PROOT)
+memcheck: check
+
+clean_failure:
+	@rm -f failure
+
+check_failure: $(CHECK_TESTS)
+	@bash -c '! test -e failure'
+
+check-%.sh: %.sh setup
+	$(Q)env CARE="$(CARE)" PROOT_RAW="$(PROOT_RAW)" PROOT="$(PROOT)" ROOTFS=$(ROOTFS) sh -ex $< $(silently); $(call check,$*)
+
+check-%.c: $(ROOTFS)/bin/% setup
+	$(call check_c,$*,$(PROOT) -b /proc -r $(ROOTFS) /bin/$*)
+
+# Special cases.
+check-test-bdc90417.c: test-bdc90417
+	$(call check_c,$<,$(PROOT) -w . ./$<)
+
+# Not supported anymore.
+# check-test-af062114.c: test-af062114
+# 	$(call check_c,$<,$(PROOT) -v -1 -q /bin/true -b . -b /lib -b /lib64 -b /proc -r $(ROOTFS) ./$< | grep -- --inhibit-rpath)
+# 	$(call check_c,$<,$(PROOT) -v -1 -q /bin/true / ./$< | grep '^./$<') deprecated
+
+check-test-5bed7141.c: test-5bed7141
+	$(call check_c,$<,$(PROOT) ./$<)
+
+check-test-5bed7143.c: test-5bed7143
+	$(call check_c,$<,$(PROOT) -r $(ROOTFS) -b . ./$<)
+	$(call check_c,$<,$(PROOT) ./$<)
+
+check-test-16573e73.c: test-16573e73
+	$(call check_c,$<,$(PROOT) ./$<)
+	$(call check_c,$<,$(PROOT) ./$< 1)
+
+check-test-82ba4ba1.c: test-82ba4ba1
+	$(call check_c,$<,$(PROOT) -0 ./$<)
+	$(call check_c,$<,! $(PROOT) -i 123:456 ./$<)
+
+check-test-kkkkkkkk.c: test-kkkkkkkk
+	$(call check_c,$<,$(PROOT) ./$<)
+
+check-test-25069c12.c: test-25069c12
+	$(call check_c,$<,$(PROOT) ./$<)
+
+check-test-25069c13.c: test-25069c13
+	$(call check_c,$<,$(PROOT) ./$<)
+
+check-test-1ffc8309.c: test-1ffc8309
+	$(call check_c,$<,env PROOT_FORCE_KOMPAT=1 $(PROOT) -k $(shell uname -r) ./$<)
+
+check-test-c5a7a0f0.c: test-c5a7a0f0
+	$(call check_c,$<,$(PROOT) -0 ./$<)
+	$(call check_c,$<,! $(PROOT) -i 123:456 ./$<)
+
+check-test-a3e68988.c: test-a3e68988
+	@which gdb >/dev/null 2>&1 || rm -f $<
+	$(call check_c,$<,$(PROOT) gdb -return-child-result -ex run -ex quit ./$<)
+
+check-test-c47aeb7d.c: test-c47aeb7d
+	@which gdb >/dev/null 2>&1 || rm -f $<
+	$(call check_c,$<,$(PROOT) gdb -return-child-result -ex run -ex quit ./$<)
+
+check-test-fdf487a0.c: test-fdf487a0
+	$(call check_c,$<,echo test | $(PROOT) ./$<)
+
+check-test-iiiiiiii.c: test-iiiiiiii
+	$(call check_c,$<,echo test | env PROOT_DONT_POLLUTE_ROOTFS=1 $(PROOT) -b /bin:/this_shall_not_exist_outside_proot ./$<)
+
+check-test-9c07fad8.c: test-9c07fad8
+	$(call check_c,$<,$(PROOT) ./$<)
+
+check-test-fa205b56.c: test-fa205b56
+	$(call check_c,$<,$(PROOT) ./$<)
+
+check_c = $(Q)if [ -e $< ]; then			\
+		$(2) $(silently); $(call check,$(1))	\
+	else						\
+		echo "  CHECK	$(1) skipped";		\
+	fi
+
+check = case "$$?" in					\
+		0)   echo "  CHECK	$(1) ok";;	\
+		125) echo "  CHECK	$(1) skipped";;	\
+		*)   echo "  CHECK	$(1) FAILED";	\
+		     touch failure ;;			\
+	esac
+
+######################################################################
+# Build a clean rootfs
+
+ROOTFS_BIN = $(ROOTFS)/bin/true $(ROOTFS)/bin/false    				 \
+       $(ROOTFS)/bin/pwd  $(ROOTFS)/bin/readlink $(ROOTFS)/bin/symlink		 \
+       $(ROOTFS)/bin/abs-true $(ROOTFS)/bin/rel-true $(ROOTFS)/bin/echo		 \
+       $(ROOTFS)/bin/argv0 $(ROOTFS)/bin/readdir $(ROOTFS)/bin/cat		 \
+       $(ROOTFS)/bin/chdir_getcwd $(ROOTFS)/bin/fchdir_getcwd $(ROOTFS)/bin/argv \
+       $(ROOTFS)/bin/fork-wait $(ROOTFS)/bin/ptrace $(ROOTFS)/bin/ptrace-2	 \
+       $(ROOTFS)/bin/puts_proc_self_exe $(ROOTFS)/bin/exec $(ROOTFS)/bin/exec-m32
+
+ROOTFS_DIR = $(ROOTFS)/bin $(ROOTFS)/tmp
+
+$(ROOTFS_BIN): | $(ROOTFS_DIR)
+
+$(ROOTFS_DIR):
+	@mkdir -p $@
+
+setup: $(ROOTFS_BIN)
+
+$(ROOTFS)/bin/abs-true:
+	@ln -fs /bin/true $@
+
+$(ROOTFS)/bin/rel-true:
+	@ln -fs ./true $@
+
+$(ROOTFS)/bin/exec-m32: exec.c
+	$(Q)$(CC) -m32 -static $^ -o $@ $(silently) || true
+
+.SECONDARY: $(patsubst %.c,$(ROOTFS)/bin/%, $(wildcard test-*.c))
+$(ROOTFS)/bin/%: %.c
+	$(Q)$(CC) -static $*.c -o $@ $(silently) || true
+
+# Special cases.
+test-bdc90417: test-bdc90417.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+# Not supported anymore.
+# test-af062114: test-af062114.c
+# 	$(Q)$(CC) $< -Wl,-rpath=foo -o $@ $(silently) || true
+
+test-5bed7141: test-5bed7141.c
+	$(Q)$(CC) $< -pthread -static -o $@ $(silently) || true
+
+test-16573e73: test-16573e73.c
+	$(Q)$(CC) $< -static -o $@ $(silently) || true
+
+test-82ba4ba1: test-82ba4ba1.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-kkkkkkkk: test-kkkkkkkk.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-25069c12: test-25069c12.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-25069c13: test-25069c13.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-5bed7143: test-5bed7143.c
+	$(Q)$(CC) $< -static -o $@ $(silently) || true
+
+test-1ffc8309: test-1ffc8309.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-c5a7a0f0: test-c5a7a0f0.c
+	$(Q)$(CC) $< -pthread -static -o $@ $(silently) || true
+
+test-a3e68988: test-a3e68988.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-fdf487a0: test-fdf487a0.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-iiiiiiii: test-iiiiiiii.c
+	$(Q)$(CC) $< -o $@ $(silently) || true
+
+test-9c07fad8: test-9c07fad8.c
+	$(Q)$(CC) -fPIE -pie $< -o $@ $(silently) || true
+
+test-fa205b56: test-fa205b56.c
+	$(Q)$(CC) $< -pthread -o $@ $(silently) || true
+
+test-c47aeb7d: test-c47aeb7d.c
+	$(Q)$(CC) $< -pthread -o $@ $(silently) || true
+
+######################################################################
+# Beautified output
+
+V = 0
+ifeq ($(V), 0)
+    quiet = quiet_
+    Q     = @
+    silently = >/dev/null 2>&1
+else
+    quiet = 
+    Q     = 
+    silently = 
+endif
diff --git a/5.1.0/tests/argv.c b/5.1.0/tests/argv.c
new file mode 100644
index 0000000..79920a6
--- /dev/null
+++ b/5.1.0/tests/argv.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+	int i;
+
+	for (i = 0; i < argc; i++)
+		printf("%s ", argv[i]);
+
+	return 0;
+}
diff --git a/5.1.0/tests/argv0.c b/5.1.0/tests/argv0.c
new file mode 100644
index 0000000..cdb3af7
--- /dev/null
+++ b/5.1.0/tests/argv0.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	puts(argv[0]);
+	return 0;
+}
diff --git a/5.1.0/tests/cat.c b/5.1.0/tests/cat.c
new file mode 100644
index 0000000..fe341e0
--- /dev/null
+++ b/5.1.0/tests/cat.c
@@ -0,0 +1,36 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+	int status;
+	int fd;
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		char buffer[1024];
+
+		fd = open(argv[i], O_RDONLY);
+		if (fd < 0) {
+			perror("open(2)");
+			exit(EXIT_FAILURE);
+		}
+
+		while ((status = read(fd, buffer, sizeof(buffer))) > 0 && write(1, buffer, status) == status)
+			errno = 0;
+
+		if (errno != 0) {
+			perror("read(2)/write(2)");
+			exit(EXIT_FAILURE);
+		}
+
+		(void) close(fd);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/chdir_getcwd.c b/5.1.0/tests/chdir_getcwd.c
new file mode 100644
index 0000000..26baa8a
--- /dev/null
+++ b/5.1.0/tests/chdir_getcwd.c
@@ -0,0 +1,34 @@
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+
+int main(int argc, char *argv[])
+{
+	char path[PATH_MAX];
+	int status;
+	int fd;
+
+	if (argc < 2) {
+		fprintf(stderr, "missing argument\n");
+		exit(EXIT_FAILURE);
+	}
+
+	status = chdir(argv[1]);
+	if (status < 0) {
+		perror("chdir()");
+		exit(EXIT_FAILURE);
+	}
+
+	if (getcwd(path, PATH_MAX) == NULL) {
+		perror("getcwd()");
+		exit(EXIT_FAILURE);
+	}
+
+	printf("%s\n", get_current_dir_name());
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/echo.c b/5.1.0/tests/echo.c
new file mode 100644
index 0000000..2a2ae6b
--- /dev/null
+++ b/5.1.0/tests/echo.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	int i;
+
+	for (i = 1; i < argc; i++)
+		puts(argv[i]);
+
+	return 0;
+}
diff --git a/5.1.0/tests/exec.c b/5.1.0/tests/exec.c
new file mode 100644
index 0000000..370765a
--- /dev/null
+++ b/5.1.0/tests/exec.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+	if (argc < 2) {
+		puts("not enough parameter: filename argv[0] argv[1] ... argv[n]");
+		exit(EXIT_FAILURE);
+	}
+
+	execve(argv[1], &argv[2], envp);
+	perror("execve");
+
+	exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/false.c b/5.1.0/tests/false.c
new file mode 100644
index 0000000..98c444a
--- /dev/null
+++ b/5.1.0/tests/false.c
@@ -0,0 +1 @@
+int main(void) { return 1; }
diff --git a/5.1.0/tests/fchdir_getcwd.c b/5.1.0/tests/fchdir_getcwd.c
new file mode 100644
index 0000000..4269b8f
--- /dev/null
+++ b/5.1.0/tests/fchdir_getcwd.c
@@ -0,0 +1,40 @@
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+
+int main(int argc, char *argv[])
+{
+	char path[PATH_MAX];
+	int status;
+	int fd;
+
+	if (argc < 2) {
+		fprintf(stderr, "missing argument\n");
+		exit(EXIT_FAILURE);
+	}
+
+	fd = open(argv[1], O_DIRECTORY);
+	if (fd < 0) {
+		perror("open()");
+		exit(EXIT_FAILURE);
+	}
+
+	status = fchdir(fd);
+	if (status < 0) {
+		perror("fchdir()");
+		exit(EXIT_FAILURE);
+	}
+
+	if (getcwd(path, PATH_MAX) == NULL) {
+		perror("getcwd()");
+		exit(EXIT_FAILURE);
+	}
+
+	printf("%s\n", get_current_dir_name());
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/fork-wait.c b/5.1.0/tests/fork-wait.c
new file mode 100644
index 0000000..5d64e68
--- /dev/null
+++ b/5.1.0/tests/fork-wait.c
@@ -0,0 +1,26 @@
+#include <stdlib.h> /* exit(3), */
+#include <unistd.h> /* fork(2), sleep(3), */
+#include <sys/types.h> /* wait(2), */
+#include <sys/wait.h>  /* wait(2), */
+
+int main(int argc, char *argv[])
+{
+	int child_status;
+	int status;
+
+	switch (fork()) {
+	case -1:
+		exit(EXIT_FAILURE);
+
+	case 0: /* Child */
+		argc > 1 && sleep(2);
+		exit(EXIT_SUCCESS);
+
+	default: /* Parent */
+		argc <= 1 && sleep(2);
+		status = wait(&child_status);
+		if (status < 0 || !WIFEXITED(child_status))
+			exit(EXIT_FAILURE);
+		exit(WEXITSTATUS(child_status));
+	}
+}
diff --git a/5.1.0/tests/ptrace-2.c b/5.1.0/tests/ptrace-2.c
new file mode 100644
index 0000000..7bcf817
--- /dev/null
+++ b/5.1.0/tests/ptrace-2.c
@@ -0,0 +1,407 @@
+/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
+ *
+ * This file is part of PRoot.
+ *
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <sys/types.h>  /* pid_t, waitpid(2), */
+#include <sys/ptrace.h> /* ptrace(3), PTRACE_*, */
+#include <sys/user.h>   /* struct user*, */
+#include <sys/wait.h>   /* waitpid(2), */
+#include <stddef.h>     /* offsetof(), */
+#include <unistd.h>     /* fork(2), getpid(2), */
+#include <errno.h>      /* errno(3), */
+#include <stdbool.h>    /* bool, true, false, */
+#include <stdlib.h>     /* exit, EXIT_*, */
+#include <stdio.h>      /* fprintf(3), stderr, */
+#include <stdint.h>     /* *int*_t, */
+
+#if !defined(ARCH_X86_64) && !defined(ARCH_ARM_EABI) && !defined(ARCH_X86) && !defined(ARCH_SH4)
+#    if defined(__x86_64__)
+#        define ARCH_X86_64 1
+#    elif defined(__ARM_EABI__)
+#        define ARCH_ARM_EABI 1
+#    elif defined(__aarch64__)
+#        define ARCH_ARM64 1
+#    elif defined(__arm__)
+#        error "Only EABI is currently supported for ARM"
+#    elif defined(__i386__)
+#        define ARCH_X86 1
+#    elif defined(__SH4__)
+#        define ARCH_SH4 1
+#    else
+#        error "Unsupported architecture"
+#    endif
+#endif
+
+/**
+ * Compute the offset of the register @reg_name in the USER area.
+ */
+#define USER_REGS_OFFSET(reg_name)			\
+	(offsetof(struct user, regs)			\
+	 + offsetof(struct user_regs_struct, reg_name))
+
+#define REG(regs, index)			\
+	(*(unsigned long*) (((uint8_t *) &regs) + reg_offset[index]))
+
+typedef enum {
+	SYSARG_NUM = 0,
+	SYSARG_1,
+	SYSARG_2,
+	SYSARG_3,
+	SYSARG_4,
+	SYSARG_5,
+	SYSARG_6,
+	SYSARG_RESULT,
+	STACK_POINTER,
+	INSTR_POINTER,
+} Reg;
+
+/* Specify the ABI registers (syscall argument passing, stack pointer).
+ * See sysdeps/unix/sysv/linux/${ARCH}/syscall.S from the GNU C Library. */
+#if defined(ARCH_X86_64)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(orig_rax),
+	[SYSARG_1]      = USER_REGS_OFFSET(rdi),
+	[SYSARG_2]      = USER_REGS_OFFSET(rsi),
+	[SYSARG_3]      = USER_REGS_OFFSET(rdx),
+	[SYSARG_4]      = USER_REGS_OFFSET(r10),
+	[SYSARG_5]      = USER_REGS_OFFSET(r8),
+	[SYSARG_6]      = USER_REGS_OFFSET(r9),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(rax),
+	[STACK_POINTER] = USER_REGS_OFFSET(rsp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(rip),
+    };
+
+    static off_t reg_offset_x86[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(orig_rax),
+	[SYSARG_1]      = USER_REGS_OFFSET(rbx),
+	[SYSARG_2]      = USER_REGS_OFFSET(rcx),
+	[SYSARG_3]      = USER_REGS_OFFSET(rdx),
+	[SYSARG_4]      = USER_REGS_OFFSET(rsi),
+	[SYSARG_5]      = USER_REGS_OFFSET(rdi),
+	[SYSARG_6]      = USER_REGS_OFFSET(rbp),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(rax),
+	[STACK_POINTER] = USER_REGS_OFFSET(rsp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(rip),
+    };
+
+    #undef  REG
+    #define REG(regs, index)					\
+	(*(unsigned long*) (regs.cs == 0x23			\
+		? (((uint8_t *) &regs) + reg_offset_x86[index]) \
+		: (((uint8_t *) &regs) + reg_offset[index])))
+
+#elif defined(ARCH_ARM_EABI)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(uregs[7]),
+	[SYSARG_1]      = USER_REGS_OFFSET(uregs[0]),
+	[SYSARG_2]      = USER_REGS_OFFSET(uregs[1]),
+	[SYSARG_3]      = USER_REGS_OFFSET(uregs[2]),
+	[SYSARG_4]      = USER_REGS_OFFSET(uregs[3]),
+	[SYSARG_5]      = USER_REGS_OFFSET(uregs[4]),
+	[SYSARG_6]      = USER_REGS_OFFSET(uregs[5]),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(uregs[0]),
+	[STACK_POINTER] = USER_REGS_OFFSET(uregs[13]),
+	[INSTR_POINTER] = USER_REGS_OFFSET(uregs[15]),
+    };
+
+#elif defined(ARCH_ARM64)
+
+    #undef  USER_REGS_OFFSET
+    #define USER_REGS_OFFSET(reg_name) offsetof(struct user_regs_struct, reg_name)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(regs[8]),
+	[SYSARG_1]      = USER_REGS_OFFSET(regs[0]),
+	[SYSARG_2]      = USER_REGS_OFFSET(regs[1]),
+	[SYSARG_3]      = USER_REGS_OFFSET(regs[2]),
+	[SYSARG_4]      = USER_REGS_OFFSET(regs[3]),
+	[SYSARG_5]      = USER_REGS_OFFSET(regs[4]),
+	[SYSARG_6]      = USER_REGS_OFFSET(regs[5]),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(regs[0]),
+	[STACK_POINTER] = USER_REGS_OFFSET(sp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(pc),
+    };
+
+#elif defined(ARCH_X86)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(orig_eax),
+	[SYSARG_1]      = USER_REGS_OFFSET(ebx),
+	[SYSARG_2]      = USER_REGS_OFFSET(ecx),
+	[SYSARG_3]      = USER_REGS_OFFSET(edx),
+	[SYSARG_4]      = USER_REGS_OFFSET(esi),
+	[SYSARG_5]      = USER_REGS_OFFSET(edi),
+	[SYSARG_6]      = USER_REGS_OFFSET(ebp),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(eax),
+	[STACK_POINTER] = USER_REGS_OFFSET(esp),
+	[INSTR_POINTER] = USER_REGS_OFFSET(eip),
+    };
+
+#elif defined(ARCH_SH4)
+
+    static off_t reg_offset[] = {
+	[SYSARG_NUM]    = USER_REGS_OFFSET(regs[3]),
+	[SYSARG_1]      = USER_REGS_OFFSET(regs[4]),
+	[SYSARG_2]      = USER_REGS_OFFSET(regs[5]),
+	[SYSARG_3]      = USER_REGS_OFFSET(regs[6]),
+	[SYSARG_4]      = USER_REGS_OFFSET(regs[7]),
+	[SYSARG_5]      = USER_REGS_OFFSET(regs[0]),
+	[SYSARG_6]      = USER_REGS_OFFSET(regs[1]),
+	[SYSARG_RESULT] = USER_REGS_OFFSET(regs[0]),
+	[STACK_POINTER] = USER_REGS_OFFSET(regs[15]),
+	[INSTR_POINTER] = USER_REGS_OFFSET(pc),
+    };
+
+#else
+
+    #error "Unsupported architecture"
+
+#endif
+
+int main(int argc, char *argv[])
+{
+	enum __ptrace_request restart_how;
+	int last_exit_status = -1;
+	pid_t *pids = NULL;
+	long status;
+	int signal;
+	pid_t pid;
+
+	if (argc <= 1) {
+		fprintf(stderr, "Usage: %s /path/to/exe [args]\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	pid = fork();
+	switch(pid) {
+	case -1:
+		perror("fork()");
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		status = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+		if (status < 0) {
+			perror("ptrace(TRACEME)");
+			exit(EXIT_FAILURE);
+		}
+
+		/* Synchronize with the tracer's event loop.  */
+		kill(getpid(), SIGSTOP);
+
+		execvp(argv[1], &argv[1]);
+		exit(EXIT_FAILURE);
+
+	default: /* parent */
+		break;
+	}
+
+	restart_how = (getenv("PTRACER_BEHAVIOR_1") == NULL
+		? PTRACE_SYSCALL
+		: PTRACE_CONT);
+
+	pids = calloc(1, sizeof(pid_t));
+	if (pids == NULL) {
+		perror("calloc()");
+		exit(EXIT_FAILURE);
+	}
+
+	signal = 0;
+	while (1) {
+		int tracee_status;
+		pid_t pid;
+		pid_t sid;
+		int i;
+
+		/* Wait for the next tracee's stop. */
+		pid = waitpid(-1, &tracee_status, __WALL);
+		if (pid < 0) {
+			perror("waitpid()");
+			if (errno != ECHILD)
+				exit(EXIT_FAILURE);
+			break;
+		}
+
+		sid = 0;
+		for (i = 0; pids[i] != 0; i++) {
+			if (pid == pids[i]) {
+				sid = i + 1;
+				break;
+			}
+		}
+		if (sid == 0) {
+			pids = realloc(pids, (i + 1 + 1) * sizeof(pid_t));
+			if (pids == NULL) {
+				perror("realloc()");
+				exit(EXIT_FAILURE);
+			}
+			pids[i + 1] = 0;
+			pids[i] = pid;
+			sid = i + 1;
+			fprintf(stderr, "sid %d -> pid %d\n", sid, pid);
+		}
+
+		if (WIFEXITED(tracee_status)) {
+			fprintf(stderr, "sid %d: exited with status %d\n",
+				sid, WEXITSTATUS(tracee_status));
+			last_exit_status = WEXITSTATUS(tracee_status);
+			continue; /* Skip the call to ptrace(SYSCALL). */
+		}
+		else if (WIFSIGNALED(tracee_status)) {
+			fprintf(stderr, "sid %d: terminated with signal %d\n",
+				sid, WTERMSIG(tracee_status));
+			continue; /* Skip the call to ptrace(SYSCALL). */
+		}
+		else if (WIFCONTINUED(tracee_status)) {
+			fprintf(stderr, "sid %d: continued\n", sid);
+			signal = SIGCONT;
+		}
+		else if (WIFSTOPPED(tracee_status)) {
+			struct user_regs_struct regs;
+
+			/* Don't use WSTOPSIG() to extract the signal
+			 * since it clears the PTRACE_EVENT_* bits. */
+			signal = (tracee_status & 0xfff00) >> 8;
+
+			switch (signal) {
+				static bool skip_bare_sigtrap = false;
+				long ptrace_options;
+
+			case SIGTRAP:
+				fprintf(stderr, "sid %d: SIGTRAP\n", sid);
+
+				status = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
+				if (status < 0) {
+					fprintf(stderr,
+						"sigtrap: ?, ?\n");
+				} else {
+					fprintf(stderr, "sigtrap: %ld == 0 ? %d\n",
+						REG(regs, SYSARG_NUM),
+						REG(regs, SYSARG_RESULT) == 0);
+				}
+
+				/* PTRACER_BEHAVIOR_1 */
+				if (restart_how != PTRACE_SYSCALL) {
+					restart_how = PTRACE_SYSCALL;
+					signal = 0;
+					break;
+				}
+
+				/* Distinguish some events from others and
+				 * automatically trace each new process with
+				 * the same options.
+				 *
+				 * Note that only the first bare SIGTRAP is
+				 * related to the tracing loop, others SIGTRAP
+				 * carry tracing information because of
+				 * TRACE*FORK/CLONE/EXEC.
+				 */
+				if (skip_bare_sigtrap) {
+					signal = 0;
+					break;
+				}
+				skip_bare_sigtrap = true;
+
+				ptrace_options = PTRACE_O_TRACESYSGOOD
+					| PTRACE_O_TRACEFORK
+					| PTRACE_O_TRACEVFORK
+					| PTRACE_O_TRACEVFORKDONE
+					| PTRACE_O_TRACECLONE
+					| PTRACE_O_TRACEEXIT;
+
+				if (getenv("PTRACER_BEHAVIOR_2") == NULL)
+					ptrace_options |= PTRACE_O_TRACEEXEC;
+
+				status = ptrace(PTRACE_SETOPTIONS, pid, NULL, ptrace_options);
+				if (status < 0) {
+					perror("ptrace(PTRACE_SETOPTIONS)");
+					exit(EXIT_FAILURE);
+				}
+				/* Fall through. */
+			case SIGTRAP | 0x80:
+				fprintf(stderr, "sid %d: PTRACE_EVENT_SYSGOOD\n", sid);
+				signal = 0;
+
+				status = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
+				if (status < 0) {
+					fprintf(stderr,
+						"syscall(?) = ?\n");
+				} else {
+					fprintf(stderr, "syscall(%ld) == 0 ? %d\n",
+						REG(regs, SYSARG_NUM),
+						REG(regs, SYSARG_RESULT) == 0);
+				}
+				break;
+
+			case SIGTRAP | PTRACE_EVENT_VFORK << 8:
+				fprintf(stderr, "sid %d: PTRACE_EVENT_VFORK\n", sid);
+				signal = 0;
+				break;
+
+			case SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8:
+				fprintf(stderr, "sid %d: PTRACE_EVENT_VFORK\n", sid);
+				signal = 0;
+				break;
+
+			case SIGTRAP | PTRACE_EVENT_FORK  << 8:
+				fprintf(stderr, "sid %d: PTRACE_EVENT_FORK\n", sid);
+				signal = 0;
+				break;
+
+			case SIGTRAP | PTRACE_EVENT_CLONE << 8:
+				fprintf(stderr, "sid %d: PTRACE_EVENT_CLONE\n", sid);
+				signal = 0;
+				break;
+
+			case SIGTRAP | PTRACE_EVENT_EXEC  << 8:
+				fprintf(stderr, "sid %d: PTRACE_EVENT_EXEC\n", sid);
+				signal = 0;
+				break;
+
+			case SIGTRAP | PTRACE_EVENT_EXIT  << 8:
+				fprintf(stderr, "sid %d: PTRACE_EVENT_EXIT\n", sid);
+				signal = 0;
+				break;
+
+			case SIGSTOP:
+				fprintf(stderr, "sid %d: SIGSTOP\n", sid);
+				signal = 0;
+				break;
+
+			default:
+				break;
+			}
+		}
+		else {
+			fprintf(stderr, "sid %d: unknown trace event\n", sid);
+			signal = 0;
+		}
+
+		/* Restart the tracee and stop it at the next entry or
+		 * exit of a system call. */
+		status = ptrace(restart_how, pid, NULL, signal);
+		if (status < 0)
+			fprintf(stderr, "ptrace(<restart_how>, %d, %d): %s\n", sid, signal, strerror(errno));
+	}
+
+	return last_exit_status;
+}
diff --git a/5.1.0/tests/ptrace.c b/5.1.0/tests/ptrace.c
new file mode 100644
index 0000000..3613139
--- /dev/null
+++ b/5.1.0/tests/ptrace.c
@@ -0,0 +1,54 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int main(int argc, char **argv)
+{
+	int child_status;
+	long status;
+	pid_t pid;
+
+	pid = (argc <= 1 ? fork() : vfork());
+	switch(pid) {
+	case -1:
+		perror("fork()");
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		sleep(2);
+		status = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+		if (status < 0) {
+			perror("ptrace(TRACEME)");
+			exit(EXIT_FAILURE);
+		}
+
+		if (argc <= 1) {
+			kill(getpid(), SIGSTOP);
+			exit(EXIT_SUCCESS);
+		}
+		else {
+			execl("true", "true", NULL);
+			exit(EXIT_FAILURE);
+		}
+
+	default: /* parent */
+		pid = waitpid(-1, &child_status, __WALL);
+		if (pid < 0) {
+			perror("waitpid()");
+			exit(EXIT_FAILURE);
+		}
+
+		if (argc <= 1) {
+			if (!WIFSTOPPED(child_status))
+				exit(EXIT_FAILURE);
+		}
+
+		exit(EXIT_SUCCESS);
+	}
+
+	return 0;
+}
diff --git a/5.1.0/tests/puts_proc_self_exe.c b/5.1.0/tests/puts_proc_self_exe.c
new file mode 100644
index 0000000..74b920f
--- /dev/null
+++ b/5.1.0/tests/puts_proc_self_exe.c
@@ -0,0 +1,18 @@
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+	char path[PATH_MAX];
+	ssize_t status;
+
+	status = readlink("/proc/self/exe", path, PATH_MAX - 1);
+	if (status < 0 || status >= PATH_MAX)
+		exit(EXIT_FAILURE);
+	path[status] = '\0';
+
+	puts(path);
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/pwd.c b/5.1.0/tests/pwd.c
new file mode 100644
index 0000000..31211c9
--- /dev/null
+++ b/5.1.0/tests/pwd.c
@@ -0,0 +1,22 @@
+#include <unistd.h> /* syscall(2), */
+#include <stdio.h>  /* perror(3), */
+#include <limits.h> /* PATH_MAX, */
+#include <stdlib.h> /* exit(3), */
+#include <sys/syscall.h> /* SYS_getcwd, */
+
+
+int main(void)
+{
+	char path[PATH_MAX];
+	int status;
+
+	status = syscall(SYS_getcwd, path, PATH_MAX);
+	if (status < 0) {
+		perror("getcwd()");
+		exit(EXIT_FAILURE);
+	}
+
+	puts(path);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/readdir.c b/5.1.0/tests/readdir.c
new file mode 100644
index 0000000..13ca8ec
--- /dev/null
+++ b/5.1.0/tests/readdir.c
@@ -0,0 +1,49 @@
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+	struct dirent *dirents;
+	DIR *dir;
+
+	int status;
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		dir = opendir(argv[i]);
+		if (dir == NULL) {
+			perror("opendir(3)");
+			exit(EXIT_FAILURE);
+		}
+
+		errno = 0;
+		while ((dirents = readdir(dir)) != NULL) {
+			printf("%s %s\n",
+				dirents->d_type == DT_BLK  ? "DT_BLK " :
+				dirents->d_type == DT_CHR  ? "DT_CHR " :
+				dirents->d_type == DT_DIR  ? "DT_DIR " :
+				dirents->d_type == DT_FIFO ? "DT_FIFO" :
+				dirents->d_type == DT_LNK  ? "DT_LNK " :
+				dirents->d_type == DT_REG  ? "DT_REG " :
+				dirents->d_type == DT_SOCK ? "DT_SOCK" :
+				"DT_UNKNOWN", dirents->d_name);
+			errno = 0;
+		}
+
+		if (errno != 0) {
+			perror("readdir(3)");
+			exit(EXIT_FAILURE);
+		}
+
+		status = closedir(dir);
+		if (status < 0) {
+			perror("closedir(3)");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/readlink.c b/5.1.0/tests/readlink.c
new file mode 100644
index 0000000..58b0f90
--- /dev/null
+++ b/5.1.0/tests/readlink.c
@@ -0,0 +1,27 @@
+#include <unistd.h> /* syscall(2), */
+#include <stdio.h>  /* perror(3), fprintf(3), */
+#include <limits.h> /* PATH_MAX, */
+#include <stdlib.h> /* exit(3), */
+#include <sys/syscall.h> /* SYS_readlink, */
+
+int main(int argc, char *argv[])
+{
+	char path[PATH_MAX];
+	int status;
+
+	if (argc != 2) {
+		fprintf(stderr, "usage: readlink FILE\n");
+		exit(EXIT_FAILURE);
+	}
+
+	status = syscall(SYS_readlink, argv[1], path, PATH_MAX);
+	if (status < 0) {
+		perror("readlink()");
+		exit(EXIT_FAILURE);
+	}
+	path[status] = '\0';
+
+	puts(path);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/symlink.c b/5.1.0/tests/symlink.c
new file mode 100644
index 0000000..1e8c195
--- /dev/null
+++ b/5.1.0/tests/symlink.c
@@ -0,0 +1,22 @@
+#include <unistd.h> /* syscall(2), */
+#include <stdio.h>  /* perror(3), fprintf(3), */
+#include <stdlib.h> /* exit(3), */
+#include <sys/syscall.h> /* SYS_symlink, */
+
+int main(int argc, char *argv[])
+{
+	int status;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: symlink REFEREE REFERER\n");
+		exit(EXIT_FAILURE);
+	}
+
+	status = syscall(SYS_symlink, argv[1], argv[2]);
+	if (status < 0) {
+		perror("symlink()");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-00000000.sh b/5.1.0/tests/test-00000000.sh
new file mode 100644
index 0000000..3bb77e9
--- /dev/null
+++ b/5.1.0/tests/test-00000000.sh
@@ -0,0 +1,5 @@
+if [ ! -x ${ROOTFS}/bin/true ]; then
+    exit 125;
+fi
+
+${PROOT} -r ${ROOTFS} /bin/true
diff --git a/5.1.0/tests/test-0228fbe7.sh b/5.1.0/tests/test-0228fbe7.sh
new file mode 100644
index 0000000..647418b
--- /dev/null
+++ b/5.1.0/tests/test-0228fbe7.sh
@@ -0,0 +1,26 @@
+if [ -z `which mcookie` ] || [ -z `which env` ] || [ -z `which head` ] || [ -z `which cmp` ] || [ -z `which rm` ] || [ ! -x  ${ROOTFS}/bin/ptrace-2 ] || [ ! -x  ${ROOTFS}/bin/true ]; then
+    exit 125;
+fi
+
+TMP1=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+
+${ROOTFS}/bin/ptrace-2 ${ROOTFS}/bin/true 2>&1 >${TMP1}
+
+${PROOT} ${ROOTFS}/bin/ptrace-2 ${ROOTFS}/bin/true 2>&1 >${TMP2}
+
+cmp ${TMP1} ${TMP2}
+
+env PTRACER_BEHAVIOR_1=1 ${ROOTFS}/bin/ptrace-2 ${ROOTFS}/bin/true 2>&1 >${TMP1}
+
+env PTRACER_BEHAVIOR_1=1 ${PROOT} ${ROOTFS}/bin/ptrace-2 ${ROOTFS}/bin/true 2>&1 >${TMP2}
+
+cmp ${TMP1} ${TMP2}
+
+env PTRACER_BEHAVIOR_2=1 ${ROOTFS}/bin/ptrace-2 ${ROOTFS}/bin/true 2>&1 >${TMP1}
+
+env PTRACER_BEHAVIOR_2=1 ${PROOT} ${ROOTFS}/bin/ptrace-2 ${ROOTFS}/bin/true 2>&1 >${TMP2}
+
+cmp ${TMP1} ${TMP2}
+
+rm -f ${TMP1} ${TMP2}
diff --git a/5.1.0/tests/test-0238c7f1.sh b/5.1.0/tests/test-0238c7f1.sh
new file mode 100644
index 0000000..e40751e
--- /dev/null
+++ b/5.1.0/tests/test-0238c7f1.sh
@@ -0,0 +1,7 @@
+if [ ! -x  ${ROOTFS}/bin/pwd ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+${PROOT} -m /:/hostfs -w /hostfs/etc -r ${ROOTFS} pwd | grep '^/hostfs/etc$'
+${PROOT} -m /:/hostfs -w /hostfs -r ${ROOTFS} pwd | grep '^/hostfs$'
+${PROOT} -m /:/hostfs -w / -r ${ROOTFS} pwd | grep '^/$'
diff --git a/5.1.0/tests/test-03969e70.sh b/5.1.0/tests/test-03969e70.sh
new file mode 100644
index 0000000..332fb54
--- /dev/null
+++ b/5.1.0/tests/test-03969e70.sh
@@ -0,0 +1,43 @@
+if [ ! -x ${ROOTFS}/bin/true ] || [ -z `which env` ]; then
+    exit 125;
+fi
+
+! ${PROOT} -r ${ROOTFS} /true
+[ $? -eq 0 ]
+
+! ${PROOT} -r ${ROOTFS} ./true
+[ $? -eq 0 ]
+
+! env PATH='' ${PROOT} -r ${ROOTFS} true
+[ $? -eq 0 ]
+
+! env PATH='' ${PROOT} -r ${ROOTFS} -w /bin true
+[ $? -eq 0 ]
+
+env PATH='' ${PROOT} -r ${ROOTFS} -w /bin ./true
+
+env PATH='' ${PROOT} -r ${ROOTFS} -w / bin/true
+
+env PATH='' ${PROOT} -r ${ROOTFS} -w / bin/./true
+
+env PATH='' ${PROOT} -r ${ROOTFS} -w / ../bin/true
+
+! env PATH='' ${PROOT} -r ${ROOTFS} -w /bin/true ../true
+[ $? -eq 0 ]
+
+! env --unset PATH ${PROOT} -r ${ROOTFS} true
+[ $? -eq 0 ]
+
+! env --unset PATH ${PROOT} -r ${ROOTFS} -w /bin true
+[ $? -eq 0 ]
+
+env --unset PATH ${PROOT} -r ${ROOTFS} -w /bin ./true
+
+env --unset PATH ${PROOT} -r ${ROOTFS} -w / /bin/true
+
+env --unset PATH ${PROOT} -r ${ROOTFS} -w / /bin/./true
+
+env --unset PATH ${PROOT} -r ${ROOTFS} -w / ../bin/true
+
+! env --unset PATH ${PROOT} -r ${ROOTFS} -w /bin/true ../true
+[ $? -eq 0 ]
diff --git a/5.1.0/tests/test-071599da.sh b/5.1.0/tests/test-071599da.sh
new file mode 100644
index 0000000..97658f5
--- /dev/null
+++ b/5.1.0/tests/test-071599da.sh
@@ -0,0 +1,16 @@
+if [ -z `which uname` ] || [ -z `which true` ] || [ -z `which env` ] || [ -z `which grep` ] || [ -z `which tail` ] || [ ! -x  ${ROOTFS}/bin/true ]; then
+    exit 125;
+fi
+
+${PROOT} -k $(uname -r) true
+env PROOT_FORCE_KOMPAT=1 ${PROOT} -k $(uname -r) true
+
+${PROOT} -k $(uname -r) ${ROOTFS}/bin/true
+env PROOT_FORCE_KOMPAT=1 ${PROOT} -k $(uname -r) ${ROOTFS}/bin/true
+
+if env LD_SHOW_AUXV=1 true | grep -q ^AT_RANDOM; then
+    env PROOT_FORCE_KOMPAT=1 ${PROOT} -k $(uname -r) env LD_SHOW_AUXV=1 true | tail -1 | grep ^AT_RANDOM
+fi
+
+! ${PROOT} -k $(uname -r) env LD_SHOW_AUXV=1 true | grep AT_SYSINFO
+[ $? -eq 0 ]
diff --git a/5.1.0/tests/test-0830d8a8.sh b/5.1.0/tests/test-0830d8a8.sh
new file mode 100644
index 0000000..73e9ea9
--- /dev/null
+++ b/5.1.0/tests/test-0830d8a8.sh
@@ -0,0 +1,5 @@
+if [ ! -x  ${ROOTFS}/bin/exec-m32 ] || [ ! -x  ${ROOTFS}/bin/true ]; then
+    exit 125;
+fi
+
+${PROOT} ${ROOTFS}/bin/exec-m32 ${ROOTFS}/bin/true
diff --git a/5.1.0/tests/test-092c5e26.sh b/5.1.0/tests/test-092c5e26.sh
new file mode 100644
index 0000000..4a6d509
--- /dev/null
+++ b/5.1.0/tests/test-092c5e26.sh
@@ -0,0 +1,41 @@
+if [ ! -x  ${ROOTFS}/bin/echo ] ||  [ ! -x  ${ROOTFS}/bin/argv0 ] || [ -z `which mcookie` ] || [ -z `which grep` ] || [ -z `which cat` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=$(mcookie)
+TMP_ABS=/tmp/${TMP}
+
+${PROOT} -r ${ROOTFS} argv0      | grep '^argv0$'
+${PROOT} -r ${ROOTFS} /bin/argv0 | grep '^/bin/argv0$'
+
+cat > ${ROOTFS}/${TMP_ABS} <<EOF
+#!/bin/argv0
+test
+EOF
+chmod +x ${ROOTFS}/${TMP_ABS}
+
+env PATH=/tmp ${PROOT} -r ${ROOTFS} ${TMP} | grep '^/bin/argv0$'
+${PROOT} -r ${ROOTFS} ${TMP_ABS}           | grep '^/bin/argv0$'
+
+# Valgrind uses LD_PRELOAD.
+if $(echo ${PROOT} | grep -q valgrind); then
+    EXTRA='-E LD_PRELOAD=.*'
+fi
+
+unset LD_LIBRARY_PATH
+
+env PROOT_FORCE_FOREIGN_BINARY=1 PATH=/tmp:/bin:/usr/bin ${PROOT} -r ${ROOTFS} -q echo ${TMP} | grep "^-U LD_LIBRARY_PATH ${EXTRA}-0 /bin/argv0 /bin/argv0 ${TMP_ABS}$"
+env PROOT_FORCE_FOREIGN_BINARY=1 ${PROOT} -r ${ROOTFS} -q echo ${TMP_ABS} | grep "^-U LD_LIBRARY_PATH ${EXTRA}-0 /bin/argv0 /bin/argv0 ${TMP_ABS}$"
+
+cat > ${ROOTFS}/${TMP_ABS} <<EOF
+FOREIGN BINARY FORMAT
+EOF
+chmod +x ${ROOTFS}/${TMP_ABS}
+
+# Valgrind prepends "/bin/sh" in front of foreign binaries.
+if ! $(echo ${PROOT} | grep -q valgrind); then
+    env PATH=/tmp:/bin:/usr/bin ${PROOT} -r ${ROOTFS} -q echo ${TMP} | grep "^-U LD_LIBRARY_PATH -0 ${TMP} ${TMP_ABS}$"
+    ${PROOT} -r ${ROOTFS} -q echo ${TMP_ABS}                | grep "^-U LD_LIBRARY_PATH -0 ${TMP_ABS} ${TMP_ABS}$"
+fi
+
+rm -f ${TMP_ABS}
diff --git a/5.1.0/tests/test-0cf405b0.c b/5.1.0/tests/test-0cf405b0.c
new file mode 100644
index 0000000..2566409
--- /dev/null
+++ b/5.1.0/tests/test-0cf405b0.c
@@ -0,0 +1,12 @@
+#include <unistd.h> /* execlp(2), */
+#include <stdlib.h> /* exit(3), */
+#include <string.h> /* strcmp(3), */
+
+int main(int argc, char *argv[])
+{
+	if (argc == 0) //strcmp(argv[0], "/proc/self/exe") == 0)
+		exit(EXIT_SUCCESS);
+
+	execlp("/proc/self/exe", NULL);
+	exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-11111111.sh b/5.1.0/tests/test-11111111.sh
new file mode 100644
index 0000000..7538832
--- /dev/null
+++ b/5.1.0/tests/test-11111111.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+if [ -z `which cat` ] || [ -z `which readlink` ] || [ -z `which mcookie` ] || [ -z `which touch` ] || [ -z `which mkdir` ] || [ -z `which ln` ] || [ -z `which grep` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+set +e
+
+x1="r1 d1 rl1 dl1" # root of the test tree.
+x2="r2 d2 rl2 dl2" # subtree of d1/dl1, every components exist.
+x3="r3 d3 rl3 dl3" # subtree of d1/dl1, no component exists.
+x4="/ /. /.."      # terminators.
+
+generate () {
+    output=${1}
+
+    make_tests ()
+    {
+	for c in ${x4} ""; do
+	    x="${1}${c}"
+	    $(cd ${x}      2>/dev/null);      cd_result=$?
+	    cat ${x}       2>/dev/null;       cat_result=$?
+	    readlink ${x}  2>/dev/null 1>&2;  readlink_result=$?
+	    echo "${x}, $cd_result, $cat_result, $readlink_result" >> $output
+	done
+    }
+
+    echo "path, chdir, cat, readlink" > $output
+    for a in ${x1}; do
+	for b in ${x2}; do
+	    make_tests "${a}/${b}"
+	done
+	for b in ${x3}; do
+	    make_tests "${a}/${b}"
+	done
+    done
+}
+
+if [ -z ${PROOT_STAGE2} ]; then
+    create_components ()
+    {
+	touch r${1}         2>/dev/null
+	mkdir -p d${1}      2>/dev/null
+	ln -fs r${1} rl${1}  2>/dev/null
+	ln -fs d${1} dl${1}  2>/dev/null
+    }
+
+    create_components 1
+    $(cd d1; create_components 2)
+
+    REF=/tmp/`mcookie`
+    mkdir -p /tmp
+
+    generate $REF
+
+    env PROOT_STAGE2=$REF ${PROOT} -w ${PWD} sh ./$0
+    exit $?
+fi
+
+TMP=/tmp/`mcookie`
+mkdir -p /tmp
+
+generate $TMP
+
+set -e
+cmp $TMP $PROOT_STAGE2
+rm $TMP $PROOT_STAGE2
diff --git a/5.1.0/tests/test-16573e73.c b/5.1.0/tests/test-16573e73.c
new file mode 100644
index 0000000..c1c1876
--- /dev/null
+++ b/5.1.0/tests/test-16573e73.c
@@ -0,0 +1,29 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main(int argc, char **ignored)
+{
+	char *const argv[] = { "true", NULL};
+	char *const envp[] = { NULL };
+
+	pid_t pid;
+	int status;
+
+	pid = (argc <= 1 ? vfork() : fork());
+	switch (pid) {
+	case -1:
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		exit(execve("/bin/true", argv, envp));
+
+	default: /* parent */
+		if (wait(&status) < 0 || !WIFEXITED(status))
+			exit(EXIT_FAILURE);
+		exit(WEXITSTATUS(status));
+	}
+
+	exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-1743dd3d.sh b/5.1.0/tests/test-1743dd3d.sh
new file mode 100644
index 0000000..3fde250
--- /dev/null
+++ b/5.1.0/tests/test-1743dd3d.sh
@@ -0,0 +1,17 @@
+if [ ! -x ${ROOTFS}/bin/true ] || [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which echo` ] || [ -z `which chmod` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/`mcookie`
+rm -f ${ROOTFS}/${TMP}
+
+mkdir -p ${ROOTFS}/tmp
+echo '#!/bin/true' > ${ROOTFS}/${TMP}
+
+chmod -x ${ROOTFS}/${TMP}
+! ${PROOT} -r ${ROOTFS} ${TMP}
+
+chmod +x ${ROOTFS}/${TMP}
+${PROOT} -r ${ROOTFS} ${TMP}
+
+rm -f ${ROOTFS}/${TMP}
diff --git a/5.1.0/tests/test-1c68c218.c b/5.1.0/tests/test-1c68c218.c
new file mode 100644
index 0000000..8de82aa
--- /dev/null
+++ b/5.1.0/tests/test-1c68c218.c
@@ -0,0 +1,25 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main()
+{
+	int status;
+	char *path;
+
+	path = tmpnam(NULL);
+	status = symlink(path, path);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	status = fchownat(AT_FDCWD, path, getuid(), getgid(), 0);
+	if (status >= 0)
+		exit(EXIT_FAILURE);
+
+	status = fchownat(AT_FDCWD, path, getuid(), getgid(), AT_SYMLINK_NOFOLLOW);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-1cd9d8f9.sh b/5.1.0/tests/test-1cd9d8f9.sh
new file mode 100644
index 0000000..12bede4
--- /dev/null
+++ b/5.1.0/tests/test-1cd9d8f9.sh
@@ -0,0 +1,5 @@
+if ! `which pwd` -P || [ -z `which grep` ] ; then
+    exit 125;
+fi
+
+${PROOT} -w /tmp pwd -P | grep '^/tmp$'
diff --git a/5.1.0/tests/test-1fedd9a3.sh b/5.1.0/tests/test-1fedd9a3.sh
new file mode 100644
index 0000000..3253188
--- /dev/null
+++ b/5.1.0/tests/test-1fedd9a3.sh
@@ -0,0 +1,62 @@
+if [ -z `which mcookie` ] || [ -z `which id` ] || [ -z `which mkdir` ] || [ -z `which touch` ] || [ -z `which chmod` ] || [ -z `which stat` ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+if [ `id -u` -eq 0 ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+mkdir -p ${TMP}/foo
+chmod a-rwx ${TMP}/foo
+chmod a-rwx ${TMP}
+
+! ${PROOT} touch ${TMP}/foo/bar
+[ $? -eq 0 ]
+
+! ${PROOT} -i 123:456 touch ${TMP}/foo/bar
+[ $? -eq 0 ]
+
+${PROOT} -0 touch ${TMP}/foo/bar
+
+stat -c %a ${TMP} | grep '^0$'
+! stat -c %a ${TMP}/foo
+[ $? -eq 0 ]
+
+! ${PROOT} -i 123:456 stat -c %a ${TMP}/foo | grep '^0$'
+[ $? -eq 0 ]
+
+${PROOT} -0 stat -c %a ${TMP}/foo | grep '^0$'
+
+chmod -R a+rwx ${TMP}
+chmod a-rwx ${TMP}/foo/bar
+chmod a-rwx ${TMP}/foo
+chmod a-rwx ${TMP}
+
+! ${PROOT} chmod g+w ${TMP}/foo/bar
+[ $? -eq 0 ]
+
+! ${PROOT} -i 123:456 chmod g+w ${TMP}/foo/bar
+[ $? -eq 0 ]
+
+${PROOT} -0 chmod g+w ${TMP}/foo/bar
+
+chmod u+wx ${TMP}
+chmod u+x ${TMP}/foo
+
+stat -c %a ${TMP}/foo/bar | grep '^20$'
+
+chmod -R +rwx ${TMP}
+rm -fr ${TMP}
+
+mkdir -p ${TMP}/foo
+chmod -rwx ${TMP}
+
+! rm -fr ${TMP}
+[ $? -eq 0 ]
+
+! ${PROOT} -i 123:456 rm -fr ${TMP}
+[ $? -eq 0 ]
+
+${PROOT} -0 rm -fr ${TMP}
diff --git a/5.1.0/tests/test-1ffc8309.c b/5.1.0/tests/test-1ffc8309.c
new file mode 100644
index 0000000..b5c01f5
--- /dev/null
+++ b/5.1.0/tests/test-1ffc8309.c
@@ -0,0 +1,30 @@
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+int main()
+{
+	int fds[2];
+	int status;
+	uint8_t buffer;
+
+	status = pipe2(fds, O_NONBLOCK);
+	if (status < 0) {
+		perror("pipe2");
+		exit(EXIT_FAILURE);
+	}
+
+	(void) alarm(5);
+
+	(void) read(fds[0], &buffer, 1);
+	if (errno != EAGAIN && errno != EWOULDBLOCK) {
+		perror("read");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-1ffc8309.sh b/5.1.0/tests/test-1ffc8309.sh
new file mode 100644
index 0000000..c270641
--- /dev/null
+++ b/5.1.0/tests/test-1ffc8309.sh
@@ -0,0 +1,9 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which env` ] || [ -z `which uname` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+mkdir ${TMP}
+
+env PROOT_FORCE_KOMPAT=1 ${PROOT} -k $(uname -r) rm -r ${TMP}
diff --git a/5.1.0/tests/test-22222222.sh b/5.1.0/tests/test-22222222.sh
new file mode 100644
index 0000000..3e47524
--- /dev/null
+++ b/5.1.0/tests/test-22222222.sh
@@ -0,0 +1,21 @@
+if [ ! -x  ${ROOTFS}/bin/readlink ] || [ -z `which mcookie` ] || [ -z `which touch` ] || [ -z `which mkdir` ] || [ -z `which ln` ] || [ -z `which grep` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+REGULAR=`mcookie`
+SYMLINK=`mcookie`
+
+touch /tmp/${REGULAR}
+ln -fs /tmp/${REGULAR} /tmp/${SYMLINK}
+
+mkdir -p ${ROOTFS}/tmp
+touch ${ROOTFS}/tmp/${REGULAR}
+ln -fs /tmp/${REGULAR} ${ROOTFS}/tmp/${SYMLINK}
+
+${PROOT} -b /tmp:/ced -r ${ROOTFS} /bin/readlink /tmp/${SYMLINK} | grep ^/tmp/${REGULAR}$
+${PROOT} -b /tmp:/ced -r ${ROOTFS} /bin/readlink /ced/${SYMLINK} | grep ^/ced/${REGULAR}$
+
+rm -f /tmp/${REGULAR}
+rm -f /tmp/${SYMLINK}
+rm -f ${ROOTFS}/tmp/${REGULAR}
+
diff --git a/5.1.0/tests/test-230f47cf.sh b/5.1.0/tests/test-230f47cf.sh
new file mode 100644
index 0000000..c6f7a4c
--- /dev/null
+++ b/5.1.0/tests/test-230f47cf.sh
@@ -0,0 +1,6 @@
+! ${PROOT} ${PROOT_RAW} /bin/true
+if [ $? -eq 0 ]; then
+    exit 125;
+fi
+
+echo exit | ${PROOT} -v 0 ${PROOT_RAW} -v 0
diff --git a/5.1.0/tests/test-230f47cg.sh.deprecated b/5.1.0/tests/test-230f47cg.sh.deprecated
new file mode 100644
index 0000000..e81015a
--- /dev/null
+++ b/5.1.0/tests/test-230f47cg.sh.deprecated
@@ -0,0 +1,40 @@
+if [ ! -x  ${ROOTFS}/bin/cat ] || [ -z `which mcookie` ] || [ -z `which echo` ] || [ -z `which cp` ] || [ -z `which grep` ]|| [ -z `which rm` ]; then
+    exit 125;
+fi
+
+! ${PROOT} ${PROOT_RAW} /bin/true
+if [ $? -eq 0 ]; then
+    exit 125;
+fi
+
+FOO1=/tmp/$(mcookie)
+FOO2=/tmp/$(mcookie)
+ROOTFS2=/$(mcookie)
+FOO3=/tmp/$(mcookie)
+
+mkdir -p ${ROOTFS}/tmp
+mkdir -p ${ROOTFS}/${ROOTFS2}/bin
+cp ${ROOTFS}/bin/cat ${ROOTFS}/${ROOTFS2}/bin/cat
+
+echo "content of foo1" > ${FOO1}
+echo "content of foo2" > ${FOO2}
+echo "content of foo3" > ${ROOTFS}/${FOO3}
+
+CMD="${PROOT}	-r ${ROOTFS}				\
+		-b ${FOO2}				\
+		-b ${FOO1}:${ROOTFS2}/${FOO1}		\
+		-b ${FOO2}:${ROOTFS2}/${FOO2}		\
+		-b ${PROOT_RAW}				\
+		${PROOT_RAW}	-r ${ROOTFS2}		\
+				-b /:/host-rootfs	\
+				-b ${FOO3}:${FOO2}	\
+				-v -1"
+
+${CMD} cat /${FOO1}		 | grep '^content of foo1$'
+${CMD} cat /host-rootfs/${FOO2}	 | grep '^content of foo2$'
+${CMD} cat /${FOO2}		 | grep '^content of foo3$'
+
+rm -fr ${FOO1}
+rm -fr ${FOO2}
+rm -fr ${ROOTFS2}
+rm -fr ${ROOTFS}/${FOO3}
diff --git a/5.1.0/tests/test-230f47ch.sh b/5.1.0/tests/test-230f47ch.sh
new file mode 100644
index 0000000..fed0ac3
--- /dev/null
+++ b/5.1.0/tests/test-230f47ch.sh
@@ -0,0 +1,25 @@
+if [ -z `which id` ] || [ -z `which uname` ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+! ${PROOT} ${PROOT_RAW} /bin/true
+if [ $? -eq 0 ]; then
+    exit 125;
+fi
+
+${PROOT} ${PROOT_RAW} -0 id -u                 | grep ^0$
+${PROOT} ${PROOT_RAW} -i 123:456 id -u         | grep ^123$
+${PROOT} ${PROOT_RAW} -k 3.33.333 uname -r     | grep ^3\.33\.333$
+
+${PROOT} -0       ${PROOT_RAW} id -u           | grep ^0$
+${PROOT} -i 123:456 ${PROOT_RAW} id -u         | grep ^123$
+${PROOT} -k 3.33.333 ${PROOT_RAW} uname -r     | grep ^3\.33\.333$
+
+${PROOT} -0 ${PROOT_RAW} -k 3.33.333 id -u     | grep ^0$
+${PROOT} -0 ${PROOT_RAW} -k 3.33.333 uname -r  | grep ^3\.33\.333$
+
+${PROOT} -k 3.33.333 ${PROOT_RAW} -0 id -u     | grep ^0$
+${PROOT} -k 3.33.333 ${PROOT_RAW} -0 uname -r  | grep ^3\.33\.333$
+
+${PROOT} -i 123:456 ${PROOT_RAW} -k 3.33.333 id -u | grep ^123$
+${PROOT} -k 3.33.333 ${PROOT_RAW} -i 123:456 id -u | grep ^123$
diff --git a/5.1.0/tests/test-2401b850.sh b/5.1.0/tests/test-2401b850.sh
new file mode 100644
index 0000000..e53460e
--- /dev/null
+++ b/5.1.0/tests/test-2401b850.sh
@@ -0,0 +1,67 @@
+if [ -z `which mcookie` ] || [ -z `which echo` ] || [ -z `which rm` ] || [ -z `which touch` ] || [ -z `which chmod` ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+
+rm -f ${TMP}
+touch ${TMP}
+chmod +x ${TMP}
+
+# Valgrind prepends "/bin/sh" in front of foreign binaries and uses
+# LD_PRELOAD.
+if $(echo ${PROOT} | grep -q valgrind); then
+    ENV=$(which env)
+    PROOT="env PROOT_FORCE_FOREIGN_BINARY=1 ${PROOT}"
+    COMMAND1="-E LD_PRELOAD=.* -0 /bin/sh /bin/sh ${TMP}"
+    TEST1="-- -U LD_LIBRARY_PATH -E LD_PRELOAD=.* -0 env ${ENV} LD_LIBRARY_PATH=test1 ${TMP}"
+    TEST2="-- -E LD_PRELOAD=.* -E LD_LIBRARY_PATH=test2 -0 /bin/sh /bin/sh ${TMP}"
+    TEST3="-- -E LD_PRELOAD=.* -E LD_LIBRARY_PATH=test2 -0 env ${ENV} LD_LIBRARY_PATH=test1 ${TMP}"
+    TEST4="-- -U LD_LIBRARY_PATH -E LD_PRELOAD=.* -0 env ${ENV} LD_TRACE_LOADED_OBJECTS=1 ${TMP}"
+    TEST5="-- -E LD_PRELOAD= -E LD_LIBRARY_PATH=test5 -0 sh /bin/sh -c ${TMP}"
+    TEST52="-- -E LD_PRELOAD= -E LD_LIBRARY_PATH=test5 -0 sh /bin/sh -c sh -c ${TMP}"
+    TEST6="-- -E LD_PRELOAD= -E LD_LIBRARY_PATH=test5 -0 env ${ENV} LD_LIBRARY_PATH=test6 ${TMP}"
+    COMMAND2="-E LD_PRELOAD=.* -0 ${TMP} ${TMP} ${TMP2}"
+else
+    COMMAND1="-0 ${TMP} ${TMP}"
+    TEST1="-- -E LD_LIBRARY_PATH=test1 ${COMMAND1}"
+    TEST2="-- -E LD_LIBRARY_PATH=test2 ${COMMAND1}"
+    TEST3="${TEST1}"
+    TEST4="-- -E LD_TRACE_LOADED_OBJECTS=1 -E LD_LIBRARY_PATH=.+ ${COMMAND1}"
+    TEST5="-- -E LD_LIBRARY_PATH=test5 ${COMMAND1}"
+    TEST52=${TEST5}
+    TEST6="-- -E LD_LIBRARY_PATH=test6 ${COMMAND1}"
+    COMMAND2="-0 ${TMP} ${TMP} ${TMP2}"
+fi
+
+  ${PROOT} -q true ${TMP}
+! ${PROOT} -q false ${TMP}
+[ $? -eq 0 ]
+
+  (cd /; ${PROOT} -q ./$(which true) ${TMP})
+! (cd /; ${PROOT} -q ./$(which false) ${TMP})
+[ $? -eq 0 ]
+
+HOST_LD_LIBRARY_PATH=$(${PROOT} -q 'echo --' env | grep LD_LIBRARY_PATH)
+test ! -z "${HOST_LD_LIBRARY_PATH}"
+
+unset LD_LIBRARY_PATH
+${PROOT} -q 'echo --' ${TMP} | grep -- "^-- -U LD_LIBRARY_PATH ${COMMAND1}$"
+${PROOT} -q 'echo --' env LD_LIBRARY_PATH=test1 ${TMP} | grep -- "^${TEST1}$"
+env LD_LIBRARY_PATH=test2 ${PROOT} -q 'echo --' ${TMP} | grep -- "^${TEST2}$"
+
+env LD_LIBRARY_PATH=test2 ${PROOT} -q 'echo --' env LD_LIBRARY_PATH=test1 ${TMP} | grep -- "^${TEST3}$"
+
+${PROOT} -q 'echo --' env LD_TRACE_LOADED_OBJECTS=1 ${TMP} | grep -E -- "^${TEST4}$"
+
+env LD_LIBRARY_PATH=test5 ${PROOT} -q 'echo --' sh -c ${TMP} | grep -- "^${TEST5}$"
+env LD_LIBRARY_PATH=test5 ${PROOT} -q 'echo --' sh -c "sh -c ${TMP}" | grep -- "^${TEST52}$"
+env LD_LIBRARY_PATH=test5 ${PROOT} -q 'echo --' env LD_LIBRARY_PATH=test6 ${TMP} | grep -- "^${TEST6}$"
+
+rm -f ${TMP2}
+echo "#!${TMP}" > ${TMP2}
+chmod +x ${TMP2}
+${PROOT} -q 'echo --' ${TMP2} | grep -- "^-- -U LD_LIBRARY_PATH ${COMMAND2}$"
+
+rm -fr ${TMP} ${TMP2}
diff --git a/5.1.0/tests/test-25069c12.c b/5.1.0/tests/test-25069c12.c
new file mode 100644
index 0000000..1f6cd52
--- /dev/null
+++ b/5.1.0/tests/test-25069c12.c
@@ -0,0 +1,14 @@
+#include <unistd.h> /* execve(2), */
+#include <stdlib.h> /* exit(3), */
+#include <string.h> /* strcmp(3), */
+
+int main(int argc, char *argv[])
+{
+	char *void_array[] = { NULL };
+
+	if (argc == 0)
+		exit(EXIT_SUCCESS);
+
+	execve("/proc/self/exe", void_array, void_array);
+	exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-25069c13.c b/5.1.0/tests/test-25069c13.c
new file mode 100644
index 0000000..dc14733
--- /dev/null
+++ b/5.1.0/tests/test-25069c13.c
@@ -0,0 +1,12 @@
+#include <unistd.h> /* execve(2), */
+#include <stdlib.h> /* exit(3), */
+#include <string.h> /* strcmp(3), */
+
+int main(int argc, char *argv[])
+{
+	if (argc == 0)
+		exit(EXIT_SUCCESS);
+
+	execve("/proc/self/exe", NULL, NULL);
+	exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-2db65cd2.sh b/5.1.0/tests/test-2db65cd2.sh
new file mode 100644
index 0000000..6c726f0
--- /dev/null
+++ b/5.1.0/tests/test-2db65cd2.sh
@@ -0,0 +1,28 @@
+if [ ! -x  ${ROOTFS}/bin/true ] || [ -z `which gdb` ]; then
+    exit 125;
+fi
+
+TMP1=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+TMP3=/tmp/$(mcookie)
+TMP4=/tmp/$(mcookie)
+TMP5=/tmp/$(mcookie)
+
+cat > ${TMP5} <<EOF
+break main
+run
+cont
+EOF
+
+COMMAND="gdb ${ROOTFS}/bin/true -batch -n -x ${TMP5}"
+
+${COMMAND} > ${TMP1}
+! grep -v 'process' ${TMP1} > ${TMP2}
+
+${PROOT} ${COMMAND} > ${TMP4}
+! grep -v 'process' ${TMP4} > ${TMP3}
+! grep -v '^proot warning: ' ${TMP3} > ${TMP4}
+
+cmp ${TMP2} ${TMP4}
+
+rm -f ${TMP1} ${TMP2} ${TMP3} ${TMP4} ${TMP5}
diff --git a/5.1.0/tests/test-305ae31d.c b/5.1.0/tests/test-305ae31d.c
new file mode 100644
index 0000000..f201f2d
--- /dev/null
+++ b/5.1.0/tests/test-305ae31d.c
@@ -0,0 +1,60 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main()
+{
+	int fd;
+	int fd_dir;
+	int fd_file;
+	char path[64]; /* 64 > sizeof("/proc//fd/") + 2 * sizeof(#ULONG_MAX) */
+	int status;
+
+	fd_dir = open("/bin", O_RDONLY);
+	if (fd_dir < 0)
+		exit(EXIT_FAILURE);
+
+	fd_file = open("/bin/true", O_RDONLY);
+	if (fd_file < 0)
+		exit(EXIT_FAILURE);
+
+	status = snprintf(path, sizeof(path), "/proc/%d/fd/%d/", getpid(), fd_dir);
+	if (status < 0 || status >= sizeof(path))
+		exit(EXIT_FAILURE);
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		exit(EXIT_FAILURE);
+	close(fd);
+
+	status = snprintf(path, sizeof(path), "/proc/%d/fd/%d/..", getpid(), fd_dir);
+	if (status < 0 || status >= sizeof(path))
+		exit(EXIT_FAILURE);
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		exit(EXIT_FAILURE);
+	close(fd);
+
+	status = snprintf(path, sizeof(path), "/proc/%d/fd/%d/..", getpid(), fd_file);
+	if (status < 0 || status >= sizeof(path))
+		exit(EXIT_FAILURE);
+
+	fd = open(path, O_RDONLY);
+	if (fd >= 0 || errno != ENOTDIR)
+		exit(EXIT_FAILURE);
+
+	status = snprintf(path, sizeof(path), "/proc/%d/fd/999999/..", getpid());
+	if (status < 0 || status >= sizeof(path))
+		exit(EXIT_FAILURE);
+
+	fd = open(path, O_RDONLY);
+	if (fd >= 0 || errno != ENOENT)
+		exit(EXIT_FAILURE);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-305ae31d.sh b/5.1.0/tests/test-305ae31d.sh
new file mode 100644
index 0000000..b7a2fb0
--- /dev/null
+++ b/5.1.0/tests/test-305ae31d.sh
@@ -0,0 +1,9 @@
+if [ -z `which mcookie` ] || [ -z `which ln` ] ||  [ -z `which true` ] ||  [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=$(mcookie)
+ln -s  /proc/self/mounts ${TMP}
+${PROOT} -b ${TMP} true
+rm ${TMP}
+
diff --git a/5.1.0/tests/test-311b7a95.sh b/5.1.0/tests/test-311b7a95.sh
new file mode 100644
index 0000000..cd93c71
--- /dev/null
+++ b/5.1.0/tests/test-311b7a95.sh
@@ -0,0 +1,18 @@
+if [ -z `which mcookie` ] || [ -z `which rm` ] || [ -z `which chmod` ] || [ -z `which echo` ]; then
+    exit 125;
+fi
+
+TMP1=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+
+echo "#! ${TMP2} -a"       > ${TMP1}
+echo "#! $(which echo) -b" > ${TMP2}
+
+chmod +x ${TMP1} ${TMP2}
+
+RESULT=$(${PROOT} ${TMP1})
+EXPECTED=$(${TMP1})
+
+test "${RESULT}" = "${EXPECTED}"
+
+rm -f ${TMP1} ${TMP2}
diff --git a/5.1.0/tests/test-33333333.c b/5.1.0/tests/test-33333333.c
new file mode 100644
index 0000000..84f56df
--- /dev/null
+++ b/5.1.0/tests/test-33333333.c
@@ -0,0 +1,23 @@
+/* Check a child is traced even if its parent doesn't call wait(2).
+ * 
+ * Reported-by: Clément BAZIN <clement.bazin@st.com>
+ *              on Ubuntu 11.10 x86_64
+ */
+
+#include <stdlib.h> /* exit(3), */
+#include <unistd.h> /* fork(2), */
+
+int main(void)
+{
+	switch (fork()) {
+	case -1:
+		exit(EXIT_FAILURE);
+
+	case 0: /* Child: XXX */
+		sleep(2);
+		return 0;
+
+	default: /* Parent: "look child, no wait(2)!" */
+		return 1;
+	}
+}
diff --git a/5.1.0/tests/test-33333334.c b/5.1.0/tests/test-33333334.c
new file mode 100644
index 0000000..7e097e3
--- /dev/null
+++ b/5.1.0/tests/test-33333334.c
@@ -0,0 +1,31 @@
+#include <stdlib.h> /* exit(3), */
+#include <unistd.h> /* fork(2), */
+
+int main(void)
+{
+	int child_status;
+	int status;
+
+	switch (fork()) {
+	case -1:
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		return 13;
+
+	default: /* parent */
+		status = wait(&child_status);
+		if (status < 0) {
+			perror("wait()");
+			exit(EXIT_FAILURE);
+		}
+
+		if (!WIFEXITED(child_status))
+			exit(EXIT_FAILURE);
+
+		if (WEXITSTATUS(child_status) != 13)
+			exit(EXIT_FAILURE);
+
+		exit(EXIT_SUCCESS);
+	}
+}
diff --git a/5.1.0/tests/test-3624be91.sh b/5.1.0/tests/test-3624be91.sh
new file mode 100644
index 0000000..a3e8a67
--- /dev/null
+++ b/5.1.0/tests/test-3624be91.sh
@@ -0,0 +1,5 @@
+if [ -z `which sh` ] || [ -z `which kill` ] || [ -z `which grep` ] || [ -z `which cut` ]; then
+    exit 125;
+fi
+
+${PROOT} sh -c 'kill -15 $(grep TracerPid /proc/self/status | cut -f 2 -d :)'
diff --git a/5.1.0/tests/test-3dec4597.sh b/5.1.0/tests/test-3dec4597.sh
new file mode 100644
index 0000000..bc4eb89
--- /dev/null
+++ b/5.1.0/tests/test-3dec4597.sh
@@ -0,0 +1,5 @@
+if [ ! -x  ${ROOTFS}/bin/pwd ]; then
+    exit 125;
+fi
+
+${PROOT} -m /tmp:/longer-tmp -w /longer-tmp -r ${ROOTFS} /bin/pwd
diff --git a/5.1.0/tests/test-44444444.c b/5.1.0/tests/test-44444444.c
new file mode 100644
index 0000000..d6f1fdc
--- /dev/null
+++ b/5.1.0/tests/test-44444444.c
@@ -0,0 +1,21 @@
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void)
+{
+	char buffer[2 * PATH_MAX];
+
+	if (!getcwd(buffer, sizeof(buffer))) {
+		perror("getcwd");
+		exit(EXIT_FAILURE);
+	}
+
+	if (readlink("/bin/abs-true", buffer, sizeof(buffer)) < 0) {
+		perror("readlink");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-517e1d6a.sh b/5.1.0/tests/test-517e1d6a.sh
new file mode 100644
index 0000000..818c72d
--- /dev/null
+++ b/5.1.0/tests/test-517e1d6a.sh
@@ -0,0 +1,33 @@
+if [ ! -x  ${ROOTFS}/bin/argv ] || [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which chmod` ] || [ -z `which env` ] || [ -z `which rm` ] || [ -z `which grep` ] || [ -z `which env` ] || [ -z `which ln` ]; then
+    exit 125;
+fi
+
+BIN_DIR=/tmp/$(mcookie)
+TMP=$(mcookie)
+TMP2=$(mcookie)
+
+mkdir ${BIN_DIR}
+echo "#! ${ROOTFS}/bin/argv -x" > ${BIN_DIR}/${TMP}
+chmod +x ${BIN_DIR}/${TMP}
+ln -s ${BIN_DIR}/${TMP} ${BIN_DIR}/${TMP2}
+
+${PROOT} env ${BIN_DIR}/${TMP} | grep "${ROOTFS}/bin/argv -x ${BIN_DIR}/${TMP}"
+
+${PROOT} env PATH=${BIN_DIR} ${TMP} | grep "${ROOTFS}/bin/argv -x ${BIN_DIR}/${TMP}"
+
+(cd ${BIN_DIR}; ${PROOT} env ./${TMP}) | grep "${ROOTFS}/bin/argv -x ./${TMP}"
+
+${PROOT} env ${BIN_DIR}/${TMP2} | grep "${ROOTFS}/bin/argv -x ${BIN_DIR}/${TMP2}"
+
+${PROOT} env PATH=${BIN_DIR} ${TMP2} | grep "${ROOTFS}/bin/argv -x ${BIN_DIR}/${TMP2}"
+
+(cd ${BIN_DIR}; ${PROOT} env ./${TMP2}) | grep "${ROOTFS}/bin/argv -x ./${TMP2}"
+
+${PROOT} ${BIN_DIR}/${TMP} | grep "${ROOTFS}/bin/argv -x ${BIN_DIR}/${TMP}"
+
+env PATH=${BIN_DIR} ${PROOT} ${TMP} | grep "${ROOTFS}/bin/argv -x ${BIN_DIR}/${TMP}"
+
+# TODO: (cd ${BIN_DIR}; ${PROOT} ./${TMP}) | grep "${ROOTFS}/bin/argv -x ./${TMP}"
+(cd ${BIN_DIR}; ${PROOT} sh -c "true; ./${TMP}") | grep "${ROOTFS}/bin/argv -x ./${TMP}"
+
+rm -fr ${BIN_DIR}
diff --git a/5.1.0/tests/test-517e1d6b.sh b/5.1.0/tests/test-517e1d6b.sh
new file mode 100644
index 0000000..94e17ae
--- /dev/null
+++ b/5.1.0/tests/test-517e1d6b.sh
@@ -0,0 +1,7 @@
+if [ -z `which true` ] || [ -z `which realpath` ] || [ -z `which grep` ] || [ -z `which env` ] || [ ! -x  ${ROOTFS}/bin/puts_proc_self_exe ]; then
+    exit 125;
+fi
+
+TRUE=$(realpath $(which true))
+
+env PROOT_FORCE_FOREIGN_BINARY=1 ${PROOT} -q ${ROOTFS}/bin/puts_proc_self_exe ${TRUE} | grep ^${TRUE}$
diff --git a/5.1.0/tests/test-51943658.c b/5.1.0/tests/test-51943658.c
new file mode 100644
index 0000000..d8a42cc
--- /dev/null
+++ b/5.1.0/tests/test-51943658.c
@@ -0,0 +1,64 @@
+#include <unistd.h> /* syscall(2), */
+#include <stdio.h>  /* perror(3), fprintf(3), */
+#include <limits.h> /* PATH_MAX, */
+#include <stdlib.h> /* exit(3), */
+#include <fcntl.h> /* openat(2), */
+
+int main(void)
+{
+	int dir_fd;
+	int dir_fd1;
+	int dir_fd2;
+	ssize_t status;
+	char path1[PATH_MAX];
+	char path2[PATH_MAX];
+	char fd_link[64];
+
+	/* Format the path to the "virtual" link. */
+
+	dir_fd = open("/", O_RDONLY);
+	if (dir_fd < 0) {
+		perror("open(2)");
+		exit(EXIT_FAILURE);
+	}
+
+	dir_fd1 = openat(dir_fd, ".", O_RDONLY);
+	if (dir_fd1 < 0) {
+		perror("openat(2)");
+		exit(EXIT_FAILURE);
+	}
+
+	dir_fd2 = openat(dir_fd, "..", O_RDONLY);
+	if (dir_fd2 < 0) {
+		perror("openat(2)");
+		exit(EXIT_FAILURE);
+	}
+
+	sprintf(fd_link, "/proc/self/fd/%d", dir_fd1);
+	status = readlink(fd_link, path1, PATH_MAX - 1);
+	if (status < 0) {
+		perror("readlink(2)");
+		exit(EXIT_FAILURE);
+	}
+	path1[status] = '\0';
+
+	sprintf(fd_link, "/proc/self/fd/%d", dir_fd2);
+	status = readlink(fd_link, path2, PATH_MAX - 1);
+	if (status < 0) {
+		perror("readlink(2)");
+		exit(EXIT_FAILURE);
+	}
+	path2[status] = '\0';
+
+	if (strcmp(path1, "/") != 0) {
+		fprintf(stderr, "/. != /");
+		exit(EXIT_FAILURE);
+	}
+
+	if (strcmp(path2, "/") != 0) {
+		fprintf(stderr, "/.. != /");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-53355a5b.sh b/5.1.0/tests/test-53355a5b.sh
new file mode 100644
index 0000000..5ae021d
--- /dev/null
+++ b/5.1.0/tests/test-53355a5b.sh
@@ -0,0 +1,13 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which chmod` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+mkdir ${TMP}
+chmod a-x ${TMP}
+! ${PROOT} sh -c "cd $TMP"
+[ $? -eq 0 ]
+
+chmod a+x ${TMP}
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-5467b986.sh b/5.1.0/tests/test-5467b986.sh
new file mode 100644
index 0000000..c6ac71a
--- /dev/null
+++ b/5.1.0/tests/test-5467b986.sh
@@ -0,0 +1,37 @@
+if [ -z `which mcookie` ] || [ -z `which grep` ] || [ ! -x ${ROOTFS}/bin/readlink ] || [ ! -x ${ROOTFS}/bin/chdir_getcwd ] || [ ! -x ${ROOTFS}/bin/fchdir_getcwd ]; then
+    exit 125;
+fi
+
+DOES_NOT_EXIST=/$(mcookie)
+${PROOT} -v -1 -b /proc -w ${DOES_NOT_EXIST} -r ${ROOTFS} readlink /proc/self/cwd | grep '^/$'
+
+${PROOT} -v -1 -w /a -b /tmp:/a -b /tmp:/b -r ${ROOTFS} pwd | grep '^/a$'
+${PROOT} -v -1 -w /a -b /tmp:/b -b /tmp:/a -r ${ROOTFS} pwd | grep '^/a$'
+${PROOT} -v -1 -w /b -b /tmp:/a -b /tmp:/b -r ${ROOTFS} pwd | grep '^/b$'
+${PROOT} -v -1 -w /b -b /tmp:/b -b /tmp:/a -r ${ROOTFS} pwd | grep '^/b$'
+
+${PROOT} -v -1 -b /tmp:/a -b /tmp:/b -r ${ROOTFS} chdir_getcwd /a | grep '^/[ab]$'
+${PROOT} -v -1 -b /tmp:/b -b /tmp:/a -r ${ROOTFS} chdir_getcwd /a | grep '^/[ab]$'
+${PROOT} -v -1 -b /tmp:/a -b /tmp:/b -r ${ROOTFS} chdir_getcwd /b | grep '^/[ab]$'
+${PROOT} -v -1 -b /tmp:/b -b /tmp:/a -r ${ROOTFS} chdir_getcwd /b | grep '^/[ab]$'
+
+${PROOT} -v -1 -b /tmp:/a -b /tmp:/b -r ${ROOTFS} fchdir_getcwd /a | grep '^/[ab]$'
+${PROOT} -v -1 -b /tmp:/b -b /tmp:/a -r ${ROOTFS} fchdir_getcwd /a | grep '^/[ab]$'
+${PROOT} -v -1 -b /tmp:/a -b /tmp:/b -r ${ROOTFS} fchdir_getcwd /b | grep '^/[ab]$'
+${PROOT} -v -1 -b /tmp:/b -b /tmp:/a -r ${ROOTFS} fchdir_getcwd /b | grep '^/[ab]$'
+
+! ${PROOT} -r ${ROOTFS} chdir_getcwd /bin/true
+[ $? -eq 0 ]
+! ${PROOT} -r ${ROOTFS} fchdir_getcwd /bin/true
+[ $? -eq 0 ]
+
+! ${PROOT} -w /bin -r ${ROOTFS} chdir_getcwd true
+[ $? -eq 0 ]
+! ${PROOT} -w /bin -r ${ROOTFS} fchdir_getcwd true
+[ $? -eq 0 ]
+
+${PROOT} -v -1 -w /usr -r / ${ROOTFS}/bin/chdir_getcwd share  | grep '^/usr/share$'
+${PROOT} -v -1 -w /usr -r / ${ROOTFS}/bin/fchdir_getcwd share | grep '^/usr/share$'
+
+(cd /; ${PROOT} -v -1 -w usr -r / ${ROOTFS}/bin/chdir_getcwd share  | grep '^/usr/share$')
+(cd /; ${PROOT} -v -1 -w usr -r / ${ROOTFS}/bin/fchdir_getcwd share | grep '^/usr/share$')
diff --git a/5.1.0/tests/test-55b731d3.sh b/5.1.0/tests/test-55b731d3.sh
new file mode 100644
index 0000000..27f26ed
--- /dev/null
+++ b/5.1.0/tests/test-55b731d3.sh
@@ -0,0 +1,5 @@
+if ! `which pwd` -P; then
+    exit 125;
+fi
+
+${PROOT} pwd -P
diff --git a/5.1.0/tests/test-55fd1da5.sh b/5.1.0/tests/test-55fd1da5.sh
new file mode 100644
index 0000000..b10fb65
--- /dev/null
+++ b/5.1.0/tests/test-55fd1da5.sh
@@ -0,0 +1,5 @@
+if [ -z `which ls` ]; then
+    exit 125;
+fi
+
+${PROOT} -b /etc:/x ls -la /x
diff --git a/5.1.0/tests/test-5996858d.sh b/5.1.0/tests/test-5996858d.sh
new file mode 100644
index 0000000..217f6c2
--- /dev/null
+++ b/5.1.0/tests/test-5996858d.sh
@@ -0,0 +1,16 @@
+if [ -z `which uname` ] || [ -z `which grep` ] || [ -z `which domainname` ] || [ -z `which hostname` ]|| [ -z `which env` ] || [ -z `which true`]; then
+    exit 125;
+fi
+
+UTSNAME="\\sysname\\nodename\\$(uname -r)\\version\\machine\\domainname\\0\\"
+
+${PROOT} -k ${UTSNAME} uname -s | grep ^sysname$
+${PROOT} -k ${UTSNAME} uname -n | grep ^nodename$
+${PROOT} -k ${UTSNAME} uname -v | grep ^version$
+${PROOT} -k ${UTSNAME} uname -m | grep ^machine$
+${PROOT} -k ${UTSNAME} domainname | grep ^domainname$
+${PROOT} -k ${UTSNAME} env LD_SHOW_AUXV=1 true | grep -E '^AT_HWCAP:[[:space:]]*0?$'
+
+${PROOT} -0 -k ${UTSNAME} sh -c 'domainname domainname2; domainname' | grep ^domainname2$
+${PROOT} -0 -k ${UTSNAME} sh -c 'hostname hostname2; hostname' | grep ^hostname2$
+${PROOT} -0 -k ${UTSNAME} sh -c 'hostname hostname2; uname -n' | grep ^hostname2$
diff --git a/5.1.0/tests/test-5bed7141.c b/5.1.0/tests/test-5bed7141.c
new file mode 100644
index 0000000..f6a7e74
--- /dev/null
+++ b/5.1.0/tests/test-5bed7141.c
@@ -0,0 +1,102 @@
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+static void *routine(void *path)
+{
+	int status;
+
+	status = chdir(path);
+	if (status < 0) {
+		perror("chdir");
+		pthread_exit((void *)-1);
+	}
+	pthread_exit(NULL);
+}
+
+static void pterror(const char *message, int error)
+{
+	fprintf(stderr, "%s: %s\n", message, strerror(error));
+}
+
+void check_cwd(const char *expected)
+{
+	char path[PATH_MAX];
+	int status;
+
+	if (getcwd(path, PATH_MAX) == NULL) {
+		perror("getcwd");
+		exit(EXIT_FAILURE);
+	}
+
+	if (strcmp(path, expected) != 0) {
+		fprintf(stderr, "getcwd: %s != %s\n", path, expected);
+		exit(EXIT_FAILURE);
+	}
+
+	status = readlink("/proc/self/cwd", path, PATH_MAX - 1);
+	if (status < 0) {
+		perror("readlink");
+		exit(EXIT_FAILURE);
+	}
+	path[status] = '\0';
+
+	if (strcmp(path, expected) != 0) {
+		fprintf(stderr, "readlink /proc/self/cwd: %s != %s\n", path, expected);
+		exit(EXIT_FAILURE);
+	}
+
+}
+
+int main(int argc, char *argv[])
+{
+	pthread_t thread;
+	int child_status;
+	void *result;
+	int status;
+
+	status = pthread_create(&thread, NULL, routine, "/etc");
+	if (status != 0) {
+		pterror("pthread_create", status);
+		exit(EXIT_FAILURE);
+	}
+
+	status = pthread_join(thread, &result);
+	if (status != 0) {
+		pterror("pthread_create", status);
+		exit(EXIT_FAILURE);
+	}
+
+	if (result != NULL)
+		exit(EXIT_FAILURE);
+
+	check_cwd("/etc");
+
+	switch (fork()) {
+	case -1:
+		perror("readlink");
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		status = chdir("/usr");
+		if (status < 0) {
+			perror("chdir");
+			exit(EXIT_FAILURE);
+		}
+		exit(EXIT_SUCCESS);
+
+	default:
+		status = wait(&child_status);
+		if (status < 0 || child_status != 0) {
+			perror("wait()");
+			exit(EXIT_FAILURE);
+		}
+		check_cwd("/etc");
+		break;
+	}
+
+	exit(EXIT_SUCCESS);
+}
+
diff --git a/5.1.0/tests/test-5bed7142.sh b/5.1.0/tests/test-5bed7142.sh
new file mode 100644
index 0000000..82574d6
--- /dev/null
+++ b/5.1.0/tests/test-5bed7142.sh
@@ -0,0 +1,11 @@
+if [ ! -x  ${ROOTFS}/bin/pwd ] || [ -z `which mkdir` ] || [ -z `which grep` ] || [ -z `which mcookie` ] || [ -z `which pwd` ]; then
+    exit 125;
+fi
+
+mkdir -p ${ROOTFS}/${PWD}
+${PROOT} -v 1 -w . -r ${ROOTFS} pwd | grep ^${PWD}$
+
+TMP=/tmp/$(mcookie)
+mkdir ${TMP}
+! ${PROOT} sh -c "cd ${TMP}; rmdir ${TMP}; $(which pwd) -P"
+[ $? -eq 0 ]
diff --git a/5.1.0/tests/test-5bed7143.c b/5.1.0/tests/test-5bed7143.c
new file mode 100644
index 0000000..a17fe22
--- /dev/null
+++ b/5.1.0/tests/test-5bed7143.c
@@ -0,0 +1,73 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#define TEMPLATE "/tmp/proot-test-5bed7143-XXXXXX"
+#define COOKIE1 "2fde3df3558fa30bec1b8ebad42df20f"
+#define COOKIE2 "2ba90289e48d1896e0601239ac25f764"
+
+int main()
+{
+	char *path1;
+	char *path2;
+	char *cwd;
+	int status;
+
+	path1 = mkdtemp(strdup(TEMPLATE));
+	if (path1 == NULL)
+		exit(EXIT_FAILURE);
+
+	status = chdir(path1);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	status = mkdir(COOKIE1, 0777);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	status = chdir(COOKIE1);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	status = creat(COOKIE2, O_RDWR);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+	close(status);
+
+	path2 = mktemp(strdup(TEMPLATE));
+	status = rename(path1, path2);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	status = access(COOKIE2, F_OK);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	cwd = get_current_dir_name();
+	if (cwd == NULL || memcmp(cwd, path2, strlen(path2)) != 0)
+		exit(EXIT_FAILURE);
+
+	status = unlink(COOKIE2);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	status = rmdir(cwd);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	if (get_current_dir_name() != NULL || errno != ENOENT)
+		exit(EXIT_FAILURE);
+
+	status = rmdir(path2);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-654decce.sh b/5.1.0/tests/test-654decce.sh
new file mode 100644
index 0000000..6f25b7f
--- /dev/null
+++ b/5.1.0/tests/test-654decce.sh
@@ -0,0 +1,59 @@
+if [ ! -x ${ROOTFS}/bin/readdir ] || [ ! -x ${ROOTFS}/bin/cat ] || [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which chmod` ]  || [ -z `which grep` ] || [ -z `which rm` ] || [ -z `which id` ]; then
+    exit 125;
+fi
+
+if [ `id -u` -eq 0 ]; then
+    exit 125;
+fi
+
+TMP1=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+TMP3=$(mcookie)
+TMP4=$(mcookie)
+
+echo "content of ${TMP1}" > ${TMP1}
+
+mkdir -p ${ROOTFS}/${TMP2}
+chmod -rw ${ROOTFS}/${TMP2}
+
+export LANG=C
+! ${PROOT} -v -1 -r ${ROOTFS} -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} readdir ${TMP2}           | grep '^opendir(3): Permission denied$'
+${PROOT} -v -1 -r ${ROOTFS} -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} readdir ${TMP2}/${TMP3}     | grep "DT_REG  ${TMP4}"
+${PROOT} -v -1 -r ${ROOTFS} -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} cat ${TMP2}/${TMP3}/${TMP4} | grep "^content of ${TMP1}$"
+${PROOT} -v -1 -r ${ROOTFS} -b /tmp:${TMP2}/${TMP3}/${TMP4} readdir ${TMP2}/${TMP3}        | grep "DT_DIR  ${TMP4}"
+# TODO ${PROOT} -v -1 -r ${ROOTFS} -b /tmp:${TMP2}/${TMP3}/${TMP4} readdir /tmp            | grep "DT_DIR  ${TMP2}"
+# TODO ${PROOT} -v -1 -r ${ROOTFS} -b /tmp:/${TMP4} readdir /                              | grep "DT_REG  ${TMP4}"
+
+${PROOT} -v -1 -r ${ROOTFS} -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} -b /etc/fstab:${TMP2}/${TMP3}/motd readdir ${TMP2}/${TMP3} | grep "DT_REG  ${TMP4}"
+${PROOT} -v -1 -r ${ROOTFS} -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} -b /etc/fstab:${TMP2}/${TMP3}/motd readdir ${TMP2}/${TMP3} | grep "DT_REG  motd"
+
+${PROOT} -v -1 -r ${ROOTFS} -b ${TMP1}:${TMP2}/${TMP3}/${TMP4}/motd -b /etc/fstab:${TMP2}/${TMP3}/motd cat ${TMP2}/${TMP3}/${TMP4}/motd | grep "^content of ${TMP1}$"
+${PROOT} -v -1 -r ${ROOTFS} -b /etc/fstab:${TMP2}/${TMP3}/motd -b ${TMP1}:${TMP2}/${TMP3}/${TMP4}/motd cat ${TMP2}/${TMP3}/${TMP4}/motd | grep "^content of ${TMP1}$"
+
+! chmod +rw ${ROOTFS}/${TMP2}
+rm -fr ${ROOTFS}/${TMP2}
+
+mkdir -p ${TMP2}
+chmod -rw ${TMP2}
+
+export LANG=C
+! ${PROOT} -v -1 -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} ${ROOTFS}/bin/readdir ${TMP2}           | grep '^opendir(3): Permission denied$'
+${PROOT} -v -1 -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} ${ROOTFS}/bin/readdir ${TMP2}/${TMP3}     | grep "DT_REG  ${TMP4}"
+${PROOT} -v -1 -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} ${ROOTFS}/bin/cat ${TMP2}/${TMP3}/${TMP4} | grep "^content of ${TMP1}$"
+${PROOT} -v -1 -b /tmp:${TMP2}/${TMP3}/${TMP4} ${ROOTFS}/bin/readdir ${TMP2}/${TMP3}        | grep "DT_DIR  ${TMP4}"
+# TODO ${PROOT} -v -1 -b /tmp:${TMP2}/${TMP3}/${TMP4} readdir /tmp                          | grep "DT_DIR  ${TMP2}"
+# TODO ${PROOT} -v -1 -b /tmp:/${TMP4} readdir /                                            | grep "DT_REG  ${TMP4}"
+
+${PROOT} -v -1 -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} -b /etc/fstab:${TMP2}/${TMP3}/motd ${ROOTFS}/bin/readdir ${TMP2}/${TMP3} | grep "DT_REG  ${TMP4}"
+${PROOT} -v -1 -b ${TMP1}:${TMP2}/${TMP3}/${TMP4} -b /etc/fstab:${TMP2}/${TMP3}/motd ${ROOTFS}/bin/readdir ${TMP2}/${TMP3} | grep "DT_REG  motd"
+
+${PROOT} -v -1 -b ${TMP1}:${TMP2}/${TMP3}/${TMP4}/motd -b /etc/fstab:${TMP2}/${TMP3}/motd ${ROOTFS}/bin/cat ${TMP2}/${TMP3}/${TMP4}/motd | grep "^content of ${TMP1}$"
+${PROOT} -v -1 -b /etc/fstab:${TMP2}/${TMP3}/motd -b ${TMP1}:${TMP2}/${TMP3}/${TMP4}/motd ${ROOTFS}/bin/cat ${TMP2}/${TMP3}/${TMP4}/motd | grep "^content of ${TMP1}$"
+
+${PROOT} -b /bin:/this1/does/not/exist -b /tmp:/this2/does/not/exist ${ROOTFS}/bin/readdir /this1/
+${PROOT} -b /bin:/this1/does/not/exist -b /tmp:/this2/does/not/exist ${ROOTFS}/bin/readdir /this2/
+${PROOT} -b /tmp:/this1/does/not/exist -b /bin:/this2/does/not/exist ${ROOTFS}/bin/readdir /this1/
+${PROOT} -b /tmp:/this1/does/not/exist -b /bin:/this2/does/not/exist ${ROOTFS}/bin/readdir /this2/
+
+! chmod +rw ${TMP1} ${TMP2}
+rm -fr ${TMP1} ${TMP2}
diff --git a/5.1.0/tests/test-66666666.c b/5.1.0/tests/test-66666666.c
new file mode 100644
index 0000000..1439842
--- /dev/null
+++ b/5.1.0/tests/test-66666666.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <errno.h>
+
+bool sigtrap_received = false;
+
+void handler(int signo)
+{
+	if (signo == SIGTRAP)
+		sigtrap_received = true;
+}
+
+int main()
+{
+	struct sigaction sa;
+	int status;
+
+	sa.sa_flags = 0;
+	sa.sa_handler = handler;
+	status = sigemptyset(&sa.sa_mask);
+	if (status < 0) {
+		perror("sigemptyset()");
+		exit(EXIT_FAILURE);
+	}
+
+	status = sigaction(SIGTRAP, &sa, 0);
+	if (status < 0) {
+		perror("sigaction(SIGTRAP)");
+		exit(EXIT_FAILURE);
+	}
+
+	status = raise(SIGTRAP);
+	if (status != 0) {
+		perror("raise(SIGTRAP)");
+		exit(EXIT_FAILURE);
+	}
+
+	if (sigtrap_received)
+		exit(EXIT_SUCCESS);
+	else
+		exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-67972fbe.sh b/5.1.0/tests/test-67972fbe.sh
new file mode 100644
index 0000000..96f3d6c
--- /dev/null
+++ b/5.1.0/tests/test-67972fbe.sh
@@ -0,0 +1,13 @@
+if [ ! -x ${ROOTFS}/bin/readdir ] || [ ! -e /bin/true ] || [ -z `which mkdir` ] || [ -z `which ln` ]  || [ -z `which rm` ] || [ -z `which grep` ] || [ -z `which mcookie` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+mkdir -p ${ROOTFS}/${TMP}/run/dbus
+mkdir -p ${ROOTFS}/${TMP}/var
+ln -s ../run ${ROOTFS}/${TMP}/var/run
+
+${PROOT} -b /bin:${TMP}/var/run/dbus -r ${ROOTFS} readdir ${TMP}/var/run/dbus/ | grep true
+
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-691786c8.sh b/5.1.0/tests/test-691786c8.sh
new file mode 100644
index 0000000..a09fda6
--- /dev/null
+++ b/5.1.0/tests/test-691786c8.sh
@@ -0,0 +1,45 @@
+if [ ! -x /usr/bin/echo ] || [ -z `which mcookie` ] || [ -z `which chmod` ] || [ -z `which env` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+echo '#!/usr/bin/echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' > ${TMP}
+
+chmod +x ${TMP}
+
+RESULT=$(${PROOT} ${TMP})
+EXPECTED=$(${TMP})
+
+[ "${RESULT}" = "${EXPECTED}" ]
+
+echo '#!//../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../usr/bin/echo XXXXXXXXX' > ${TMP}
+
+RESULT=$(${PROOT} ${TMP})
+EXPECTED=$(${TMP})
+
+[ "${RESULT}" = "${EXPECTED}" ]
+[ "${RESULT}" = "${TMP}" ]
+
+echo '#!/../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../usr/bin/echo XXXXXXXXX' > ${TMP}
+
+! ${PROOT} ${TMP}
+[ $? -eq 0 ]
+
+! ${TMP}
+[ $? -eq 0 ]
+
+echo '#!                                                                                                                                                                                                        ' > ${TMP}
+
+${PROOT} ${TMP}
+
+echo '#!' > ${TMP}
+
+${PROOT} ${TMP}
+
+/usr/bin/echo "#!${TMP}" > ${TMP}
+
+env LANG=C ${PROOT} ${TMP} 2>&1 | grep 'Too many levels of symbolic links'
+[ $? -eq 0 ]
+
+rm -f ${TMP}
diff --git a/5.1.0/tests/test-6b5a254a.sh b/5.1.0/tests/test-6b5a254a.sh
new file mode 100644
index 0000000..f43ae3f
--- /dev/null
+++ b/5.1.0/tests/test-6b5a254a.sh
@@ -0,0 +1,25 @@
+if [ -z `which mcookie` ] ||  [ -z `which echo` ] || [ -z `which touch` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+FOO1=/tmp/$(mcookie)
+FOO2=/tmp/$(mcookie)
+FOO3=/tmp/$(mcookie)
+FOO4=/tmp/$(mcookie)
+
+echo "content of FOO1" > ${FOO1}
+echo "content of FOO2" > ${FOO2}
+
+ln -s ${FOO1} ${FOO3} # FOO3 -> FOO1
+ln -s ${FOO2} ${FOO4} # FOO4 -> FOO2
+
+${PROOT} -b ${FOO3}:${FOO4} cat ${FOO2} | grep '^content of FOO1$'
+${PROOT} -b ${FOO4}:${FOO3} cat ${FOO1} | grep '^content of FOO2$'
+
+${PROOT} -b ${FOO3}:${FOO4}! cat ${FOO2} | grep '^content of FOO2$'
+${PROOT} -b ${FOO4}:${FOO3}! cat ${FOO1} | grep '^content of FOO1$'
+
+${PROOT} -v -1 -b ${FOO1} -b ${FOO3}                 cat ${FOO1} | grep '^content of FOO1$'
+${PROOT} -v -1 -b ${FOO1} -b ${FOO2}:/tmp/../${FOO1} cat ${FOO1} | grep '^content of FOO2$'
+
+rm -f ${FOO1} ${FOO2} ${FOO3}
diff --git a/5.1.0/tests/test-6d1e2650.sh b/5.1.0/tests/test-6d1e2650.sh
new file mode 100644
index 0000000..f5358a0
--- /dev/null
+++ b/5.1.0/tests/test-6d1e2650.sh
@@ -0,0 +1,8 @@
+if [ ! -x  ${ROOTFS}/bin/true ] || [ -z `which env` ]; then
+    exit 125;
+fi
+
+! env PATH=/nib ${PROOT} -r ${ROOTFS} true
+[ $? -eq 0 ]
+
+env PATH=/bin ${PROOT} -r ${ROOTFS} true
diff --git a/5.1.0/tests/test-6fb08ce1.sh b/5.1.0/tests/test-6fb08ce1.sh
new file mode 100644
index 0000000..63deef7
--- /dev/null
+++ b/5.1.0/tests/test-6fb08ce1.sh
@@ -0,0 +1,10 @@
+if [ -z `which mcookie` ] || [ -z `which grep` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+echo "OK" > ${TMP}
+
+${PROOT} -b ${TMP}:/etc/fstab -b /dev/null -b /etc cat /etc/fstab | grep ^OK$
+
+rm ${TMP}
diff --git a/5.1.0/tests/test-713b6910.sh b/5.1.0/tests/test-713b6910.sh
new file mode 100644
index 0000000..82e01fd
--- /dev/null
+++ b/5.1.0/tests/test-713b6910.sh
@@ -0,0 +1,51 @@
+if [ -z `which mcookie` ] || [ -z `which rm` ] || [ -z `which cat` ] || [ -z `which chmod` ] || [ -z `which ln` ] || [ -z `which grep` ] || [ -z `which mkdir` ] || [ ! -x  ${ROOTFS}/bin/readlink ]; then
+    exit 125;
+fi
+
+######################################################################
+
+TMP1=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+TMP3=/tmp/$(mcookie)
+TMP4=/tmp/$(mcookie)
+
+rm -fr ${TMP1} ${TMP2} ${TMP3} ${TMP4}
+
+######################################################################
+
+cat > ${TMP1} <<'EOF'
+#!/bin/sh
+echo $0
+EOF
+
+chmod +x ${TMP1}
+ln -s ${TMP1} ${TMP2}
+
+${PROOT} ${TMP2} | grep -v ${TMP1}
+${PROOT} ${TMP2} | grep ${TMP2}
+
+######################################################################
+
+mkdir -p ${TMP3}
+cd ${TMP3}
+
+ln -s $(which true) false
+! ${PROOT} false
+
+echo "#!$(which false)" > true
+chmod a-x true
+${PROOT} true
+
+######################################################################
+
+ln -s ${ROOTFS}/bin/readlink ${TMP4}
+
+TEST1=$(${PROOT} ${ROOTFS}/bin/readlink /proc/self/exe)
+TEST2=$(${PROOT} ${TMP4} /proc/self/exe)
+
+test "${TEST1}" = "${TEST2}"
+
+######################################################################
+
+cd /
+rm -fr ${TMP1} ${TMP2} ${TMP3} ${TMP4}
diff --git a/5.1.0/tests/test-7601199b.sh b/5.1.0/tests/test-7601199b.sh
new file mode 100644
index 0000000..fc489b4
--- /dev/null
+++ b/5.1.0/tests/test-7601199b.sh
@@ -0,0 +1,5 @@
+if [ ! -x /bin/sh ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+${PROOT} -w /tmp /bin/sh -c 'echo $PWD' | grep '^/tmp$'
diff --git a/5.1.0/tests/test-77777777.c.unreliable b/5.1.0/tests/test-77777777.c.unreliable
new file mode 100644
index 0000000..09683cb
--- /dev/null
+++ b/5.1.0/tests/test-77777777.c.unreliable
@@ -0,0 +1,51 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int main()
+{
+	int child_status;
+	int status;
+	pid_t pid;
+
+	pid = fork();
+	switch (pid) {
+	case -1:
+		perror("fork()");
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		status = raise(SIGSTOP);
+		if (status != 0) {
+			perror("raise(SIGSTOP)");
+			exit(EXIT_FAILURE);
+		}
+		sleep(1);
+		exit(EXIT_FAILURE);
+
+	default: /* parent */
+		status = waitpid(pid, &child_status, WUNTRACED);
+		if (status < 0) {
+			perror("waitpid()");
+			exit(EXIT_FAILURE);
+		}
+
+		if (WIFEXITED(child_status))
+			printf("exited, status=%d\n", WEXITSTATUS(child_status));
+		else if (WIFSIGNALED(child_status))
+			printf("killed by signal %d\n", WTERMSIG(child_status));
+		else if (WIFSTOPPED(child_status))
+			printf("stopped by signal %d\n", WSTOPSIG(child_status));
+		else if (WIFCONTINUED(child_status))
+			printf("continued\n");
+
+		if (WIFSTOPPED(child_status))
+			exit(EXIT_SUCCESS);
+		else
+			exit(EXIT_FAILURE);
+	}
+}
+
diff --git a/5.1.0/tests/test-79cf6614.c b/5.1.0/tests/test-79cf6614.c
new file mode 100644
index 0000000..cdb8d81
--- /dev/null
+++ b/5.1.0/tests/test-79cf6614.c
@@ -0,0 +1,32 @@
+/*
+ * Submitted-by: Thomas P. HIGDON <thomas.p.higdon@gmail.com>
+ * Ref.: https://groups.google.com/d/msg/proot_me/4WbUndy-aXI/lmKiDfoIK_IJ
+ */
+
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main()
+{
+	int status;
+	struct timeval times[2] = {
+		{.tv_sec = 52353, .tv_usec = 0},
+		{ .tv_sec = 52353, .tv_usec = 0 } };
+	char tmp[] = "proot-XXXXXX";
+
+	mktemp(tmp);
+	if (tmp[0] == '\0')
+		exit(EXIT_FAILURE);
+
+	(void) unlink(tmp);
+
+	status = symlink("/etc/fstab", tmp);
+	if (status < 0)
+		exit(EXIT_FAILURE);
+
+	status = lutimes(tmp, times);
+	exit(status < 0 && errno != ENOSYS ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
diff --git a/5.1.0/tests/test-82ba4ba1.c b/5.1.0/tests/test-82ba4ba1.c
new file mode 100644
index 0000000..fd78dc6
--- /dev/null
+++ b/5.1.0/tests/test-82ba4ba1.c
@@ -0,0 +1,59 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+	uid_t ruid = 13, euid = 13, suid = 13;
+	gid_t rgid = 13, egid = 13, sgid = 13;
+	int status;
+
+	status = getresuid(&ruid, &euid, &suid);
+	if (status != 0 || ruid != 0 || euid != 0 || suid != 0) {
+		perror("getresuid");
+		fprintf(stderr, "%ld %ld %ld\n", (unsigned long) ruid, (unsigned long) euid, (unsigned long) suid);
+		exit(EXIT_FAILURE);
+	}
+
+	status = getresgid(&rgid, &egid, &sgid);
+	if (status != 0 || rgid != 0 || egid != 0 || sgid != 0) {
+		perror("getresgid");
+		fprintf(stderr, "%ld %ld %ld\n", (unsigned long) ruid, (unsigned long) euid, (unsigned long) suid);
+		exit(EXIT_FAILURE);
+	}
+
+	status = setresgid(1, 1, 1);
+	if (status != 0) {
+		perror("setresgid");
+		exit(EXIT_FAILURE);
+	}
+
+	status = getresgid(&rgid, &egid, &sgid);
+	if (status != 0 || rgid != 1 || egid != 1 || sgid != 1) {
+		perror("getresgid");
+		fprintf(stderr, "%ld %ld %ld\n", (unsigned long) rgid, (unsigned long) egid, (unsigned long) sgid);
+		exit(EXIT_FAILURE);
+	}
+
+	if (status != 0 || rgid != 1 || egid != 1 || sgid != 1) {
+		perror("getresgid");
+		fprintf(stderr, "%ld %ld %ld\n", (unsigned long) ruid, (unsigned long) euid, (unsigned long) suid);
+		exit(EXIT_FAILURE);
+	}
+
+	status = setresuid(1, 1, 1);
+	if (status != 0) {
+		perror("setresuid");
+		exit(EXIT_FAILURE);
+	}
+
+	status = getresuid(&ruid, &euid, &suid);
+	if (status != 0 || ruid != 1 || euid != 1 || suid != 1) {
+		perror("getresuid");
+		fprintf(stderr, "%ld %ld %ld\n", (unsigned long) ruid, (unsigned long) euid, (unsigned long) suid);
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-82ba4ba1.sh b/5.1.0/tests/test-82ba4ba1.sh
new file mode 100644
index 0000000..7d4241a
--- /dev/null
+++ b/5.1.0/tests/test-82ba4ba1.sh
@@ -0,0 +1,41 @@
+if [ ! -x /bin/true ] || [ -z `which id` ] || [ -z `which grep` ] || [ -z `which env` ] || [ -z `which chown` ] || [ -z `which chroot` ]; then
+    exit 125;
+fi
+
+if [ `id -u` -eq 0 ]; then
+    exit 125;
+fi
+
+${PROOT} -i 123:456 id -u | grep ^123$
+${PROOT} -i 123:456 id -g | grep ^456$
+
+${PROOT} -i 123:456 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_UID:[[:space:]]*123$'
+${PROOT} -i 123:456 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_EUID:[[:space:]]*123$'
+${PROOT} -i 123:456 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_GID:[[:space:]]*456$'
+${PROOT} -i 123:456 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_EGID:[[:space:]]*456$'
+
+! ${PROOT} -i 123:456 chown root.root /root
+[ $? -eq 0 ]
+
+! chroot / /bin/true
+EXPECTED=$?
+
+! ${PROOT} -i 123:456 chroot / /bin/true
+[ $? -eq ${EXPECTED} ]
+
+! ${PROOT} -i 123:456 chroot /tmp/.. /bin/true
+[ $? -eq ${EXPECTED} ]
+
+! ${PROOT} -i 123:456 chroot /tmp /bin/true
+[ $? -eq 0 ]
+
+${PROOT} -0 id -u | grep ^0$
+${PROOT} -0 id -g | grep ^0$
+${PROOT} -0 chown root.root /root
+${PROOT} -0 chroot / /bin/true
+${PROOT} -0 chroot /tmp/.. /bin/true
+
+${PROOT} -0 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_UID:[[:space:]]*0$'
+${PROOT} -0 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_EUID:[[:space:]]*0$'
+${PROOT} -0 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_GID:[[:space:]]*0$'
+${PROOT} -0 env LD_SHOW_AUXV=1 /bin/true | grep '^AT_EGID:[[:space:]]*0$'
diff --git a/5.1.0/tests/test-88888888.c b/5.1.0/tests/test-88888888.c
new file mode 100644
index 0000000..0960955
--- /dev/null
+++ b/5.1.0/tests/test-88888888.c
@@ -0,0 +1,73 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main()
+{
+	int fd;
+
+	fd = open("/bin/true", O_RDONLY);
+	if (fd < 0) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+	fd = open("/bin/true/", O_RDONLY);
+	if (fd >= 0 || errno != ENOTDIR) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+	fd = open("/bin/true/.", O_RDONLY);
+	if (fd >= 0 || errno != ENOTDIR) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+	fd = open("/bin/true/..", O_RDONLY);
+	if (fd >= 0 || errno != ENOTDIR) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+	fd = open("/6a05942f08d5a72de56483487963deec", O_RDONLY);
+	if (fd >= 0 || errno != ENOENT) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+	fd = open("/6a05942f08d5a72de56483487963deec/", O_RDONLY);
+	if (fd >= 0 || errno != ENOENT) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+	fd = open("/6a05942f08d5a72de56483487963deec/.", O_RDONLY);
+	if (fd >= 0 || errno != ENOENT) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+#if 0
+	/* This test fails in OBS, why?  */
+	fd = open("/6a05942f08d5a72de56483487963deec/..", O_RDONLY);
+	if (fd >= 0 || errno != ENOENT) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+#endif
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-8a83376a.sh b/5.1.0/tests/test-8a83376a.sh
new file mode 100644
index 0000000..dd1b4ba
--- /dev/null
+++ b/5.1.0/tests/test-8a83376a.sh
@@ -0,0 +1,5 @@
+if [ ! -e /bin/true ] || [ -z `which ldd` ]; then
+    exit 125;
+fi
+
+${PROOT} ldd /bin/true
diff --git a/5.1.0/tests/test-8e5fa256.sh b/5.1.0/tests/test-8e5fa256.sh
new file mode 100644
index 0000000..259ea37
--- /dev/null
+++ b/5.1.0/tests/test-8e5fa256.sh
@@ -0,0 +1,43 @@
+if [ ! -x  ${ROOTFS}/bin/readlink ] || [ ! -x  ${ROOTFS}/bin/symlink ] || [ -z `which mcookie` ] || [ -z `which rm` ] || [ -z `which ln` ] || [ -z `which mkdir` ]; then
+    exit 125;
+fi
+
+LINK_NAME1=`mcookie`
+LINK_NAME2=`mcookie`
+
+rm -f /tmp/${LINK_NAME1}
+rm -f /tmp/${LINK_NAME2}
+
+mkdir -p ${ROOTFS}/tmp
+
+ln -s /tmp/ced-host /tmp/${LINK_NAME1}
+ln -s /tmp/ced-guest ${ROOTFS}/tmp/${LINK_NAME1}
+${PROOT} -r ${ROOTFS} readlink /tmp/${LINK_NAME1} | grep ^/tmp/ced-guest$
+${PROOT} -b /tmp -r ${ROOTFS} readlink /tmp/${LINK_NAME1} | grep ^/tmp/ced-host$
+${PROOT} -b /tmp:/foo -r ${ROOTFS} readlink /foo/${LINK_NAME1} | grep ^/foo/ced-host$
+${PROOT} -b /tmp:/foo -r ${ROOTFS} readlink /tmp/${LINK_NAME1} | grep ^/tmp/ced-guest$
+
+${PROOT} -b /:/host-rootfs -r ${ROOTFS} readlink /tmp/${LINK_NAME1} | grep ^/tmp/ced-guest$
+${PROOT} -b /:/host-rootfs -b /tmp:/foo -r ${ROOTFS} readlink /tmp/${LINK_NAME1} | grep ^/tmp/ced-guest$
+
+# Always use the deepest binding, deepest from the host point-of-view.
+${PROOT} -b /:/host-rootfs -r ${ROOTFS} readlink /tmp/${LINK_NAME1} | grep ^/tmp/ced-guest$
+${PROOT} -b /:/host-rootfs -b /tmp -r ${ROOTFS} readlink /tmp/${LINK_NAME1} | grep ^/tmp/ced-host$
+${PROOT} -b /:/host-rootfs -b /tmp:/foo -r ${ROOTFS} readlink /foo/${LINK_NAME1} | grep ^/foo/ced-host$
+${PROOT} -b /:/host-rootfs -b /tmp -r ${ROOTFS} readlink /host-rootfs/tmp/${LINK_NAME1} | grep ^/tmp/ced-host$
+${PROOT} -b /:/host-rootfs -b /tmp:/foo -r ${ROOTFS} readlink /host-rootfs/tmp/${LINK_NAME1} | grep ^/foo/ced-host$
+
+rm /tmp/${LINK_NAME1}
+rm ${ROOTFS}/tmp/${LINK_NAME1}
+
+${PROOT} -b /:/host-rootfs -b /tmp -w /bin -r ${ROOTFS} symlink /bin/bar /bin/${LINK_NAME1}
+${PROOT} -b /:/host-rootfs -b /tmp -w /bin -r ${ROOTFS} readlink ${LINK_NAME1} | grep ^/bin/bar$
+rm ${ROOTFS}/bin/${LINK_NAME1}
+
+${PROOT} -b /:/host-rootfs -b /tmp -w /tmp -r ${ROOTFS} symlink /bin/bar /tmp/${LINK_NAME1}
+${PROOT} -b /:/host-rootfs -b /tmp -w /tmp -r ${ROOTFS} readlink ${LINK_NAME1} | grep ^/bin/bar$
+${PROOT} -b /:/host-rootfs -b /tmp:/foo -w /foo -r ${ROOTFS} symlink /foo/bar /foo/${LINK_NAME2}
+${PROOT} -b /:/host-rootfs -b /tmp:/foo -w /foo -r ${ROOTFS} readlink ${LINK_NAME2} | grep ^/foo/bar$
+${PROOT} -b /:/host-rootfs -b /tmp -w /host-rootfs/tmp -r ${ROOTFS} readlink ${LINK_NAME2} | grep ^/foo/bar$
+rm /tmp/${LINK_NAME2}
+rm /tmp/${LINK_NAME1}
diff --git a/5.1.0/tests/test-99999999.sh b/5.1.0/tests/test-99999999.sh
new file mode 100644
index 0000000..f0a8c84
--- /dev/null
+++ b/5.1.0/tests/test-99999999.sh
@@ -0,0 +1,52 @@
+if [ ! -x  ${ROOTFS}/bin/readlink ] || [ -z `which readlink` ] || [ -z `which cut` ] || [ -z `which grep` ] || [ -z `which md5sum` ]; then
+    exit 125;
+fi
+
+WHICH_READLINK=$(readlink -f $(which readlink))
+
+${PROOT} readlink /proc/self/exe         | grep ^${WHICH_READLINK}$
+${PROOT} sh -c 'readlink /proc/self/exe' | grep ^${WHICH_READLINK}$
+${PROOT} bash -c 'readlink /proc/$$/exe'   | grep ^${WHICH_READLINK}$
+${PROOT} -b /proc -r ${ROOTFS} readlink /proc/self/exe | grep ^/bin/readlink$
+
+${PROOT} readlink /proc/1/../self/exe         | grep ^${WHICH_READLINK}$
+${PROOT} sh -c 'readlink /proc/1/../self/exe' | grep ^${WHICH_READLINK}$
+${PROOT} bash -c 'readlink /proc/1/../$$/exe'   | grep ^${WHICH_READLINK}$
+${PROOT} -b /proc -r ${ROOTFS} readlink /proc/1/../self/exe | grep ^/bin/readlink$
+
+! ${PROOT} readlink /proc/self/exe/
+[ $? -eq 0 ]
+
+! ${PROOT} readlink /proc/self/exe/..
+[ $? -eq 0 ]
+
+! ${PROOT} readlink /proc/self/exe/../exe
+[ $? -eq 0 ]
+
+! ${PROOT} -b /proc readlink /proc/self/exe/
+[ $? -eq 0 ]
+
+! ${PROOT} -b /proc readlink /proc/self/exe/..
+[ $? -eq 0 ]
+
+! ${PROOT} -b /proc readlink /proc/self/exe/../exe
+[ $? -eq 0 ]
+
+TEST=$(${PROOT} readlink /proc/self/fd/0 | grep -E "^/proc/[[:digit:]]+/fd/0$" | true)
+test -z $TEST
+
+TEST=$(${PROOT} -b /proc -r ${ROOTFS} readlink /proc/self/fd/0 | grep -E "^/proc/[[:digit:]]+/fd/0$" | true)
+test -z $TEST
+
+if [ ! -z $$ ]; then
+TEST=$(readlink -f /proc/$$/exe)
+${PROOT} sh -c 'true; readlink /proc/$$/exe' | grep ${TEST}
+fi
+
+MD5=$(md5sum $(which md5sum) | cut -f 1 -d ' ')
+
+MD5_PROOT=$(${PROOT} md5sum /proc/self/exe | cut -f 1 -d ' ')
+test ${MD5_PROOT} = ${MD5}
+
+MD5_PROOT=$(${PROOT} -b /proc md5sum /proc/self/exe | cut -f 1 -d ' ')
+test ${MD5_PROOT} = ${MD5}
diff --git a/5.1.0/tests/test-9c07fad8.c b/5.1.0/tests/test-9c07fad8.c
new file mode 100644
index 0000000..a852025
--- /dev/null
+++ b/5.1.0/tests/test-9c07fad8.c
@@ -0,0 +1,16 @@
+#include <linux/unistd.h>
+
+int check = 0;
+
+static void __attribute__((constructor)) init(void)
+{
+	if (check > 0)
+		_exit(1);
+
+	check++;
+}
+
+int main(void)
+{
+	return 0;
+}
diff --git a/5.1.0/tests/test-9f5eeb72.sh b/5.1.0/tests/test-9f5eeb72.sh
new file mode 100644
index 0000000..79999e4
--- /dev/null
+++ b/5.1.0/tests/test-9f5eeb72.sh
@@ -0,0 +1,157 @@
+if [ -z `which mkdir` ] || [ -z `which chmod` ] || [ -z `which touch` ] || [ -z `which ln` ] || [ -z `which cpio` ] || [ -z `which stat` ] || [ -z `which cat` ] || [ -z `which readlink` ] || [ -z `which mcookie` ] || [ -z `which mknod` ]; then
+    exit 125;
+fi
+
+if [ ! -e $CARE ]; then
+    exit 125;
+fi
+unset PROOT
+
+TMP=/tmp/$(mcookie)
+mkdir ${TMP}
+cd ${TMP}
+
+export LANG=en_US.UTF-8
+mkdir a
+echo "I'm a bee" > a/b
+echo "I'm a sea" > a/c
+chmod -w a
+touch Å‚
+ln Å‚ d
+ln -s dangling_symlink e
+mknod f p
+mkdir -p   x/y
+chmod -rwx x
+
+for BUNCH in \
+    "FORMAT=/              EXTRACT=''" \
+    "FORMAT=.raw           EXTRACT='${CARE} -x'" \
+    "FORMAT=.cpio          EXTRACT='${CARE} -x'" \
+    "FORMAT=.cpio.gz       EXTRACT='${CARE} -x'" \
+    "FORMAT=.cpio.lzo      EXTRACT='${CARE} -x'" \
+    "FORMAT=.tar           EXTRACT='${CARE} -x'" \
+    "FORMAT=.tgz           EXTRACT='${CARE} -x'" \
+    "FORMAT=.tar.gz        EXTRACT='${CARE} -x'" \
+    "FORMAT=.tzo           EXTRACT='${CARE} -x'" \
+    "FORMAT=.tar.lzo       EXTRACT='${CARE} -x'" \
+    "FORMAT=.bin           EXTRACT='${CARE} -x'" \
+    "FORMAT=.bin           EXTRACT='sh -c'" \
+    "FORMAT=.gz.bin        EXTRACT='sh -c'" \
+    "FORMAT=.lzo.bin       EXTRACT='sh -c'" \
+    "FORMAT=.cpio.bin      EXTRACT='sh -c'" \
+    "FORMAT=.cpio.gz.bin   EXTRACT='sh -c'" \
+    "FORMAT=.cpio.lzo.bin  EXTRACT='sh -c'" \
+    "FORMAT=.tar.bin       EXTRACT='sh -c'" \
+    "FORMAT=.tgz.bin       EXTRACT='sh -c'" \
+    "FORMAT=.tzo.bin       EXTRACT='sh -c'" \
+    "FORMAT=.tar.gz.bin    EXTRACT='sh -c'" \
+    "FORMAT=.tar.lzo.bin   EXTRACT='sh -c'"
+do
+    eval $BUNCH
+    CWD=${PWD}
+
+    if echo ${FORMAT} | grep '.bin' && ${CARE} -V | grep '(.bin): no'; then
+	continue
+    fi
+
+    # Check: permissions, unordered archive, UTF-8, hard-links
+    ${CARE} -o test${FORMAT} cat a/b Å‚ d a/c
+
+    if [ -n "${EXTRACT}" ]; then
+	! chmod +rwx -R test-${FORMAT}-1
+	rm -fr test-${FORMAT}-1
+	mkdir test-${FORMAT}-1
+	cd test-${FORMAT}-1
+	${EXTRACT} ../test${FORMAT}
+    fi
+
+    test -d test/rootfs/${CWD}/a
+    test -f test/rootfs/${CWD}/a/b
+    test -f test/rootfs/${CWD}/a/c
+    test -f test/rootfs/${CWD}/Å‚
+    test -f test/rootfs/${CWD}/d
+
+    INODE1=$(stat -c %i test/rootfs/${CWD}/d)
+    INODE2=$(stat -c %i test/rootfs/${CWD}/Å‚)
+    [ $INODE1 -eq $INODE2 ]
+
+    PERM1=$(stat -c %a ${CWD}/a)
+    PERM2=$(stat -c %a test/rootfs/${CWD}/a)
+    [ $PERM1 -eq $PERM2 ]
+
+    if [ -n "${EXTRACT}" ]; then
+	cd ..
+    else
+	! chmod +rwx -R test
+	rm -fr test
+    fi
+
+    # Check: last archived version wins, symlinks
+    ${CARE} -o test${FORMAT} sh -c 'ls a; ls a/b; ls -l e'
+
+    if [ -n "${EXTRACT}" ]; then
+	! chmod +rwx -R test-${FORMAT}-2
+	rm -fr test-${FORMAT}-2
+	mkdir test-${FORMAT}-2
+	cd test-${FORMAT}-2
+	${EXTRACT} ../test${FORMAT}
+    fi
+
+    B=$(cat test/rootfs/${CWD}/a/b)
+    [ x"$B" != x ]
+    [ "$B" = "I'm a bee" ]
+
+    test -L test/rootfs/${CWD}/e
+
+    F=$(readlink test/rootfs/${CWD}/e)
+    [ x"$F" != x ]
+    [ "$F" = "dangling_symlink" ]
+
+    if [ -n "${EXTRACT}" ]; then
+	cd ..
+    else
+	! chmod +rwx -R test
+	rm -fr test
+    fi
+
+    # Check: non-regular files are archived/extractable
+    ${CARE} -d -p /dev -p /proc -o test${FORMAT} sh -c 'ls -l f'
+
+    if [ -n "${EXTRACT}" ]; then
+	! chmod +rwx -R test-${FORMAT}-1
+	rm -fr test-${FORMAT}-1
+	mkdir test-${FORMAT}-1
+	cd test-${FORMAT}-1
+	${EXTRACT} ../test${FORMAT}
+    fi
+
+    [ "fifo" = "$(stat -c %F test/rootfs/${CWD}/f)" ]
+
+    if [ -n "${EXTRACT}" ]; then
+	cd ..
+    else
+	! chmod +rwx -R test
+	rm -fr test
+    fi
+
+    # Check: extractable archive
+    ${CARE} -o test${FORMAT} chmod -R +rwx x
+
+    if [ -n "${EXTRACT}" ]; then
+	! chmod +rwx -R test-${FORMAT}-3
+	rm -fr test-${FORMAT}-3
+	mkdir test-${FORMAT}-3
+	cd test-${FORMAT}-3
+	${EXTRACT} ../test${FORMAT}
+
+	cd ..
+    else
+	! chmod +rwx -R test
+	rm -fr test
+    fi
+done
+
+cd ..
+chmod +rwx -R ${TMP}
+rm -fr ${TMP}
+
diff --git a/5.1.0/tests/test-a3e68988.c b/5.1.0/tests/test-a3e68988.c
new file mode 100644
index 0000000..5f74412
--- /dev/null
+++ b/5.1.0/tests/test-a3e68988.c
@@ -0,0 +1,114 @@
+#include <linux/auxvec.h> /* AT_*, */
+#include <stdio.h>        /* printf(3), */
+#include <sys/types.h>    /* open(2), */
+#include <sys/stat.h>     /* open(2), */
+#include <fcntl.h>        /* open(2), */
+#include <unistd.h>       /* read(2), close(2), */
+#include <stdlib.h>       /* exit(3), EXIT_*, realloc(3), free(3), */
+
+struct auxv {
+	long type;
+	long value;
+} __attribute__((packed));
+
+void print_auxv(struct auxv *auxv)
+{
+#define CASE(a)							\
+	case (a):						\
+		printf("%s = 0x%lx\n", #a, auxv->value);	\
+		break;
+
+	switch (auxv->type) {
+	CASE(AT_NULL)
+	CASE(AT_IGNORE)
+	CASE(AT_EXECFD)
+	CASE(AT_PHDR)
+	CASE(AT_PHENT)
+	CASE(AT_PHNUM)
+	CASE(AT_PAGESZ)
+	CASE(AT_BASE)
+	CASE(AT_FLAGS)
+	CASE(AT_ENTRY)
+	CASE(AT_NOTELF)
+	CASE(AT_UID)
+	CASE(AT_EUID)
+	CASE(AT_GID)
+	CASE(AT_EGID)
+	CASE(AT_PLATFORM)
+	CASE(AT_HWCAP)
+	CASE(AT_CLKTCK)
+	CASE(AT_SECURE)
+	CASE(AT_BASE_PLATFORM)
+	CASE(AT_RANDOM)
+#if defined(AT_HWCAP2)
+	CASE(AT_HWCAP2)
+#endif
+	CASE(AT_EXECFN)
+#if defined(AT_SYSINFO)
+	CASE(AT_SYSINFO)
+#endif
+#if defined(AT_SYSINFO_EHDR)
+	CASE(AT_SYSINFO_EHDR)
+#endif
+	default:
+		printf("unknown (%ld) = 0x%lx\n", auxv->type, auxv->value);
+		break;
+	}
+
+#undef CASE
+}
+
+extern char **environ;
+
+int main()
+{
+	long at_base_proc = 0;
+	long at_base_mem = 0;
+	struct auxv *auxv;
+	void *data = NULL;
+	size_t size = 0;
+	void **pointer;
+	int status;
+	int fd;
+
+	for (pointer = (void **) environ; *pointer != NULL; pointer++)
+		/* Nothing */;
+
+	for (auxv = (void *) ++pointer; auxv->type != AT_NULL; auxv++) {
+		if (auxv->type == AT_BASE)
+			at_base_mem = auxv->value;
+
+		print_auxv(auxv);
+	}
+
+	printf("----------------------------------------------------------------------\n");
+
+	fd = open("/proc/self/auxv", O_RDONLY);
+	if (fd < 0)
+		exit(EXIT_FAILURE);
+
+#define CHUNK_SIZE 1024
+
+	do {
+		data = realloc(data, size + CHUNK_SIZE);
+		if (data == NULL)
+			exit(EXIT_FAILURE);
+
+		status = read(fd, data + size, CHUNK_SIZE);
+		size += CHUNK_SIZE;
+	} while (status > 0);
+
+	for (auxv = data; auxv->type != AT_NULL; auxv++) {
+		if (auxv->type == AT_BASE)
+			at_base_proc = auxv->value;
+
+		print_auxv(auxv);
+	}
+
+	(void) close(fd);
+	(void) free(data);
+
+	exit((at_base_proc != 0 && at_base_mem == at_base_proc)
+	     ? EXIT_SUCCESS
+	     : EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-a4d7ed70.sh b/5.1.0/tests/test-a4d7ed70.sh
new file mode 100644
index 0000000..6008043
--- /dev/null
+++ b/5.1.0/tests/test-a4d7ed70.sh
@@ -0,0 +1,16 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ]  || [ -z `which ln` ] || [ -z `which ls` ] || [ -z `which rm` ] || [ -z `which cat` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+mkdir ${TMP}
+ln -s /proc/self/fd ${TMP}/fd
+ln -s ${TMP}/fd/0 ${TMP}/stdin
+
+${PROOT} \ls ${TMP}/stdin | grep ^${TMP}/stdin$
+
+echo OK > ${TMP2}
+${PROOT} cat ${TMP}/stdin < ${TMP2} | grep ^OK$
+
+rm -fr ${TMP} ${TMP2}
diff --git a/5.1.0/tests/test-a8e69d6f.c b/5.1.0/tests/test-a8e69d6f.c
new file mode 100644
index 0000000..3f5f96a
--- /dev/null
+++ b/5.1.0/tests/test-a8e69d6f.c
@@ -0,0 +1,24 @@
+#include <unistd.h> /* syscall(2), */
+#include <stdio.h>  /* perror(3), fprintf(3), */
+#include <stdlib.h> /* exit(3), */
+#include <sys/syscall.h> /* SYS_lstat, */
+#include <sys/stat.h>  /* struct stat, */
+
+int main(void)
+{
+	struct stat stat;
+	int status;
+
+	status = syscall(SYS_lstat, "/proc/self/cwd/", &stat);
+	if (status < 0) {
+		perror("lstat()");
+		exit(EXIT_FAILURE);
+	}
+
+	if (S_ISLNK(stat.st_mode)) {
+		fprintf(stderr, "trailing '/' ignored\n");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-aaaaaaaa.sh b/5.1.0/tests/test-aaaaaaaa.sh
new file mode 100644
index 0000000..7cbfd43
--- /dev/null
+++ b/5.1.0/tests/test-aaaaaaaa.sh
@@ -0,0 +1,63 @@
+if [ ! -x ${ROOTFS}/bin/true ] || [ -z `which id` ] || [ -z `which mcookie` ] || [ -z `which ln` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+if [ `id -u` -eq 0 ]; then
+    exit 125;
+fi
+
+DONT_EXIST=/$(mcookie)
+
+${PROOT} -r ${ROOTFS} true
+
+! ${PROOT} ${DONT_EXIST} true
+[ $? -eq 0 ]
+
+${PROOT} -r ${ROOTFS} true
+${PROOT} -r /etc -r ${ROOTFS} true
+
+! ${PROOT} -r ${ROOTFS} -r ${DONT_EXIST} true
+[ $? -eq 0 ]
+
+! ${PROOT} -r ${DONT_EXIST} ${ROOTFS} true
+[ $? -eq 0 ]
+
+! ${PROOT} ${ROOTFS} -r ${ROOTFS} true
+[ $? -eq 0 ]
+
+! ${PROOT} -v
+[ $? -eq 0 ]
+
+${PROOT} -b /bin/true:${DONT_EXIST} ${DONT_EXIST}
+
+! ${PROOT} -r / -b /etc:/ true
+[ $? -eq 0 ]
+
+! ${PROOT} -b /etc:/ true
+[ $? -eq 0 ]
+
+${PROOT} -b /etc:/ -r / true
+
+TMP1=/tmp/$(mcookie)
+TMP2=/tmp/$(mcookie)
+
+echo "${TMP1}" > ${TMP1}
+echo "${TMP2}" > ${TMP2}
+
+REGULAR=/tmp/$(mcookie)
+SYMLINK_TO_REGULAR=/tmp/$(mcookie)
+ln -s ${REGULAR} ${SYMLINK_TO_REGULAR}
+
+${PROOT} -v -1 -b ${TMP1}:${REGULAR} -b ${TMP2}:${SYMLINK_TO_REGULAR} cat ${REGULAR} | grep "^${TMP2}$"
+${PROOT} -v -1 -b ${TMP2}:${SYMLINK_TO_REGULAR} -b ${TMP1}:${REGULAR} cat ${REGULAR} | grep "^${TMP1}$"
+
+${PROOT} -v -1 -b ${TMP1}:${REGULAR} -b ${TMP2}:${SYMLINK_TO_REGULAR}! cat ${REGULAR} | grep "^${TMP1}$"
+${PROOT} -v -1 -b ${TMP1}:${REGULAR} -b ${TMP2}:${SYMLINK_TO_REGULAR}! cat ${SYMLINK_TO_REGULAR} | grep "^${TMP2}$"
+
+${PROOT} -v -1 -b ${TMP1}:${REGULAR}! -b ${TMP2}:${SYMLINK_TO_REGULAR}! cat ${REGULAR} | grep "^${TMP1}$"
+${PROOT} -v -1 -b ${TMP1}:${REGULAR}! -b ${TMP2}:${SYMLINK_TO_REGULAR}! cat ${SYMLINK_TO_REGULAR} | grep "^${TMP2}$"
+
+${PROOT} -v -1 -b ${TMP1}:${REGULAR} -b ${TMP2}:${SYMLINK_TO_REGULAR} cat ${SYMLINK_TO_REGULAR} | grep "^${TMP2}$"
+${PROOT} -v -1 -b ${TMP2}:${SYMLINK_TO_REGULAR} -b ${TMP1}:${REGULAR} cat ${SYMLINK_TO_REGULAR} | grep "^${TMP1}$"
+
+rm -fr ${TMP1} ${TMP2} ${REGULAR} $SYMLINK_TO_REGULAR}
diff --git a/5.1.0/tests/test-af062114.c b/5.1.0/tests/test-af062114.c
new file mode 100644
index 0000000..f4a4b62
--- /dev/null
+++ b/5.1.0/tests/test-af062114.c
@@ -0,0 +1,37 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+int main(void)
+{
+	int fd;
+	int status;
+	bool stop = false;
+
+	fd = open("/proc/self/cmdline", O_RDONLY);
+	if (fd < 0) {
+		perror("open()");
+		exit(EXIT_FAILURE);
+	}
+
+	do {
+		char buffer;
+		status = read(fd, &buffer, 1);
+		if (status < 0) {
+			perror("read()");
+			exit(EXIT_FAILURE);
+		}
+
+		stop = (status == 0);
+
+		status = write(1, &buffer, 1);
+		if (status < 0) {
+			perror("write()");
+			exit(EXIT_FAILURE);
+		}
+	} while (!stop);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-b161bc0a.sh b/5.1.0/tests/test-b161bc0a.sh
new file mode 100644
index 0000000..9f9bc90
--- /dev/null
+++ b/5.1.0/tests/test-b161bc0a.sh
@@ -0,0 +1,6 @@
+if [ -z `which pwd` ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+${PROOT} -w /tmp/a -m /etc:/tmp/a pwd | grep '^/tmp/a$'
+
diff --git a/5.1.0/tests/test-b6df3cbe.sh b/5.1.0/tests/test-b6df3cbe.sh
new file mode 100644
index 0000000..3020e5e
--- /dev/null
+++ b/5.1.0/tests/test-b6df3cbe.sh
@@ -0,0 +1,16 @@
+if [ -z `which mcookie` ] ||  [ -z `which cat` ] || [ -z `which tr` ] || [ -z `which grep` ] || [ -z `which grep` ] || [ -z `which chmod` ]; then
+    exit 125;
+fi
+
+TMP=$(mcookie)
+
+cat > /tmp/${TMP} <<EOF
+#!/bin/sh
+
+cat /proc/\$$/cmdline
+EOF
+
+chmod +x /tmp/${TMP}
+(cd /tmp; ${PROOT} sh -c "./${TMP}") | tr '\000' ' ' | grep "^/bin/sh ./${TMP} $"
+
+rm /tmp/${TMP}
diff --git a/5.1.0/tests/test-b94dd86a.sh b/5.1.0/tests/test-b94dd86a.sh
new file mode 100644
index 0000000..65e8743
--- /dev/null
+++ b/5.1.0/tests/test-b94dd86a.sh
@@ -0,0 +1,6 @@
+if [ ! -x  ${ROOTFS}/bin/true ]; then
+    exit 125;
+fi
+
+${PROOT} -w /bin -r ${ROOTFS} ./true
+
diff --git a/5.1.0/tests/test-bbbbbbbb.sh b/5.1.0/tests/test-bbbbbbbb.sh
new file mode 100644
index 0000000..0591eb9
--- /dev/null
+++ b/5.1.0/tests/test-bbbbbbbb.sh
@@ -0,0 +1,24 @@
+if [ -z `which mcookie` ] || [ -z `which rm` ] || [ -z `which ln` ]; then
+    exit 125;
+fi
+
+DONT_EXIST=$(mcookie)
+TMP1=$(mcookie)
+TMP2=$(mcookie)
+
+rm -f /tmp/${DONT_EXIST}
+${PROOT} ln -sf /${DONT_EXIST} /tmp/
+${PROOT} ln -sf /${DONT_EXIST} /tmp/
+
+rm -f /tmp/${DONT_EXIST}
+  ${PROOT} ln -sf /etc/fstab/${DONT_EXIST} /tmp/
+! ${PROOT} ln -sf /etc/fstab/${DONT_EXIST} /tmp/
+
+rm -f /tmp/${DONT_EXIST}
+rm -f /tmp/${TMP1} /tmp/${TMP2}
+touch /tmp/${TMP2}
+ln -sf /tmp/${DONT_EXIST} /tmp/${TMP1}
+! ${PROOT} ln /tmp/${TMP2} /tmp/${TMP1}
+
+rm -f /tmp/${TMP1} /tmp/${TMP2}
+rm -f /tmp/${DONT_EXIST}
diff --git a/5.1.0/tests/test-bdc90417.c b/5.1.0/tests/test-bdc90417.c
new file mode 100644
index 0000000..fa02349
--- /dev/null
+++ b/5.1.0/tests/test-bdc90417.c
@@ -0,0 +1,34 @@
+#define _GNU_SOURCE       /* See feature_test_macros(7) */
+#include <unistd.h>       /* execv(3), syscall(2), */
+#include <sys/syscall.h>  /* SYS_*, */
+#include <sys/time.h>     /* *rlimit(2), */
+#include <sys/resource.h> /* *rlimit(2), */
+#include <stdlib.h>       /* EXIT_*, exit(3), */
+
+int main(int argc, char *argv[])
+{
+	char *const dummy_argv[] = { "test", "stage2", NULL };
+	long brk1, brk2;
+	int status;
+	struct rlimit rlimit;
+
+	switch (argc) {
+	case 1: /* 1st step: set the stack limit to the max.  */
+		status = getrlimit(RLIMIT_STACK, &rlimit);
+		if (status < 0)
+			exit(EXIT_FAILURE);
+
+		rlimit.rlim_cur = rlimit.rlim_max;
+
+		status = setrlimit(RLIMIT_STACK, &rlimit);
+		if (status < 0)
+			exit(EXIT_FAILURE);
+
+		return execv(argv[0], dummy_argv);
+
+	default: /* 2nd step: try to allocate some heap space.  */
+		brk1 = syscall(SYS_brk, 0);
+		brk2 = syscall(SYS_brk, brk1 + 1024 * 1024);
+		exit(brk1 != brk2 ? EXIT_SUCCESS : EXIT_FAILURE);
+	}
+}
diff --git a/5.1.0/tests/test-c10e2073.c b/5.1.0/tests/test-c10e2073.c
new file mode 100644
index 0000000..83c4821
--- /dev/null
+++ b/5.1.0/tests/test-c10e2073.c
@@ -0,0 +1,37 @@
+#include <unistd.h> /* syscall(2), */
+#include <stdio.h>  /* perror(3), fprintf(3), */
+#include <limits.h> /* PATH_MAX, */
+#include <stdlib.h> /* exit(3), */
+#include <string.h> /* strlen(3), */
+#include <sys/syscall.h> /* SYS_readlink, SYS_getcwd, */
+
+int main(void)
+{
+	char path[PATH_MAX];
+	int status;
+
+	status = syscall(SYS_readlink, "/proc/self/cwd", path, PATH_MAX);
+	if (status < 0) {
+		perror("readlink()");
+		exit(EXIT_FAILURE);
+	}
+	path[status] = '\0';
+
+	if (status != strlen(path)) {
+		fprintf(stderr, "readlink() returned the wrong size %d != %z.\n", status, strlen(path));
+		exit(EXIT_FAILURE);
+	}
+
+	status = syscall(SYS_getcwd, path, PATH_MAX);
+	if (status < 0) {
+		perror("getcwd()");
+		exit(EXIT_FAILURE);
+	}
+
+	if (status != strlen(path) + 1) {
+		fprintf(stderr, "getcwd() returned the wrong size %d != %z.\n", status, strlen(path));
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-c15999f9.sh b/5.1.0/tests/test-c15999f9.sh
new file mode 100644
index 0000000..9c25b13
--- /dev/null
+++ b/5.1.0/tests/test-c15999f9.sh
@@ -0,0 +1,12 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which test` ] || [ -z `which grep` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+mkdir ${TMP}
+
+${PROOT} -b /bin/true:${TMP}/true /bin/true
+! test -e ${TMP}/true
+[ $? -eq 0 ]
+
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-c47aeb7d.c b/5.1.0/tests/test-c47aeb7d.c
new file mode 100644
index 0000000..255c9ac
--- /dev/null
+++ b/5.1.0/tests/test-c47aeb7d.c
@@ -0,0 +1,33 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void *print_hello(void *id)
+{
+	pthread_exit(id);
+}
+
+int main(void)
+{
+	const int nb_threads = 10;
+	pthread_t threads[nb_threads];
+	int status;
+	long i;
+
+	for(i = 0; i < nb_threads; i++) {
+		status = pthread_create(&threads[i], NULL, print_hello, (void *) i);
+		if (status != 0)
+			exit(EXIT_FAILURE);
+	}
+
+	for(i = 0; i < nb_threads; i++) {
+		intptr_t result;
+
+		status = pthread_join(threads[i], (void **) &result);
+		if (status != 0 || (int) result != i)
+			exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-c5a7a0f0.c b/5.1.0/tests/test-c5a7a0f0.c
new file mode 100644
index 0000000..652c0e6
--- /dev/null
+++ b/5.1.0/tests/test-c5a7a0f0.c
@@ -0,0 +1,93 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+static void *setuid_124(void *unused)
+{
+	int status;
+
+	status = setuid(124);
+	if (status < 0) {
+		perror("setuid");
+		pthread_exit((void *)-1);
+	}
+
+	if (getuid() != 124) {
+		perror("getuid");
+		pthread_exit((void *)-1);
+	}
+
+	pthread_exit(NULL);
+}
+
+static void pterror(const char *message, int error)
+{
+	fprintf(stderr, "%s: %s\n", message, strerror(error));
+}
+
+int main(void)
+{
+	pthread_t thread;
+	int child_status;
+	void *result;
+	int status;
+
+	switch(fork()) {
+	case -1:
+		perror("fork");
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		status = setuid(123);
+		if (status < 0) {
+			perror("setuid");
+			exit(EXIT_FAILURE);
+		}
+
+		if (getuid() != 123) {
+			perror("getuid");
+			exit(EXIT_FAILURE);
+		}
+		exit(EXIT_SUCCESS);
+
+	default: /* parent */
+		break;
+	}
+
+	status = wait(&child_status);
+	if (status < 0 || child_status != 0) {
+		perror("wait()");
+		exit(EXIT_FAILURE);
+	}
+
+	if (getuid() != 0) {
+		fprintf(stderr, "getuid() == %d != 0\n", getuid());
+		exit(EXIT_FAILURE);
+	}
+
+	status = pthread_create(&thread, NULL, setuid_124, NULL);
+	if (status != 0) {
+		pterror("pthread_create", status);
+		exit(EXIT_FAILURE);
+	}
+
+	status = pthread_join(thread, &result);
+	if (status != 0) {
+		pterror("pthread_create", status);
+		exit(EXIT_FAILURE);
+	}
+
+	if (result != NULL) {
+		fprintf(stderr, "result != NULL\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (getuid() != 124) {
+		fprintf(stderr, "getuid() == %d != 124\n", getuid());
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-c68d18dc.sh b/5.1.0/tests/test-c68d18dc.sh
new file mode 100644
index 0000000..6c1727c
--- /dev/null
+++ b/5.1.0/tests/test-c68d18dc.sh
@@ -0,0 +1,29 @@
+if [ -z `which mkdir` ] || [ -z `which rm` ] || [ -z `which mcookie` ] || [ -z `which chmod` ] || [ -z `which ln` ]; then
+    exit 125;
+fi
+
+if [ ! -e $CARE ]; then
+    exit 125;
+fi
+unset PROOT
+
+SYMLINK=/tmp/$(mcookie)
+FOLDER=/tmp/$(mcookie)
+SCRIPT=${FOLDER}/script.sh
+ARCHIVE=/tmp/$(mcookie)/
+
+mkdir ${FOLDER}
+
+echo "true" > ${SCRIPT}
+chmod +x ${SCRIPT}
+
+ln -s ${FOLDER} ${SYMLINK}
+
+cd ${SYMLINK}
+${CARE} -r ${FOLDER} -o ${ARCHIVE} sh ./script.sh
+
+test -e ${ARCHIVE}/rootfs${SCRIPT}
+
+${ARCHIVE}/re-execute.sh
+
+rm -fr ${SYMLINK} ${FOLDER} ${ARCHIVE}
diff --git a/5.1.0/tests/test-c6b77b77.mk b/5.1.0/tests/test-c6b77b77.mk
new file mode 100644
index 0000000..ebdd56e
--- /dev/null
+++ b/5.1.0/tests/test-c6b77b77.mk
@@ -0,0 +1,5 @@
+SHELL=/bin/bash
+FOO:=$(shell test -e /dev/null && echo OK)
+
+all:
+	@/usr/bin/test -n "$(FOO)"
diff --git a/5.1.0/tests/test-c6b77b77.sh b/5.1.0/tests/test-c6b77b77.sh
new file mode 100644
index 0000000..8d9797c
--- /dev/null
+++ b/5.1.0/tests/test-c6b77b77.sh
@@ -0,0 +1,5 @@
+if [ -z `which make` ]; then
+    exit 125;
+fi
+
+${PROOT} make -f ${PWD}/test-c6b77b77.mk
diff --git a/5.1.0/tests/test-careauth.sh b/5.1.0/tests/test-careauth.sh
new file mode 100644
index 0000000..dd4f986
--- /dev/null
+++ b/5.1.0/tests/test-careauth.sh
@@ -0,0 +1,26 @@
+if [ -z `which env` ] || [ -z `which rm` ] || [ -z `which mcookie` ] || [ -z `which true` ]; then
+    exit 125;
+fi
+
+if [ ! -e $CARE ]; then
+    exit 125;
+fi
+unset PROOT
+
+TMP=$(mcookie)
+
+cd /tmp
+env ICEAUTHORITY= ${CARE} -o ${TMP} true
+${CARE} -x ./${TMP}
+./${TMP}/re-execute.sh
+rm -fr ${TMP}
+
+env XAUTHORITY= ${CARE} -o ${TMP} true
+${CARE} -x ./${TMP}
+./${TMP}/re-execute.sh
+rm -fr ${TMP}
+
+${CARE} -o ${TMP} -p ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../ true
+${CARE} -x ./${TMP}
+./${TMP}/re-execute.sh
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-careexit.sh b/5.1.0/tests/test-careexit.sh
new file mode 100644
index 0000000..ff1b543
--- /dev/null
+++ b/5.1.0/tests/test-careexit.sh
@@ -0,0 +1,25 @@
+if [ -z `which cpio` ] || [ -z `which rm` ] || [ -z `which mcookie` ]; then
+    exit 125;
+fi
+
+if [ ! -e $CARE ]; then
+    exit 125;
+fi
+unset PROOT
+
+TMP=/tmp/$(mcookie)
+
+${CARE} -o ${TMP}.cpio sh -c 'exit 0'
+
+cd /tmp
+cpio -idmuvF ${TMP}.cpio
+
+${TMP}/re-execute.sh
+
+set +e
+${TMP}/re-execute.sh sh -c 'exit 132'
+status=$?
+set -e
+[ $status -eq 132 ]
+
+rm -f ${TMP}.cpio
diff --git a/5.1.0/tests/test-carehwcp.sh b/5.1.0/tests/test-carehwcp.sh
new file mode 100644
index 0000000..926970a
--- /dev/null
+++ b/5.1.0/tests/test-carehwcp.sh
@@ -0,0 +1,15 @@
+if [ ! -x /bin/true ] || [ -z `which grep` ] || [ -z `which env` ] || [ -z `which mcookie`]  || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+if [ ! -e $CARE ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+${CARE} -o ${TMP}/ env LD_SHOW_AUXV=1 true   | grep '^AT_HWCAP:[[:space:]]*0$'
+${TMP}/re-execute.sh                         | grep '^AT_HWCAP:[[:space:]]*0$'
+${TMP}/re-execute.sh env LD_SHOW_AUXV=1 true | grep '^AT_HWCAP:[[:space:]]*0$'
+
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-carequot.sh b/5.1.0/tests/test-carequot.sh
new file mode 100644
index 0000000..da764b4
--- /dev/null
+++ b/5.1.0/tests/test-carequot.sh
@@ -0,0 +1,18 @@
+if [ -z `which env` ] || [ -z `which rm` ] || [ -z `which mcookie` ] || [ -z `which true` ]; then
+    exit 125;
+fi
+
+if [ ! -e $CARE ]; then
+    exit 125;
+fi
+unset PROOT
+
+TMP=/tmp/$(mcookie)
+
+env 'COMP_WORDBREAKS= 	
+"'\''><;|&(:' ${CARE} -o ${TMP}.raw true
+
+cd /tmp; ${CARE} -x ${TMP}.raw
+${TMP}/re-execute.sh
+
+rm -fr ${TMP}.raw ${TMP}
diff --git a/5.1.0/tests/test-cb1143ab.sh b/5.1.0/tests/test-cb1143ab.sh
new file mode 100644
index 0000000..60da868
--- /dev/null
+++ b/5.1.0/tests/test-cb1143ab.sh
@@ -0,0 +1,58 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ] ||  [ -z `which ln` ] ||  [ -z `which ls` ]; then
+    exit 125;
+fi
+
+D1=`mcookie`
+D2=`mcookie`
+LINK=`mcookie`
+F=`mcookie`
+TMP=/tmp/${D1}/${D2}
+
+mkdir -p ${TMP}
+ln -s ${TMP}/./. ${TMP}/${LINK}
+
+${PROOT} \ls ${TMP}/${LINK} | grep ^${LINK}$
+${PROOT} \ls ${TMP}/${LINK}/ | grep ^${LINK}$
+${PROOT} \ls ${TMP}/${LINK}/. | grep ^${LINK}$
+${PROOT} \ls ${TMP}/${LINK}/.. | grep ^${D2}$
+${PROOT} \ls ${TMP}/${LINK}/./.. | grep ^${D2}$
+
+rm ${TMP}/${LINK}
+touch ${TMP}/${F}
+ln -s ${TMP}/${F} ${TMP}/${LINK}
+
+${PROOT} \ls ${TMP}/${LINK}
+! ${PROOT} \ls ${TMP}/${LINK}/
+[ $? -eq 0 ]
+
+! ${PROOT} \ls ${TMP}/${LINK}/.
+[ $? -eq 0 ]
+
+! ${PROOT} \ls ${TMP}/${LINK}/..
+[ $? -eq 0 ]
+
+! ${PROOT} \ls ${TMP}/${LINK}/./..
+[ $? -eq 0 ]
+
+! ${PROOT} \ls ${TMP}/${LINK}/../..
+[ $? -eq 0 ]
+
+${PROOT} -b /tmp/${D1}:${TMP}/${F} \ls ${TMP}/${LINK}
+${PROOT} -b /tmp/${D1}:${TMP}/${F} \ls ${TMP}/${LINK}/
+${PROOT} -b /tmp/${D1}:${TMP}/${F} \ls ${TMP}/${LINK}/.
+${PROOT} -b /tmp/${D1}:${TMP}/${F} \ls ${TMP}/${LINK}/..
+
+rm ${TMP}/${LINK}
+ln -s ${TMP}/${D1} ${TMP}/${LINK}
+
+${PROOT} -b /tmp/${F}:${TMP}/${D1} \ls ${TMP}/${LINK}
+! ${PROOT} -b /tmp/${F}:${TMP}/${D1} \ls ${TMP}/${LINK}/
+[ $? -eq 0 ]
+
+! ${PROOT} -b /tmp/${F}:${TMP}/${D1} \ls ${TMP}/${LINK}/.
+[ $? -eq 0 ]
+
+! ${PROOT} -b /tmp/${F}:${TMP}/${D1} \ls ${TMP}/${LINK}/..
+[ $? -eq 0 ]
+
+rm -fr /tmp/${D1}
diff --git a/5.1.0/tests/test-cccccccc.sh b/5.1.0/tests/test-cccccccc.sh
new file mode 100644
index 0000000..c528312
--- /dev/null
+++ b/5.1.0/tests/test-cccccccc.sh
@@ -0,0 +1,14 @@
+if [ -z `which mcookie` ] || [ -z `which rmdir` ] || [ -z `which mkdir` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+mkdir ${TMP}
+
+! ${PROOT} rmdir ${TMP}/.
+[ $? -eq 0 ]
+
+! ${PROOT} rmdir ${TMP}/./
+[ $? -eq 0 ]
+
+${PROOT} rmdir ${TMP}
diff --git a/5.1.0/tests/test-cdd39012.sh b/5.1.0/tests/test-cdd39012.sh
new file mode 100644
index 0000000..1e86c5c
--- /dev/null
+++ b/5.1.0/tests/test-cdd39012.sh
@@ -0,0 +1,11 @@
+if [ ! -x  ${ROOTFS}/bin/ptrace ] || [ ! -x  ${ROOTFS}/bin/ptrace-2 ] || [ ! -x  ${ROOTFS}/bin/true ]; then
+    exit 125;
+fi
+
+${PROOT} -r ${ROOTFS} ptrace
+${PROOT} -r ${ROOTFS} ptrace 2
+
+${PROOT} -r ${ROOTFS} ptrace-2 /bin/true
+
+${PROOT} -r ${ROOTFS} ptrace-2 /bin/fork-wait
+${PROOT} -r ${ROOTFS} ptrace-2 /bin/fork-wait 2
diff --git a/5.1.0/tests/test-cea75343.sh b/5.1.0/tests/test-cea75343.sh
new file mode 100644
index 0000000..0fb5b91
--- /dev/null
+++ b/5.1.0/tests/test-cea75343.sh
@@ -0,0 +1,40 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which cat` ] || [ -z `which grep` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP1=/tmp/`mcookie`
+TMP2=/tmp/`mcookie`
+TMP3=/tmp/`mcookie`
+
+# /a/b/c
+# /a/b
+# /a/d
+# /a
+
+echo 'binding 1' > ${TMP1}
+echo 'binding 2' > ${TMP2}
+
+mkdir -p ${TMP3}/a/b
+
+BINDINGS="-b ${TMP1}:${TMP3}/a/b/c -b ${TMP3}/a/b -b ${TMP2}:${TMP3}/a/d -b ${TMP3}/a"
+${PROOT} ${BINDINGS} cat ${TMP3}/a/b/c | grep '^binding 1$'
+
+BINDINGS="-b ${TMP3}/a -b ${TMP2}:${TMP3}/a/d -b ${TMP3}/a/b -b ${TMP1}:${TMP3}/a/b/c"
+${PROOT} ${BINDINGS} cat ${TMP3}/a/d   | grep '^binding 2$'
+
+mkdir -p ${TMP3}/c/b
+
+# /c/b/a
+# /c/b
+# /c/d
+# /c
+
+BINDINGS="-b ${TMP1}:${TMP3}/c/b/a -b ${TMP3}/c/b -b ${TMP2}:${TMP3}/c/d -b ${TMP3}/c"
+${PROOT} ${BINDINGS} cat ${TMP3}/c/b/a | grep '^binding 1$'
+
+BINDINGS="-b ${TMP3}/c -b ${TMP2}:${TMP3}/c/d -b ${TMP3}/c/b -b ${TMP1}:${TMP3}/c/b/a"
+${PROOT} ${BINDINGS} cat ${TMP3}/c/d | grep '^binding 2$'
+
+rm ${TMP1}
+rm ${TMP2}
+rm -fr ${TMP3}
diff --git a/5.1.0/tests/test-commmmmm.sh b/5.1.0/tests/test-commmmmm.sh
new file mode 100644
index 0000000..9bae7f3
--- /dev/null
+++ b/5.1.0/tests/test-commmmmm.sh
@@ -0,0 +1,25 @@
+if [ -z `which mcookie` ] || [ -z `which cat` ] || [ -z `which grep` ] || [ -z `which chmod` ] || [ -z `which cut` ] || [ -z `which rm` ] || [ -z `which ln` ] || [ -z `which env` ]; then
+    exit 125;
+fi
+
+TMP=$(mcookie)
+TMP2=$(echo ${TMP} | cut -b 1-15)
+TMP3=$(mcookie)
+TMP4=$(echo ${TMP3} | cut -b 1-15)
+
+${PROOT} cat /proc/self/comm          | grep cat
+${PROOT} $(which cat) /proc/self/comm | grep cat
+
+echo '#!/bin/sh' > /tmp/${TMP}
+chmod +x /tmp/${TMP}
+
+# TODO: (cd /tmp; ${PROOT} env LD_SHOW_AUXV=1 ./${TMP}) | grep ^AT_EXECFN:[[:space:]]*./${TMP}$
+
+echo 'cat /proc/$$/comm' >> /tmp/${TMP}
+
+${PROOT} /tmp/${TMP} | grep ^${TMP2}$
+
+ln -s /tmp/${TMP} /tmp/${TMP3}
+${PROOT} /tmp/${TMP3} /proc/self/comm | grep ^${TMP4}$
+
+rm -f /tmp/${TMP} /tmp/${TMP3}
diff --git a/5.1.0/tests/test-d1be631a.sh b/5.1.0/tests/test-d1be631a.sh
new file mode 100644
index 0000000..c3cb425
--- /dev/null
+++ b/5.1.0/tests/test-d1be631a.sh
@@ -0,0 +1,13 @@
+if [ -z `which mknod`] || [ `id -u` -eq 0 ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+! ${PROOT} mknod ${TMP} b 1 1
+[ $? -eq 0 ]
+
+! ${PROOT} -i 123:456 mknod ${TMP} b 1 1
+[ $? -eq 0 ]
+
+${PROOT} -0 mknod ${TMP} b 1 1
diff --git a/5.1.0/tests/test-d1da0d8d.sh b/5.1.0/tests/test-d1da0d8d.sh
new file mode 100644
index 0000000..8dd6931
--- /dev/null
+++ b/5.1.0/tests/test-d1da0d8d.sh
@@ -0,0 +1,6 @@
+if [ ! -x  ${ROOTFS}/bin/readlink ] || [ ! -e /proc/self/cwd ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+${PROOT} -m /proc -m /tmp:/asym -w /asym -r ${ROOTFS} /bin/readlink /proc/self/cwd | grep '^/asym$'
+${PROOT} -m /proc -m /tmp:/asym -w /tmp  -r ${ROOTFS} /bin/readlink /proc/self/cwd | grep '^/tmp$'
diff --git a/5.1.0/tests/test-d2175fc3.sh b/5.1.0/tests/test-d2175fc3.sh
new file mode 100644
index 0000000..d43b266
--- /dev/null
+++ b/5.1.0/tests/test-d2175fc3.sh
@@ -0,0 +1,9 @@
+if [ ! -x  ${ROOTFS}/bin/readlink ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+${PROOT} -r ${ROOTFS} /bin/readlink /bin/abs-true | grep '^/bin/true$'
+${PROOT} -r ${ROOTFS} /bin/readlink /bin/rel-true | grep '^\./true$'
+
+${PROOT} -b /:/host-rootfs -r ${ROOTFS} /bin/readlink /bin/abs-true | grep '^/bin/true$'
+${PROOT} -b /:/host-rootfs -r ${ROOTFS} /bin/readlink /bin/rel-true | grep '^./true$'
diff --git a/5.1.0/tests/test-d2175fc4.c b/5.1.0/tests/test-d2175fc4.c
new file mode 100644
index 0000000..07e1d8b
--- /dev/null
+++ b/5.1.0/tests/test-d2175fc4.c
@@ -0,0 +1,31 @@
+#include <unistd.h> /* syscall(2), */
+#include <stdio.h>  /* perror(3), fprintf(3), */
+#include <limits.h> /* PATH_MAX, */
+#include <stdlib.h> /* exit(3), */
+#include <strings.h> /* bzero(3), */
+#include <sys/syscall.h> /* SYS_readlink, */
+
+int main(int argc, char *argv[])
+{
+	char path[PATH_MAX];
+	int status;
+
+	bzero(path, sizeof(path));
+
+	status = syscall(SYS_readlink, "/proc/self/exe", path, PATH_MAX);
+	if (status < 0) {
+		perror("readlink()");
+		exit(EXIT_FAILURE);
+	}
+
+	if (status >= PATH_MAX)
+		return 125;
+
+	if (path[status] != '\0') {
+		path[PATH_MAX - 1] = '\0';
+		puts(path);
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-d92b57ca.sh b/5.1.0/tests/test-d92b57ca.sh
new file mode 100644
index 0000000..ddb108a
--- /dev/null
+++ b/5.1.0/tests/test-d92b57ca.sh
@@ -0,0 +1,5 @@
+if [ -z `which env` ] || [ -z `which true` ]; then
+    exit 125;
+fi
+
+env PROOT_NO_SUBRECONF=1 ${PROOT} ${PROOT} -v 1 true
diff --git a/5.1.0/tests/test-dddddddd.sh b/5.1.0/tests/test-dddddddd.sh
new file mode 100644
index 0000000..122cc50
--- /dev/null
+++ b/5.1.0/tests/test-dddddddd.sh
@@ -0,0 +1,36 @@
+if [ -z `which mcookie` ] || [ -z `which rm` ] || [ -z `which ln` ] || [ -z `which realpath` ] || [ -z `which mkdir` ] || [ -z `which rmdir` ]; then
+    exit 125;
+fi
+
+CHECK1=$(realpath -e /proc/self/exe)
+CHECK2=$(realpath /proc/self/exe)
+
+if [ "${CHECK1}" != "${CHECK2}" ]; then
+    exit 125;
+fi
+
+TMP="/tmp/$(mcookie)"
+TMP2="/tmp/$(mcookie)"
+
+RMDIR=$(realpath -e $(which rmdir))
+MKDIR=$(realpath -e $(which mkdir))
+
+export LANG=C
+
+ln -s /bin ${TMP}
+! ${RMDIR} ${TMP} > ${TMP}.ref 2>&1
+! ${PROOT} -v -1 ${RMDIR} ${TMP} > ${TMP}.res 2>&1
+cmp ${TMP}.ref ${TMP}.res
+
+ln -s /this/does/not/exist ${TMP2}
+! ${MKDIR} ${TMP2} > ${TMP2}.ref 2>&1
+! ${PROOT} -v -1 ${MKDIR} ${TMP2} > ${TMP2}.res 2>&1
+cmp ${TMP2}.ref ${TMP2}.res
+
+rm -f ${TMP}
+rm -f ${TMP}.ref
+rm -f ${TMP}.res
+
+rm -f ${TMP2}
+rm -f ${TMP2}.ref
+rm -f ${TMP2}.res
diff --git a/5.1.0/tests/test-de756935.sh b/5.1.0/tests/test-de756935.sh
new file mode 100644
index 0000000..8cafa40
--- /dev/null
+++ b/5.1.0/tests/test-de756935.sh
@@ -0,0 +1,12 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which bash` ] || [ -z `which grep` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+mkdir -p ${TMP}
+cd ${TMP}
+
+${PROOT} -b ${PWD}:/foo -w /foo bash -c 'pwd' | grep '^/foo$'
+
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-df4de4db.sh b/5.1.0/tests/test-df4de4db.sh
new file mode 100644
index 0000000..8b362fe
--- /dev/null
+++ b/5.1.0/tests/test-df4de4db.sh
@@ -0,0 +1,10 @@
+if [ ! -x  ${ROOTFS}/bin/fork-wait ] || [ -z `which strace` ]; then
+    exit 125;
+fi
+
+${PROOT} strace ${ROOTFS}/bin/fork-wait
+${PROOT} strace ${ROOTFS}/bin/fork-wait 2
+
+${PROOT} strace -f ${ROOTFS}/bin/fork-wait
+${PROOT} strace -f ${ROOTFS}/bin/fork-wait 2
+
diff --git a/5.1.0/tests/test-dfb0c3b6.sh b/5.1.0/tests/test-dfb0c3b6.sh
new file mode 100644
index 0000000..e0013e0
--- /dev/null
+++ b/5.1.0/tests/test-dfb0c3b6.sh
@@ -0,0 +1,27 @@
+if [ -z `which sh` ] || [ -z `which readlink` ] || [ -z `which grep` ] || [ -z `which echo` ]  || [ -z `which mcookie` ] || [ ! -e /proc/self/fd/0 ]; then
+    exit 125;
+fi
+
+${PROOT} readlink /proc/self | grep -E "^[[:digit:]]+$"
+
+! ${PROOT} readlink /proc/self/..
+[ $? -eq 0 ]
+
+${PROOT} readlink /proc/self/../self | grep -E "^[[:digit:]]+$"
+
+${PROOT} sh -c 'echo "OK" | readlink /proc/self/fd/0' | grep -E "^pipe:\[[[:digit:]]+\]$"
+
+! ${PROOT} sh -c 'echo "OK" | readlink /proc/self/fd/0/'
+[ $? -eq 0 ]
+
+! ${PROOT} sh -c 'echo "OK" | readlink /proc/self/fd/0/..'
+[ $? -eq 0 ]
+
+! ${PROOT} sh -c 'echo "OK" | readlink /proc/self/fd/0/../0'
+[ $? -eq 0 ]
+
+${PROOT} sh -c 'echo "echo OK" | sh /proc/self/fd/0' | grep ^OK$
+
+TMP=/tmp/$(mcookie)
+${PROOT} sh -c "exec 6<>${TMP}; readlink /proc/self/fd/6" | grep ^${TMP}
+rm -f ${TMP}
diff --git a/5.1.0/tests/test-e87b34ae.c b/5.1.0/tests/test-e87b34ae.c
new file mode 100644
index 0000000..d99c029
--- /dev/null
+++ b/5.1.0/tests/test-e87b34ae.c
@@ -0,0 +1,34 @@
+#include <unistd.h> /* syscall(2), fork(2), usleep(3), */
+#include <stdio.h>  /* perror(3), printf(3), */
+#include <limits.h> /* PATH_MAX, */
+#include <stdlib.h> /* exit(3), */
+#include <sys/syscall.h> /* SYS_readlink, SYS_getcwd, */
+#include <errno.h> /* errno, */
+
+int main(void)
+{
+	pid_t pid;
+	int status;
+	int i;
+
+	for (i = 0; i < 1000; i++) {
+		pid = fork();
+		switch (pid) {
+		case -1:
+			/* Is the maximum number of processes
+			 * reached?  */
+			if (errno == EAGAIN)
+				break;
+			perror("fork()");
+			exit(EXIT_FAILURE);
+
+		case 0: /* child */
+			exit(EXIT_SUCCESS);
+
+		default: /* parent */
+			break;
+		}
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-e87ca6ca.sh b/5.1.0/tests/test-e87ca6ca.sh
new file mode 100644
index 0000000..0056d2e
--- /dev/null
+++ b/5.1.0/tests/test-e87ca6ca.sh
@@ -0,0 +1,18 @@
+if [ -z `which mcookie` ] || [ -z `which cp` ] || [ -z `which true` ] || [ -z `which setcap` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+if [ `id -u` -eq 0 ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+
+cp $(which true) ${TMP}
+
+! ${PROOT} -i 123:456 setcap cap_setuid+ep ${TMP}
+[ $? -eq 0 ]
+
+${PROOT} -0 setcap cap_setuid+ep ${TMP}
+
+rm -f ${TMP}
diff --git a/5.1.0/tests/test-e940896f.sh b/5.1.0/tests/test-e940896f.sh
new file mode 100644
index 0000000..fbc07a1
--- /dev/null
+++ b/5.1.0/tests/test-e940896f.sh
@@ -0,0 +1,22 @@
+if [ ! -x ${ROOTFS}/bin/readdir ] || [ -z `which mcookie` ] || [ -z `which rm` ]  || [ -z `which mkdir` ] || [ -z `which chmod` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP1=/tmp/$(mcookie)
+TMP2=${TMP1}/$(mcookie)/$(mcookie)
+
+rm -fr ${TMP1}
+rm -fr ${ROOTFS}/${TMP1}
+
+mkdir -p ${TMP2}
+mkdir -p ${ROOTFS}/${TMP1}
+chmod -w ${ROOTFS}/${TMP1}
+
+cd ${TMP2}
+${PROOT} -r ${ROOTFS} -b . readdir ${TMP1}
+${PROOT} -r ${ROOTFS} -b . readdir ${TMP2}
+${PROOT} -r ${ROOTFS} -b . readdir ${TMP2}/..
+${PROOT} -r ${ROOTFS} -b . readdir ${TMP2}/../..
+
+rm -fr ${TMP1}
+rm -fr ${ROOTFS}/${TMP1}
diff --git a/5.1.0/tests/test-e99993c8.sh b/5.1.0/tests/test-e99993c8.sh
new file mode 100644
index 0000000..91cd8b9
--- /dev/null
+++ b/5.1.0/tests/test-e99993c8.sh
@@ -0,0 +1,8 @@
+if [ -z `which uname` ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+LONG_RELEASE=0123456789012345678901234567890123456789012345678901234567890123456789
+
+${PROOT} -k 3.33.333 uname -r | grep ^3.33.333$
+${PROOT} -k ${LONG_RELEASE} uname -r | grep ^0123456789012345678901234567890123456789012345678901234567890123$
diff --git a/5.1.0/tests/test-eddeba0e.sh b/5.1.0/tests/test-eddeba0e.sh
new file mode 100644
index 0000000..f3bf1e3
--- /dev/null
+++ b/5.1.0/tests/test-eddeba0e.sh
@@ -0,0 +1,5 @@
+if ! `which pwd` -P || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+${PROOT} pwd -P | grep "^$PWD$"
diff --git a/5.1.0/tests/test-f7089d4f.sh b/5.1.0/tests/test-f7089d4f.sh
new file mode 100644
index 0000000..d90c88e
--- /dev/null
+++ b/5.1.0/tests/test-f7089d4f.sh
@@ -0,0 +1,5 @@
+if [ -z `which timeout` ] || [ -z `which msgmerge` ] || [ ! -e /dev/null ]; then
+    exit 125;
+fi
+
+timeout 5s ${PROOT} msgmerge -q /dev/null /dev/null
diff --git a/5.1.0/tests/test-fa205b56.c b/5.1.0/tests/test-fa205b56.c
new file mode 100644
index 0000000..94c814d
--- /dev/null
+++ b/5.1.0/tests/test-fa205b56.c
@@ -0,0 +1,37 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define NUM_THREADS 5
+
+void *exec(void *id)
+{
+	char *const argv[] = { "true", NULL };
+
+	if ((long) id == NUM_THREADS - 1)
+		execve("/usr/bin/true", argv, NULL);
+	else
+		sleep(50);
+
+	pthread_exit(NULL);
+}
+
+int main()
+{
+	pthread_t threads[NUM_THREADS];
+	int status;
+	long i;
+
+	exit(125); /* NYI */
+
+	for(i = 0; i < NUM_THREADS ; i++) {
+		status = pthread_create(&threads[i], NULL, exec, (void *) i);
+		if (status)
+			exit(EXIT_FAILURE);
+		sleep(1);
+	}
+
+	sleep(50);
+	exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-fbca9cc2.sh b/5.1.0/tests/test-fbca9cc2.sh
new file mode 100644
index 0000000..a35b550
--- /dev/null
+++ b/5.1.0/tests/test-fbca9cc2.sh
@@ -0,0 +1,8 @@
+if [ -z `which strace` ] ||  [ -z `which true` ] || [ -z `which grep` ] || [ -z `which wc` ]; then
+    exit 125;
+fi
+
+${PROOT} strace -e trace=execve true 2>&1 | grep '^execve.*= 0$'
+
+RESULT=$(${PROOT} strace -e trace=execve true 2>&1 | grep '^execve' | wc -l)
+test "${RESULT}" = "1"
diff --git a/5.1.0/tests/test-fdf487a0.c b/5.1.0/tests/test-fdf487a0.c
new file mode 100644
index 0000000..964158b
--- /dev/null
+++ b/5.1.0/tests/test-fdf487a0.c
@@ -0,0 +1,31 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main()
+{
+	int fd;
+
+	fd = openat(0, "foo", O_RDONLY);
+	if (fd >= 0 || errno != ENOTDIR) {
+		printf("1. %d %d\n", fd, (int) errno);
+		exit(EXIT_FAILURE);
+	}
+
+	fd = openat(0, "", O_RDONLY);
+	if (fd >= 0 || errno != ENOENT) {
+		printf("2. %d %d\n", fd, (int) errno);
+		exit(EXIT_FAILURE);
+	}
+
+	fd = openat(0, NULL, O_RDONLY);
+	if (fd >= 0 || errno != EFAULT) {
+		printf("3. %d %d\n", fd, (int) errno);
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-ffffffff.sh b/5.1.0/tests/test-ffffffff.sh
new file mode 100644
index 0000000..c003c3f
--- /dev/null
+++ b/5.1.0/tests/test-ffffffff.sh
@@ -0,0 +1,12 @@
+if [ -z `which mcookie` ] || [ -z `which touch` ] || [ -z `which stat` ] || [ -z `which grep` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+touch ${TMP}
+
+${PROOT} -0 stat -c %u:%g ${TMP} | grep 0:0
+
+${PROOT} -i 123:456 stat -c %u:%g ${TMP} | grep 123:456
+
+rm ${TMP}
diff --git a/5.1.0/tests/test-gggggggg.sh b/5.1.0/tests/test-gggggggg.sh
new file mode 100644
index 0000000..af511de
--- /dev/null
+++ b/5.1.0/tests/test-gggggggg.sh
@@ -0,0 +1,19 @@
+if [ -z `which mcookie` ] || [ -z `which env` ] || [ -z `which mkdir` ] || [ -z `which rm` ] || [ ! -x ${ROOTFS}/bin/readdir ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+mkdir ${TMP}
+
+! env PROOT_DONT_POLLUTE_ROOTFS=1 ${PROOT} -b /bin:${TMP}/dont/create ${ROOTFS}/bin/readdir ${TMP} | grep -w dont
+[ $? -eq 0 ]
+
+env PROOT_DONT_POLLUTE_ROOTFS=1 ${PROOT} -b /bin:${TMP}/dont/create test -e ${TMP}/dont
+
+${PROOT} -b /bin:${TMP}/dont/create test -e ${TMP}/dont
+
+! test -e ${TMP}/dont
+[ $? -eq 0 ]
+
+chmod +rx -R ${TMP}
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-hhhhhhhh.sh b/5.1.0/tests/test-hhhhhhhh.sh
new file mode 100644
index 0000000..5f89cb3
--- /dev/null
+++ b/5.1.0/tests/test-hhhhhhhh.sh
@@ -0,0 +1,23 @@
+if [ ! -x  ${ROOTFS}/bin/true ] || [ -h /bin/true ] || [ -h /bin ] || [ -z `which mcookie` ] || [ -z `which true` ] || [ -z `which mkdir` ] || [ -z `which ln` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+mkdir -p ${ROOTFS}/${TMP}
+
+A=$(mcookie)
+B=$(mcookie)
+
+! ln -s /bin/true   -r ${ROOTFS}/${TMP}/${A}
+! ln -s ${TMP}/${A} -r ${ROOTFS}/${TMP}/${B}
+
+if [ ! -e ${ROOTFS}/${TMP}/${A} ]; then
+    exit 125;
+fi
+
+env PATH=${TMP} ${PROOT} -r ${ROOTFS} ${B}
+
+rm -f ${TMP}/${B}  # just in case it also exists in the host env.
+${PROOT} -r ${ROOTFS} /${TMP}/${B}
+
+rm -fr ${ROOTFS}/${TMP}
diff --git a/5.1.0/tests/test-iiiiiiii.c b/5.1.0/tests/test-iiiiiiii.c
new file mode 100644
index 0000000..f772a34
--- /dev/null
+++ b/5.1.0/tests/test-iiiiiiii.c
@@ -0,0 +1,49 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void)
+{
+	int result;
+	int status;
+	char *path;
+	int fd;
+
+	path = strdup("/tmp/proot-test-iiiiiiii-XXXXXX");
+	if (path == NULL) {
+		result = 125;
+		goto end;
+	}
+
+	mktemp(path);
+	if (path[0] == '\0') {
+		result = 125;
+		goto end;
+	}
+
+	status = symlink("/this_shall_not_exist_outside_proot", path);
+	if (status < 0) {
+		result = 125;
+		goto end;
+	}
+
+	/* For faccessat(2) and fchmodat(2) syscalls, the fourth
+	 * parameter is *not* used by the kernel, only the libc uses
+	 * it.  As a consequence, PRoot shall ignore this flag.
+	 *
+	 * To be sure this parameter is really ignored by PRoot, we
+	 * set it to NOFOLLOW when performing a direct faccessat(2) to
+	 * a symlink which is broken from the host point-of-view, but
+	 * valid from a guest point-of-view.  When PRoot does not
+	 * honor this flag, the faccessat(2) is performed against the
+	 * referee anyway.
+	 */
+	status = syscall(SYS_faccessat, AT_FDCWD, path, X_OK, AT_SYMLINK_NOFOLLOW);
+	result = (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+
+end:
+	(void) unlink(path);
+	exit(result);
+}
diff --git a/5.1.0/tests/test-kkkkkkkk.c b/5.1.0/tests/test-kkkkkkkk.c
new file mode 100644
index 0000000..2747c11
--- /dev/null
+++ b/5.1.0/tests/test-kkkkkkkk.c
@@ -0,0 +1,142 @@
+#include <unistd.h>       /* syscall(2), sysconf(3), */
+#include <sys/syscall.h>  /* SYS_brk,         */
+#include <stdio.h>        /* puts(3),         */
+#include <stdlib.h>       /* exit(3), EXIT_*, */
+#include <stdint.h>       /* uint*_t,         */
+#include <sys/mman.h>     /* mmap(2), MAP_*,  */
+#include <string.h>       /* memset(3), */
+
+int main()
+{
+	int exit_status = EXIT_SUCCESS;
+	uint8_t *current_brk = 0;
+	uint8_t *initial_brk;
+	uint8_t *new_brk;
+	uint8_t *old_brk;
+	int failure = 0;
+	long page_size;
+	int i;
+
+	page_size = sysconf(_SC_PAGE_SIZE);
+	if (page_size <= 0)
+		return 125;
+
+	void test_brk(int increment, int expected_result) {
+		new_brk = (uint8_t *) syscall(SYS_brk, current_brk + increment);
+		if ((new_brk == current_brk) == expected_result)
+			failure = 1;
+		current_brk = (uint8_t *) syscall(SYS_brk, 0);
+	}
+
+	void test_result() {
+		if (!failure)
+			puts("OK");
+		else {
+			puts("failure");
+			exit_status = EXIT_FAILURE;
+		}
+	}
+
+	void test_title(const char *title) {
+		failure = 0;
+		printf("%-45s : ", title);
+		fflush(stdout);
+	}
+
+	test_title("Initialization");
+	test_brk(0, 1);
+	initial_brk = current_brk;
+	test_result();
+
+	test_title("Don't set the \"brk\" below its initial value");
+	test_brk(page_size, 1);
+	test_brk(-2 * page_size, 0);
+	test_brk(-page_size, 1);
+	test_result();
+
+	test_title("Don't overlap \"brk\" pages");
+	test_brk(page_size, 1);
+	test_brk(page_size, 1);
+	test_result();
+
+	/* Preparation for the test "Re-allocated heap is initialized".  */
+	old_brk = current_brk - page_size;
+	memset(old_brk, 0xFF, page_size);
+
+	test_title("Don't allocate the same \"brk\" page twice");
+	test_brk(-page_size, 1);
+	test_brk(page_size, 1);
+	test_result();
+
+	test_title("Re-allocated \"brk\" pages are initialized");
+	for (i = 0; i < page_size; i++) {
+		if (old_brk[i] != 0) {
+			printf("(index = %d, value = 0x%x) ", i, old_brk[i]);
+			failure = 1;
+			break;
+		}
+	}
+	test_result();
+
+#if 0
+	test_title("Don't allocate \"brk\" pages over \"mmap\" pages");
+	new_brk = mmap(current_brk, page_size / 2, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+	if (new_brk == (void *) -1)
+		puts("unknown");
+	else {
+		test_brk(page_size, 0);
+		test_result();
+	}
+#endif
+
+	test_title("All \"brk\" pages are writable (please wait)");
+#if 0
+	if (munmap(current_brk, page_size / 2) != 0)
+		puts("unknown");
+	else {
+#endif
+		while (current_brk - initial_brk < 512*1024*1024UL) {
+			old_brk = current_brk;
+
+			test_brk(page_size, -1);
+			if (old_brk == current_brk)
+				break;
+
+			for (i = 0; i < page_size; i++)
+				old_brk[i] = 0xAA;
+		}
+		test_result();
+#if 0
+	}
+#endif
+
+	test_title("Maximum size of the heap >= 1MB");
+	failure = (current_brk - initial_brk) < 1024 * 1024;
+	test_result();
+
+	test_title("All \"brk\" pages are cleared (please wait)");
+	test_brk(initial_brk - current_brk, 1);
+	if (current_brk != initial_brk)
+		puts("unknown");
+	else {
+		while (current_brk - initial_brk < 1024*1024*1024UL) {
+			old_brk = current_brk;
+
+			test_brk(3 * page_size, -1);
+			if (old_brk == current_brk)
+				break;
+
+			for (i = 0; i < 3 * page_size; i++) {
+				if (old_brk[i] != 0) {
+					printf("(index = %d, value = 0x%x) ", i, old_brk[i]);
+					failure = 1;
+					goto end;
+				}
+			}
+		}
+	end:
+		test_result();
+	}
+
+	exit(exit_status);
+}
diff --git a/5.1.0/tests/test-mmmmmmmm.sh b/5.1.0/tests/test-mmmmmmmm.sh
new file mode 100644
index 0000000..94c380a
--- /dev/null
+++ b/5.1.0/tests/test-mmmmmmmm.sh
@@ -0,0 +1,15 @@
+if [ -z `which mcookie` ] || [ -z `which rmdir` ] || [ -z `which mkdir` ]; then
+    exit 125;
+fi
+
+TMP=$(mcookie)
+cd /tmp
+
+${PROOT} mkdir ./${TMP}
+${PROOT} rmdir ./${TMP}
+
+${PROOT} mkdir ${TMP}/
+${PROOT} rmdir ${TMP}/
+
+${PROOT} mkdir ./${TMP}/
+${PROOT} rmdir ./${TMP}/
diff --git a/5.1.0/tests/test-nnnnnnnn.c b/5.1.0/tests/test-nnnnnnnn.c
new file mode 100644
index 0000000..723186c
--- /dev/null
+++ b/5.1.0/tests/test-nnnnnnnn.c
@@ -0,0 +1,81 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main()
+{
+	const char *sockname = "/test-nnnnnnnn-socket";
+	struct sockaddr_un sockaddr;
+	socklen_t socklen;
+	mode_t mask;
+	int status;
+	int fd;
+
+	/* root can create $hostfs/test-nnnnnnnn-socket.  */
+	if (getuid() == 0)
+		return 125;
+
+	/* clean-up previous socket.  */
+	(void) unlink(sockname);
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0) {
+		perror("socket");
+		exit(EXIT_FAILURE);
+	}
+
+	bzero(&sockaddr, sizeof(sockaddr));
+	sockaddr.sun_family = AF_UNIX;
+	strcpy(sockaddr.sun_path, sockname);
+
+	mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
+	status = bind(fd, (const struct sockaddr *) &sockaddr, SUN_LEN(&sockaddr));
+	if (status < 0) {
+		perror("bind");
+		exit(EXIT_FAILURE);
+	}
+	umask(mask);
+
+	status = listen(fd, 50);
+	if (status < 0) {
+		perror("listen");
+		exit(EXIT_FAILURE);
+	}
+
+	bzero(&sockaddr, sizeof(sockaddr));
+
+	socklen = sizeof(sockaddr);
+	status = getsockname(fd, (struct sockaddr *) &sockaddr, &socklen);
+	if (status < 0) {
+		perror("getsockname");
+		exit(EXIT_FAILURE);
+	}
+
+	if (socklen != SUN_LEN(&sockaddr) + 1) {
+		fprintf(stderr, "socklen: %d != %d + 1\n", socklen, SUN_LEN(&sockaddr));
+		exit(EXIT_FAILURE);
+	}
+
+	if (sockaddr.sun_family != AF_UNIX) {
+		fprintf(stderr, "! AF_UNIX\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (socklen == sizeof(sockaddr) + 1)
+		status = strncmp(sockaddr.sun_path, sockname, sizeof(sockaddr.sun_path));
+	else
+		status = strcmp(sockaddr.sun_path, sockname);
+
+	if (status != 0) {
+		fprintf(stderr, "! %s\n", sockname);
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-oooooooo.c b/5.1.0/tests/test-oooooooo.c
new file mode 100755
index 0000000..98cf0d9
--- /dev/null
+++ b/5.1.0/tests/test-oooooooo.c
@@ -0,0 +1,42 @@
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+	int i;
+
+	for (i = 0; i < 999; i++) {
+		int status;
+		int fds[2];
+		pid_t pid;
+
+		status = pipe(fds);
+		if (status < 0) {
+			perror("pipe");
+			break;
+		}
+
+		pid = fork();
+		switch (pid) {
+		case -1:
+			perror("fork");
+			exit(EXIT_FAILURE);
+
+		case 0: /* child */
+			do status = write(fds[1], "!", 1); while (status > 0);
+			perror("write");
+			exit(EXIT_FAILURE);
+
+		default: /* parent */
+			status = kill(pid, SIGKILL);
+			if (status < 0) {
+				perror("kill");
+				exit(EXIT_FAILURE);
+			}
+		}
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-pppppppp.sh b/5.1.0/tests/test-pppppppp.sh
new file mode 100644
index 0000000..4aacdbe
--- /dev/null
+++ b/5.1.0/tests/test-pppppppp.sh
@@ -0,0 +1,18 @@
+if [ -z `which mcookie` ] || [ -z `which true` ] || [ -z `which mkdir` ]|| [ -z `which env` ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+mkdir -p ${TMP}/true
+
+! ${PROOT} true
+if [ $? -eq 0 ]; then
+    exit 125;
+fi
+
+env PATH=${TMP}:${PATH} ${PROOT} true
+
+env PATH=${TMP}:${PATH} ${PROOT} env true
+
+rm -fr ${TMP}
+
diff --git a/5.1.0/tests/test-proocare.sh b/5.1.0/tests/test-proocare.sh
new file mode 100644
index 0000000..7f69416
--- /dev/null
+++ b/5.1.0/tests/test-proocare.sh
@@ -0,0 +1,27 @@
+if [ ! -e /boot ] || [ -z `which mcookie` ] || [ -z `which ln` ] || [ -z `which mkdir` ] || [ -z `which rm` ]; then
+    exit 125;
+fi
+
+if [ ! -e $CARE ]; then
+    exit 125;
+fi
+unset PROOT
+
+TMP_PROOT=/tmp/$(mcookie)
+TMP_OUTPUT=/tmp/$(mcookie)/
+
+ln -s ${CARE} ${TMP_PROOT}
+mkdir ${TMP_OUTPUT}
+
+${TMP_PROOT} -b /boot:/toob ${CARE} -o ${TMP_OUTPUT}/ ls /toob
+
+test -e ${TMP_OUTPUT}/rootfs/toob
+
+! test -e ${TMP_OUTPUT}/rootfs/boot
+[ $? -eq 0 ]
+
+${TMP_OUTPUT}/re-execute.sh
+
+rm -fr ${TMP_PROOT} ${TMP_OUTPUT}
+
+
diff --git a/5.1.0/tests/test-ptrace00.c b/5.1.0/tests/test-ptrace00.c
new file mode 100644
index 0000000..6a17239
--- /dev/null
+++ b/5.1.0/tests/test-ptrace00.c
@@ -0,0 +1,85 @@
+/* Extracted from strace-4.8/strace.c:test_ptrace_setoptions_for_all.  */
+
+#include <sys/ptrace.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int main(void)
+{
+	bool does_work = false;
+	int status;
+	pid_t pid;
+
+	switch(pid = fork()) {
+	case -1:
+		perror("fork");
+		exit(EXIT_FAILURE);
+
+	case 0:
+		status = ptrace(PTRACE_TRACEME, 0, 0, 0);
+		if (status < 0) {
+			perror("ptrace(PTRACE_TRACEME)");
+			exit(EXIT_FAILURE);
+		}
+
+		kill(getpid(), SIGSTOP);
+		exit(EXIT_SUCCESS);
+
+	default:
+		break;
+	}
+
+	while (1) {
+		fprintf(stderr, ">>> pid = wait(&status)\n");
+		pid = wait(&status);
+		if (pid < 0) {
+			perror("wait");
+			exit(EXIT_FAILURE);
+		}
+		else if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status) == 0) {
+				fprintf(stderr, ">>> EXITSTATUS(status) == 0\n");
+				break;
+			}
+			fprintf(stderr, "WEXITSTATUS != 0\n");
+			exit(EXIT_FAILURE);
+		}
+		else if (WIFSIGNALED(status)) {
+			fprintf(stderr, "WIFSIGNALED\n");
+			exit(EXIT_FAILURE);
+		}
+		else if (!WIFSTOPPED(status)) {
+			fprintf(stderr, "!WIFSTOPPED\n");
+			exit(EXIT_FAILURE);
+		}
+		else if (WSTOPSIG(status) == SIGSTOP) {
+			fprintf(stderr, ">>> ptrace(PTRACE_SETOPTIONS, ...)\n");
+			status = ptrace(PTRACE_SETOPTIONS, pid, 0,
+					PTRACE_O_TRACESYSGOOD |	PTRACE_O_TRACEEXEC);
+			if (status < 0) {
+				perror("ptrace(PTRACE_SETOPTIONS)");
+				exit(EXIT_FAILURE);
+			}
+		}
+		else if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
+			fprintf(stderr, ">>> does_work = true\n");
+			does_work = true;
+		}
+
+		fprintf(stderr, ">>> ptrace(PTRACE_SYSCALL, ...)\n");
+		status = ptrace(PTRACE_SYSCALL, pid, 0, 0);
+		if (status < 0) {
+			perror("ptrace(PTRACE_SYSCALL)");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	fprintf(stderr, ">>> exit(...)\n");
+	exit(does_work ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-ptrace01.c b/5.1.0/tests/test-ptrace01.c
new file mode 100644
index 0000000..6fe7113
--- /dev/null
+++ b/5.1.0/tests/test-ptrace01.c
@@ -0,0 +1,45 @@
+#include <unistd.h>     /* fork(2), */
+#include <stdio.h>      /* perror(3), fprintf(3), */
+#include <stdlib.h>     /* exit(3), */
+#include <sys/ptrace.h> /* ptrace(2), */
+#include <sys/types.h>  /* waitpid(2), */
+#include <sys/wait.h>   /* waitpid(2), */
+
+int main(void)
+{
+	int child_status, status;
+	pid_t pid;
+
+	pid = fork();
+	switch (pid) {
+	case -1:
+		perror("fork()");
+		exit(EXIT_FAILURE);
+
+	case 0: /* child */
+		status = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+		if (status < 0) {
+			perror("ptrace(TRACEME)");
+			exit(EXIT_FAILURE);
+		}
+
+		exit(EXIT_SUCCESS);
+
+	default: /* parent */
+		status = waitpid(pid, &child_status, 0);
+		if (status < 0) {
+			perror("waitpid()");
+			exit(EXIT_FAILURE);
+		}
+
+		if (!WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0) {
+			perror("unexpected child status\n");
+			exit(EXIT_FAILURE);
+		}
+
+		exit(EXIT_SUCCESS);
+	}
+
+	/* Unreachable. */
+	exit(EXIT_FAILURE);
+}
diff --git a/5.1.0/tests/test-rrrrrrrr.sh b/5.1.0/tests/test-rrrrrrrr.sh
new file mode 100644
index 0000000..8fb3f39
--- /dev/null
+++ b/5.1.0/tests/test-rrrrrrrr.sh
@@ -0,0 +1,7 @@
+if [ ! -x  ${ROOTFS}/bin/readlink ] || [ -z `which realpath` ] || [ -z `which grep` ]; then
+    exit 125;
+fi
+
+RESULT=$(realpath ${ROOTFS})
+
+${PROOT} -b /proc -r ${ROOTFS} readlink /proc/self/root | grep ^${RESULT}$
diff --git a/5.1.0/tests/test-ssssssss.c b/5.1.0/tests/test-ssssssss.c
new file mode 100644
index 0000000..3431be1
--- /dev/null
+++ b/5.1.0/tests/test-ssssssss.c
@@ -0,0 +1,55 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdio.h>
+#include <assert.h>
+
+int main()
+{
+	struct sockaddr_un sockaddr;
+	socklen_t socklen;
+	char *sockname;
+	mode_t mask;
+	int status;
+	int fd;
+
+	sockname = strdup("proot-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxXXXXXX");
+	if (sockname == NULL)
+		return 125;
+
+	(void) mktemp(sockname);
+	if (sockname[0] == '\0')
+		return 125;
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0) {
+		perror("socket");
+		exit(EXIT_FAILURE);
+	}
+
+	bzero(&sockaddr, sizeof(sockaddr));
+	sockaddr.sun_family = AF_UNIX;
+
+	assert(strlen(sockname) == sizeof(sockaddr.sun_path));
+	memcpy(sockaddr.sun_path, sockname, sizeof(sockaddr.sun_path));
+
+	chdir("/tmp");
+
+	(void) unlink(sockaddr.sun_path);
+	status = bind(fd, (const struct sockaddr *) &sockaddr, sizeof(sockaddr));
+	if (status < 0) {
+		perror("bind");
+		exit(EXIT_FAILURE);
+	}
+
+	(void) unlink(sockaddr.sun_path);
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/test-wwwwwwww.sh b/5.1.0/tests/test-wwwwwwww.sh
new file mode 100644
index 0000000..24d2cfc
--- /dev/null
+++ b/5.1.0/tests/test-wwwwwwww.sh
@@ -0,0 +1,10 @@
+if [ -z `which mcookie` ] || [ -z `which mkdir` ] || [ -z `which rm` ] || [ ! -x ${ROOTFS}/bin/pwd ]; then
+    exit 125;
+fi
+
+TMP=/tmp/$(mcookie)
+mkdir ${TMP}
+cd ${TMP}
+${PROOT} sh -c "cd ..; rm -r ${TMP}; mkdir ${TMP}; cd ${TMP}; ${ROOTFS}/bin/pwd"
+
+rm -fr ${TMP}
diff --git a/5.1.0/tests/test-xxxxxxxx.c b/5.1.0/tests/test-xxxxxxxx.c
new file mode 100644
index 0000000..e8335e3
--- /dev/null
+++ b/5.1.0/tests/test-xxxxxxxx.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+extern char *environ[];
+
+#define CONTENT "this isn't an executable"
+
+int main(void)
+{
+	char * const argv[] = { "argv0", "argv1", "argv2", NULL };
+	char tmp_name[] = "/tmp/proot-XXXXXX";
+	int status;
+	int fd;
+
+	status = execve("/tmp", argv, environ);
+	if (errno != EACCES) {
+		perror("execve (1)");
+		exit(EXIT_FAILURE);
+	}
+
+	fd = mkstemp(tmp_name);
+	if (fd < 0) {
+		perror("mkstemp");
+		exit(EXIT_FAILURE);
+	}
+
+	status = write(fd, CONTENT, sizeof(CONTENT));
+	if (status != sizeof(CONTENT)) {
+		perror("write");
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+
+	status = chmod(tmp_name, 0700);
+	if (status < 0)  {
+		perror("chmod");
+		exit(EXIT_FAILURE);
+	}
+
+	status = execve(tmp_name, argv, environ);
+	if (errno != ENOEXEC) {
+		perror("execve (2)");
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Check the stack integrity: %F + %F\n", (double) status, (double) errno);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/5.1.0/tests/true.c b/5.1.0/tests/true.c
new file mode 100644
index 0000000..78f2de1
--- /dev/null
+++ b/5.1.0/tests/true.c
@@ -0,0 +1 @@
+int main(void) { return 0; }
diff --git a/5.1.0/tests/validation.mk b/5.1.0/tests/validation.mk
new file mode 100644
index 0000000..c2d0786
--- /dev/null
+++ b/5.1.0/tests/validation.mk
@@ -0,0 +1,133 @@
+libuv-version     = 0.10.27
+coreutils-version = 8.21
+perl-version      = 5.18.1
+ltp-version       = 20140422
+opt-version       = 20140422
+gdb-version       = 7.6.1
+proot-version     = 3.2.2
+glibc-version     = 2.17
+
+libuv     = libuv-$(libuv-version)
+coreutils = coreutils-$(coreutils-version)
+perl      = perl-$(perl-version)
+ltp       = ltp-$(ltp-version)
+opt       = opt-$(opt-version)
+gdb       = gdb-$(gdb-version)
+proot     = PRoot-$(proot-version)
+glibc     = glibc-$(glibc-version)
+
+testsuites = $(libuv) $(perl) $(ltp) $(opt) $(gdb) $(proot) $(coreutils) # $(glibc) too long.
+logs       = $(testsuites:=.log)
+
+logs: $(logs)
+
+.PHONY: clean
+clean:
+	rm -f $(logs)
+	rm -fr $(testsuites)
+
+.PHONY: distclean
+ distclean: clean
+	rm -f $(testsuites:=.tar.*)
+
+######################################################################
+
+$(libuv).tar.gz:
+	wget https://github.com/joyent/libuv/archive/v$(libuv-version).tar.gz -O $@
+
+$(libuv).log: $(libuv).tar.gz
+	rm -fr $(libuv)
+	tar -xf $<
+	$(MAKE) -C $(libuv)
+	($(MAKE) -C $(libuv) test 2>&1 || true) | tee $@
+
+######################################################################
+
+$(coreutils).tar.xz:
+	wget http://ftp.gnu.org/gnu/coreutils/$(coreutils).tar.xz
+
+$(coreutils).log: $(coreutils).tar.xz
+	rm -fr $(coreutils)
+	tar -xf $<
+	cd $(coreutils) && ./configure
+	$(MAKE) -C $(coreutils)
+	($(MAKE) -C $(coreutils) check || true) | tee $@
+
+######################################################################
+
+$(perl).tar.gz:
+	wget http://www.cpan.org/src/5.0/$(perl).tar.gz
+
+$(perl).log: $(perl).tar.gz
+	rm -fr $(perl)
+	tar -xf $<
+	cd $(perl) && ./configure.gnu
+	$(MAKE) -C $(perl)
+	($(MAKE) -C $(perl) check || true) | tee $@
+
+######################################################################
+
+$(ltp).tar.gz:
+	wget https://github.com/linux-test-project/ltp/archive/$(ltp-version).tar.gz -O $@
+
+$(ltp).log: $(ltp).tar.gz
+	rm -fr $(ltp)
+	tar -xf $<
+	$(MAKE) -C $(ltp) autotools
+	cd $(ltp) && ./configure --prefix=$(PWD)/$(ltp)/install
+	$(MAKE) -C $(ltp)
+	$(MAKE) -C $(ltp) install
+	sed -i s/^msgctl10/#/ $(ltp)/install/runtest/syscalls # is too CPU intensive
+	sed -i s/^msgctl11/#/ $(ltp)/install/runtest/syscalls # is too CPU intensive
+	($(ltp)/install/runltp -f syscalls || true) | tee $@
+
+######################################################################
+
+$(opt).log: $(ltp).tar.gz
+	rm -fr $(opt)
+	mkdir $(opt)
+	tar -C $(opt) -xf $< $(ltp)/testcases/open_posix_testsuite
+	$(MAKE) -C $(opt)/$(ltp)/testcases/open_posix_testsuite  -j 1 # has broken // build
+	($(MAKE) -C $(opt)/$(ltp)/testcases/open_posix_testsuite -j 1 test || true) | tee $@
+
+######################################################################
+
+$(gdb).tar.gz:
+	wget http://ftp.gnu.org/gnu/gdb/$(gdb).tar.gz
+
+$(gdb).log: $(gdb).tar.gz
+	rm -fr $(gdb)
+	tar -xf $<
+	cd $(gdb) && ./configure
+	$(MAKE) -C $(gdb)
+	rm -f $(gdb)/gdb/testsuite/gdb.base/attach-twice.exp     # kills PRoot explicitly
+	($(MAKE) -C $(gdb)/gdb/testsuite check-gdb.base1 check-gdb.base2 check-gdb.server || true) | tee $@
+
+######################################################################
+
+$(glibc).tar.xz:
+	wget http://ftp.gnu.org/gnu/glibc/$(glibc).tar.xz -O $@
+
+$(glibc).log: $(glibc).tar.xz
+	rm -fr $(glibc)
+	tar -xf $<
+	mkdir -p $(glibc)/build/prefix
+	cd $(glibc)/build && ../configure --prefix=$(PWD)/prefix
+	$(MAKE) -C $(glibc)/build
+	cp /usr/lib*/libgcc_s.so.1  $(glibc)/build
+	cp /usr/lib*/libstdc++.so.6 $(glibc)/build
+	sed -i s/tst-atexit3//g $(glibc)/dlfcn/Makefile # fails natively on Slack64-14.1
+	sed -i s/tst-cputimer1//g $(glibc)/rt/Makefile  # fails natively on Slack64-14.1
+	sed -i 's/tests: check-abi/tests: /g' $(glibc)/Makerules # fails natively on Slack64-14.1
+	($(MAKE) -j 1 -C $(glibc)/build check || true) | tee $@  # has broken // build
+
+######################################################################
+
+$(proot).tar.gz:
+	wget https://github.com/cedric-vincent/proot/archive/v$(proot-version).tar.gz -O $@
+
+$(proot).log: $(proot).tar.gz
+	rm -fr $(proot)
+	tar -xf $<
+	$(MAKE) -C $(proot)/src
+	($(MAKE) -C $(proot)/tests || true) | tee $@