Add related code which make libcareplus can run basic demo on aarch64. Signed-off-by: Jiajie Li <lijiajie11@huawei.com>
502 lines
12 KiB
Diff
502 lines
12 KiB
Diff
From 35b9c6934fc5c1e2ea4cf7e30b91b3b91e48074d Mon Sep 17 00:00:00 2001
|
|
From: Jiajie Li <lijiajie11@huawei.com>
|
|
Date: Mon, 12 Oct 2020 16:16:57 +0800
|
|
Subject: [PATCH 39/89] kpatch_ptrace: Split function kpatch_ptrace_waitpid
|
|
|
|
The function kpatch_ptrace_waitpid is arch related, let's
|
|
rename it with kpatch_arch_ptrace_waitpid, and make the
|
|
defination in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c
|
|
|
|
Signed-off-by: Jiajie Li <lijiajie11@huawei.com>
|
|
Signed-off-by: Ying Fang <fangying1@huawei.com>
|
|
---
|
|
src/arch/aarch64/arch_ptrace.c | 145 +++++++++++++++++++++++++++++++++
|
|
src/arch/x86/arch_ptrace.c | 140 +++++++++++++++++++++++++++++++
|
|
src/include/kpatch_ptrace.h | 20 +++++
|
|
src/kpatch_ptrace.c | 130 +----------------------------
|
|
4 files changed, 307 insertions(+), 128 deletions(-)
|
|
|
|
diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c
|
|
index e69de29..fb19e86 100644
|
|
--- a/src/arch/aarch64/arch_ptrace.c
|
|
+++ b/src/arch/aarch64/arch_ptrace.c
|
|
@@ -0,0 +1,145 @@
|
|
+#include <stdlib.h>
|
|
+#include <errno.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <time.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/ptrace.h>
|
|
+#include <sys/wait.h>
|
|
+#include <asm/unistd.h>
|
|
+
|
|
+#include <unistd.h>
|
|
+#include <sys/syscall.h>
|
|
+#include <linux/auxvec.h>
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <sys/socket.h>
|
|
+
|
|
+#include "include/kpatch_process.h"
|
|
+#include "include/kpatch_common.h"
|
|
+#include "include/kpatch_ptrace.h"
|
|
+#include "include/kpatch_log.h"
|
|
+
|
|
+#include <gelf.h>
|
|
+
|
|
+int
|
|
+kpatch_arch_ptrace_waitpid(kpatch_process_t *proc,
|
|
+ struct timespec *timeout,
|
|
+ const sigset_t *sigset)
|
|
+{
|
|
+ struct kpatch_ptrace_ctx *pctx;
|
|
+ siginfo_t siginfo;
|
|
+ int ret, status;
|
|
+ pid_t pid;
|
|
+ struct user_regs_struct regs;
|
|
+ struct iovec regs_iov;
|
|
+
|
|
+ regs_iov.iov_base = ®s;
|
|
+ regs_iov.iov_len = sizeof(regs);
|
|
+
|
|
+ /* Immediately reap one attached thread */
|
|
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
|
|
+
|
|
+ if (pid < 0) {
|
|
+ kplogerror("can't wait for tracees\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* There is none ready, wait for notification via signal */
|
|
+ if (pid == 0) {
|
|
+ ret = sigtimedwait(sigset, &siginfo, timeout);
|
|
+ if (ret == -1 && errno == EAGAIN) {
|
|
+ /* We have timeouted */
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (ret == -1 && errno == EINVAL) {
|
|
+ kperr("invalid timeout\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* We have got EINTR and must restart */
|
|
+ if (ret == -1 && errno == EINTR)
|
|
+ return 0;
|
|
+
|
|
+ /**
|
|
+ * Kernel stacks signals that follow too quickly.
|
|
+ * Deal with it by waiting for any child, not just
|
|
+ * one that is specified in signal
|
|
+ */
|
|
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
|
|
+
|
|
+ if (pid == 0) {
|
|
+ kperr("missing waitpid for %d\n", siginfo.si_pid);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (pid < 0) {
|
|
+ kplogerror("can't wait for tracee %d\n", siginfo.si_pid);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!WIFSTOPPED(status) && WIFSIGNALED(status)) {
|
|
+ /* Continue, resending the signal */
|
|
+ ret = ptrace(PTRACE_CONT, pid, NULL,
|
|
+ (void *)(uintptr_t)WTERMSIG(status));
|
|
+ if (ret < 0) {
|
|
+ kplogerror("can't start tracee %d\n", pid);
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (WIFEXITED(status)) {
|
|
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0UL);
|
|
+ if (pctx == NULL) {
|
|
+ kperr("got unexpected child '%d' exit\n", pid);
|
|
+ } else {
|
|
+ /* It's dead */
|
|
+ pctx->pid = pctx->running = 0;
|
|
+ }
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ ret = ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, (void *)®s_iov);
|
|
+ if (ret < 0) {
|
|
+ kplogerror("can't get regs %d\n", pid);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ pctx = kpatch_ptrace_find_thread(proc, pid, regs.pc);
|
|
+
|
|
+ if (pctx == NULL) {
|
|
+ /* We either don't know anything about this thread or
|
|
+ * even worse -- we stopped it in the wrong place.
|
|
+ * Bail out.
|
|
+ */
|
|
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0);
|
|
+ if (pctx != NULL)
|
|
+ pctx->running = 0;
|
|
+
|
|
+ /* TODO: fix the latter by SINGLESTEPping such a thread with
|
|
+ * the original instruction in place */
|
|
+ kperr("the thread ran out: %d, pc= %llx, expected = %lx\n", pid,
|
|
+ regs.pc, pctx->execute_until);
|
|
+ errno = ESRCH;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ pctx->running = 0;
|
|
+
|
|
+ /* Restore thread registers, pctx is now valid */
|
|
+ kpdebug("Got thread %d at %llx\n", pctx->pid,
|
|
+ regs.pc - BREAK_INSN_LENGTH);
|
|
+
|
|
+ regs.pc = pctx->execute_until;
|
|
+
|
|
+ ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void*)NT_PRSTATUS, (void*)®s_iov);
|
|
+ if (ret < 0) {
|
|
+ kplogerror("can't set regs - %d\n", pctx->pid);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c
|
|
index e69de29..6e943fd 100644
|
|
--- a/src/arch/x86/arch_ptrace.c
|
|
+++ b/src/arch/x86/arch_ptrace.c
|
|
@@ -0,0 +1,140 @@
|
|
+#include <stdlib.h>
|
|
+#include <errno.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <time.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/ptrace.h>
|
|
+#include <sys/wait.h>
|
|
+#include <asm/unistd.h>
|
|
+
|
|
+#include <unistd.h>
|
|
+#include <sys/syscall.h>
|
|
+#include <linux/auxvec.h>
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <sys/socket.h>
|
|
+
|
|
+#include "include/kpatch_process.h"
|
|
+#include "include/kpatch_common.h"
|
|
+#include "include/kpatch_ptrace.h"
|
|
+#include "include/kpatch_log.h"
|
|
+
|
|
+#include <gelf.h>
|
|
+
|
|
+int kpatch_arch_ptrace_waitpid(kpatch_process_t *proc,
|
|
+ struct timespec *timeout,
|
|
+ const sigset_t *sigset)
|
|
+{
|
|
+ struct kpatch_ptrace_ctx *pctx;
|
|
+ siginfo_t siginfo;
|
|
+ int ret, status;
|
|
+ pid_t pid;
|
|
+ struct user_regs_struct regs;
|
|
+
|
|
+ /* Immediately reap one attached thread */
|
|
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
|
|
+
|
|
+ if (pid < 0) {
|
|
+ kplogerror("can't wait for tracees\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* There is none ready, wait for notification via signal */
|
|
+ if (pid == 0) {
|
|
+ ret = sigtimedwait(sigset, &siginfo, timeout);
|
|
+ if (ret == -1 && errno == EAGAIN) {
|
|
+ /* We have timeouted */
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (ret == -1 && errno == EINVAL) {
|
|
+ kperr("invalid timeout\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* We have got EINTR and must restart */
|
|
+ if (ret == -1 && errno == EINTR)
|
|
+ return 0;
|
|
+
|
|
+ /**
|
|
+ * Kernel stacks signals that follow too quickly.
|
|
+ * Deal with it by waiting for any child, not just
|
|
+ * one that is specified in signal
|
|
+ */
|
|
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
|
|
+
|
|
+ if (pid == 0) {
|
|
+ kperr("missing waitpid for %d\n", siginfo.si_pid);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (pid < 0) {
|
|
+ kplogerror("can't wait for tracee %d\n", siginfo.si_pid);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!WIFSTOPPED(status) && WIFSIGNALED(status)) {
|
|
+ /* Continue, resending the signal */
|
|
+ ret = ptrace(PTRACE_CONT, pid, NULL,
|
|
+ (void *)(uintptr_t)WTERMSIG(status));
|
|
+ if (ret < 0) {
|
|
+ kplogerror("can't start tracee %d\n", pid);
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (WIFEXITED(status)) {
|
|
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0UL);
|
|
+ if (pctx == NULL) {
|
|
+ kperr("got unexpected child '%d' exit\n", pid);
|
|
+ } else {
|
|
+ /* It's dead */
|
|
+ pctx->pid = pctx->running = 0;
|
|
+ }
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ ret = ptrace(PTRACE_GETREGS, pid, NULL, ®s);
|
|
+ if (ret < 0) {
|
|
+ kplogerror("can't get regs %d\n", pid);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ pctx = kpatch_ptrace_find_thread(proc, pid, regs.rip);
|
|
+
|
|
+ if (pctx == NULL) {
|
|
+ /* We either don't know anything about this thread or
|
|
+ * even worse -- we stopped it in the wrong place.
|
|
+ * Bail out.
|
|
+ */
|
|
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0);
|
|
+ if (pctx != NULL)
|
|
+ pctx->running = 0;
|
|
+
|
|
+ /* TODO: fix the latter by SINGLESTEPping such a thread with
|
|
+ * the original instruction in place */
|
|
+ kperr("the thread ran out: %d, rip = %llx, expected = %lx\n", pid,
|
|
+ regs.rip, pctx->execute_until);
|
|
+ errno = ESRCH;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ pctx->running = 0;
|
|
+
|
|
+ /* Restore thread registers, pctx is now valid */
|
|
+ kpdebug("Got thread %d at %llx\n", pctx->pid,
|
|
+ regs.rip - BREAK_INSN_LENGTH);
|
|
+
|
|
+ regs.rip = pctx->execute_until;
|
|
+
|
|
+ ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, ®s);
|
|
+ if (ret < 0) {
|
|
+ kplogerror("can't set regs - %d\n", pctx->pid);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h
|
|
index 7557e1f..1c7d33e 100644
|
|
--- a/src/include/kpatch_ptrace.h
|
|
+++ b/src/include/kpatch_ptrace.h
|
|
@@ -102,4 +102,24 @@ kpatch_process_memcpy(kpatch_process_t *proc,
|
|
unsigned long dst,
|
|
unsigned long src,
|
|
size_t size);
|
|
+
|
|
+#define BREAK_INSN_LENGTH 1
|
|
+#define BREAK_INSN {0xcc}
|
|
+
|
|
+#define SEC_TO_MSEC 1000
|
|
+#define MSEC_TO_NSEC 1000000
|
|
+
|
|
+#define for_each_thread(proc, pctx) \
|
|
+ list_for_each_entry(pctx, &proc->ptrace.pctxs, list)
|
|
+
|
|
+struct kpatch_ptrace_ctx *
|
|
+kpatch_ptrace_find_thread(kpatch_process_t *proc,
|
|
+ pid_t pid,
|
|
+ unsigned long rip);
|
|
+
|
|
+int
|
|
+kpatch_arch_ptrace_waitpid(kpatch_process_t *proc,
|
|
+ struct timespec *timeout,
|
|
+ const sigset_t *sigset);
|
|
+
|
|
#endif
|
|
diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c
|
|
index 8910aa8..3c57288 100644
|
|
--- a/src/kpatch_ptrace.c
|
|
+++ b/src/kpatch_ptrace.c
|
|
@@ -180,16 +180,8 @@ int kpatch_ptrace_get_entry_point(struct kpatch_ptrace_ctx *pctx,
|
|
return entry[0] == AT_ENTRY ? 0 : -1;
|
|
}
|
|
|
|
-#define BREAK_INSN_LENGTH 1
|
|
-#define BREAK_INSN {0xcc}
|
|
|
|
-#define SEC_TO_MSEC 1000
|
|
-#define MSEC_TO_NSEC 1000000
|
|
-
|
|
-#define for_each_thread(proc, pctx) \
|
|
- list_for_each_entry(pctx, &proc->ptrace.pctxs, list)
|
|
-
|
|
-static struct kpatch_ptrace_ctx *
|
|
+struct kpatch_ptrace_ctx *
|
|
kpatch_ptrace_find_thread(kpatch_process_t *proc,
|
|
pid_t pid,
|
|
unsigned long rip)
|
|
@@ -213,124 +205,6 @@ kpatch_ptrace_find_thread(kpatch_process_t *proc,
|
|
return NULL;
|
|
}
|
|
|
|
-static inline int
|
|
-kpatch_ptrace_waitpid(kpatch_process_t *proc,
|
|
- struct timespec *timeout,
|
|
- const sigset_t *sigset)
|
|
-{
|
|
- struct kpatch_ptrace_ctx *pctx;
|
|
- siginfo_t siginfo;
|
|
- int ret, status;
|
|
- pid_t pid;
|
|
- struct user_regs_struct regs;
|
|
-
|
|
- /* Immediately reap one attached thread */
|
|
- pid = waitpid(-1, &status, __WALL | WNOHANG);
|
|
-
|
|
- if (pid < 0) {
|
|
- kplogerror("can't wait for tracees\n");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- /* There is none ready, wait for notification via signal */
|
|
- if (pid == 0) {
|
|
- ret = sigtimedwait(sigset, &siginfo, timeout);
|
|
- if (ret == -1 && errno == EAGAIN) {
|
|
- /* We have timeouted */
|
|
- return -1;
|
|
- }
|
|
-
|
|
- if (ret == -1 && errno == EINVAL) {
|
|
- kperr("invalid timeout\n");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- /* We have got EINTR and must restart */
|
|
- if (ret == -1 && errno == EINTR)
|
|
- return 0;
|
|
-
|
|
- /**
|
|
- * Kernel stacks signals that follow too quickly.
|
|
- * Deal with it by waiting for any child, not just
|
|
- * one that is specified in signal
|
|
- */
|
|
- pid = waitpid(-1, &status, __WALL | WNOHANG);
|
|
-
|
|
- if (pid == 0) {
|
|
- kperr("missing waitpid for %d\n", siginfo.si_pid);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (pid < 0) {
|
|
- kplogerror("can't wait for tracee %d\n", siginfo.si_pid);
|
|
- return -1;
|
|
- }
|
|
- }
|
|
-
|
|
- if (!WIFSTOPPED(status) && WIFSIGNALED(status)) {
|
|
- /* Continue, resending the signal */
|
|
- ret = ptrace(PTRACE_CONT, pid, NULL,
|
|
- (void *)(uintptr_t)WTERMSIG(status));
|
|
- if (ret < 0) {
|
|
- kplogerror("can't start tracee %d\n", pid);
|
|
- return -1;
|
|
- }
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (WIFEXITED(status)) {
|
|
- pctx = kpatch_ptrace_find_thread(proc, pid, 0UL);
|
|
- if (pctx == NULL) {
|
|
- kperr("got unexpected child '%d' exit\n", pid);
|
|
- } else {
|
|
- /* It's dead */
|
|
- pctx->pid = pctx->running = 0;
|
|
- }
|
|
- return 1;
|
|
- }
|
|
-
|
|
- ret = ptrace(PTRACE_GETREGS, pid, NULL, ®s);
|
|
- if (ret < 0) {
|
|
- kplogerror("can't get regs %d\n", pid);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- pctx = kpatch_ptrace_find_thread(proc, pid, regs.rip);
|
|
-
|
|
- if (pctx == NULL) {
|
|
- /* We either don't know anything about this thread or
|
|
- * even worse -- we stopped it in the wrong place.
|
|
- * Bail out.
|
|
- */
|
|
- pctx = kpatch_ptrace_find_thread(proc, pid, 0);
|
|
- if (pctx != NULL)
|
|
- pctx->running = 0;
|
|
-
|
|
- /* TODO: fix the latter by SINGLESTEPping such a thread with
|
|
- * the original instruction in place */
|
|
- kperr("the thread ran out: %d, rip = %llx, expected = %lx\n", pid,
|
|
- regs.rip, pctx->execute_until);
|
|
- errno = ESRCH;
|
|
- return -1;
|
|
- }
|
|
-
|
|
- pctx->running = 0;
|
|
-
|
|
- /* Restore thread registers, pctx is now valid */
|
|
- kpdebug("Got thread %d at %llx\n", pctx->pid,
|
|
- regs.rip - BREAK_INSN_LENGTH);
|
|
-
|
|
- regs.rip = pctx->execute_until;
|
|
-
|
|
- ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, ®s);
|
|
- if (ret < 0) {
|
|
- kplogerror("can't set regs - %d\n", pctx->pid);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- return 1;
|
|
-}
|
|
-
|
|
struct breakpoint {
|
|
unsigned long addr;
|
|
unsigned char orig_code[BREAK_INSN_LENGTH];
|
|
@@ -441,7 +315,7 @@ kpatch_ptrace_execute_until(kpatch_process_t *proc,
|
|
break;
|
|
}
|
|
|
|
- rv = kpatch_ptrace_waitpid(proc, &timeout, &sigset);
|
|
+ rv = kpatch_arch_ptrace_waitpid(proc, &timeout, &sigset);
|
|
if (rv < 0)
|
|
break;
|
|
|
|
--
|
|
2.23.0
|
|
|