--- /dev/null
+From: Roland McGrath <roland@redhat.com>
+Date: Sun Apr 20 14:35:12 2008 -0700
+Subject: x86 tracehook
+References: FATE#304321
+Patch-mainline: no
+
+Apply the changes from x86-utrace branch of
+git://git.kernel.org/pub/scm/linux/kernel/git/frob/linux-2.6-utrace
+plus later cleanups.
+
+Signed-off-by: Roland McGrath <roland@redhat.com>
+Signed-off-by: Petr Tesarik <ptesarik@suse.cz>
+
+---
+ arch/x86/Kconfig | 1
+ arch/x86/kernel/ptrace.c | 34 +-----
+ arch/x86/kernel/signal_32.c | 11 +-
+ arch/x86/kernel/signal_64.c | 49 ++-------
+ include/asm-x86/ptrace.h | 5
+ include/asm-x86/syscall.h | 213 ++++++++++++++++++++++++++++++++++++++++++
+ include/asm-x86/thread_info.h | 4
+ 7 files changed, 251 insertions(+), 66 deletions(-)
+
+--- linux-2.6.27.orig/arch/x86/Kconfig 2008-10-20 11:46:16.000000000 +0200
++++ linux-2.6.27/arch/x86/Kconfig 2008-10-20 17:24:26.000000000 +0200
+@@ -29,6 +29,7 @@ config X86
+ select HAVE_FTRACE
+ select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
+ select HAVE_ARCH_KGDB if !X86_VOYAGER
++ select HAVE_ARCH_TRACEHOOK
+ select HAVE_GENERIC_DMA_COHERENT if X86_32
+ select HAVE_EFFICIENT_UNALIGNED_ACCESS
+
+--- linux-2.6.27.orig/arch/x86/kernel/ptrace.c 2008-10-20 11:46:16.000000000 +0200
++++ linux-2.6.27/arch/x86/kernel/ptrace.c 2008-10-20 11:46:16.000000000 +0200
+@@ -14,6 +14,7 @@
+ #include <linux/errno.h>
+ #include <linux/ptrace.h>
+ #include <linux/regset.h>
++#include <linux/tracehook.h>
+ #include <linux/user.h>
+ #include <linux/elf.h>
+ #include <linux/security.h>
+@@ -1375,30 +1376,6 @@ void send_sigtrap(struct task_struct *ts
+ force_sig_info(SIGTRAP, &info, tsk);
+ }
+
+-static void syscall_trace(struct pt_regs *regs)
+-{
+- if (!(current->ptrace & PT_PTRACED))
+- return;
+-
+-#if 0
+- printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
+- current->comm,
+- regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0),
+- current_thread_info()->flags, current->ptrace);
+-#endif
+-
+- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+- ? 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 (current->exit_code) {
+- send_sig(current->exit_code, current, 1);
+- current->exit_code = 0;
+- }
+-}
+
+ #ifdef CONFIG_X86_32
+ # define IS_IA32 1
+@@ -1443,8 +1420,9 @@ asmregparm long syscall_trace_enter(stru
+ if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
+ ret = -1L;
+
+- if (ret || test_thread_flag(TIF_SYSCALL_TRACE))
+- syscall_trace(regs);
++ if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
++ tracehook_report_syscall_entry(regs))
++ ret = -1L;
+
+ if (unlikely(current->audit_context)) {
+ if (IS_IA32)
+@@ -1473,7 +1451,7 @@ asmregparm void syscall_trace_leave(stru
+ audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+- syscall_trace(regs);
++ tracehook_report_syscall_exit(regs, 0);
+
+ /*
+ * If TIF_SYSCALL_EMU is set, we only get here because of
+@@ -1489,6 +1467,6 @@ asmregparm void syscall_trace_leave(stru
+ * system call instruction.
+ */
+ if (test_thread_flag(TIF_SINGLESTEP) &&
+- (current->ptrace & PT_PTRACED))
++ tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
+ send_sigtrap(current, regs, 0);
+ }
+--- linux-2.6.27.orig/arch/x86/kernel/signal_32.c 2008-10-20 11:46:16.000000000 +0200
++++ linux-2.6.27/arch/x86/kernel/signal_32.c 2008-10-20 11:46:16.000000000 +0200
+@@ -17,6 +17,7 @@
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+ #include <linux/wait.h>
++#include <linux/tracehook.h>
+ #include <linux/elf.h>
+ #include <linux/smp.h>
+ #include <linux/mm.h>
+@@ -558,8 +559,6 @@ handle_signal(unsigned long sig, siginfo
+ * handler too.
+ */
+ regs->flags &= ~X86_EFLAGS_TF;
+- if (test_thread_flag(TIF_SINGLESTEP))
+- ptrace_notify(SIGTRAP);
+
+ spin_lock_irq(¤t->sighand->siglock);
+ sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
+@@ -573,6 +572,9 @@ handle_signal(unsigned long sig, siginfo
+ current->instrumentation &= ~PTS_SELF;
+ }
+
++ tracehook_signal_handler(sig, info, ka, regs,
++ test_thread_flag(TIF_SINGLESTEP));
++
+ return 0;
+ }
+
+@@ -666,5 +668,10 @@ do_notify_resume(struct pt_regs *regs, v
+ if (thread_info_flags & _TIF_SIGPENDING)
+ do_signal(regs);
+
++ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
++ clear_thread_flag(TIF_NOTIFY_RESUME);
++ tracehook_notify_resume(regs);
++ }
++
+ clear_thread_flag(TIF_IRET);
+ }
+--- linux-2.6.27.orig/arch/x86/kernel/signal_64.c 2008-10-20 11:46:16.000000000 +0200
++++ linux-2.6.27/arch/x86/kernel/signal_64.c 2008-10-20 11:46:16.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/errno.h>
+ #include <linux/wait.h>
+ #include <linux/ptrace.h>
++#include <linux/tracehook.h>
+ #include <linux/unistd.h>
+ #include <linux/stddef.h>
+ #include <linux/personality.h>
+@@ -26,6 +27,7 @@
+ #include <asm/proto.h>
+ #include <asm/ia32_unistd.h>
+ #include <asm/mce.h>
++#include <asm/syscall.h>
+ #include "sigframe.h"
+
+ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+@@ -355,35 +357,6 @@ give_sigsegv:
+ }
+
+ /*
+- * Return -1L or the syscall number that @regs is executing.
+- */
+-static long current_syscall(struct pt_regs *regs)
+-{
+- /*
+- * We always sign-extend a -1 value being set here,
+- * so this is always either -1L or a syscall number.
+- */
+- return regs->orig_ax;
+-}
+-
+-/*
+- * Return a value that is -EFOO if the system call in @regs->orig_ax
+- * returned an error. This only works for @regs from @current.
+- */
+-static long current_syscall_ret(struct pt_regs *regs)
+-{
+-#ifdef CONFIG_IA32_EMULATION
+- if (test_thread_flag(TIF_IA32))
+- /*
+- * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
+- * and will match correctly in comparisons.
+- */
+- return (int) regs->ax;
+-#endif
+- return regs->ax;
+-}
+-
+-/*
+ * OK, we're invoking a handler
+ */
+
+@@ -394,9 +367,9 @@ handle_signal(unsigned long sig, siginfo
+ int ret;
+
+ /* Are we from a system call? */
+- if (current_syscall(regs) >= 0) {
++ if (syscall_get_nr(current, regs) >= 0) {
+ /* If so, check system call restarting.. */
+- switch (current_syscall_ret(regs)) {
++ switch (syscall_get_error(current, regs)) {
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ regs->ax = -EINTR;
+@@ -453,8 +426,6 @@ handle_signal(unsigned long sig, siginfo
+ * handler too.
+ */
+ regs->flags &= ~X86_EFLAGS_TF;
+- if (test_thread_flag(TIF_SINGLESTEP))
+- ptrace_notify(SIGTRAP);
+
+ spin_lock_irq(¤t->sighand->siglock);
+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+@@ -462,6 +433,9 @@ handle_signal(unsigned long sig, siginfo
+ sigaddset(¤t->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
++
++ tracehook_signal_handler(sig, info, ka, regs,
++ test_thread_flag(TIF_SINGLESTEP));
+ }
+
+ if (current->instrumentation & PTS_SELF) {
+@@ -523,9 +497,9 @@ static void do_signal(struct pt_regs *re
+ }
+
+ /* Did we come from a system call? */
+- if (current_syscall(regs) >= 0) {
++ if (syscall_get_nr(current, regs) >= 0) {
+ /* Restart the system call - no handlers present */
+- switch (current_syscall_ret(regs)) {
++ switch (syscall_get_error(current, regs)) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+@@ -563,6 +537,11 @@ void do_notify_resume(struct pt_regs *re
+ /* deal with pending signal delivery */
+ if (thread_info_flags & _TIF_SIGPENDING)
+ do_signal(regs);
++
++ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
++ clear_thread_flag(TIF_NOTIFY_RESUME);
++ tracehook_notify_resume(regs);
++ }
+ }
+
+ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+--- linux-2.6.27.orig/include/asm-x86/ptrace.h 2008-10-10 00:13:53.000000000 +0200
++++ linux-2.6.27/include/asm-x86/ptrace.h 2008-10-20 17:23:29.000000000 +0200
+@@ -213,6 +213,11 @@ static inline unsigned long frame_pointe
+ return regs->bp;
+ }
+
++static inline unsigned long user_stack_pointer(struct pt_regs *regs)
++{
++ return regs->sp;
++}
++
+ /*
+ * These are defined as per linux/ptrace.h, which see.
+ */
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.27/include/asm-x86/syscall.h 2008-10-20 17:32:17.000000000 +0200
+@@ -0,0 +1,213 @@
++/*
++ * Access to user system call parameters and results
++ *
++ * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
++ *
++ * This copyrighted material is made available to anyone wishing to use,
++ * modify, copy, or redistribute it subject to the terms and conditions
++ * of the GNU General Public License v.2.
++ *
++ * See asm-generic/syscall.h for descriptions of what we must do here.
++ */
++
++#ifndef _ASM_SYSCALL_H
++#define _ASM_SYSCALL_H 1
++
++#include <linux/sched.h>
++#include <linux/err.h>
++
++static inline long syscall_get_nr(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ /*
++ * We always sign-extend a -1 value being set here,
++ * so this is always either -1L or a syscall number.
++ */
++ return regs->orig_ax;
++}
++
++static inline void syscall_rollback(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ regs->ax = regs->orig_ax;
++}
++
++static inline long syscall_get_error(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ unsigned long error = regs->ax;
++#ifdef CONFIG_IA32_EMULATION
++ /*
++ * TS_COMPAT is set for 32-bit syscall entries and then
++ * remains set until we return to user mode.
++ */
++ if (task_thread_info(task)->status & TS_COMPAT)
++ /*
++ * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
++ * and will match correctly in comparisons.
++ */
++ error = (long) (int) error;
++#endif
++ return IS_ERR_VALUE(error) ? error : 0;
++}
++
++static inline long syscall_get_return_value(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ return regs->ax;
++}
++
++static inline void syscall_set_return_value(struct task_struct *task,
++ struct pt_regs *regs,
++ int error, long val)
++{
++ regs->ax = (long) error ?: val;
++}
++
++#ifdef CONFIG_X86_32
++
++static inline void syscall_get_arguments(struct task_struct *task,
++ struct pt_regs *regs,
++ unsigned int i, unsigned int n,
++ unsigned long *args)
++{
++ BUG_ON(i + n > 6);
++ memcpy(args, ®s->bx + i, n * sizeof(args[0]));
++}
++
++static inline void syscall_set_arguments(struct task_struct *task,
++ struct pt_regs *regs,
++ unsigned int i, unsigned int n,
++ const unsigned long *args)
++{
++ BUG_ON(i + n > 6);
++ memcpy(®s->bx + i, args, n * sizeof(args[0]));
++}
++
++#else /* CONFIG_X86_64 */
++
++static inline void syscall_get_arguments(struct task_struct *task,
++ struct pt_regs *regs,
++ unsigned int i, unsigned int n,
++ unsigned long *args)
++{
++# ifdef CONFIG_IA32_EMULATION
++ if (task_thread_info(task)->status & TS_COMPAT)
++ switch (i) {
++ case 0:
++ if (!n--) break;
++ *args++ = regs->bx;
++ case 1:
++ if (!n--) break;
++ *args++ = regs->cx;
++ case 2:
++ if (!n--) break;
++ *args++ = regs->dx;
++ case 3:
++ if (!n--) break;
++ *args++ = regs->si;
++ case 4:
++ if (!n--) break;
++ *args++ = regs->di;
++ case 5:
++ if (!n--) break;
++ *args++ = regs->bp;
++ case 6:
++ if (!n--) break;
++ default:
++ BUG();
++ break;
++ }
++ else
++# endif
++ switch (i) {
++ case 0:
++ if (!n--) break;
++ *args++ = regs->di;
++ case 1:
++ if (!n--) break;
++ *args++ = regs->si;
++ case 2:
++ if (!n--) break;
++ *args++ = regs->dx;
++ case 3:
++ if (!n--) break;
++ *args++ = regs->r10;
++ case 4:
++ if (!n--) break;
++ *args++ = regs->r8;
++ case 5:
++ if (!n--) break;
++ *args++ = regs->r9;
++ case 6:
++ if (!n--) break;
++ default:
++ BUG();
++ break;
++ }
++}
++
++static inline void syscall_set_arguments(struct task_struct *task,
++ struct pt_regs *regs,
++ unsigned int i, unsigned int n,
++ const unsigned long *args)
++{
++# ifdef CONFIG_IA32_EMULATION
++ if (task_thread_info(task)->status & TS_COMPAT)
++ switch (i) {
++ case 0:
++ if (!n--) break;
++ regs->bx = *args++;
++ case 1:
++ if (!n--) break;
++ regs->cx = *args++;
++ case 2:
++ if (!n--) break;
++ regs->dx = *args++;
++ case 3:
++ if (!n--) break;
++ regs->si = *args++;
++ case 4:
++ if (!n--) break;
++ regs->di = *args++;
++ case 5:
++ if (!n--) break;
++ regs->bp = *args++;
++ case 6:
++ if (!n--) break;
++ default:
++ BUG();
++ break;
++ }
++ else
++# endif
++ switch (i) {
++ case 0:
++ if (!n--) break;
++ regs->di = *args++;
++ case 1:
++ if (!n--) break;
++ regs->si = *args++;
++ case 2:
++ if (!n--) break;
++ regs->dx = *args++;
++ case 3:
++ if (!n--) break;
++ regs->r10 = *args++;
++ case 4:
++ if (!n--) break;
++ regs->r8 = *args++;
++ case 5:
++ if (!n--) break;
++ regs->r9 = *args++;
++ case 6:
++ if (!n--) break;
++ default:
++ BUG();
++ break;
++ }
++}
++
++#endif /* CONFIG_X86_32 */
++
++#endif /* _ASM_SYSCALL_H */
+--- linux-2.6.27.orig/include/asm-x86/thread_info.h 2008-10-10 00:13:53.000000000 +0200
++++ linux-2.6.27/include/asm-x86/thread_info.h 2008-10-20 17:23:10.000000000 +0200
+@@ -71,6 +71,7 @@ struct thread_info {
+ * Warning: layout of LSW is hardcoded in entry.S
+ */
+ #define TIF_SYSCALL_TRACE 0 /* syscall trace active */
++#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
+ #define TIF_SIGPENDING 2 /* signal pending */
+ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+ #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/
+@@ -93,6 +94,7 @@ struct thread_info {
+ #define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */
+
+ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
++#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
+ #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
+ #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+@@ -133,7 +135,7 @@ struct thread_info {
+
+ /* Only used for 64 bit */
+ #define _TIF_DO_NOTIFY_MASK \
+- (_TIF_SIGPENDING|_TIF_MCE_NOTIFY)
++ (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME)
+
+ /* flags to check in __switch_to() */
+ #define _TIF_WORK_CTXSW \