[CRIU] [PATCH 30/78] infect: Move pie tracing code into infect.c

Cyrill Gorcunov gorcunov at openvz.org
Mon Nov 7 08:36:15 PST 2016


From: Pavel Emelyanov <xemul at virtuozzo.com>

Note -- presumably it's another functionality block inside compel,
so another .c file might be tempting here.

Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
 criu/cr-restore.c               |   6 +-
 criu/include/infect.h           |  17 +++++
 criu/include/parasite-syscall.h |  17 +----
 criu/infect.c                   | 153 +++++++++++++++++++++++++++++++++++++++-
 criu/parasite-syscall.c         | 147 +-------------------------------------
 5 files changed, 174 insertions(+), 166 deletions(-)

diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 0629da03971c..b77db9fb7b2e 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -70,6 +70,7 @@
 #include "file-lock.h"
 #include "action-scripts.h"
 #include "shmem.h"
+#include "infect.h"
 #include "aio.h"
 #include "lsm.h"
 #include "seccomp.h"
@@ -1607,7 +1608,8 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag)
 				return -1;
 			}
 
-			ret = ptrace_stop_pie(pid, rsti(item)->breakpoint, flag);
+			ret = compel_stop_pie(pid, rsti(item)->breakpoint,
+					flag, fault_injected(FI_NO_BREAKPOINTS));
 			if (ret < 0)
 				return -1;
 		}
@@ -1942,7 +1944,7 @@ static int restore_root_task(struct pstree_item *init)
 		goto skip_for_check;
 
 	if (ret == 0)
-		ret = parasite_stop_on_syscall(task_entries->nr_threads,
+		ret = compel_stop_on_syscall(task_entries->nr_threads,
 			__NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag);
 
 	if (clear_breakpoints())
diff --git a/criu/include/infect.h b/criu/include/infect.h
index b906617e06be..4f7ae1c85e4c 100644
--- a/criu/include/infect.h
+++ b/criu/include/infect.h
@@ -58,5 +58,22 @@ extern int compel_run_in_thread(pid_t pid, unsigned int cmd,
 					struct parasite_ctl *ctl,
 					struct thread_ctx *octx);
 
+/*
+ * The PTRACE_SYSCALL will trap task twice -- on
+ * enter into and on exit from syscall. If we trace
+ * a single task, we may skip half of all getregs
+ * calls -- on exit we don't need them.
+ */
+enum trace_flags {
+	TRACE_ALL,
+	TRACE_ENTER,
+	TRACE_EXIT,
+};
+
+extern int compel_stop_on_syscall(int tasks, int sys_nr,
+		int sys_nr_compat, enum trace_flags trace);
+
+extern int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp);
+
 extern int compel_unmap(struct parasite_ctl *ctl, unsigned long addr);
 #endif
diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h
index f05bb74098cf..bcdc8b369b32 100644
--- a/criu/include/parasite-syscall.h
+++ b/criu/include/parasite-syscall.h
@@ -45,6 +45,7 @@ struct infect_ctx {
 
 #define INFECT_NO_MEMFD		0x1	/* don't use memfd() */
 #define INFECT_FAIL_CONNECT	0x2	/* make parasite connect() fail */
+#define INFECT_NO_BREAKPOINTS	0x4	/* no breakpoints in pie tracking */
 
 struct parasite_ctl;
 
@@ -101,20 +102,4 @@ extern int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
 extern bool arch_can_dump_task(struct parasite_ctl *ctl);
 extern bool seized_native(struct parasite_ctl *ctl);
 
-/*
- * The PTRACE_SYSCALL will trap task twice -- on
- * enter into and on exit from syscall. If we trace
- * a single task, we may skip half of all getregs
- * calls -- on exit we don't need them.
- */
-enum trace_flags {
-	TRACE_ALL,
-	TRACE_ENTER,
-	TRACE_EXIT,
-};
-
-extern int parasite_stop_on_syscall(int tasks, int sys_nr,
-		int sys_nr_compat, enum trace_flags trace);
-extern int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf);
-
 #endif /* __CR_PARASITE_SYSCALL_H__ */
diff --git a/criu/infect.c b/criu/infect.c
index fc235136edfe..a2782179c087 100644
--- a/criu/infect.c
+++ b/criu/infect.c
@@ -902,11 +902,12 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
 		return -1;
 
 	/* Go to sigreturn as closer as we can */
-	ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag);
+	ret = compel_stop_pie(pid, ctl->sigreturn_addr, &flag,
+			ctl->ictx.flags & INFECT_NO_BREAKPOINTS);
 	if (ret < 0)
 		return ret;
 
