#define TIF_SINGLESTEP         4       /* singlestepping active */
 #define TIF_SYSCALL_AUDIT      5       /* syscall auditing active */
 #define TIF_SECCOMP            6       /* secure computing */
+#define TIF_NOTIFY_RESUME      7       /* callback before returning to user */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE             18
-#define TIF_FREEZE             19
+#define TIF_FREEZE             19      /* Freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1 << TIF_SECCOMP)
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_USEDFPU           (1 << TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_FREEZE            (1 << TIF_FREEZE)
                                 _TIF_SYSCALL_AUDIT | _TIF_SECCOMP)
 
 /* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK      (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING    | \
-                                _TIF_NEED_RESCHED  | _TIF_SYSCALL_AUDIT | \
-                                _TIF_SINGLESTEP    | _TIF_RESTORE_SIGMASK)
+#define _TIF_ALLWORK_MASK      (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING      | \
+                                _TIF_NEED_RESCHED  | _TIF_SYSCALL_AUDIT   | \
+                                _TIF_SINGLESTEP    | _TIF_RESTORE_SIGMASK | \
+                                _TIF_NOTIFY_RESUME)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK         (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
 
 work_notifysig:
        gettr   tr1, LINK
 
-       movi    do_signal, r6
+       movi    do_notify_resume, r6
        ptabs   r6, tr0
        or      SP, ZERO, r2
-       or      ZERO, ZERO, r3
-       blink   tr0, LINK           /* Call do_signal(regs, 0), return here */
+       or      r7, ZERO, r3
+       blink   tr0, LINK           /* Call do_notify_resume(regs, current_thread_info->flags), return here */
 
 restore_all:
        /* Do prefetches */
        beq/l   r6, ZERO, tr0
 
        /* Trace it by calling syscall_trace before and after */
-       movi    syscall_trace, r4
+       movi    do_syscall_trace_enter, r4
        or      SP, ZERO, r2
-       or      ZERO, ZERO, r3
        ptabs   r4, tr0
        blink   tr0, LINK
 
-       /* Reload syscall number as r5 is trashed by syscall_trace */
+       /* Save the retval */
+       st.q    SP, FRAME_R(2), r2
+
+       /* Reload syscall number as r5 is trashed by do_syscall_trace_enter */
        ld.q    SP, FRAME_S(FSYSCALL_ID), r5
        andi    r5, 0x1ff, r5
 
        /* We get back here only if under trace */
        st.q    SP, FRAME_R(9), r2      /* Save return value */
 
-       movi    syscall_trace, LINK
+       movi    do_syscall_trace_leave, LINK
        or      SP, ZERO, r2
-       movi    1, r3
        ptabs   LINK, tr0
        blink   tr0, LINK
 
 
         nop
 #endif
        sti
-       ! XXX setup arguments...
        mov     r15, r4
-       mov     #1, r5
-       mov.l   4f, r0                  ! do_syscall_trace
+       mov.l   8f, r0                  ! do_syscall_trace_leave
        jsr     @r0
         nop
        bra     resume_userspace
        .align  2
 syscall_trace_entry:
        !                       Yes it is traced.
-       ! XXX setup arguments...
        mov     r15, r4
-       mov     #0, r5
-       mov.l   4f, r11         ! Call do_syscall_trace which notifies
+       mov.l   7f, r11         ! Call do_syscall_trace_enter which notifies
        jsr     @r11            ! superior (will chomp R[0-7])
         nop
+       mov.l   r0, @(OFF_R0,r15)       ! Save return value
        !                       Reload R0-R4 from kernel stack, where the
        !                       parent may have modified them using
        !                       ptrace(POKEUSR).  (Note that R0-R2 are
 #endif
 2:     .long   NR_syscalls
 3:     .long   sys_call_table
-4:     .long   do_syscall_trace
 #ifdef CONFIG_TRACE_IRQFLAGS
 5:     .long   trace_hardirqs_on
 6:     .long   trace_hardirqs_off
 #endif
+7:     .long   do_syscall_trace_enter
+8:     .long   do_syscall_trace_leave
 
 #include <linux/io.h>
 #include <linux/audit.h>
 #include <linux/seccomp.h>
+#include <linux/tracehook.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
        return ret;
 }
 
-asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
-       struct task_struct *tsk = current;
+       long ret = 0;
 
        secure_computing(regs->regs[0]);
 
