diff --git a/cr-restore.c b/cr-restore.c index 7141c6c39..a903ab2bd 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -1579,20 +1579,9 @@ static int attach_to_tasks(bool root_seized, enum trace_flags *flag) return -1; } - ret = ptrace_set_breakpoint(pid, item->rst->breakpoint); + ret = ptrace_stop_pie(pid, item->rst->breakpoint, flag); if (ret < 0) return -1; - - /* A breakpoint was not set */ - if (ret > 0) - *flag = TRACE_EXIT; - else { - *flag = TRACE_ENTER; - if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL)) { - pr_perror("Unable to start %d", pid); - return -1; - } - } } } diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h index 5d2df08c7..62d0ba49e 100644 --- a/include/parasite-syscall.h +++ b/include/parasite-syscall.h @@ -139,5 +139,6 @@ enum trace_flags { extern int parasite_stop_on_syscall(int tasks, int sys_nr, enum trace_flags trace); extern int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr); +extern int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf); #endif /* __CR_PARASITE_SYSCALL_H__ */ diff --git a/parasite-syscall.c b/parasite-syscall.c index 9102b2367..db92c6beb 100644 --- a/parasite-syscall.c +++ b/parasite-syscall.c @@ -871,21 +871,9 @@ static int parasite_fini_seized(struct parasite_ctl *ctl) return -1; /* Go to sigreturn as closer as we can */ - ret = ptrace_set_breakpoint(pid, ctl->sigreturn_addr); + ret = ptrace_stop_pie(pid, ctl->sigreturn_addr, &flag); if (ret < 0) return ret; - if (ret > 0) - flag = TRACE_EXIT; - else { - /* Start tracing syscalls */ - ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); - if (ret) { - pr_perror("ptrace"); - return -1; - } - - flag = TRACE_ENTER; - } if (parasite_stop_on_syscall(1, __NR_rt_sigreturn, flag)) return -1; @@ -1238,3 +1226,34 @@ err_restore: parasite_cure_seized(ctl); return NULL; } + +int ptrace_stop_pie(pid_t pid, void *addr, enum trace_flags *tf) +{ + int ret; + + 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("ptrace"); + return -1; + } + + *tf = TRACE_ENTER; + return 0; +}