-	if (parasite_stop_on_syscall(1, __NR(rt_sigreturn, 0),
+	if (compel_stop_on_syscall(1, __NR(rt_sigreturn, 0),
 				__NR(rt_sigreturn, 1), flag))
 		return -1;
 
@@ -1052,7 +1053,7 @@ int compel_unmap(struct parasite_ctl *ctl, unsigned long addr)
 	if (ret)
 		goto err;
 
-	ret = parasite_stop_on_syscall(1, __NR(munmap, 0),
+	ret = compel_stop_on_syscall(1, __NR(munmap, 0),
 			__NR(munmap, 1), TRACE_ENTER);
 
 	if (restore_thread_ctx(pid, &ctl->orig))
@@ -1061,3 +1062,149 @@ err:
 	return ret;
 }
 
+int compel_stop_pie(pid_t pid, void *addr, enum trace_flags *tf, bool no_bp)
+{
+	int ret;
+
+	if (no_bp) {
+		pr_debug("Force no-breakpoints restore\n");
+		ret = 0;
+	} else
+		ret = ptrace_set_breakpoint(pid, addr);
+	if (ret < 0)
+		return ret;
+
+	if (ret > 0) {
+		/*
+		 * PIE will stop on a breakpoint, next
+		 * stop after that will be syscall enter.
+		 */
+		*tf = TRACE_EXIT;
+		return 0;
+	}
+
+	/*
+	 * No breakpoints available -- start tracing it
+	 * in a per-syscall manner.
+	 */
+	ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
+	if (ret) {
+		pr_perror("Unable to restart the %d process", pid);
+		return -1;
+	}
+
+	*tf = TRACE_ENTER;
+	return 0;
+}
+
+static bool task_is_trapped(int status, pid_t pid)
+{
+	if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
+		return true;
+
+	pr_err("Task %d is in unexpected state: %x\n", pid, status);
+	if (WIFEXITED(status))
+		pr_err("Task exited with %d\n", WEXITSTATUS(status));
+	if (WIFSIGNALED(status))
+		pr_err("Task signaled with %d: %s\n",
+			WTERMSIG(status), strsignal(WTERMSIG(status)));
+	if (WIFSTOPPED(status))
+		pr_err("Task stopped with %d: %s\n",
+			WSTOPSIG(status), strsignal(WSTOPSIG(status)));
+	if (WIFCONTINUED(status))
+		pr_err("Task continued\n");
+
+	return false;
+}
+
+static inline int is_required_syscall(user_regs_struct_t *regs, pid_t pid,
+		const int sys_nr, const int sys_nr_compat)
+{
+	const char *mode = user_regs_native(regs) ? "native" : "compat";
+	int req_sysnr = user_regs_native(regs) ? sys_nr : sys_nr_compat;
+
+	pr_debug("%d (%s) is going to execute the syscall %lu, required is %d\n",
+		pid, mode, REG_SYSCALL_NR(*regs), req_sysnr);
+
+	return (REG_SYSCALL_NR(*regs) == req_sysnr);
+}
+
+/*
+ * Trap tasks on the exit from the specified syscall
+ *
+ * tasks - number of processes, which should be trapped
+ * sys_nr - the required syscall number
+ * sys_nr_compat - the required compatible syscall number
+ */
+int compel_stop_on_syscall(int tasks,
+	const int sys_nr, const int sys_nr_compat,
+	enum trace_flags trace)
+{
+	user_regs_struct_t regs;
+	int status, ret;
+	pid_t pid;
+
+	if (tasks > 1)
+		trace = TRACE_ALL;
+
+	/* Stop all threads on the enter point in sys_rt_sigreturn */
+	while (tasks) {
+		pid = wait4(-1, &status, __WALL, NULL);
+		if (pid == -1) {
+			pr_perror("wait4 failed");
+			return -1;
+		}
+
+		if (!task_is_trapped(status, pid))
+			return -1;
+
+		pr_debug("%d was trapped\n", pid);
+
+		if (trace == TRACE_EXIT) {
+			trace = TRACE_ENTER;
+			pr_debug("`- Expecting exit\n");
+			goto goon;
+		}
+		if (trace == TRACE_ENTER)
+			trace = TRACE_EXIT;
+
+		ret = ptrace_get_regs(pid, &regs);
+		if (ret) {
+			pr_perror("ptrace");
+			return -1;
+		}
+
+		if (is_required_syscall(&regs, pid, sys_nr, sys_nr_compat)) {
+			/*
+			 * The process is going to execute the required syscall,
+			 * the next stop will be on the exit from this syscall
+			 */
+			ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
+			if (ret) {
+				pr_perror("ptrace");
+				return -1;
+			}
+
+			pid = wait4(pid, &status, __WALL, NULL);
+			if (pid == -1) {
+				pr_perror("wait4 failed");
+				return -1;
+			}
+
+			if (!task_is_trapped(status, pid))
+				return -1;
+
+			pr_debug("%d was stopped\n", pid);
+			tasks--;
+			continue;
+		}
+goon:
+		ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
+		if (ret) {
+			pr_perror("ptrace");
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
index c40e60abd045..9e43db20dca1 100644
--- a/criu/parasite-syscall.c
+++ b/criu/parasite-syscall.c
@@ -612,117 +612,6 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
 
 /* This is officially the 50000'th line in the CRIU source code */
 
-static bool task_is_trapped(int status, pid_t pid)
-{
-	if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
-		return true;
-
-	pr_err("Task %d is in unexpected state: %x\n", pid, status);
-	if (WIFEXITED(status))
-		pr_err("Task exited with %d\n", WEXITSTATUS(status));
-	if (WIFSIGNALED(status))
-		pr_err("Task signaled with %d: %s\n",
-			WTERMSIG(status), strsignal(WTERMSIG(status)));
-	if (WIFSTOPPED(status))
-		pr_err("Task stopped with %d: %s\n",
-			WSTOPSIG(status), strsignal(WSTOPSIG(status)));
-	if (WIFCONTINUED(status))
-		pr_err("Task continued\n");
-
-	return false;
-}
-
-static inline int is_required_syscall(user_regs_struct_t *regs, pid_t pid,
-		const int sys_nr, const int sys_nr_compat)
-{
-	const char *mode = user_regs_native(regs) ? "native" : "compat";
-	int req_sysnr = user_regs_native(regs) ? sys_nr : sys_nr_compat;
-
-	pr_debug("%d (%s) is going to execute the syscall %lu, required is %d\n",
-		pid, mode, REG_SYSCALL_NR(*regs), req_sysnr);
-
-	return (REG_SYSCALL_NR(*regs) == req_sysnr);
-}
-/*
- * Trap tasks on the exit from the specified syscall
- *
- * tasks - number of processes, which should be trapped
- * sys_nr - the required syscall number
- * sys_nr_compat - the required compatible syscall number
- */
-int parasite_stop_on_syscall(int tasks,
-	const int sys_nr, const int sys_nr_compat,
-	enum trace_flags trace)
-{
-	user_regs_struct_t regs;
-	int status, ret;
-	pid_t pid;
-
-	if (tasks > 1)
-		trace = TRACE_ALL;
-
-	/* Stop all threads on the enter point in sys_rt_sigreturn */
-	while (tasks) {
-		pid = wait4(-1, &status, __WALL, NULL);
-		if (pid == -1) {
-			pr_perror("wait4 failed");
-			return -1;
-		}
-
-		if (!task_is_trapped(status, pid))
-			return -1;
-
-		pr_debug("%d was trapped\n", pid);
-
-		if (trace == TRACE_EXIT) {
-			trace = TRACE_ENTER;
-			pr_debug("`- Expecting exit\n");
-			goto goon;
-		}
-		if (trace == TRACE_ENTER)
-			trace = TRACE_EXIT;
-
-		ret = ptrace_get_regs(pid, &regs);
-		if (ret) {
-			pr_perror("ptrace");
-			return -1;
-		}
-
-		if (is_required_syscall(&regs, pid, sys_nr, sys_nr_compat)) {
-			/*
-			 * The process is going to execute the required syscall,
-			 * the next stop will be on the exit from this syscall
-			 */
-			ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
-			if (ret) {
-				pr_perror("ptrace");
-				return -1;
-			}
-
-			pid = wait4(pid, &status, __WALL, NULL);
-			if (pid == -1) {
-				pr_perror("wait4 failed");
-				return -1;
-			}
-
-			if (!task_is_trapped(status, pid))
-				return -1;
-
-			pr_debug("%d was stopped\n", pid);
-			tasks--;
-			continue;
-		}
-goon:
-		ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
-		if (ret) {
-			pr_perror("ptrace");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
 int parasite_dump_cgroup(struct parasite_ctl *ctl, struct parasite_dump_cgroup_args *cgroup)
 {
 	int ret;
@@ -781,6 +670,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 		ctl->ictx.flags |= INFECT_NO_MEMFD;
 	if (fault_injected(FI_PARASITE_CONNECT))
 		ctl->ictx.flags |= INFECT_FAIL_CONNECT;
+	if (fault_injected(FI_NO_BREAKPOINTS))
+		ctl->ictx.flags |= INFECT_NO_BREAKPOINTS;
 
 	parasite_ensure_args_size(dump_pages_args_size(vma_area_list));
 	parasite_ensure_args_size(aio_rings_args_size(vma_area_list));
@@ -797,37 +688,3 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 	return ctl;
 }
 
-int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf)
-{
-	int ret;
-
-	if (fault_injected(FI_NO_BREAKPOINTS)) {
-		pr_debug("Force no-breakpoints restore\n");
-		ret = 0;
-	} else
-		ret = ptrace_set_breakpoint(pid, addr);
-	if (ret < 0)
-		return ret;
-
-	if (ret > 0) {
-		/*
-		 * PIE will stop on a breakpoint, next
-		 * stop after that will be syscall enter.
-		 */
-		*tf = TRACE_EXIT;
-		return 0;
-	}
-
-	/*
-	 * No breakpoints available -- start tracing it
-	 * in a per-syscall manner.
-	 */
-	ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
-	if (ret) {
-		pr_perror("Unable to restart the %d process", pid);
-		return -1;
-	}
-
-	*tf = TRACE_ENTER;
-	return 0;
-}
-- 
2.7.4



More information about the CRIU mailing list