This small commit introduces a global state of system calls for ARM
making it possible for a debugger or checkpointing to gain information
about another process' state with respect to system calls.

The patch is based on this proposal from Roland McGrath:
https://patchwork.kernel.org/patch/32101/

Cc: Roland McGrath <[email protected]>
Signed-off-by: Christoffer Dall <[email protected]>
Acked-by: Oren Laadan <[email protected]>
---
 arch/arm/include/asm/syscall.h |   31 +++++++++++++++++++++++++++++++
 arch/arm/kernel/asm-offsets.c  |    1 +
 arch/arm/kernel/entry-common.S |    8 +++++++-
 arch/arm/kernel/ptrace.c       |    2 --
 arch/arm/kernel/signal.c       |   14 +++++++-------
 5 files changed, 46 insertions(+), 10 deletions(-)
 create mode 100644 arch/arm/include/asm/syscall.h

diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h
new file mode 100644
index 0000000..3b3248f
--- /dev/null
+++ b/arch/arm/include/asm/syscall.h
@@ -0,0 +1,31 @@
+/*
+ * syscalls.h - Linux syscall interfaces for ARM
+ *
+ * Copyright (c) 2010 Christoffer Dall
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#ifndef _ASM_ARM_SYSCALLS_H
+#define _ASM_ARM_SYSCALLS_H
+
+static inline int syscall_get_nr(struct task_struct *task,
+                                struct pt_regs *regs)
+{
+       return (int)(task_thread_info(task)->syscall);
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+                                           struct pt_regs *regs)
+{
+       return regs->ARM_r0;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+                                    struct pt_regs *regs)
+{
+       return regs->ARM_r0;
+}
+
+#endif /* _ASM_ARM_SYSCALLS_H */
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 4a88125..726a0ad 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -48,6 +48,7 @@ int main(void)
   DEFINE(TI_CPU,               offsetof(struct thread_info, cpu));
   DEFINE(TI_CPU_DOMAIN,                offsetof(struct thread_info, 
cpu_domain));
   DEFINE(TI_CPU_SAVE,          offsetof(struct thread_info, cpu_context));
+  DEFINE(TI_SYSCALL,           offsetof(struct thread_info, syscall));
   DEFINE(TI_USED_CP,           offsetof(struct thread_info, used_cp));
   DEFINE(TI_TP_VALUE,          offsetof(struct thread_info, tp_value));
   DEFINE(TI_FPSTATE,           offsetof(struct thread_info, fpstate));
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 2c1db77..f694f4d 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -30,6 +30,9 @@ ret_fast_syscall:
        tst     r1, #_TIF_WORK_MASK
        bne     fast_work_pending
 
+       mov     r2, #-1
+       str     r2, [tsk, #TI_SYSCALL]
+
        /* perform architecture specific actions before user return */
        arch_ret_to_user r1, lr
 
@@ -47,7 +50,6 @@ work_pending:
        tst     r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME
        beq     no_work_pending
        mov     r0, sp                          @ 'regs'
-       mov     r2, why                         @ 'syscall'
        bl      do_notify_resume
        b       ret_slow_syscall                @ Check work again
 
@@ -62,6 +64,9 @@ ret_slow_syscall:
        ldr     r1, [tsk, #TI_FLAGS]
        tst     r1, #_TIF_WORK_MASK
        bne     work_pending
+
+       mov     r2, #-1
+       str     r2, [tsk, #TI_SYSCALL]
 no_work_pending:
        /* perform architecture specific actions before user return */
        arch_ret_to_user r1, lr
@@ -274,6 +279,7 @@ ENTRY(vector_swi)
        eor     scno, scno, #__NR_SYSCALL_BASE  @ check OS number
 #endif
 
+       str     scno, [tsk, #TI_SYSCALL]        @ store syscall nr. globally
        stmdb   sp!, {r4, r5}                   @ push fifth and sixth args
        tst     ip, #_TIF_SYSCALL_TRACE         @ are we tracing syscalls?
        bne     __sys_trace
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index a2ea385..44ab437 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -863,8 +863,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, 
int scno)
        ip = regs->ARM_ip;
        regs->ARM_ip = why;
 
-       current_thread_info()->syscall = scno;
-
        /* the 0x80 provides a way for the tracing parent to distinguish
           between a syscall stop and SIGTRAP delivery */
        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index e7714f3..f695239 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -527,7 +527,7 @@ static inline void setup_syscall_restart(struct pt_regs 
*regs)
 static int
 handle_signal(unsigned long sig, struct k_sigaction *ka,
              siginfo_t *info, sigset_t *oldset,
-             struct pt_regs * regs, int syscall)
+             struct pt_regs *regs)
 {
        struct thread_info *thread = current_thread_info();
        struct task_struct *tsk = current;
@@ -537,7 +537,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        /*
         * If we were from a system call, check for system call restarting...
         */
-       if (syscall) {
+       if (thread->syscall != -1) {
                switch (regs->ARM_r0) {
                case -ERESTART_RESTARTBLOCK:
                case -ERESTARTNOHAND:
@@ -601,7 +601,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-static void do_signal(struct pt_regs *regs, int syscall)
+static void do_signal(struct pt_regs *regs)
 {
        struct k_sigaction ka;
        siginfo_t info;
@@ -629,7 +629,7 @@ static void do_signal(struct pt_regs *regs, int syscall)
                        oldset = &current->saved_sigmask;
                else
                        oldset = &current->blocked;
-               if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 
0) {
+               if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
                        /*
                         * A signal was successfully delivered; the saved
                         * sigmask will have been stored in the signal frame,
@@ -647,7 +647,7 @@ static void do_signal(struct pt_regs *regs, int syscall)
        /*
         * No signal to deliver to the process - restart the syscall.
         */
-       if (syscall) {
+       if (current_thread_info()->syscall != -1) {
                if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
                        if (thumb_mode(regs)) {
                                regs->ARM_r7 = __NR_restart_syscall - 
__NR_SYSCALL_BASE;
@@ -689,10 +689,10 @@ static void do_signal(struct pt_regs *regs, int syscall)
 }
 
 asmlinkage void
-do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
+do_notify_resume(struct pt_regs *regs, unsigned int thread_flags)
 {
        if (thread_flags & _TIF_SIGPENDING)
-               do_signal(regs, syscall);
+               do_signal(regs);
 
        if (thread_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
-- 
1.5.6.5

_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
[email protected]
https://openvz.org/mailman/listinfo/devel

Reply via email to