-       if (unlikely(current->audit_context) && entryexit)
-               audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
-                                  regs->regs[0]);
-
-       if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
-           !test_thread_flag(TIF_SINGLESTEP))
-               goto out;
-       if (!(tsk->ptrace & PT_PTRACED))
-               goto out;
-
-       /* 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) &&
-                                !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
-
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (tsk->exit_code) {
-               send_sig(tsk->exit_code, tsk, 1);
-               tsk->exit_code = 0;
-       }
+       if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+           tracehook_report_syscall_entry(regs))
+               /*
+                * Tracing decided this syscall should not happen.
+                * We'll return a bogus call number to get an ENOSYS
+                * error, but leave the original number in regs->regs[0].
+                */
+               ret = -1L;
 
-out:
-       if (unlikely(current->audit_context) && !entryexit)
+       if (unlikely(current->audit_context))
                audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[3],
                                    regs->regs[4], regs->regs[5],
                                    regs->regs[6], regs->regs[7]);
 
+       return ret ?: regs->regs[0];
+}
+
+asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
+{
+       int step;
+
+       if (unlikely(current->audit_context))
+               audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
+                                  regs->regs[0]);
+
+       step = test_thread_flag(TIF_SINGLESTEP);
+       if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, step);
 }
 
 #include <linux/syscalls.h>
 #include <linux/audit.h>
 #include <linux/seccomp.h>
+#include <linux/tracehook.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
        return sys_ptrace(request, pid, addr, data);
 }
 
-asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs)
 {
-       struct task_struct *tsk = current;
+       long long ret = 0;
 
        secure_computing(regs->regs[9]);
 
-       if (unlikely(current->audit_context) && entryexit)
-               audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
-                                  regs->regs[9]);
-
-       if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
-           !test_thread_flag(TIF_SINGLESTEP))
-               goto out;
-       if (!(tsk->ptrace & PT_PTRACED))
-               goto out;
-
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
-                               !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
-
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (tsk->exit_code) {
-               send_sig(tsk->exit_code, tsk, 1);
-               tsk->exit_code = 0;
-       }
+       if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+           tracehook_report_syscall_entry(regs))
+               /*
+                * Tracing decided this syscall should not happen.
+                * We'll return a bogus call number to get an ENOSYS
+                * error, but leave the original number in regs->regs[0].
+                */
+               ret = -1LL;
 
-out:
-       if (unlikely(current->audit_context) && !entryexit)
+       if (unlikely(current->audit_context))
                audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[1],
                                    regs->regs[2], regs->regs[3],
                                    regs->regs[4], regs->regs[5]);
+
+       return ret ?: regs->regs[9];
+}
+
+asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
+{
+       if (unlikely(current->audit_context))
+               audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
+                                  regs->regs[9]);
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, 0);
 }
 
 /* Called with interrupts disabled */
 
 #include <linux/binfmts.h>
 #include <linux/freezer.h>
 #include <linux/io.h>
+#include <linux/tracehook.h>
 #include <asm/system.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
                switch (regs->regs[0]) {
                        case -ERESTART_RESTARTBLOCK:
                        case -ERESTARTNOHAND:
+                       no_system_call_restart:
                                regs->regs[0] = -EINTR;
                                break;
 
                        case -ERESTARTSYS:
-                               if (!(ka->sa.sa_flags & SA_RESTART)) {
-                                       regs->regs[0] = -EINTR;
-                                       break;
-                               }
+                               if (!(ka->sa.sa_flags & SA_RESTART))
+                                       goto no_system_call_restart;
                        /* fallthrough */
                        case -ERESTARTNOINTR:
                                regs->regs[0] = save_r0;
                         * clear the TIF_RESTORE_SIGMASK flag */
                        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                                clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+                       tracehook_signal_handler(signr, &info, &ka, regs,
+                                       test_thread_flag(TIF_SINGLESTEP));
                }
 
                return;
        }
 
- no_signal:
+no_signal:
        /* Did we come from a system call? */
        if (regs->tra >= 0) {
                /* Restart the system call - no handlers present */
 }
 
 asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
