[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, ®s);
+ if (ret) {
+ pr_perror("ptrace");
+ return -1;
+ }
+
+ if (is_required_syscall(®s, 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, ®s);
- if (ret) {
- pr_perror("ptrace");
- return -1;
- }
-
- if (is_required_syscall(®s, 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