-                                __u32 thread_info_flags)
+                                unsigned long thread_info_flags)
 {
        /* deal with pending signal delivery */
-       if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+       if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs, save_r0);
+
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+       }
 }
 
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+static int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+       siginfo_t info;
+       int signr;
+       struct k_sigaction ka;
+
+       /*
+        * We want the common case to go fast, which
+        * is why we may in certain cases get here from
+        * kernel mode. Just return without doing anything
+        * if so.
+        */
+       if (!user_mode(regs))
+               return 1;
+
+       if (try_to_freeze())
+               goto no_signal;
+
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = ¤t->saved_sigmask;
+       else if (!oldset)
+               oldset = ¤t->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, 0);
+
+       if (signr > 0) {
+               /* Whee!  Actually deliver the signal.  */
+               handle_signal(signr, &info, &ka, oldset, regs);
+
+               /*
+                * If a signal was successfully delivered, the saved sigmask
+                * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
+                * flag.
+                */
+               if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                       clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+               tracehook_signal_handler(signr, &info, &ka, regs, 0);
+               return 1;
+       }
+
+no_signal:
+       /* Did we come from a system call? */
+       if (regs->syscall_nr >= 0) {
+               /* Restart the system call - no handlers present */
+               switch (regs->regs[REG_RET]) {
+               case -ERESTARTNOHAND:
+               case -ERESTARTSYS:
+               case -ERESTARTNOINTR:
+                       /* Decode Syscall # */
+                       regs->regs[REG_RET] = regs->syscall_nr;
+                       regs->pc -= 4;
+                       break;
+
+               case -ERESTART_RESTARTBLOCK:
+                       regs->regs[REG_RET] = __NR_restart_syscall;
+                       regs->pc -= 4;
+                       break;
+               }
+       }
+
+       /* No signal to deliver -- put the saved sigmask back */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
+       }
+
+       return 0;
+}
 
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
                switch (regs->regs[REG_RET]) {
                        case -ERESTART_RESTARTBLOCK:
                        case -ERESTARTNOHAND:
+                       no_system_call_restart:
                                regs->regs[REG_RET] = -EINTR;
                                break;
 
                        case -ERESTARTSYS:
-                               if (!(ka->sa.sa_flags & SA_RESTART)) {
-                                       regs->regs[REG_RET] = -EINTR;
-                                       break;
-                               }
+                               if (!(ka->sa.sa_flags & SA_RESTART))
+                                       goto no_system_call_restart;
                        /* fallthrough */
                        case -ERESTARTNOINTR:
                                /* Decode syscall # */
        spin_unlock_irq(¤t->sighand->siglock);
 }
 
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- *
- * Note that we go through the signals twice: once to check the signals that
- * the kernel can handle, and then we build all the user-level signal handling
- * stack-frames in one go after that.
- */
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
 {
-       siginfo_t info;
-       int signr;
-       struct k_sigaction ka;
-
-       /*
-        * We want the common case to go fast, which
-        * is why we may in certain cases get here from
-        * kernel mode. Just return without doing anything
-        * if so.
-        */
-       if (!user_mode(regs))
-               return 1;
-
-       if (try_to_freeze())
-               goto no_signal;
-
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
-               oldset = ¤t->saved_sigmask;
-       else if (!oldset)
-               oldset = ¤t->blocked;
-
-       signr = get_signal_to_deliver(&info, &ka, regs, 0);
-
-       if (signr > 0) {
-               /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &info, &ka, oldset, regs);
+       if (thread_info_flags & _TIF_SIGPENDING)
+               do_signal(regs, 0);
 
-               /*
-                * If a signal was successfully delivered, the saved sigmask
-                * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
-                * flag.
-                */
-               if (test_thread_flag(TIF_RESTORE_SIGMASK))
-                       clear_thread_flag(TIF_RESTORE_SIGMASK);
-
-               return 1;
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
        }
-
-no_signal:
-       /* Did we come from a system call? */
-       if (regs->syscall_nr >= 0) {
-               /* Restart the system call - no handlers present */
-               switch (regs->regs[REG_RET]) {
-               case -ERESTARTNOHAND:
-               case -ERESTARTSYS:
-               case -ERESTARTNOINTR:
-                       /* Decode Syscall # */
-                       regs->regs[REG_RET] = regs->syscall_nr;
-                       regs->pc -= 4;
-                       break;
-
-               case -ERESTART_RESTARTBLOCK:
-                       regs->regs[REG_RET] = __NR_restart_syscall;
-                       regs->pc -= 4;
-                       break;
-               }
-       }
-
-       /* No signal to deliver -- put the saved sigmask back */
-       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-               clear_thread_flag(TIF_RESTORE_SIGMASK);
-               sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
-       }
-
-       return 0;
 }