rpms/kernel/FC-6 linux-2.6-libata-restore-combined-mode.patch, NONE, 1.1 linux-2.6-utrace-core.patch, 1.2, 1.3 linux-2.6-utrace-ptrace-compat-avr32.patch, NONE, 1.1 linux-2.6-utrace-ptrace-compat-ia64.patch, NONE, 1.1 linux-2.6-utrace-ptrace-compat-s390.patch, NONE, 1.1 linux-2.6-utrace-ptrace-compat-sparc64.patch, 1.2, 1.3 linux-2.6-utrace-ptrace-compat.patch, 1.3, 1.4 linux-2.6-utrace-regset-avr32.patch, NONE, 1.1 linux-2.6-utrace-regset-ia64.patch, NONE, 1.1 linux-2.6-utrace-regset-s390.patch, NONE, 1.1 linux-2.6-utrace-regset-sparc64.patch, 1.2, 1.3 linux-2.6-utrace-regset.patch, 1.2, 1.3 linux-2.6-utrace-tracehook-avr32.patch, NONE, 1.1 linux-2.6-utrace-tracehook-ia64.patch, NONE, 1.1 linux-2.6-utrace-tracehook-s390.patch, NONE, 1.1 linux-2.6-utrace-tracehook-sparc64.patch, 1.2, 1.3 linux-2.6-utrace-tracehook-um.patch, 1.2, 1.3 linux-2.6-utrace-tracehook.patch, 1.2, 1.3 kernel-2.6.spec, 1.2991, 1.2992

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Thu Jul 19 17:46:38 UTC 2007


Author: cebbert

Update of /cvs/dist/rpms/kernel/FC-6
In directory cvs.devel.redhat.com:/tmp/cvs-serv6823

Modified Files:
	kernel-2.6.spec 
Added Files:
	linux-2.6-libata-restore-combined-mode.patch 
	linux-2.6-utrace-core.patch 
	linux-2.6-utrace-ptrace-compat-avr32.patch 
	linux-2.6-utrace-ptrace-compat-ia64.patch 
	linux-2.6-utrace-ptrace-compat-s390.patch 
	linux-2.6-utrace-ptrace-compat-sparc64.patch 
	linux-2.6-utrace-ptrace-compat.patch 
	linux-2.6-utrace-regset-avr32.patch 
	linux-2.6-utrace-regset-ia64.patch 
	linux-2.6-utrace-regset-s390.patch 
	linux-2.6-utrace-regset-sparc64.patch 
	linux-2.6-utrace-regset.patch 
	linux-2.6-utrace-tracehook-avr32.patch 
	linux-2.6-utrace-tracehook-ia64.patch 
	linux-2.6-utrace-tracehook-s390.patch 
	linux-2.6-utrace-tracehook-sparc64.patch 
	linux-2.6-utrace-tracehook-um.patch 
	linux-2.6-utrace-tracehook.patch 
Log Message:
* Thu Jul 19 2007 Chuck Ebbert <cebbert at redhat.com>
- restore the libata COMBINED_MODE hacks
- set CONFIG_NF_CONNTRACK_PROC_COMPAT
- restore the old firewire stack
- new utrace backport


linux-2.6-libata-restore-combined-mode.patch:
 drivers/ata/Kconfig      |    5 ++
 drivers/ata/libata-sff.c |   20 +++++---
 drivers/pci/quirks.c     |  113 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/ioport.h   |    1 
 kernel/resource.c        |   21 ++++++++
 5 files changed, 154 insertions(+), 6 deletions(-)

--- NEW FILE linux-2.6-libata-restore-combined-mode.patch ---
Restore the combined_mode hacks for libata/ide.

---
 drivers/ata/Kconfig      |    5 ++
 drivers/ata/libata-sff.c |   20 +++++---
 drivers/pci/quirks.c     |  113 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/ioport.h   |    1 
 kernel/resource.c        |   21 ++++++++
 5 files changed, 154 insertions(+), 6 deletions(-)

--- linux-2.6.22.noarch.orig/drivers/ata/Kconfig
+++ linux-2.6.22.noarch/drivers/ata/Kconfig
@@ -27,6 +27,11 @@ config ATA_NONSTANDARD
        bool
        default n
 
+config SATA_INTEL_COMBINED
+	bool
+	depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
+	default y
+
 config ATA_ACPI
 	bool
 	depends on ACPI && PCI
--- linux-2.6.22.noarch.orig/drivers/ata/libata-sff.c
+++ linux-2.6.22.noarch/drivers/ata/libata-sff.c
@@ -791,13 +791,21 @@ static int ata_init_legacy_port(struct a
 	}
 
 	/* request cmd_port */
-	if (request_region(cmd_port, 8, "libata"))
-		legacy_dr->cmd_port[port_no] = cmd_port;
-	else {
-		dev_printk(KERN_WARNING, host->dev,
-			   "0x%0lX IDE port busy\n", cmd_port);
-		return -EBUSY;
+	if (!request_region(cmd_port, 8, "libata")) {
+		struct resource *conflict, res;
+		res.start = cmd_port
+		res.end = res.start + 8 - 1;
+		conflict = ____request_resource(&ioport_resource, &res);
+		while (conflict->child)
+			conflict = ____request_resource(conflict, &res);
+		if (strcmp(conflict->name, "libata"))
+			dev_printk(KERN_WARNING, host->dev,
+				   "0x%0lX IDE port busy -- conflict with %s\n",
+				   cmd_port, conflict->name);
+			return -EBUSY;
+		}
 	}
+	legacy_dr->cmd_port[port_no] = cmd_port;
 
 	/* iomap cmd and ctl ports */
 	legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
--- linux-2.6.22.noarch.orig/drivers/pci/quirks.c
+++ linux-2.6.22.noarch/drivers/pci/quirks.c
@@ -1304,6 +1304,119 @@ static void __init quirk_alder_ioapic(st
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_EESSC,	quirk_alder_ioapic );
 #endif
 
+enum ide_combined_type { COMBINED = 0, IDE = 1, LIBATA = 2 };
+/* Defaults to combined */
+static enum ide_combined_type combined_mode;
+
+static int __init combined_setup(char *str)
+{
+	if (!strncmp(str, "ide", 3))
+		combined_mode = IDE;
+	else if (!strncmp(str, "libata", 6))
+		combined_mode = LIBATA;
+	else /* "combined" or anything else defaults to old behavior */
+		combined_mode = COMBINED;
+
+	return 1;
+}
+__setup("combined_mode=", combined_setup);
+
+#ifdef CONFIG_SATA_INTEL_COMBINED
+static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
+{
+	u8 prog, comb, tmp;
+	int ich = 0;
+
+	/*
+	 * Narrow down to Intel SATA PCI devices.
+	 */
+	switch (pdev->device) {
+	/* PCI ids taken from drivers/scsi/ata_piix.c */
+	case 0x24d1:
+	case 0x24df:
+	case 0x25a3:
+	case 0x25b0:
+		ich = 5;
+		break;
+	case 0x2651:
+	case 0x2652:
+	case 0x2653:
+	case 0x2680:	/* ESB2 */
+		ich = 6;
+		break;
+	case 0x27c0:
+	case 0x27c4:
+		ich = 7;
+		break;
+	case 0x2828:	/* ICH8M */
+		ich = 8;
+		break;
+	default:
+		/* we do not handle this PCI device */
+		return;
+	}
+
+	/*
+	 * Read combined mode register.
+	 */
+	pci_read_config_byte(pdev, 0x90, &tmp);	/* combined mode reg */
+
+	if (ich == 5) {
+		tmp &= 0x6;  /* interesting bits 2:1, PATA primary/secondary */
+		if (tmp == 0x4)		/* bits 10x */
+			comb = (1 << 0);	/* SATA port 0, PATA port 1 */
+		else if (tmp == 0x6)	/* bits 11x */
+			comb = (1 << 2);	/* PATA port 0, SATA port 1 */
+		else
+			return;			/* not in combined mode */
+	} else {
+		WARN_ON((ich != 6) && (ich != 7) && (ich != 8));
+		tmp &= 0x3;  /* interesting bits 1:0 */
+		if (tmp & (1 << 0))
+			comb = (1 << 2);	/* PATA port 0, SATA port 1 */
+		else if (tmp & (1 << 1))
+			comb = (1 << 0);	/* SATA port 0, PATA port 1 */
+		else
+			return;			/* not in combined mode */
+	}
+
+	/*
+	 * Read programming interface register.
+	 * (Tells us if it's legacy or native mode)
+	 */
+	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+
+	/* if SATA port is in native mode, we're ok. */
+	if (prog & comb)
+		return;
+
+	/* Don't reserve any so the IDE driver can get them (but only if
+	 * combined_mode=ide).
+	 */
+	if (combined_mode == IDE)
+		return;
+
+	/* Grab them both for libata if combined_mode=libata. */
+	if (combined_mode == LIBATA) {
+		request_region(0x1f0, 8, "libata");	/* port 0 */
+		request_region(0x170, 8, "libata");	/* port 1 */
+		return;
+	}
+
+	/* SATA port is in legacy mode.  Reserve port so that
+	 * IDE driver does not attempt to use it.  If request_region
+	 * fails, it will be obvious at boot time, so we don't bother
+	 * checking return values.
+	 */
+	if (comb == (1 << 0))
+		request_region(0x1f0, 8, "libata");	/* port 0 */
+	else
+		request_region(0x170, 8, "libata");	/* port 1 */
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_ANY_ID,	  quirk_intel_ide_combined );
+#endif /* CONFIG_SATA_INTEL_COMBINED */
+
+
 int pcie_mch_quirk;
 EXPORT_SYMBOL(pcie_mch_quirk);
 
--- linux-2.6.22.noarch.orig/include/linux/ioport.h
+++ linux-2.6.22.noarch/include/linux/ioport.h
@@ -99,6 +99,7 @@ extern struct resource ioport_resource;
 extern struct resource iomem_resource;
 
 extern int request_resource(struct resource *root, struct resource *new);
+extern struct resource * ____request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
 extern int insert_resource(struct resource *parent, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
--- linux-2.6.22.noarch.orig/kernel/resource.c
+++ linux-2.6.22.noarch/kernel/resource.c
@@ -213,6 +213,27 @@ int request_resource(struct resource *ro
 EXPORT_SYMBOL(request_resource);
 
 /**
+ * ____request_resource - reserve a resource, with resource conflict returned
+ * @root: root resource descriptor
+ * @new: resource descriptor desired by caller
+ *
+ * Returns:
+ * On success, NULL is returned.
+ * On error, a pointer to the conflicting resource is returned.
+ */
+struct resource *____request_resource(struct resource *root, struct resource *new)
+{
+	struct resource *conflict;
+
+	write_lock(&resource_lock);
+	conflict = __request_resource(root, new);
+	write_unlock(&resource_lock);
+	return conflict;
+}
+
+EXPORT_SYMBOL(____request_resource);
+
+/**
  * release_resource - release a previously reserved resource
  * @old: resource pointer
  */

linux-2.6-utrace-core.patch:
 Documentation/DocBook/Makefile    |    2 
 Documentation/DocBook/utrace.tmpl |   23 
 Documentation/utrace.txt          |  579 +++++++++
 include/linux/sched.h             |    5 
 include/linux/tracehook.h         |   85 +
 include/linux/utrace.h            |  544 +++++++++
 init/Kconfig                      |   18 
 kernel/Makefile                   |    1 
 kernel/utrace.c                   | 2263 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 3502 insertions(+), 18 deletions(-)

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.2 -r 1.3 linux-2.6-utrace-core.patch
Index: linux-2.6-utrace-core.patch
===================================================================
RCS file: linux-2.6-utrace-core.patch
diff -N linux-2.6-utrace-core.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-core.patch	19 Jul 2007 17:46:36 -0000	1.3
@@ -0,0 +1,3793 @@
+[PATCH 3] utrace core
+
+This adds the utrace facility, a new modular interface in the kernel for
+implementing user thread tracing and debugging.  This fits on top of the
+tracehook_* layer, so the new code is well-isolated.
+
+The new interface is in <linux/utrace.h>, and Documentation/utrace.txt
+describes it.  It allows for multiple separate tracing engines to work in
+parallel without interfering with each other.  Higher-level tracing
+facilities can be implemented as loadable kernel modules using this layer.
+
+The new facility is made optional under CONFIG_UTRACE.
+Normal configurations will always want to enable it.
+It's optional to emphasize the clean separation of the code,
+and in case some stripped-down embedded configurations might want to
+omit it to save space (when ptrace and the like can never be used).
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+
+---
+
+ kernel/Makefile                   |    1 
+ kernel/utrace.c                   | 2263 +++++++++++++++++++++++++++++++++++++
+ Documentation/utrace.txt          |  579 +++++++++
+ Documentation/DocBook/Makefile    |    2 
+ Documentation/DocBook/utrace.tmpl |   23 
+ include/linux/tracehook.h         |   85 +
+ include/linux/utrace.h            |  544 +++++++++
+ include/linux/sched.h             |    5 
+ init/Kconfig                      |   20 
+ 9 files changed, 3504 insertions(+), 18 deletions(-)
+ create kernel/utrace.c
+ create Documentation/utrace.txt
+ create Documentation/DocBook/utrace.tmpl
+ create include/linux/utrace.h
+
+--- linux-2.6/kernel/Makefile
++++ linux-2.6/kernel/Makefile
+@@ -51,6 +51,7 @@ obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
+ obj-$(CONFIG_UTS_NS) += utsname.o
+ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
+ obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
++obj-$(CONFIG_UTRACE) += utrace.o
+ 
+ ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
+ # According to Alan Modra <alan at linuxcare.com.au>, the -fno-omit-frame-pointer is
+--- linux-2.6/kernel/utrace.c
++++ linux-2.6/kernel/utrace.c
+@@ -0,0 +1,2263 @@
++/*
++ * utrace infrastructure interface for debugging user processes
++ *
++ * Copyright (C) 2006, 2007 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.
++ *
++ * Red Hat Author: Roland McGrath.
++ */
++
++#include <linux/utrace.h>
++#include <linux/tracehook.h>
++#include <linux/err.h>
++#include <linux/sched.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <asm/tracehook.h>
++
++
++#define UTRACE_DEBUG 1
++#ifdef UTRACE_DEBUG
++#define CHECK_INIT(p)	atomic_set(&(p)->check_dead, 1)
++#define CHECK_DEAD(p)	BUG_ON(!atomic_dec_and_test(&(p)->check_dead))
++#else
++#define CHECK_INIT(p)	do { } while (0)
++#define CHECK_DEAD(p)	do { } while (0)
++#endif
++
++/*
++ * Per-thread structure task_struct.utrace points to.
++ *
++ * The task itself never has to worry about this going away after
++ * some event is found set in task_struct.utrace_flags.
++ * Once created, this pointer is changed only when the task is quiescent
++ * (TASK_TRACED or TASK_STOPPED with the siglock held, or dead).
++ *
++ * For other parties, the pointer to this is protected by RCU and
++ * task_lock.  Since call_rcu is never used while the thread is alive and
++ * using this struct utrace, we can overlay the RCU data structure used
++ * only for a dead struct with some local state used only for a live utrace
++ * on an active thread.
++ */
++struct utrace
++{
++	union {
++		struct rcu_head dead;
++		struct {
++			struct task_struct *cloning;
++			struct utrace_signal *signal;
++		} live;
++		struct {
++			unsigned long flags;
++		} exit;
++	} u;
++
++	struct list_head engines;
++	spinlock_t lock;
++#ifdef UTRACE_DEBUG
++	atomic_t check_dead;
++#endif
++};
++
++static struct kmem_cache *utrace_cachep;
++static struct kmem_cache *utrace_engine_cachep;
++
++static int __init
++utrace_init(void)
++{
++	utrace_cachep =
++		kmem_cache_create("utrace_cache",
++				  sizeof(struct utrace), 0,
++				  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
++	utrace_engine_cachep =
++		kmem_cache_create("utrace_engine_cache",
++				  sizeof(struct utrace_attached_engine), 0,
++				  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
++	return 0;
++}
++subsys_initcall(utrace_init);
++
++
++/*
++ * Make sure target->utrace is allocated, and return with it locked on
++ * success.  This function mediates startup races.  The creating parent
++ * task has priority, and other callers will delay here to let its call
++ * succeed and take the new utrace lock first.
++ */
++static struct utrace *
++utrace_first_engine(struct task_struct *target,
++		    struct utrace_attached_engine *engine)
++	__acquires(utrace->lock)
++{
++	struct utrace *utrace;
++
++	/*
++	 * If this is a newborn thread and we are not the creator,
++	 * we have to wait for it.  The creator gets the first chance
++	 * to attach.  The PF_STARTING flag is cleared after its
++	 * report_clone hook has had a chance to run.
++	 */
++	if (target->flags & PF_STARTING) {
++		utrace = current->utrace;
++		if (utrace == NULL || utrace->u.live.cloning != target) {
++			yield();
++			return (signal_pending(current)
++				? ERR_PTR(-ERESTARTNOINTR) : NULL);
++		}
++	}
++
++	utrace = kmem_cache_alloc(utrace_cachep, GFP_KERNEL);
++	if (unlikely(utrace == NULL))
++		return ERR_PTR(-ENOMEM);
++
++	utrace->u.live.cloning = NULL;
++	utrace->u.live.signal = NULL;
++	INIT_LIST_HEAD(&utrace->engines);
++	list_add(&engine->entry, &utrace->engines);
++	spin_lock_init(&utrace->lock);
++	CHECK_INIT(utrace);
++
++	spin_lock(&utrace->lock);
++	task_lock(target);
++	if (likely(target->utrace == NULL)) {
++		rcu_assign_pointer(target->utrace, utrace);
++
++		/*
++		 * The task_lock protects us against another thread doing
++		 * the same thing.  We might still be racing against
++		 * tracehook_release_task.  It's called with ->exit_state
++		 * set to EXIT_DEAD and then checks ->utrace with an
++		 * smp_mb() in between.  If EXIT_DEAD is set, then
++		 * release_task might have checked ->utrace already and saw
++		 * it NULL; we can't attach.  If we see EXIT_DEAD not yet
++		 * set after our barrier, then we know release_task will
++		 * see our target->utrace pointer.
++		 */
++		smp_mb();
++		if (likely(target->exit_state != EXIT_DEAD)) {
++			task_unlock(target);
++			return utrace;
++		}
[...3400 lines suppressed...]
++	 * /proc/PID/status, where it is called with only rcu_read_lock held.
++	 *
++	 * If this engine returns %NULL, another engine may supply the result.
++	 */
++	struct task_struct *(*tracer_task)(struct utrace_attached_engine *,
++					   struct task_struct *target);
++};
++
++
++/*
++ * These are the exported entry points for tracing engines to use.
++ */
++struct utrace_attached_engine *utrace_attach(struct task_struct *target,
++					     int flags,
++					     const struct utrace_engine_ops *,
++					     void *data);
++int utrace_detach(struct task_struct *target,
++		  struct utrace_attached_engine *engine);
++int utrace_set_flags(struct task_struct *target,
++		     struct utrace_attached_engine *engine,
++		     unsigned long flags);
++int utrace_inject_signal(struct task_struct *target,
++			 struct utrace_attached_engine *engine,
++			 u32 action, siginfo_t *info,
++			 const struct k_sigaction *ka);
++const struct utrace_regset *utrace_regset(struct task_struct *target,
++					  struct utrace_attached_engine *,
++					  const struct utrace_regset_view *,
++					  int which);
++
++
++/*
++ * Hooks in <linux/tracehook.h> call these entry points to the utrace dispatch.
++ */
++int utrace_quiescent(struct task_struct *, struct utrace_signal *);
++void utrace_release_task(struct task_struct *);
++int utrace_get_signal(struct task_struct *, struct pt_regs *,
++		      siginfo_t *, struct k_sigaction *);
++void utrace_report_clone(unsigned long clone_flags, struct task_struct *child);
++void utrace_report_vfork_done(pid_t child_pid);
++void utrace_report_exit(long *exit_code);
++void utrace_report_death(struct task_struct *, struct utrace *);
++void utrace_report_delayed_group_leader(struct task_struct *);
++int utrace_report_jctl(int type);
++void utrace_report_exec(struct linux_binprm *bprm, struct pt_regs *regs);
++void utrace_report_syscall(struct pt_regs *regs, int is_exit);
++struct task_struct *utrace_tracer_task(struct task_struct *);
++int utrace_allow_access_process_vm(struct task_struct *);
++int utrace_unsafe_exec(struct task_struct *);
++void utrace_signal_handler_singlestep(struct task_struct *, struct pt_regs *);
++
++/*
++ * <linux/tracehook.h> uses these accessors to avoid #ifdef CONFIG_UTRACE.
++ */
++static inline unsigned long tsk_utrace_flags(struct task_struct *tsk)
++{
++	return tsk->utrace_flags;
++}
++static inline struct utrace *tsk_utrace_struct(struct task_struct *tsk)
++{
++	return tsk->utrace;
++}
++static inline void utrace_init_task(struct task_struct *child)
++{
++	child->utrace_flags = 0;
++	child->utrace = NULL;
++}
++
++#else  /* !CONFIG_UTRACE */
++
++static unsigned long tsk_utrace_flags(struct task_struct *tsk)
++{
++	return 0;
++}
++static struct utrace *tsk_utrace_struct(struct task_struct *tsk)
++{
++	return NULL;
++}
++static inline void utrace_init_task(struct task_struct *child)
++{
++}
++
++/*
++ * The calls to these should all be in if (0) and optimized out entirely.
++ * We have stubs here only so tracehook.h doesn't need to #ifdef them
++ * to avoid external references in case of unoptimized compilation.
++ */
++static inline int utrace_quiescent(struct task_struct *tsk, void *ignored)
++{
++	BUG();
++	return 0;
++}
++static inline void utrace_release_task(struct task_struct *tsk)
++{
++	BUG();
++}
++static inline int utrace_get_signal(struct task_struct *tsk,
++				    struct pt_regs *regs,
++				    siginfo_t *info, struct k_sigaction *ka)
++{
++	BUG();
++	return 0;
++}
++static inline void utrace_report_clone(unsigned long clone_flags,
++				       struct task_struct *child)
++{
++	BUG();
++}
++static inline void utrace_report_vfork_done(pid_t child_pid)
++{
++	BUG();
++}
++static inline void utrace_report_exit(long *exit_code)
++{
++	BUG();
++}
++static inline void utrace_report_death(struct task_struct *tsk, void *ignored)
++{
++	BUG();
++}
++static inline void utrace_report_delayed_group_leader(struct task_struct *tsk)
++{
++	BUG();
++}
++static inline int utrace_report_jctl(int type)
++{
++	BUG();
++	return 0;
++}
++static inline void utrace_report_exec(struct linux_binprm *bprm,
++				      struct pt_regs *regs)
++{
++	BUG();
++}
++static inline void utrace_report_syscall(struct pt_regs *regs, int is_exit)
++{
++	BUG();
++}
++static inline struct task_struct *utrace_tracer_task(struct task_struct *tsk)
++{
++	BUG();
++	return NULL;
++}
++static inline int utrace_allow_access_process_vm(struct task_struct *tsk)
++{
++	BUG();
++	return 0;
++}
++static inline int utrace_unsafe_exec(struct task_struct *tsk)
++{
++	BUG();
++	return 0;
++}
++static inline void utrace_signal_handler_singlestep(struct task_struct *tsk,
++						    struct pt_regs *regs)
++{
++	BUG();
++}
++
++#endif  /* CONFIG_UTRACE */
++
++#endif	/* linux/utrace.h */
+--- linux-2.6/include/linux/sched.h
++++ linux-2.6/include/linux/sched.h
+@@ -1029,6 +1029,11 @@ struct task_struct {
+ 	struct audit_context *audit_context;
+ 	seccomp_t seccomp;
+ 
++#ifdef CONFIG_UTRACE
++	struct utrace *utrace;
++	unsigned long utrace_flags;
++#endif
++
+ /* Thread group tracking */
+    	u32 parent_exec_id;
+    	u32 self_exec_id;
+--- linux-2.6/init/Kconfig
++++ linux-2.6/init/Kconfig
+@@ -686,3 +686,21 @@ config STOP_MACHINE
+ menu "Block layer"
+ source "block/Kconfig"
+ endmenu
++
++menu "Process debugging support"
++
++config UTRACE
++	bool "Infrastructure for tracing and debugging user processes"
++	default y
++	depends on MODULES
++	help
++	  Enable the utrace process tracing interface.
++	  This is an internal kernel interface to track events in user
++	  threads, extract and change user thread state.  This interface
++	  is exported to kernel modules, and is also used to implement ptrace.
++	  If you disable this, no facilities for debugging user processes
++	  will be available, nor the facilities used by UML and other
++	  applications.  Unless you are making a specially stripped-down
++	  kernel and are very sure you don't need these facilitiies,
++	  say Y.
++endmenu

linux-2.6-utrace-ptrace-compat-avr32.patch:
 ptrace.c |  107 ++++++++++-----------------------------------------------------
 1 files changed, 18 insertions(+), 89 deletions(-)

--- NEW FILE linux-2.6-utrace-ptrace-compat-avr32.patch ---
[PATCH 4d] utrace: avr32 ptrace compatibility

From: Haavard Skinnemoen <hskinnemoen at atmel.com>

Rip out most of the ptrace code for AVR32 and replace it with the much
nicer utrace stuff.  It builds in all possible combinations of
CONFIG_UTRACE and CONFIG_PTRACE, and it seems to work as far as I've tested
it with strace and some simple debugging with gdb.

Signed-off-by: Haavard Skinnemoen <hskinnemoen at atmel.com>
Signed-off-by: Roland McGrath <roland at redhat.com>

---

 arch/avr32/kernel/ptrace.c |  107 +++++++-------------------------------------
 1 files changed, 18 insertions(+), 89 deletions(-)

--- linux-2.6/arch/avr32/kernel/ptrace.c
+++ linux-2.6/arch/avr32/kernel/ptrace.c
@@ -78,115 +78,44 @@ const struct utrace_regset_view *utrace_
 }
 #endif /* CONFIG_UTRACE */
 
+#ifdef CONFIG_PTRACE
 
-#if 0
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+static const struct ptrace_layout_segment avr32_uarea[] = {
+	{ 0, ELF_NGREG * sizeof(long), 0, 0 },
+	{ 0, 0, -1, 0 },
+};
+
+int arch_ptrace(long *request, struct task_struct *child,
+		struct utrace_attached_engine *engine,
+		unsigned long addr, unsigned long data, long *val)
 {
-	unsigned long tmp;
-	int ret;
-
 	pr_debug("arch_ptrace(%ld, %d, %#lx, %#lx)\n",
-		 request, child->pid, addr, data);
+		 *request, child->pid, addr, data);
 
 	pr_debug("ptrace: Enabling monitor mode...\n");
 	__mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE);
 
-	switch (request) {
-	/* Read the word at location addr in the child process */
-	case PTRACE_PEEKTEXT:
-	case PTRACE_PEEKDATA:
-		ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		if (ret == sizeof(tmp))
-			ret = put_user(tmp, (unsigned long __user *)data);
-		else
-			ret = -EIO;
-		break;
-
+	switch (*request) {
 	case PTRACE_PEEKUSR:
-		ret = ptrace_read_user(child, addr,
-				       (unsigned long __user *)data);
-		break;
-
-	/* Write the word in data at location addr */
-	case PTRACE_POKETEXT:
-	case PTRACE_POKEDATA:
-		ret = access_process_vm(child, addr, &data, sizeof(data), 1);
-		if (ret == sizeof(data))
-			ret = 0;
-		else
-			ret = -EIO;
-		break;
+		return ptrace_peekusr(child, engine, avr32_uarea, addr, data);
 
 	case PTRACE_POKEUSR:
-		ret = ptrace_write_user(child, addr, data);
-		break;
-
-	/* continue and stop at next (return from) syscall */
-	case PTRACE_SYSCALL:
-	/* restart after signal */
-	case PTRACE_CONT:
-		ret = -EIO;
-		if (!valid_signal(data))
-			break;
-		if (request == PTRACE_SYSCALL)
-			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		else
-			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		child->exit_code = data;
-		/* XXX: Are we sure no breakpoints are active here? */
-		wake_up_process(child);
-		ret = 0;
-		break;
-
-	/*
-	 * Make the child exit. Best I can do is send it a
-	 * SIGKILL. Perhaps it should be put in the status that it
-	 * wants to exit.
-	 */
-	case PTRACE_KILL:
-		ret = 0;
-		if (child->exit_state == EXIT_ZOMBIE)
-			break;
-		child->exit_code = SIGKILL;
-		wake_up_process(child);
-		break;
-
-	/*
-	 * execute single instruction.
-	 */
-	case PTRACE_SINGLESTEP:
-		ret = -EIO;
-		if (!valid_signal(data))
-			break;
-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		ptrace_single_step(child);
-		child->exit_code = data;
-		wake_up_process(child);
-		ret = 0;
-		break;
-
-	/* Detach a process that was attached */
-	case PTRACE_DETACH:
-		ret = ptrace_detach(child, data);
+		return ptrace_pokeusr(child, engine, avr32_uarea, addr, data);
 		break;
 
 	case PTRACE_GETREGS:
-		ret = ptrace_getregs(child, (void __user *)data);
+		return ptrace_whole_regset(child, engine, data, 0, 0);
 		break;
 
 	case PTRACE_SETREGS:
-		ret = ptrace_setregs(child, (const void __user *)data);
-		break;
-
-	default:
-		ret = ptrace_request(child, request, addr, data);
+		return ptrace_whole_regset(child, engine, data, 0, 1);
 		break;
 	}
 
-	pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC));
-	return ret;
+	return -ENOSYS;
 }
-#endif
+#endif /* CONFIG_PTRACE */
+#endif /* CONFIG_UTRACE */
 
 asmlinkage void syscall_trace(struct pt_regs *regs, int is_exit)
 {

linux-2.6-utrace-ptrace-compat-ia64.patch:
 ia32/sys_ia32.c |   40 ++
 kernel/ptrace.c | 1016 ++++++--------------------------------------------------
 2 files changed, 159 insertions(+), 897 deletions(-)

--- NEW FILE linux-2.6-utrace-ptrace-compat-ia64.patch ---
[PATCH 4a] utrace: ia64 ptrace compatibility

This patch implements ptrace compatibility for ia64.

Signed-off-by: Roland McGrath <roland at redhat.com>
Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy at intel.com>
Signed-off-by: Bibo mao <bibo.mao at intel.com>

---

 arch/ia64/ia32/sys_ia32.c |   40 ++
 arch/ia64/kernel/ptrace.c | 1016 +++++----------------------------------------
 2 files changed, 159 insertions(+), 897 deletions(-)

--- linux-2.6/arch/ia64/ia32/sys_ia32.c
+++ linux-2.6/arch/ia64/ia32/sys_ia32.c
@@ -2340,6 +2340,46 @@ const struct utrace_regset_view utrace_i
 };
 #endif
 
+#ifdef CONFIG_PTRACE
+/*
+ * This matches the arch/i386/kernel/ptrace.c definitions.
+ */
+
+static const struct ptrace_layout_segment ia32_uarea[] = {
+	{0, sizeof(struct user_regs_struct32), 0, 0},
+	{0, 0, -1, 0}
+};
+
+fastcall int arch_compat_ptrace(compat_long_t *request,
+		struct task_struct *child,
+		struct utrace_attached_engine *engine,
+		compat_ulong_t addr, compat_ulong_t data,
+		compat_long_t *retval)
+{
+	switch (*request) {
+		case PTRACE_PEEKUSR:
+			return ptrace_compat_peekusr(child, engine, ia32_uarea,
+					addr, data);
+		case PTRACE_POKEUSR:
+			return ptrace_compat_pokeusr(child, engine, ia32_uarea,
+					addr, data);
+		case IA32_PTRACE_GETREGS:
+			return ptrace_whole_regset(child, engine, data, 0, 0);
+		case IA32_PTRACE_SETREGS:
+			return ptrace_whole_regset(child, engine, data, 0, 1);
+		case IA32_PTRACE_GETFPREGS:
+			return ptrace_whole_regset(child, engine, data, 1, 0);
+		case IA32_PTRACE_SETFPREGS:
+			return ptrace_whole_regset(child, engine, data, 1, 1);
+		case IA32_PTRACE_GETFPXREGS:
+			return ptrace_whole_regset(child, engine, data, 2, 0);
+		case IA32_PTRACE_SETFPXREGS:
+			return ptrace_whole_regset(child, engine, data, 2, 1);
+	}
+	return -ENOSYS;
+}
+#endif
+
 typedef struct {
 	unsigned int	ss_sp;
 	unsigned int	ss_flags;
--- linux-2.6/arch/ia64/kernel/ptrace.c
+++ linux-2.6/arch/ia64/kernel/ptrace.c
@@ -554,81 +554,6 @@ ia64_sync_user_rbs (struct task_struct *
 	return 0;
 }
 
-#if 0				/* XXX */
-static inline int
-thread_matches (struct task_struct *thread, unsigned long addr)
-{
-	unsigned long thread_rbs_end;
-	struct pt_regs *thread_regs;
-
-	if (ptrace_check_attach(thread, 0) < 0)
-		/*
-		 * If the thread is not in an attachable state, we'll
-		 * ignore it.  The net effect is that if ADDR happens
-		 * to overlap with the portion of the thread's
-		 * register backing store that is currently residing
-		 * on the thread's kernel stack, then ptrace() may end
-		 * up accessing a stale value.  But if the thread
-		 * isn't stopped, that's a problem anyhow, so we're
-		 * doing as well as we can...
-		 */
-		return 0;
-
-	thread_regs = task_pt_regs(thread);
-	thread_rbs_end = ia64_get_user_rbs_end(thread, thread_regs, NULL);
-	if (!on_kernel_rbs(addr, thread_regs->ar_bspstore, thread_rbs_end))
-		return 0;
-
-	return 1;	/* looks like we've got a winner */
-}
-
-/*
- * GDB apparently wants to be able to read the register-backing store
- * of any thread when attached to a given process.  If we are peeking
- * or poking an address that happens to reside in the kernel-backing
- * store of another thread, we need to attach to that thread, because
- * otherwise we end up accessing stale data.
- *
- * task_list_lock must be read-locked before calling this routine!
- */
-static struct task_struct *
-find_thread_for_addr (struct task_struct *child, unsigned long addr)
-{
-	struct task_struct *p;
-	struct mm_struct *mm;
-	struct list_head *this, *next;
-	int mm_users;
-
-	if (!(mm = get_task_mm(child)))
-		return child;
-
-	/* -1 because of our get_task_mm(): */
-	mm_users = atomic_read(&mm->mm_users) - 1;
-	if (mm_users <= 1)
-		goto out;		/* not multi-threaded */
-
-	/*
-	 * Traverse the current process' children list.  Every task that
-	 * one attaches to becomes a child.  And it is only attached children
-	 * of the debugger that are of interest (ptrace_check_attach checks
-	 * for this).
-	 */
- 	list_for_each_safe(this, next, &current->children) {
-		p = list_entry(this, struct task_struct, sibling);
-		if (p->tgid != child->tgid)
-			continue;
-		if (thread_matches(p, addr)) {
-			child = p;
-			goto out;
-		}
-	}
-
-  out:
-	mmput(mm);
-	return child;
-}
-#endif
-
 /*
  * Write f32-f127 back to task->thread.fph if it has been modified.
  */
@@ -792,828 +717,6 @@ access_nat_bits (struct task_struct *chi
 	return 0;
 }
 
-#if 0
-static int
-access_uarea (struct task_struct *child, unsigned long addr,
-	      unsigned long *data, int write_access)
-{
-	unsigned long *ptr, regnum, urbs_end, rnat_addr, cfm;
-	struct switch_stack *sw;
-	struct pt_regs *pt;
-#	define pt_reg_addr(pt, reg)	((void *)			    \
-					 ((unsigned long) (pt)		    \
-					  + offsetof(struct pt_regs, reg)))
-
-
-	pt = task_pt_regs(child);
-	sw = (struct switch_stack *) (child->thread.ksp + 16);
-
-	if ((addr & 0x7) != 0) {
-		dprintk("ptrace: unaligned register address 0x%lx\n", addr);
-		return -1;
-	}
-
-	if (addr < PT_F127 + 16) {
-		/* accessing fph */
-		if (write_access)
-			ia64_sync_fph(child);
-		else
-			ia64_flush_fph(child);
-		ptr = (unsigned long *)
-			((unsigned long) &child->thread.fph + addr);
-	} else if ((addr >= PT_F10) && (addr < PT_F11 + 16)) {
-		/* scratch registers untouched by kernel (saved in pt_regs) */
-		ptr = pt_reg_addr(pt, f10) + (addr - PT_F10);
-	} else if (addr >= PT_F12 && addr < PT_F15 + 16) {
-		/*
-		 * Scratch registers untouched by kernel (saved in
-		 * switch_stack).
-		 */
-		ptr = (unsigned long *) ((long) sw
-					 + (addr - PT_NAT_BITS - 32));
-	} else if (addr < PT_AR_LC + 8) {
-		/* preserved state: */
-		struct unw_frame_info info;
-		char nat = 0;
-		int ret;
-
-		unw_init_from_blocked_task(&info, child);
-		if (unw_unwind_to_user(&info) < 0)
-			return -1;
-
-		switch (addr) {
-		      case PT_NAT_BITS:
-			return access_nat_bits(child, pt, &info,
-					       data, write_access);
-
-		      case PT_R4: case PT_R5: case PT_R6: case PT_R7:
-			if (write_access) {
-				/* read NaT bit first: */
-				unsigned long dummy;
-
-				ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4,
-						 &dummy, &nat);
-				if (ret < 0)
-					return ret;
-			}
-			return unw_access_gr(&info, (addr - PT_R4)/8 + 4, data,
-					     &nat, write_access);
-
-		      case PT_B1: case PT_B2: case PT_B3:
-		      case PT_B4: case PT_B5:
-			return unw_access_br(&info, (addr - PT_B1)/8 + 1, data,
-					     write_access);
-
-		      case PT_AR_EC:
-			return unw_access_ar(&info, UNW_AR_EC, data,
-					     write_access);
-
-		      case PT_AR_LC:
-			return unw_access_ar(&info, UNW_AR_LC, data,
-					     write_access);
-
-		      default:
-			if (addr >= PT_F2 && addr < PT_F5 + 16)
-				return access_fr(&info, (addr - PT_F2)/16 + 2,
-						 (addr & 8) != 0, data,
-						 write_access);
-			else if (addr >= PT_F16 && addr < PT_F31 + 16)
-				return access_fr(&info,
-						 (addr - PT_F16)/16 + 16,
-						 (addr & 8) != 0,
-						 data, write_access);
-			else {
-				dprintk("ptrace: rejecting access to register "
-					"address 0x%lx\n", addr);
-				return -1;
-			}
-		}
-	} else if (addr < PT_F9+16) {
-		/* scratch state */
-		switch (addr) {
-		      case PT_AR_BSP:
-			/*
-			 * By convention, we use PT_AR_BSP to refer to
-			 * the end of the user-level backing store.
-			 * Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof)
-			 * to get the real value of ar.bsp at the time
-			 * the kernel was entered.
-			 *
-			 * Furthermore, when changing the contents of
-			 * PT_AR_BSP (or PT_CFM) we MUST copy any
-			 * users-level stacked registers that are
-			 * stored on the kernel stack back to
-			 * user-space because otherwise, we might end
-			 * up clobbering kernel stacked registers.
-			 * Also, if this happens while the task is
-			 * blocked in a system call, which convert the
-			 * state such that the non-system-call exit
-			 * path is used.  This ensures that the proper
-			 * state will be picked up when resuming
-			 * execution.  However, it *also* means that
-			 * once we write PT_AR_BSP/PT_CFM, it won't be
-			 * possible to modify the syscall arguments of
-			 * the pending system call any longer.  This
-			 * shouldn't be an issue because modifying
-			 * PT_AR_BSP/PT_CFM generally implies that
-			 * we're either abandoning the pending system
-			 * call or that we defer it's re-execution
-			 * (e.g., due to GDB doing an inferior
-			 * function call).
-			 */
-			urbs_end = ia64_get_user_rbs_end(child, pt, &cfm);
-			if (write_access) {
-				if (*data != urbs_end) {
-					if (ia64_sync_user_rbs(child, sw,
-							       pt->ar_bspstore,
-							       urbs_end) < 0)
-						return -1;
-					if (in_syscall(pt))
-						convert_to_non_syscall(child,
-								       pt,
-								       cfm);
-					/*
-					 * Simulate user-level write
-					 * of ar.bsp:
-					 */
-					pt->loadrs = 0;
-					pt->ar_bspstore = *data;
-				}
-			} else
-				*data = urbs_end;
-			return 0;
-
-		      case PT_CFM:
-			urbs_end = ia64_get_user_rbs_end(child, pt, &cfm);
-			if (write_access) {
-				if (((cfm ^ *data) & PFM_MASK) != 0) {
-					if (ia64_sync_user_rbs(child, sw,
-							       pt->ar_bspstore,
-							       urbs_end) < 0)
-						return -1;
-					if (in_syscall(pt))
-						convert_to_non_syscall(child,
-								       pt,
-								       cfm);
-					pt->cr_ifs = ((pt->cr_ifs & ~PFM_MASK)
-						      | (*data & PFM_MASK));
-				}
-			} else
-				*data = cfm;
-			return 0;
-
-		      case PT_CR_IPSR:
-			if (write_access)
-				pt->cr_ipsr = ((*data & IPSR_MASK)
-					       | (pt->cr_ipsr & ~IPSR_MASK));
-			else
-				*data = (pt->cr_ipsr & IPSR_MASK);
-			return 0;
-
-		      case PT_AR_RSC:
-			if (write_access)
-				pt->ar_rsc = *data | (3 << 2); /* force PL3 */
-			else
-				*data = pt->ar_rsc;
-			return 0;
-
-		      case PT_AR_RNAT:
-			urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
-			rnat_addr = (long) ia64_rse_rnat_addr((long *)
-							      urbs_end);
-			if (write_access)
-				return ia64_poke(child, sw, urbs_end,
-						 rnat_addr, *data);
-			else
-				return ia64_peek(child, sw, urbs_end,
-						 rnat_addr, data);
-
-		      case PT_R1:
-			ptr = pt_reg_addr(pt, r1);
-			break;
-		      case PT_R2:  case PT_R3:
-			ptr = pt_reg_addr(pt, r2) + (addr - PT_R2);
-			break;
-		      case PT_R8:  case PT_R9:  case PT_R10: case PT_R11:
-			ptr = pt_reg_addr(pt, r8) + (addr - PT_R8);
-			break;
-		      case PT_R12: case PT_R13:
-			ptr = pt_reg_addr(pt, r12) + (addr - PT_R12);
-			break;
-		      case PT_R14:
-			ptr = pt_reg_addr(pt, r14);
-			break;
-		      case PT_R15:
-			ptr = pt_reg_addr(pt, r15);
-			break;
-		      case PT_R16: case PT_R17: case PT_R18: case PT_R19:
-		      case PT_R20: case PT_R21: case PT_R22: case PT_R23:
-		      case PT_R24: case PT_R25: case PT_R26: case PT_R27:
-		      case PT_R28: case PT_R29: case PT_R30: case PT_R31:
-			ptr = pt_reg_addr(pt, r16) + (addr - PT_R16);
-			break;
-		      case PT_B0:
-			ptr = pt_reg_addr(pt, b0);
-			break;
-		      case PT_B6:
-			ptr = pt_reg_addr(pt, b6);
-			break;
-		      case PT_B7:
-			ptr = pt_reg_addr(pt, b7);
-			break;
-		      case PT_F6:  case PT_F6+8: case PT_F7: case PT_F7+8:
-		      case PT_F8:  case PT_F8+8: case PT_F9: case PT_F9+8:
-			ptr = pt_reg_addr(pt, f6) + (addr - PT_F6);
-			break;
-		      case PT_AR_BSPSTORE:
-			ptr = pt_reg_addr(pt, ar_bspstore);
-			break;
-		      case PT_AR_UNAT:
-			ptr = pt_reg_addr(pt, ar_unat);
-			break;
-		      case PT_AR_PFS:
-			ptr = pt_reg_addr(pt, ar_pfs);
-			break;
-		      case PT_AR_CCV:
-			ptr = pt_reg_addr(pt, ar_ccv);
-			break;
-		      case PT_AR_FPSR:
-			ptr = pt_reg_addr(pt, ar_fpsr);
-			break;
-		      case PT_CR_IIP:
-			ptr = pt_reg_addr(pt, cr_iip);
-			break;
-		      case PT_PR:
-			ptr = pt_reg_addr(pt, pr);
-			break;
-			/* scratch register */
-
-		      default:
-			/* disallow accessing anything else... */
-			dprintk("ptrace: rejecting access to register "
-				"address 0x%lx\n", addr);
-			return -1;
-		}
-	} else if (addr <= PT_AR_SSD) {
-		ptr = pt_reg_addr(pt, ar_csd) + (addr - PT_AR_CSD);
-	} else {
-		/* access debug registers */
-
-		if (addr >= PT_IBR) {
-			regnum = (addr - PT_IBR) >> 3;
-			ptr = &child->thread.ibr[0];
-		} else {
-			regnum = (addr - PT_DBR) >> 3;
-			ptr = &child->thread.dbr[0];
-		}
-
-		if (regnum >= 8) {
-			dprintk("ptrace: rejecting access to register "
-				"address 0x%lx\n", addr);
-			return -1;
-		}
-#ifdef CONFIG_PERFMON
-		/*
-		 * Check if debug registers are used by perfmon. This
-		 * test must be done once we know that we can do the
-		 * operation, i.e. the arguments are all valid, but
-		 * before we start modifying the state.
-		 *
-		 * Perfmon needs to keep a count of how many processes
-		 * are trying to modify the debug registers for system
-		 * wide monitoring sessions.
-		 *
-		 * We also include read access here, because they may
-		 * cause the PMU-installed debug register state
-		 * (dbr[], ibr[]) to be reset. The two arrays are also
-		 * used by perfmon, but we do not use
-		 * IA64_THREAD_DBG_VALID. The registers are restored
-		 * by the PMU context switch code.
-		 */
-		if (pfm_use_debug_registers(child)) return -1;
-#endif
-
-		if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
-			child->thread.flags |= IA64_THREAD_DBG_VALID;
-			memset(child->thread.dbr, 0,
-			       sizeof(child->thread.dbr));
-			memset(child->thread.ibr, 0,
-			       sizeof(child->thread.ibr));
-		}
-
-		ptr += regnum;
-
-		if ((regnum & 1) && write_access) {
-			/* don't let the user set kernel-level breakpoints: */
-			*ptr = *data & ~(7UL << 56);
-			return 0;
-		}
-	}
-	if (write_access)
-		*ptr = *data;
-	else
-		*data = *ptr;
-	return 0;
-}
-
-static long
-ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
-{
-	unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val;
-	struct unw_frame_info info;
-	struct ia64_fpreg fpval;
-	struct switch_stack *sw;
-	struct pt_regs *pt;
-	long ret, retval = 0;
-	char nat = 0;
-	int i;
-
-	if (!access_ok(VERIFY_WRITE, ppr, sizeof(struct pt_all_user_regs)))
-		return -EIO;
-
-	pt = task_pt_regs(child);
-	sw = (struct switch_stack *) (child->thread.ksp + 16);
-	unw_init_from_blocked_task(&info, child);
-	if (unw_unwind_to_user(&info) < 0) {
-		return -EIO;
-	}
-
-	if (((unsigned long) ppr & 0x7) != 0) {
-		dprintk("ptrace:unaligned register address %p\n", ppr);
-		return -EIO;
-	}
-
-	if (access_uarea(child, PT_CR_IPSR, &psr, 0) < 0
-	    || access_uarea(child, PT_AR_EC, &ec, 0) < 0
-	    || access_uarea(child, PT_AR_LC, &lc, 0) < 0
-	    || access_uarea(child, PT_AR_RNAT, &rnat, 0) < 0
-	    || access_uarea(child, PT_AR_BSP, &bsp, 0) < 0
-	    || access_uarea(child, PT_CFM, &cfm, 0)
-	    || access_uarea(child, PT_NAT_BITS, &nat_bits, 0))
-		return -EIO;
-
-	/* control regs */
-
-	retval |= __put_user(pt->cr_iip, &ppr->cr_iip);
-	retval |= __put_user(psr, &ppr->cr_ipsr);
-
-	/* app regs */
-
-	retval |= __put_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]);
-	retval |= __put_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]);
-	retval |= __put_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]);
-	retval |= __put_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]);
-	retval |= __put_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]);
-	retval |= __put_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]);
-
-	retval |= __put_user(ec, &ppr->ar[PT_AUR_EC]);
-	retval |= __put_user(lc, &ppr->ar[PT_AUR_LC]);
-	retval |= __put_user(rnat, &ppr->ar[PT_AUR_RNAT]);
-	retval |= __put_user(bsp, &ppr->ar[PT_AUR_BSP]);
-	retval |= __put_user(cfm, &ppr->cfm);
-
-	/* gr1-gr3 */
-
-	retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long));
-	retval |= __copy_to_user(&ppr->gr[2], &pt->r2, sizeof(long) *2);
-
-	/* gr4-gr7 */
-
-	for (i = 4; i < 8; i++) {
-		if (unw_access_gr(&info, i, &val, &nat, 0) < 0)
-			return -EIO;
-		retval |= __put_user(val, &ppr->gr[i]);
-	}
-
-	/* gr8-gr11 */
-
-	retval |= __copy_to_user(&ppr->gr[8], &pt->r8, sizeof(long) * 4);
-
-	/* gr12-gr15 */
-
-	retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 2);
-	retval |= __copy_to_user(&ppr->gr[14], &pt->r14, sizeof(long));
-	retval |= __copy_to_user(&ppr->gr[15], &pt->r15, sizeof(long));
-
-	/* gr16-gr31 */
-
-	retval |= __copy_to_user(&ppr->gr[16], &pt->r16, sizeof(long) * 16);
-
-	/* b0 */
-
-	retval |= __put_user(pt->b0, &ppr->br[0]);
-
-	/* b1-b5 */
-
-	for (i = 1; i < 6; i++) {
-		if (unw_access_br(&info, i, &val, 0) < 0)
-			return -EIO;
-		__put_user(val, &ppr->br[i]);
-	}
-
-	/* b6-b7 */
-
-	retval |= __put_user(pt->b6, &ppr->br[6]);
-	retval |= __put_user(pt->b7, &ppr->br[7]);
-
-	/* fr2-fr5 */
-
-	for (i = 2; i < 6; i++) {
-		if (unw_get_fr(&info, i, &fpval) < 0)
-			return -EIO;
-		retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval));
-	}
-
-	/* fr6-fr11 */
-
-	retval |= __copy_to_user(&ppr->fr[6], &pt->f6,
-				 sizeof(struct ia64_fpreg) * 6);
-
-	/* fp scratch regs(12-15) */
-
-	retval |= __copy_to_user(&ppr->fr[12], &sw->f12,
-				 sizeof(struct ia64_fpreg) * 4);
-
-	/* fr16-fr31 */
-
-	for (i = 16; i < 32; i++) {
-		if (unw_get_fr(&info, i, &fpval) < 0)
-			return -EIO;
-		retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval));
-	}
-
-	/* fph */
-
-	ia64_flush_fph(child);
-	retval |= __copy_to_user(&ppr->fr[32], &child->thread.fph,
-				 sizeof(ppr->fr[32]) * 96);
-
-	/*  preds */
-
-	retval |= __put_user(pt->pr, &ppr->pr);
-
-	/* nat bits */
-
-	retval |= __put_user(nat_bits, &ppr->nat);
-
-	ret = retval ? -EIO : 0;
-	return ret;
-}
-#endif /* ptrace_getregs() */
-
-#if 0
-static long
-ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
-{
-	unsigned long psr, rsc, ec, lc, rnat, bsp, cfm, nat_bits, val = 0;
-	struct unw_frame_info info;
-	struct switch_stack *sw;
-	struct ia64_fpreg fpval;
-	struct pt_regs *pt;
-	long ret, retval = 0;
-	int i;
-
-	memset(&fpval, 0, sizeof(fpval));
-
-	if (!access_ok(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs)))
-		return -EIO;
-
-	pt = task_pt_regs(child);
-	sw = (struct switch_stack *) (child->thread.ksp + 16);
-	unw_init_from_blocked_task(&info, child);
-	if (unw_unwind_to_user(&info) < 0) {
-		return -EIO;
-	}
-
-	if (((unsigned long) ppr & 0x7) != 0) {
-		dprintk("ptrace:unaligned register address %p\n", ppr);
-		return -EIO;
-	}
-
-	/* control regs */
-
-	retval |= __get_user(pt->cr_iip, &ppr->cr_iip);
-	retval |= __get_user(psr, &ppr->cr_ipsr);
-
-	/* app regs */
-
-	retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]);
-	retval |= __get_user(rsc, &ppr->ar[PT_AUR_RSC]);
-	retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]);
-	retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]);
-	retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]);
-	retval |= __get_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]);
-
-	retval |= __get_user(ec, &ppr->ar[PT_AUR_EC]);
-	retval |= __get_user(lc, &ppr->ar[PT_AUR_LC]);
-	retval |= __get_user(rnat, &ppr->ar[PT_AUR_RNAT]);
-	retval |= __get_user(bsp, &ppr->ar[PT_AUR_BSP]);
-	retval |= __get_user(cfm, &ppr->cfm);
-
-	/* gr1-gr3 */
-
-	retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long));
-	retval |= __copy_from_user(&pt->r2, &ppr->gr[2], sizeof(long) * 2);
-
-	/* gr4-gr7 */
-
-	for (i = 4; i < 8; i++) {
-		retval |= __get_user(val, &ppr->gr[i]);
-		/* NaT bit will be set via PT_NAT_BITS: */
-		if (unw_set_gr(&info, i, val, 0) < 0)
-			return -EIO;
-	}
-
-	/* gr8-gr11 */
-
-	retval |= __copy_from_user(&pt->r8, &ppr->gr[8], sizeof(long) * 4);
-
-	/* gr12-gr15 */
-
-	retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 2);
-	retval |= __copy_from_user(&pt->r14, &ppr->gr[14], sizeof(long));
-	retval |= __copy_from_user(&pt->r15, &ppr->gr[15], sizeof(long));
-
-	/* gr16-gr31 */
-
-	retval |= __copy_from_user(&pt->r16, &ppr->gr[16], sizeof(long) * 16);
-
-	/* b0 */
-
-	retval |= __get_user(pt->b0, &ppr->br[0]);
-
-	/* b1-b5 */
-
-	for (i = 1; i < 6; i++) {
-		retval |= __get_user(val, &ppr->br[i]);
-		unw_set_br(&info, i, val);
-	}
-
-	/* b6-b7 */
-
-	retval |= __get_user(pt->b6, &ppr->br[6]);
-	retval |= __get_user(pt->b7, &ppr->br[7]);
-
-	/* fr2-fr5 */
-
-	for (i = 2; i < 6; i++) {
-		retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval));
-		if (unw_set_fr(&info, i, fpval) < 0)
-			return -EIO;
-	}
-
-	/* fr6-fr11 */
-
-	retval |= __copy_from_user(&pt->f6, &ppr->fr[6],
-				   sizeof(ppr->fr[6]) * 6);
-
-	/* fp scratch regs(12-15) */
-
-	retval |= __copy_from_user(&sw->f12, &ppr->fr[12],
-				   sizeof(ppr->fr[12]) * 4);
-
-	/* fr16-fr31 */
-
-	for (i = 16; i < 32; i++) {
-		retval |= __copy_from_user(&fpval, &ppr->fr[i],
-					   sizeof(fpval));
-		if (unw_set_fr(&info, i, fpval) < 0)
-			return -EIO;
-	}
-
-	/* fph */
-
-	ia64_sync_fph(child);
-	retval |= __copy_from_user(&child->thread.fph, &ppr->fr[32],
-				   sizeof(ppr->fr[32]) * 96);
-
-	/* preds */
-
-	retval |= __get_user(pt->pr, &ppr->pr);
-
-	/* nat bits */
-
-	retval |= __get_user(nat_bits, &ppr->nat);
-
-	retval |= access_uarea(child, PT_CR_IPSR, &psr, 1);
-	retval |= access_uarea(child, PT_AR_RSC, &rsc, 1);
-	retval |= access_uarea(child, PT_AR_EC, &ec, 1);
-	retval |= access_uarea(child, PT_AR_LC, &lc, 1);
-	retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1);
-	retval |= access_uarea(child, PT_AR_BSP, &bsp, 1);
-	retval |= access_uarea(child, PT_CFM, &cfm, 1);
-	retval |= access_uarea(child, PT_NAT_BITS, &nat_bits, 1);
-
-	ret = retval ? -EIO : 0;
-	return ret;
-}
-#endif /* ptrace_setregs() */
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
- */
-void
-ptrace_disable (struct task_struct *child)
-{
-	struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child));
-
-	/* make sure the single step/taken-branch trap bits are not set: */
-	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-	child_psr->ss = 0;
-	child_psr->tb = 0;
-}
-
-#if 0 				/* XXX */
-asmlinkage long
-sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
-{
-	struct pt_regs *pt;
-	unsigned long urbs_end, peek_or_poke;
-	struct task_struct *child;
-	struct switch_stack *sw;
-	long ret;
-
-	lock_kernel();
-	ret = -EPERM;
-	if (request == PTRACE_TRACEME) {
-		ret = ptrace_traceme();
-		goto out;
-	}
-
-	peek_or_poke = (request == PTRACE_PEEKTEXT
-			|| request == PTRACE_PEEKDATA
-			|| request == PTRACE_POKETEXT
-			|| request == PTRACE_POKEDATA);
-	ret = -ESRCH;
-	read_lock(&tasklist_lock);
-	{
-		child = find_task_by_pid(pid);
-		if (child) {
-			if (peek_or_poke)
-				child = find_thread_for_addr(child, addr);
-			get_task_struct(child);
-		}
-	}
-	read_unlock(&tasklist_lock);
-	if (!child)
-		goto out;
-	ret = -EPERM;
-	if (pid == 1)		/* no messing around with init! */
-		goto out_tsk;
-
-	if (request == PTRACE_ATTACH) {
-		ret = ptrace_attach(child);
-		goto out_tsk;
-	}
-
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		goto out_tsk;
-
-	pt = task_pt_regs(child);
-	sw = (struct switch_stack *) (child->thread.ksp + 16);
-
-	switch (request) {
-	      case PTRACE_PEEKTEXT:
-	      case PTRACE_PEEKDATA:
-		/* read word at location addr */
-		urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
-		ret = ia64_peek(child, sw, urbs_end, addr, &data);
-		if (ret == 0) {
-			ret = data;
-			/* ensure "ret" is not mistaken as an error code: */
-			force_successful_syscall_return();
-		}
-		goto out_tsk;
-
-	      case PTRACE_POKETEXT:
-	      case PTRACE_POKEDATA:
-		/* write the word at location addr */
-		urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
-		ret = ia64_poke(child, sw, urbs_end, addr, data);
-		goto out_tsk;
-
-	      case PTRACE_PEEKUSR:
-		/* read the word at addr in the USER area */
-		if (access_uarea(child, addr, &data, 0) < 0) {
-			ret = -EIO;
-			goto out_tsk;
-		}
-		ret = data;
-		/* ensure "ret" is not mistaken as an error code */
-		force_successful_syscall_return();
-		goto out_tsk;
-
-	      case PTRACE_POKEUSR:
-		/* write the word at addr in the USER area */
-		if (access_uarea(child, addr, &data, 1) < 0) {
-			ret = -EIO;
-			goto out_tsk;
-		}
-		ret = 0;
-		goto out_tsk;
-
-	      case PTRACE_OLD_GETSIGINFO:
-		/* for backwards-compatibility */
-		ret = ptrace_request(child, PTRACE_GETSIGINFO, addr, data);
-		goto out_tsk;
-
-	      case PTRACE_OLD_SETSIGINFO:
-		/* for backwards-compatibility */
-		ret = ptrace_request(child, PTRACE_SETSIGINFO, addr, data);
-		goto out_tsk;
-
-	      case PTRACE_SYSCALL:
-		/* continue and stop at next (return from) syscall */
-	      case PTRACE_CONT:
-		/* restart after signal. */
-		ret = -EIO;
-		if (!valid_signal(data))
-			goto out_tsk;
-		if (request == PTRACE_SYSCALL)
-			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		else
-			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		child->exit_code = data;
-
-		/*
-		 * Make sure the single step/taken-branch trap bits
-		 * are not set:
-		 */
-		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-		ia64_psr(pt)->ss = 0;
-		ia64_psr(pt)->tb = 0;
-
-		wake_up_process(child);
-		ret = 0;
-		goto out_tsk;
-
-	      case PTRACE_KILL:
-		/*
-		 * Make the child exit.  Best I can do is send it a
-		 * sigkill.  Perhaps it should be put in the status
-		 * that it wants to exit.
-		 */
-		if (child->exit_state == EXIT_ZOMBIE)
-			/* already dead */
-			goto out_tsk;
-		child->exit_code = SIGKILL;
-
-		ptrace_disable(child);
-		wake_up_process(child);
-		ret = 0;
-		goto out_tsk;
-
-	      case PTRACE_SINGLESTEP:
-		/* let child execute for one instruction */
-	      case PTRACE_SINGLEBLOCK:
-		ret = -EIO;
-		if (!valid_signal(data))
-			goto out_tsk;
-
-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		set_tsk_thread_flag(child, TIF_SINGLESTEP);
-		if (request == PTRACE_SINGLESTEP) {
-			ia64_psr(pt)->ss = 1;
-		} else {
-			ia64_psr(pt)->tb = 1;
-		}
-		child->exit_code = data;
-
-		/* give it a chance to run. */
-		wake_up_process(child);
-		ret = 0;
-		goto out_tsk;
-
-	      case PTRACE_DETACH:
-		/* detach a process that was attached. */
-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		ret = ptrace_detach(child, data);
-		goto out_tsk;
-
-	      case PTRACE_GETREGS:
-		ret = ptrace_getregs(child,
-				     (struct pt_all_user_regs __user *) data);
-		goto out_tsk;
-
-	      case PTRACE_SETREGS:
-		ret = ptrace_setregs(child,
-				     (struct pt_all_user_regs __user *) data);
-		goto out_tsk;
-
-	      default:
-		ret = ptrace_request(child, request, addr, data);
-		goto out_tsk;
-	}
-  out_tsk:
-	put_task_struct(child);
-  out:
-	unlock_kernel();
-	return ret;
-}
-#endif
 
 /* "asmlinkage" so the input arguments are preserved... */
 
@@ -1667,6 +770,9 @@ syscall_trace_leave (long arg0, long arg
 	}
 }
 
+
+#ifdef CONFIG_UTRACE
+
 /* Utrace implementation starts here */
 
 typedef struct utrace_get {
@@ -2454,3 +1560,119 @@ const struct utrace_regset_view *utrace_
 #endif
 	return &utrace_ia64_native;
 }
+#endif	/* CONFIG_UTRACE */
+
+
+#ifdef CONFIG_PTRACE
+
+#define WORD(member, num) \
+	offsetof(struct pt_all_user_regs, member), \
+	offsetof(struct pt_all_user_regs, member) + num * sizeof(long)
+static const struct ptrace_layout_segment pt_all_user_regs_layout[] = {
+	{WORD(nat, 1),			0,	ELF_NAT_OFFSET},
+	{WORD(cr_iip, 1),		0,	ELF_CR_IIP_OFFSET},
+	{WORD(cfm, 1),			0,	ELF_CFM_OFFSET},
+	{WORD(cr_ipsr, 1),		0,	ELF_CR_IPSR_OFFSET},
+	{WORD(pr, 1),			0,	ELF_PR_OFFSET},
+	{WORD(gr[0], 1),		-1,	-1},
+	{WORD(gr[1], 31),		0,	ELF_GR_OFFSET(1)},
+	{WORD(br[0], 8),		0, 	ELF_BR_OFFSET(0)},
+	{WORD(ar[0], 16),		-1,	-1},
+	{WORD(ar[PT_AUR_RSC], 4),	0,	ELF_AR_RSC_OFFSET},
+	{WORD(ar[PT_AUR_RNAT+1], 12),	-1,	-1},
+	{WORD(ar[PT_AUR_CCV], 1),	0,	ELF_AR_CCV_OFFSET},
+	{WORD(ar[PT_AUR_CCV+1], 3),	-1,	-1},
+	{WORD(ar[PT_AUR_UNAT], 1), 	0,	ELF_AR_UNAT_OFFSET},
+	{WORD(ar[PT_AUR_UNAT+1], 3),	-1,	-1},
+	{WORD(ar[PT_AUR_FPSR], 1), 	0,	ELF_AR_FPSR_OFFSET},
+	{WORD(ar[PT_AUR_FPSR+1], 23), 	-1,	-1},
+	{WORD(ar[PT_AUR_PFS], 3),  	0,	ELF_AR_PFS_OFFSET},
+	{WORD(ar[PT_AUR_EC+1], 62),	-1,	-1},
+	{offsetof(struct pt_all_user_regs, fr[0]),
+	 offsetof(struct pt_all_user_regs, fr[2]),
+	 -1, -1},
+	{offsetof(struct pt_all_user_regs, fr[2]),
+	 offsetof(struct pt_all_user_regs, fr[128]),
+	 1, 2 * sizeof(elf_fpreg_t)},
+	{0, 0, -1, 0}
+};
+#undef WORD
+
+#define NEXT(addr, sum)	(addr + sum * sizeof(long))
+static const struct ptrace_layout_segment pt_uarea_layout[] = {
+	{PT_F32,	PT_NAT_BITS,		1,	ELF_FP_OFFSET(32)},
+	{PT_NAT_BITS,	NEXT(PT_NAT_BITS, 1),	0,	ELF_NAT_OFFSET},
+	{PT_F2, 	PT_F10,			1,	ELF_FP_OFFSET(2)},
+	{PT_F10, 	PT_R4, 			1,	ELF_FP_OFFSET(10)},
+	{PT_R4, 	PT_B1, 			0,	ELF_GR_OFFSET(4)},
+	{PT_B1, 	PT_AR_EC, 		0,	ELF_BR_OFFSET(1)},
+	{PT_AR_EC, 	PT_AR_LC,	 	0,	ELF_AR_EC_OFFSET},
+	{PT_AR_LC, 	NEXT(PT_AR_LC, 1), 	0,	ELF_AR_LC_OFFSET},
+	{PT_CR_IPSR,	PT_CR_IIP,		0,	ELF_CR_IPSR_OFFSET},
+	{PT_CR_IIP,	PT_AR_UNAT,		0,	ELF_CR_IIP_OFFSET},
+	{PT_AR_UNAT,	PT_AR_PFS,		0, 	ELF_AR_UNAT_OFFSET},
+	{PT_AR_PFS,	PT_AR_RSC,		0,	ELF_AR_PFS_OFFSET},
+	{PT_AR_RSC,	PT_AR_RNAT,		0,	ELF_AR_RSC_OFFSET},
+	{PT_AR_RNAT,	PT_AR_BSPSTORE,		0,	ELF_AR_RNAT_OFFSET},
+	{PT_AR_BSPSTORE,PT_PR,			0,	ELF_AR_BSPSTORE_OFFSET},
+	{PT_PR,		PT_B6,			0,	ELF_PR_OFFSET},
+	{PT_B6,		PT_AR_BSP,		0,	ELF_BR_OFFSET(6)},
+	{PT_AR_BSP,	PT_R1,			0,	ELF_AR_BSP_OFFSET},
+	{PT_R1,		PT_R12,			0,	ELF_GR_OFFSET(1)},
+	{PT_R12,	PT_R8,			0,	ELF_GR_OFFSET(12)},
+	{PT_R8,		PT_R16,			0,	ELF_GR_OFFSET(8)},
+	{PT_R16,	PT_AR_CCV,		0,	ELF_GR_OFFSET(16)},
+	{PT_AR_CCV,	PT_AR_FPSR,		0,	ELF_AR_CCV_OFFSET},
+	{PT_AR_FPSR,	PT_B0,			0,	ELF_AR_FPSR_OFFSET},
+	{PT_B0,		PT_B7,			0,	ELF_BR_OFFSET(0)},
+	{PT_B7,		PT_F6,			0,	ELF_BR_OFFSET(7)},
+	{PT_F6,		PT_AR_CSD,		1,	ELF_FP_OFFSET(6)},
+	{PT_AR_CSD,	NEXT(PT_AR_CSD, 2),	0,	ELF_AR_CSD_OFFSET},
+	{PT_DBR,	NEXT(PT_DBR, 8), 	2,	0},
+	{PT_IBR,	NEXT(PT_IBR, 8),	2,	8 * sizeof(long)},
+	{0, 0, -1, 0}
+};
+#undef NEXT
+
+int arch_ptrace(long *request, struct task_struct *child,
+		struct utrace_attached_engine *engine,
+		unsigned long addr, unsigned long data, long *val)
+{
+	int ret = -ENOSYS;
+	switch (*request) {
+	case PTRACE_OLD_GETSIGINFO:
+		*request = PTRACE_GETSIGINFO;
+		break;
+	case PTRACE_OLD_SETSIGINFO:
+		*request = PTRACE_SETSIGINFO;
+		break;
+
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
+	case PTRACE_PEEKDATA:
+		ret = access_process_vm(child, addr, val, sizeof(*val), 0);
+		ret = ret == sizeof(*val) ? 0 : -EIO;
+		break;
+
+	case PTRACE_PEEKUSR:
+		return ptrace_layout_access(child, engine,
+					    utrace_native_view(current),
+					    pt_uarea_layout,
+					    addr, sizeof(long),
+					    NULL, val, 0);
+	case PTRACE_POKEUSR:
+		return ptrace_pokeusr(child, engine,
+				      pt_uarea_layout, addr, data);
+
+	case PTRACE_GETREGS:
+	case PTRACE_SETREGS:
+		return ptrace_layout_access(child, engine,
+					    utrace_native_view(current),
+					    pt_all_user_regs_layout,
+					    0, sizeof(struct pt_all_user_regs),
+					    (void __user *) data, NULL,
+					    *request == PTRACE_SETREGS);
+	}
+	return ret;
+}
+
+#endif	/* CONFIG_PTRACE */

linux-2.6-utrace-ptrace-compat-s390.patch:
 compat_wrapper.S |    2 
 ptrace.c         |  151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 152 insertions(+), 1 deletion(-)

--- NEW FILE linux-2.6-utrace-ptrace-compat-s390.patch ---
[PATCH 4c] utrace: s390 ptrace compatibility

This patch implements ptrace compatibility for s390.

Signed-off-by: Roland McGrath <roland at redhat.com>
Signed-off-by: David Wilder <dwilder at us.ibm.com>

---

 arch/s390/kernel/ptrace.c         |  151 +++++++++++++++++++++++++++++++++++++
 arch/s390/kernel/compat_wrapper.S |    2 
 2 files changed, 152 insertions(+), 1 deletions(-)

--- linux-2.6/arch/s390/kernel/ptrace.c
+++ linux-2.6/arch/s390/kernel/ptrace.c
@@ -575,6 +575,157 @@ const struct utrace_regset_view *utrace_
 }
 
 
+#ifdef CONFIG_PTRACE
+static const struct ptrace_layout_segment s390_uarea[] = {
+	{PT_PSWMASK, PT_FPC, 0, 0},
+	{PT_FPC, PT_CR_9, 1, 0},
+	{PT_CR_9, PT_IEEE_IP, 2, 0},
+	{PT_IEEE_IP, sizeof(struct user), -1, -1},
+	{0, 0, -1, 0}
+};
+
+int arch_ptrace(long *request, struct task_struct *child,
+		struct utrace_attached_engine *engine,
+		unsigned long addr, unsigned long data, long *val)
+{
+	ptrace_area parea;
+	unsigned long tmp;
+	int copied;
+
+	switch (*request) {
+	case PTRACE_PEEKUSR:
+#ifdef CONFIG_64BIT
+		/*
+		 * Stupid gdb peeks/pokes the access registers in 64 bit with
+		 * an alignment of 4. Programmers from hell...
+		 */
+		if (addr >= PT_ACR0 && addr < PT_ACR15) {
+			if (addr & 3)
+				return -EIO;
+			tmp = *(unsigned long *)
+				((char *) child->thread.acrs + addr - PT_ACR0);
+			return put_user(tmp, (unsigned long __user *) data);
+		}
+		else if (addr == PT_ACR15) {
+			/*
+			 * Very special case: old & broken 64 bit gdb reading
+			 * from acrs[15]. Result is a 64 bit value. Read the
+			 * 32 bit acrs[15] value and shift it by 32. Sick...
+			 */
+			tmp = ((unsigned long) child->thread.acrs[15]) << 32;
+			return put_user(tmp, (unsigned long __user *) data);
+		}
+#endif
+		return ptrace_peekusr(child, engine, s390_uarea, addr, data);
+	case PTRACE_POKEUSR:
+#ifdef CONFIG_64BIT
+		if (addr >= PT_ACR0 && addr < PT_ACR15) {
+			if (addr & 3)
+				return -EIO;
+			*(unsigned long *) ((char *) child->thread.acrs
+					    + addr - PT_ACR0) = data;
+			return 0;
+		}
+		else if (addr == PT_ACR15) {
+			/*
+			 * Very special case: old & broken 64 bit gdb writing
+			 * to acrs[15] with a 64 bit value. Ignore the lower
+			 * half of the value and write the upper 32 bit to
+			 * acrs[15]. Sick...
+			 */
+			child->thread.acrs[15] = data >> 32;
+			return 0;
+		}
+#endif
+		return ptrace_pokeusr(child, engine, s390_uarea, addr, data);
+
+	case PTRACE_PEEKUSR_AREA:
+	case PTRACE_POKEUSR_AREA:
+		if (copy_from_user(&parea, (ptrace_area __user *) addr,
+				   sizeof(parea)))
+			return -EFAULT;
+		if ((parea.kernel_addr | parea.len) & (sizeof(data) - 1))
+			return -EIO;
+		return ptrace_layout_access(child, engine,
+					    utrace_native_view(current),
+					    s390_uarea,
+					    parea.kernel_addr, parea.len,
+					    (void __user *) parea.process_addr,
+					    NULL,
+					    *request == PTRACE_POKEUSR_AREA);
+
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKDATA:
+		/* Remove high order bit from address (only for 31 bit). */
+		addr &= PSW_ADDR_INSN;
+		/* read word at location addr. */
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		if (copied != sizeof(tmp))
+			return -EIO;
+		return put_user(tmp, (unsigned long __user *) data);
+
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEDATA:
+		/* Remove high order bit from address (only for 31 bit). */
+		addr &= PSW_ADDR_INSN;
+		/* write the word at location addr. */
+		copied = access_process_vm(child, addr, &data, sizeof(data),1);
+		if (copied != sizeof(data))
+			return -EIO;
+		return 0;
+	}
+
+	return -ENOSYS;
+}
+
+#ifdef CONFIG_COMPAT
+static const struct ptrace_layout_segment s390_compat_uarea[] = {
+	{PT_PSWMASK / 2, PT_FPC / 2, 0, 0},
+	{PT_FPC / 2, PT_CR_9 / 2, 1, 0},
+	{PT_CR_9 / 2, PT_IEEE_IP / 2, 2, 0},
+	{PT_IEEE_IP / 2, sizeof(struct user32), -1, -1},
+	{0, 0, -1, 0}
+};
+
+int arch_compat_ptrace(compat_long_t *request,
+		       struct task_struct *child,
+		       struct utrace_attached_engine *engine,
+		       compat_ulong_t addr, compat_ulong_t data,
+		       compat_long_t *val)
+{
+	ptrace_area_emu31 parea;
+
+	switch (*request) {
+	case PTRACE_PEEKUSR:
+		return ptrace_compat_peekusr(child, engine, s390_compat_uarea,
+					     addr, data);
+	case PTRACE_POKEUSR:
+		return ptrace_compat_pokeusr(child, engine, s390_compat_uarea,
+					     addr, data);
+	case PTRACE_PEEKUSR_AREA:
+	case PTRACE_POKEUSR_AREA:
+		if (copy_from_user(&parea, ((ptrace_area_emu31 __user *)
+					    (unsigned long) addr),
+				   sizeof(parea)))
+			return -EFAULT;
+		if ((parea.kernel_addr | parea.len) & (sizeof(data) - 1))
+			return -EIO;
+		return ptrace_layout_access(child, engine,
+					    utrace_native_view(current),
+					    s390_compat_uarea,
+					    parea.kernel_addr, parea.len,
+					    (void __user *)
+					    (unsigned long) parea.process_addr,
+					    NULL,
+					    *request == PTRACE_POKEUSR_AREA);
+	}
+
+	return -ENOSYS;
+}
+#endif	/* CONFIG_COMPAT */
+#endif	/* CONFIG_PTRACE */
+
+
 asmlinkage void
 syscall_trace(struct pt_regs *regs, int entryexit)
 {
--- linux-2.6/arch/s390/kernel/compat_wrapper.S
+++ linux-2.6/arch/s390/kernel/compat_wrapper.S
@@ -121,7 +121,7 @@ sys32_ptrace_wrapper:
 	lgfr	%r3,%r3			# long
 	llgtr	%r4,%r4			# long
 	llgfr	%r5,%r5			# long
-	jg	sys_ptrace		# branch to system call
+	jg	compat_sys_ptrace	# branch to system call
 
 	.globl	sys32_alarm_wrapper
 sys32_alarm_wrapper:

linux-2.6-utrace-ptrace-compat-sparc64.patch:
 ptrace.c |  566 +++++++++++----------------------------------------------------
 1 files changed, 100 insertions(+), 466 deletions(-)

Index: linux-2.6-utrace-ptrace-compat-sparc64.patch
===================================================================
RCS file: linux-2.6-utrace-ptrace-compat-sparc64.patch
diff -N linux-2.6-utrace-ptrace-compat-sparc64.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-ptrace-compat-sparc64.patch	19 Jul 2007 17:46:36 -0000	1.3
@@ -0,0 +1,599 @@
+[PATCH 4b] utrace: sparc64 ptrace compatibility
+
+This patch implements ptrace compatibility for sparc64.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+
+---
+
+ arch/sparc64/kernel/ptrace.c |  566 +++++++-----------------------------------
+ 1 files changed, 100 insertions(+), 466 deletions(-)
+
+--- linux-2.6/arch/sparc64/kernel/ptrace.c
++++ linux-2.6/arch/sparc64/kernel/ptrace.c
+@@ -667,484 +667,118 @@ void flush_ptrace_access(struct vm_area_
+ 	}
+ }
+ 
+-#if 0				/* XXX */
+-asmlinkage void do_ptrace(struct pt_regs *regs)
++#ifdef CONFIG_PTRACE
++static const struct ptrace_layout_segment sparc64_getregs_layout[] = {
++	{ 0, offsetof(struct pt_regs, u_regs[15]), 0, sizeof(long) },
++	{ offsetof(struct pt_regs, u_regs[15]),
++	  offsetof(struct pt_regs, tstate),
++	  -1, 0 },
++	{ offsetof(struct pt_regs, tstate), offsetof(struct pt_regs, y),
++	  0, 32 * sizeof(long) },
++	{0, 0, -1, 0}
++};
++
++int arch_ptrace(long *request, struct task_struct *child,
++		struct utrace_attached_engine *engine,
++		unsigned long addr, unsigned long data,
++		long *retval)
+ {
+-	int request = regs->u_regs[UREG_I0];
+-	pid_t pid = regs->u_regs[UREG_I1];
+-	unsigned long addr = regs->u_regs[UREG_I2];
+-	unsigned long data = regs->u_regs[UREG_I3];
+-	unsigned long addr2 = regs->u_regs[UREG_I4];
+-	struct task_struct *child;
+-	int ret;
+-
+-	if (test_thread_flag(TIF_32BIT)) {
+-		addr &= 0xffffffffUL;
+-		data &= 0xffffffffUL;
+-		addr2 &= 0xffffffffUL;
+-	}
+-	lock_kernel();
+-#ifdef DEBUG_PTRACE
+-	{
+-		char *s;
+-
+-		if ((request >= 0) && (request <= 24))
+-			s = pt_rq [request];
+-		else
+-			s = "unknown";
+-
+-		if (request == PTRACE_POKEDATA && data == 0x91d02001){
+-			printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n",
+-				pid, addr, addr2);
+-		} else 
+-			printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
+-			       s, request, pid, addr, data, addr2);
+-	}
+-#endif
+-	if (request == PTRACE_TRACEME) {
+-		ret = ptrace_traceme();
+-		if (ret < 0)
+-			pt_error_return(regs, -ret);
+-		else
+-			pt_succ_return(regs, 0);
+-		goto out;
+-	}
+-
+-	child = ptrace_get_task_struct(pid);
+-	if (IS_ERR(child)) {
+-		ret = PTR_ERR(child);
+-		pt_error_return(regs, -ret);
+-		goto out;
+-	}
+-
+-	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
+-	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
+-		if (ptrace_attach(child)) {
+-			pt_error_return(regs, EPERM);
+-			goto out_tsk;
+-		}
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
+-
+-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+-	if (ret < 0) {
+-		pt_error_return(regs, -ret);
+-		goto out_tsk;
+-	}
+-
+-	if (!(test_thread_flag(TIF_32BIT))	&&
+-	    ((request == PTRACE_READDATA64)		||
+-	     (request == PTRACE_WRITEDATA64)		||
+-	     (request == PTRACE_READTEXT64)		||
+-	     (request == PTRACE_WRITETEXT64)		||
+-	     (request == PTRACE_PEEKTEXT64)		||
+-	     (request == PTRACE_POKETEXT64)		||
+-	     (request == PTRACE_PEEKDATA64)		||
+-	     (request == PTRACE_POKEDATA64))) {
+-		addr = regs->u_regs[UREG_G2];
+-		addr2 = regs->u_regs[UREG_G3];
+-		request -= 30; /* wheee... */
+-	}
+-
+-	switch(request) {
+-	case PTRACE_PEEKUSR:
+-		if (addr != 0)
+-			pt_error_return(regs, EIO);
+-		else
+-			pt_succ_return(regs, 0);
+-		goto out_tsk;
+-
+-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+-	case PTRACE_PEEKDATA: {
+-		unsigned long tmp64;
+-		unsigned int tmp32;
+-		int res, copied;
+-
+-		res = -EIO;
+-		if (test_thread_flag(TIF_32BIT)) {
+-			copied = access_process_vm(child, addr,
+-						   &tmp32, sizeof(tmp32), 0);
+-			tmp64 = (unsigned long) tmp32;
+-			if (copied == sizeof(tmp32))
+-				res = 0;
+-		} else {
+-			copied = access_process_vm(child, addr,
+-						   &tmp64, sizeof(tmp64), 0);
+-			if (copied == sizeof(tmp64))
+-				res = 0;
+-		}
+-		if (res < 0)
+-			pt_error_return(regs, -res);
+-		else
+-			pt_os_succ_return(regs, tmp64, (void __user *) data);
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_POKETEXT: /* write the word at location addr. */
+-	case PTRACE_POKEDATA: {
+-		unsigned long tmp64;
+-		unsigned int tmp32;
+-		int copied, res = -EIO;
+-
+-		if (test_thread_flag(TIF_32BIT)) {
+-			tmp32 = data;
+-			copied = access_process_vm(child, addr,
+-						   &tmp32, sizeof(tmp32), 1);
+-			if (copied == sizeof(tmp32))
+-				res = 0;
+-		} else {
+-			tmp64 = data;
+-			copied = access_process_vm(child, addr,
+-						   &tmp64, sizeof(tmp64), 1);
+-			if (copied == sizeof(tmp64))
+-				res = 0;
+-		}
+-		if (res < 0)
+-			pt_error_return(regs, -res);
+-		else
+-			pt_succ_return(regs, res);
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_GETREGS: {
+-		struct pt_regs32 __user *pregs =
+-			(struct pt_regs32 __user *) addr;
+-		struct pt_regs *cregs = task_pt_regs(child);
+-		int rval;
+-
+-		if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
+-		    __put_user(cregs->tpc, (&pregs->pc)) ||
+-		    __put_user(cregs->tnpc, (&pregs->npc)) ||
+-		    __put_user(cregs->y, (&pregs->y))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		for (rval = 1; rval < 16; rval++)
+-			if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
+-				pt_error_return(regs, EFAULT);
+-				goto out_tsk;
+-			}
+-		pt_succ_return(regs, 0);
+-#ifdef DEBUG_PTRACE
+-		printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
+-#endif
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_GETREGS64: {
+-		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
+-		struct pt_regs *cregs = task_pt_regs(child);
+-		unsigned long tpc = cregs->tpc;
+-		int rval;
+-
+-		if ((task_thread_info(child)->flags & _TIF_32BIT) != 0)
+-			tpc &= 0xffffffff;
+-		if (__put_user(cregs->tstate, (&pregs->tstate)) ||
+-		    __put_user(tpc, (&pregs->tpc)) ||
+-		    __put_user(cregs->tnpc, (&pregs->tnpc)) ||
+-		    __put_user(cregs->y, (&pregs->y))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		for (rval = 1; rval < 16; rval++)
+-			if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
+-				pt_error_return(regs, EFAULT);
+-				goto out_tsk;
+-			}
+-		pt_succ_return(regs, 0);
+-#ifdef DEBUG_PTRACE
+-		printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
+-#endif
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_SETREGS: {
+-		struct pt_regs32 __user *pregs =
+-			(struct pt_regs32 __user *) addr;
+-		struct pt_regs *cregs = task_pt_regs(child);
+-		unsigned int psr, pc, npc, y;
+-		int i;
+-
+-		/* Must be careful, tracing process can only set certain
+-		 * bits in the psr.
+-		 */
+-		if (__get_user(psr, (&pregs->psr)) ||
+-		    __get_user(pc, (&pregs->pc)) ||
+-		    __get_user(npc, (&pregs->npc)) ||
+-		    __get_user(y, (&pregs->y))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		cregs->tstate &= ~(TSTATE_ICC);
+-		cregs->tstate |= psr_to_tstate_icc(psr);
+-               	if (!((pc | npc) & 3)) {
+-			cregs->tpc = pc;
+-			cregs->tnpc = npc;
+-		}
+-		cregs->y = y;
+-		for (i = 1; i < 16; i++) {
+-			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
+-				pt_error_return(regs, EFAULT);
+-				goto out_tsk;
+-			}
+-		}
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_SETREGS64: {
+-		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
+-		struct pt_regs *cregs = task_pt_regs(child);
+-		unsigned long tstate, tpc, tnpc, y;
+-		int i;
+-
+-		/* Must be careful, tracing process can only set certain
+-		 * bits in the psr.
+-		 */
+-		if (__get_user(tstate, (&pregs->tstate)) ||
+-		    __get_user(tpc, (&pregs->tpc)) ||
+-		    __get_user(tnpc, (&pregs->tnpc)) ||
+-		    __get_user(y, (&pregs->y))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) {
+-			tpc &= 0xffffffff;
+-			tnpc &= 0xffffffff;
+-		}
+-		tstate &= (TSTATE_ICC | TSTATE_XCC);
+-		cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
+-		cregs->tstate |= tstate;
+-		if (!((tpc | tnpc) & 3)) {
+-			cregs->tpc = tpc;
+-			cregs->tnpc = tnpc;
+-		}
+-		cregs->y = y;
+-		for (i = 1; i < 16; i++) {
+-			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
+-				pt_error_return(regs, EFAULT);
+-				goto out_tsk;
+-			}
+-		}
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_GETFPREGS: {
+-		struct fps {
+-			unsigned int regs[32];
+-			unsigned int fsr;
+-			unsigned int flags;
+-			unsigned int extra;
+-			unsigned int fpqd;
+-			struct fq {
+-				unsigned int insnaddr;
+-				unsigned int insn;
+-			} fpq[16];
+-		};
+-		struct fps __user *fps = (struct fps __user *) addr;
+-		unsigned long *fpregs = task_thread_info(child)->fpregs;
+-
+-		if (copy_to_user(&fps->regs[0], fpregs,
+-				 (32 * sizeof(unsigned int))) ||
+-		    __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) ||
+-		    __put_user(0, (&fps->fpqd)) ||
+-		    __put_user(0, (&fps->flags)) ||
+-		    __put_user(0, (&fps->extra)) ||
+-		    clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_GETFPREGS64: {
+-		struct fps {
+-			unsigned int regs[64];
+-			unsigned long fsr;
+-		};
+-		struct fps __user *fps = (struct fps __user *) addr;
+-		unsigned long *fpregs = task_thread_info(child)->fpregs;
+-
+-		if (copy_to_user(&fps->regs[0], fpregs,
+-				 (64 * sizeof(unsigned int))) ||
+-		    __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_SETFPREGS: {
+-		struct fps {
+-			unsigned int regs[32];
+-			unsigned int fsr;
+-			unsigned int flags;
+-			unsigned int extra;
+-			unsigned int fpqd;
+-			struct fq {
+-				unsigned int insnaddr;
+-				unsigned int insn;
+-			} fpq[16];
+-		};
+-		struct fps __user *fps = (struct fps __user *) addr;
+-		unsigned long *fpregs = task_thread_info(child)->fpregs;
+-		unsigned fsr;
+-
+-		if (copy_from_user(fpregs, &fps->regs[0],
+-				   (32 * sizeof(unsigned int))) ||
+-		    __get_user(fsr, (&fps->fsr))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL;
+-		task_thread_info(child)->xfsr[0] |= fsr;
+-		if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
+-			task_thread_info(child)->gsr[0] = 0;
+-		task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
+-
+-	case PTRACE_SETFPREGS64: {
+-		struct fps {
+-			unsigned int regs[64];
+-			unsigned long fsr;
+-		};
+-		struct fps __user *fps = (struct fps __user *) addr;
+-		unsigned long *fpregs = task_thread_info(child)->fpregs;
+-
+-		if (copy_from_user(fpregs, &fps->regs[0],
+-				   (64 * sizeof(unsigned int))) ||
+-		    __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) {
+-			pt_error_return(regs, EFAULT);
+-			goto out_tsk;
+-		}
+-		if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
+-			task_thread_info(child)->gsr[0] = 0;
+-		task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
++	void __user *uaddr = (void __user *) addr;
++	struct pt_regs *uregs = uaddr;
++	int err = -ENOSYS;
++
++	switch (*request) {
++	case PTRACE_GETREGS64:
++		err = ptrace_layout_access(child, engine,
++					   &utrace_sparc64_native_view,
++					   sparc64_getregs_layout,
++					   0, offsetof(struct pt_regs, y),
++					   uaddr, NULL, 0);
++		if (!err &&
++		    (put_user(task_pt_regs(child)->y, &uregs->y) ||
++		     put_user(task_pt_regs(child)->fprs, &uregs->fprs)))
++			err = -EFAULT;
++		break;
+ 
+-	case PTRACE_READTEXT:
+-	case PTRACE_READDATA: {
+-		int res = ptrace_readdata(child, addr,
+-					  (char __user *)addr2, data);
+-		if (res == data) {
+-			pt_succ_return(regs, 0);
+-			goto out_tsk;
+-		}
+-		if (res >= 0)
+-			res = -EIO;
+-		pt_error_return(regs, -res);
+-		goto out_tsk;
+-	}
++	case PTRACE_SETREGS64:
++		err = ptrace_layout_access(child, engine,
++					   &utrace_sparc64_native_view,
++					   sparc64_getregs_layout,
++					   0, offsetof(struct pt_regs, y),
++					   uaddr, NULL, 1);
++		if (!err &&
++		    (get_user(task_pt_regs(child)->y, &uregs->y) ||
++		     get_user(task_pt_regs(child)->fprs, &uregs->fprs)))
++			err = -EFAULT;
++		break;
+ 
+-	case PTRACE_WRITETEXT:
+-	case PTRACE_WRITEDATA: {
+-		int res = ptrace_writedata(child, (char __user *) addr2,
+-					   addr, data);
+-		if (res == data) {
+-			pt_succ_return(regs, 0);
+-			goto out_tsk;
+-		}
+-		if (res >= 0)
+-			res = -EIO;
+-		pt_error_return(regs, -res);
+-		goto out_tsk;
+-	}
+-	case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
+-		addr = 1;
++	case PTRACE_GETFPREGS64:
++	case PTRACE_SETFPREGS64:
++		err = ptrace_regset_access(child, engine,
++					   utrace_native_view(current),
++					   2, 0, 34 * sizeof(long), uaddr,
++					   (*request == PTRACE_SETFPREGS64));
++		break;
+ 
+-	case PTRACE_CONT: { /* restart after signal. */
+-		if (!valid_signal(data)) {
+-			pt_error_return(regs, EIO);
+-			goto out_tsk;
+-		}
+-
+-		if (request == PTRACE_SYSCALL) {
+-			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		} else {
+-			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-
+-		child->exit_code = data;
+-#ifdef DEBUG_PTRACE
+-		printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
+-			child->pid, child->exit_code,
+-			task_pt_regs(child)->tpc,
+-			task_pt_regs(child)->tnpc);
+-		       
+-#endif
+-		wake_up_process(child);
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
++	case PTRACE_SUNDETACH:
++		*request = PTRACE_DETACH;
++		break;
+ 
+-/*
+- * make the child exit.  Best I can do is send it a sigkill. 
+- * perhaps it should be put in the status that it wants to 
+- * exit.
+- */
+-	case PTRACE_KILL: {
+-		if (child->exit_state == EXIT_ZOMBIE) {	/* already dead */
+-			pt_succ_return(regs, 0);
+-			goto out_tsk;
+-		}
+-		child->exit_code = SIGKILL;
+-		wake_up_process(child);
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
++	default:
++		break;
++	};
++	return err;
++}
+ 
+-	case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+-		int error = ptrace_detach(child, data);
+-		if (error) {
+-			pt_error_return(regs, EIO);
+-			goto out_tsk;
+-		}
+-		pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
++#ifdef CONFIG_COMPAT
++static const struct ptrace_layout_segment sparc32_getregs_layout[] = {
++	{ 0, offsetof(struct pt_regs32, u_regs[0]),
++	  0, GENREG32_PSR * sizeof(u32) },
++	{ offsetof(struct pt_regs32, u_regs[0]),
++	  offsetof(struct pt_regs32, u_regs[15]),
++	  0, 1 * sizeof(u32) },
++	{ offsetof(struct pt_regs32, u_regs[15]), sizeof(struct pt_regs32),
++	  -1, 0 },
++	{0, 0, -1, 0}
++};
++
++int arch_compat_ptrace(compat_long_t *request, struct task_struct *child,
++		       struct utrace_attached_engine *engine,
++		       compat_ulong_t addr, compat_ulong_t data,
++		       compat_long_t *retval)
++{
++	void __user *uaddr = (void __user *) (unsigned long) addr;
++	int err = -ENOSYS;
+ 
+-	/* PTRACE_DUMPCORE unsupported... */
++	switch (*request) {
++	case PTRACE_GETREGS:
++	case PTRACE_SETREGS:
++		err = ptrace_layout_access(child, engine,
++					   &utrace_sparc32_view,
++					   sparc32_getregs_layout,
++					   0, sizeof(struct pt_regs32),
++					   uaddr, NULL,
++					   (*request ==
++					    PTRACE_SETREGS));
++		break;
+ 
+-	case PTRACE_GETEVENTMSG: {
+-		int err;
++	case PTRACE_GETFPREGS:
++	case PTRACE_SETFPREGS:
++		err = ptrace_whole_regset(child, engine, addr, 1,
++					  (*request == PTRACE_SETFPREGS));
++		break;
+ 
+-		if (test_thread_flag(TIF_32BIT))
+-			err = put_user(child->ptrace_message,
+-				       (unsigned int __user *) data);
+-		else
+-			err = put_user(child->ptrace_message,
+-				       (unsigned long __user *) data);
+-		if (err)
+-			pt_error_return(regs, -err);
+-		else
+-			pt_succ_return(regs, 0);
++	case PTRACE_SUNDETACH:
++		*request = PTRACE_DETACH;
+ 		break;
+-	}
+ 
+-	default: {
+-		int err = ptrace_request(child, request, addr, data);
+-		if (err)
+-			pt_error_return(regs, -err);
+-		else
+-			pt_succ_return(regs, 0);
+-		goto out_tsk;
+-	}
+-	}
+-out_tsk:
+-	if (child)
+-		put_task_struct(child);
+-out:
+-	unlock_kernel();
++	default:
++		break;
++	};
++	return err;
+ }
+-#endif
++#endif	/* CONFIG_COMPAT */
++#endif /* CONFIG_PTRACE */
+ 
+ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+ {

linux-2.6-utrace-ptrace-compat.patch:
 arch/i386/kernel/ptrace.c       |   40 
 arch/powerpc/kernel/ptrace.c    |  250 ++++
 arch/powerpc/kernel/signal_32.c |   52 +
 arch/powerpc/lib/sstep.c        |    3 
 arch/x86_64/ia32/ia32entry.S    |    2 
 arch/x86_64/ia32/ptrace32.c     |   56 -
 arch/x86_64/kernel/ptrace.c     |   46 
 fs/proc/base.c                  |   40 
 include/asm-x86_64/ptrace-abi.h |    3 
 include/asm-x86_64/tracehook.h  |    1 
 include/linux/ptrace.h          |  221 +++-
 include/linux/sched.h           |    4 
 init/Kconfig                    |   15 
 kernel/Makefile                 |    3 
 kernel/exit.c                   |   13 
 kernel/fork.c                   |    2 
 kernel/ptrace.c                 | 2051 +++++++++++++++++++++++++++++++++++++---
 kernel/sys_ni.c                 |    4 
 18 files changed, 2632 insertions(+), 174 deletions(-)

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.3 -r 1.4 linux-2.6-utrace-ptrace-compat.patch
Index: linux-2.6-utrace-ptrace-compat.patch
===================================================================
RCS file: linux-2.6-utrace-ptrace-compat.patch
diff -N linux-2.6-utrace-ptrace-compat.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-ptrace-compat.patch	19 Jul 2007 17:46:36 -0000	1.4
@@ -0,0 +1,3118 @@
+[PATCH 4] utrace: ptrace compatibility
+
+ptrace compatibility on top of <linux/utrace.h> interfaces.
+This attempts to be precisely compatible with existing ptrace behavior.
+It does not extend, improve, or change it.
+
+The ptrace support is made an option, CONFIG_PTRACE.  For now, noone will
+want to turn this off except maybe a bizarre embedded configuration.  But
+it looks forward to a day when we can punt the ptrace system call completely.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+
+---
+
+ fs/proc/base.c                  |   40 +
+ arch/i386/kernel/ptrace.c       |   40 +
+ arch/x86_64/ia32/ptrace32.c     |   56 +
+ arch/x86_64/ia32/ia32entry.S    |    2 
+ arch/x86_64/kernel/ptrace.c     |   46 +
+ arch/powerpc/kernel/ptrace.c    |  250 +++++
+ arch/powerpc/kernel/signal_32.c |   52 +
+ arch/powerpc/lib/sstep.c        |    3 
+ kernel/fork.c                   |    2 
+ kernel/exit.c                   |   13 
+ kernel/ptrace.c                 | 2051 +++++++++++++++++++++++++++++++++++++--
+ kernel/sys_ni.c                 |    4 
+ kernel/Makefile                 |    3 
+ include/linux/sched.h           |    4 
+ include/linux/ptrace.h          |  221 +++-
+ include/asm-x86_64/tracehook.h  |    1 
+ include/asm-x86_64/ptrace-abi.h |    3 
+ init/Kconfig                    |   15 
+ 18 files changed, 2632 insertions(+), 174 deletions(-)
+
+--- linux-2.6/fs/proc/base.c
++++ linux-2.6/fs/proc/base.c
+@@ -151,6 +151,46 @@ static int get_nr_threads(struct task_st
+ 	return count;
+ }
+ 
++static int __ptrace_may_attach(struct task_struct *task)
++{
++	/* May we inspect the given task?
++	 * This check is used both for attaching with ptrace
++	 * and for allowing access to sensitive information in /proc.
++	 *
++	 * ptrace_attach denies several cases that /proc allows
++	 * because setting up the necessary parent/child relationship
++	 * or halting the specified task is impossible.
++	 */
++	int dumpable = 0;
++	/* Don't let security modules deny introspection */
++	if (task == current)
++		return 0;
++	if (((current->uid != task->euid) ||
++	     (current->uid != task->suid) ||
++	     (current->uid != task->uid) ||
++	     (current->gid != task->egid) ||
++	     (current->gid != task->sgid) ||
++	     (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
++		return -EPERM;
++	smp_rmb();
++	if (task->mm)
++		dumpable = task->mm->dumpable;
++	if (!dumpable && !capable(CAP_SYS_PTRACE))
++		return -EPERM;
++
++	return security_ptrace(current, task);
++}
++
++int ptrace_may_attach(struct task_struct *task)
++{
++	int err;
++	task_lock(task);
++	err = __ptrace_may_attach(task);
++	task_unlock(task);
++	return !err;
++}
++
++
+ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+ {
+ 	struct task_struct *task = get_proc_task(inode);
+--- linux-2.6/arch/i386/kernel/ptrace.c
++++ linux-2.6/arch/i386/kernel/ptrace.c
+@@ -735,6 +735,46 @@ const struct utrace_regset_view *utrace_
+ 	return &utrace_i386_native;
+ }
+ 
++#ifdef CONFIG_PTRACE
++static const struct ptrace_layout_segment i386_uarea[] = {
++	{0, FRAME_SIZE*4, 0, 0},
++	{FRAME_SIZE*4, offsetof(struct user, u_debugreg[0]), -1, 0},
++	{offsetof(struct user, u_debugreg[0]),
++	 offsetof(struct user, u_debugreg[8]), 4, 0},
++	{0, 0, -1, 0}
++};
++
++int arch_ptrace(long *req, struct task_struct *child,
++		struct utrace_attached_engine *engine,
++		unsigned long addr, unsigned long data, long *val)
++{
++	switch (*req) {
++	case PTRACE_PEEKUSR:
++		return ptrace_peekusr(child, engine, i386_uarea, addr, data);
++	case PTRACE_POKEUSR:
++		return ptrace_pokeusr(child, engine, i386_uarea, addr, data);
++	case PTRACE_GETREGS:
++		return ptrace_whole_regset(child, engine, data, 0, 0);
++	case PTRACE_SETREGS:
++		return ptrace_whole_regset(child, engine, data, 0, 1);
++	case PTRACE_GETFPREGS:
++		return ptrace_whole_regset(child, engine, data, 1, 0);
++	case PTRACE_SETFPREGS:
++		return ptrace_whole_regset(child, engine, data, 1, 1);
++	case PTRACE_GETFPXREGS:
++		return ptrace_whole_regset(child, engine, data, 2, 0);
++	case PTRACE_SETFPXREGS:
++		return ptrace_whole_regset(child, engine, data, 2, 1);
++	case PTRACE_GET_THREAD_AREA:
++	case PTRACE_SET_THREAD_AREA:
++		return ptrace_onereg_access(child, engine,
++					    utrace_native_view(current), 3,
++					    addr, (void __user *)data,
++					    *req == PTRACE_SET_THREAD_AREA);
++	}
++	return -ENOSYS;
++}
++#endif
+ 
+ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+ {
+--- linux-2.6/arch/x86_64/ia32/ptrace32.c
++++ linux-2.6/arch/x86_64/ia32/ptrace32.c
+@@ -166,11 +166,6 @@ static int getreg32(struct task_struct *
+ 
+ #undef R32
+ 
+-asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
+-{
+-	return -ENOSYS;
+-}
+-
+ static int
+ ia32_genregs_get(struct task_struct *target,
+ 		 const struct utrace_regset *regset,
+@@ -600,3 +595,54 @@ const struct utrace_regset_view utrace_i
+ 	.name = "i386", .e_machine = EM_386,
+ 	.regsets = ia32_regsets, .n = ARRAY_SIZE(ia32_regsets)
+ };
++
++
++#ifdef CONFIG_PTRACE
++/*
++ * This matches the arch/i386/kernel/ptrace.c definitions.
++ */
++
++static const struct ptrace_layout_segment ia32_uarea[] = {
++	{0, sizeof(struct user_regs_struct32), 0, 0},
++	{sizeof(struct user_regs_struct32),
++	 offsetof(struct user32, u_debugreg[0]), -1, 0},
++	{offsetof(struct user32, u_debugreg[0]),
++	 offsetof(struct user32, u_debugreg[8]), 4, 0},
++	{0, 0, -1, 0}
++};
++
++int arch_compat_ptrace(compat_long_t *req, struct task_struct *child,
++		       struct utrace_attached_engine *engine,
++		       compat_ulong_t addr, compat_ulong_t data,
++		       compat_long_t *val)
++{
++	switch (*req) {
++	case PTRACE_PEEKUSR:
++		return ptrace_compat_peekusr(child, engine, ia32_uarea,
++					     addr, data);
++	case PTRACE_POKEUSR:
++		return ptrace_compat_pokeusr(child, engine, ia32_uarea,
++					     addr, data);
++	case PTRACE_GETREGS:
++		return ptrace_whole_regset(child, engine, data, 0, 0);
++	case PTRACE_SETREGS:
++		return ptrace_whole_regset(child, engine, data, 0, 1);
++	case PTRACE_GETFPREGS:
++		return ptrace_whole_regset(child, engine, data, 1, 0);
++	case PTRACE_SETFPREGS:
++		return ptrace_whole_regset(child, engine, data, 1, 1);
++	case PTRACE_GETFPXREGS:
++		return ptrace_whole_regset(child, engine, data, 2, 0);
++	case PTRACE_SETFPXREGS:
++		return ptrace_whole_regset(child, engine, data, 2, 1);
++	case PTRACE_GET_THREAD_AREA:
++	case PTRACE_SET_THREAD_AREA:
++		return ptrace_onereg_access(child, engine,
[...2725 lines suppressed...]
++				struct utrace_attached_engine *engine,
++				const struct utrace_regset_view *view,
++				int setno, unsigned long offset,
++				unsigned int size, void __user *data,
++				int write);
++
++/*
++ * Convenience wrapper for doing access to a whole utrace_regset for ptrace.
++ */
++static inline int ptrace_whole_regset(struct task_struct *child,
++				      struct utrace_attached_engine *engine,
++				      long data, int setno, int write)
++{
++	return ptrace_regset_access(child, engine, utrace_native_view(current),
++				    setno, 0, -1, (void __user *)data, write);
++}
++
++/*
++ * Convenience function doing access to a single slot in a utrace_regset.
++ * The regno value gives a slot number plus regset->bias.
++ * The value accessed is regset->size bytes long.
++ */
++extern int ptrace_onereg_access(struct task_struct *child,
++				struct utrace_attached_engine *engine,
++				const struct utrace_regset_view *view,
++				int setno, unsigned long regno,
++				void __user *data, int write);
++
++
++/*
++ * An array of these describes the layout of the virtual struct user
++ * accessed by PEEKUSR/POKEUSR, or the structure used by GETREGS et al.
++ * The array is terminated by an element with .end of zero.
++ * An element describes the range [.start, .end) of struct user offsets,
++ * measured in bytes; it maps to the regset in the view's regsets array
++ * at the index given by .regset, at .offset bytes into that regset's data.
++ * If .regset is -1, then the [.start, .end) range reads as zero
++ * if .offset is zero, and is skipped on read (user's buffer unchanged)
++ * if .offset is -1.
++ */
++struct ptrace_layout_segment {
++	unsigned int start, end, regset, offset;
++};
++
++/*
++ * Convenience function for doing access to a ptrace compatibility layout.
++ * The offset and size are in bytes.
++ */
++extern int ptrace_layout_access(struct task_struct *child,
++				struct utrace_attached_engine *engine,
++				const struct utrace_regset_view *view,
++				const struct ptrace_layout_segment layout[],
++				unsigned long offset, unsigned int size,
++				void __user *data, void *kdata, int write);
++
++
++/* Convenience wrapper for the common PTRACE_PEEKUSR implementation.  */
++static inline int ptrace_peekusr(struct task_struct *child,
++				 struct utrace_attached_engine *engine,
++				 const struct ptrace_layout_segment layout[],
++				 unsigned long addr, long data)
++{
++	return ptrace_layout_access(child, engine, utrace_native_view(current),
++				    layout, addr, sizeof(long),
++				    (unsigned long __user *)data, NULL, 0);
++}
++
++/* Convenience wrapper for the common PTRACE_PEEKUSR implementation.  */
++static inline int ptrace_pokeusr(struct task_struct *child,
++				 struct utrace_attached_engine *engine,
++				 const struct ptrace_layout_segment layout[],
++				 unsigned long addr, long data)
++{
++	return ptrace_layout_access(child, engine, utrace_native_view(current),
++				    layout, addr, sizeof(long),
++				    NULL, &data, 1);
++}
++
++/*
++ * Called in copy_process.
++ */
++static inline void ptrace_init_task(struct task_struct *tsk)
++{
++	INIT_LIST_HEAD(&tsk->ptracees);
++}
++
++/*
++ * Called in do_exit, after setting PF_EXITING, no locks are held.
++ */
++void ptrace_exit(struct task_struct *tsk);
++
++/*
++ * Called in do_wait, with tasklist_lock held for reading.
++ * This reports any ptrace-child that is ready as do_wait would a normal child.
++ * If there are no ptrace children, returns -ECHILD.
++ * If there are some ptrace children but none reporting now, returns 0.
++ * In those cases the tasklist_lock is still held so next_thread(tsk) works.
++ * For any other return value, tasklist_lock is released before return.
++ */
++int ptrace_do_wait(struct task_struct *tsk,
++		   pid_t pid, int options, struct siginfo __user *infop,
++		   int __user *stat_addr, struct rusage __user *rusagep);
++
++
++#ifdef CONFIG_COMPAT
++#include <linux/compat.h>
++
++extern int arch_compat_ptrace(compat_long_t *request,
++			      struct task_struct *child,
++			      struct utrace_attached_engine *engine,
++			      compat_ulong_t a, compat_ulong_t d,
++			      compat_long_t *retval);
++
++/* Convenience wrapper for the common PTRACE_PEEKUSR implementation.  */
++static inline int ptrace_compat_peekusr(
++	struct task_struct *child, struct utrace_attached_engine *engine,
++	const struct ptrace_layout_segment layout[],
++	compat_ulong_t addr, compat_ulong_t data)
++{
++	compat_ulong_t *udata = (compat_ulong_t __user *) (unsigned long) data;
++	return ptrace_layout_access(child, engine, utrace_native_view(current),
++				    layout, addr, sizeof(compat_ulong_t),
++				    udata, NULL, 0);
++}
++
++/* Convenience wrapper for the common PTRACE_PEEKUSR implementation.  */
++static inline int ptrace_compat_pokeusr(
++	struct task_struct *child, struct utrace_attached_engine *engine,
++	const struct ptrace_layout_segment layout[],
++	compat_ulong_t addr, compat_ulong_t data)
++{
++	return ptrace_layout_access(child, engine, utrace_native_view(current),
++				    layout, addr, sizeof(compat_ulong_t),
++				    NULL, &data, 1);
++}
++#endif	/* CONFIG_COMPAT */
++
++#else  /* no CONFIG_PTRACE */
++static inline void ptrace_init_task(struct task_struct *tsk) { }
++static inline void ptrace_exit(struct task_struct *tsk) { }
++static inline int ptrace_do_wait(struct task_struct *tsk,
++				 pid_t pid, int options,
++				 struct siginfo __user *infop,
++				 int __user *stat_addr,
++				 struct rusage __user *rusagep)
++{
++	return -ECHILD;
++}
++#endif	/* CONFIG_PTRACE */
++
++
+ #ifndef force_successful_syscall_return
+ /*
+  * System call handlers that, upon successful completion, need to return a
+--- linux-2.6/include/asm-x86_64/tracehook.h
++++ linux-2.6/include/asm-x86_64/tracehook.h
+@@ -15,6 +15,7 @@
+ 
+ #include <linux/sched.h>
+ #include <asm/ptrace.h>
++#include <asm/proto.h>
+ 
+ /*
+  * See linux/tracehook.h for the descriptions of what these need to do.
+--- linux-2.6/include/asm-x86_64/ptrace-abi.h
++++ linux-2.6/include/asm-x86_64/ptrace-abi.h
+@@ -48,4 +48,7 @@
+ 
+ #define PTRACE_ARCH_PRCTL	  30	/* arch_prctl for child */
+ 
++#define PTRACE_SYSEMU		  31
++#define PTRACE_SYSEMU_SINGLESTEP  32
++
+ #endif
+--- linux-2.6/init/Kconfig
++++ linux-2.6/init/Kconfig
+@@ -692,10 +692,21 @@ endmenu
+ 
+ menu "Process debugging support"
+ 
++config PTRACE
++	bool "Legacy ptrace system call interface"
++	default y
++	select UTRACE
++	depends on PROC_FS
++	help
++	  Enable the ptrace system call.
++	  This is traditionally used by debuggers like GDB,
++	  and is used by UML and some other applications.
++	  Unless you are very sure you won't run anything that needs it,
++	  say Y.
++
+ config UTRACE
+ 	bool "Infrastructure for tracing and debugging user processes"
+-	default y
+-	depends on MODULES
++	default y if MODULES || PTRACE
+ 	help
+ 	  Enable the utrace process tracing interface.
+ 	  This is an internal kernel interface to track events in user

linux-2.6-utrace-regset-avr32.patch:
 ptrace.c |  108 +++++++++++++++++++++++++--------------------------------------
 1 files changed, 43 insertions(+), 65 deletions(-)

--- NEW FILE linux-2.6-utrace-regset-avr32.patch ---
[PATCH 2d] utrace: avr32 regset support

From: Haavard Skinnemoen <hskinnemoen at atmel.com>

Rip out most of the ptrace code for AVR32 and replace it with the much
nicer utrace stuff.

CC: Haavard Skinnemoen <hskinnemoen at atmel.com>
Signed-off-by: Roland McGrath <roland at redhat.com>

---

 arch/avr32/kernel/ptrace.c |  108 ++++++++++++++++++--------------------------
 1 files changed, 43 insertions(+), 65 deletions(-)

--- linux-2.6/arch/avr32/kernel/ptrace.c
+++ linux-2.6/arch/avr32/kernel/ptrace.c
@@ -14,94 +14,72 @@
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/user.h>
+#include <linux/tracehook.h>
 
+#include <asm/tracehook.h>
 #include <asm/mmu_context.h>
 #include <linux/kdebug.h>
 
+#ifdef CONFIG_UTRACE
+
 static struct pt_regs *get_user_regs(struct task_struct *tsk)
 {
 	return (struct pt_regs *)((unsigned long)task_stack_page(tsk) +
 				  THREAD_SIZE - sizeof(struct pt_regs));
 }
 
-#if 0
-/*
- * Read the word at offset "offset" into the task's "struct user". We
- * actually access the pt_regs struct stored on the kernel stack.
- */
-static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
-			    unsigned long __user *data)
+static int genregs_get(struct task_struct *target,
+		       const struct utrace_regset *regset,
+		       unsigned int pos, unsigned int count,
+		       void *kbuf, void __user *ubuf)
 {
-	unsigned long *regs;
-	unsigned long value;
-
-	pr_debug("ptrace_read_user(%p, %#lx, %p)\n",
-		 tsk, offset, data);
-
-	if (offset & 3 || offset >= sizeof(struct user)) {
-		printk("ptrace_read_user: invalid offset 0x%08lx\n", offset);
-		return -EIO;
-	}
+	struct pt_regs *regs = get_user_regs(target);
 
-	regs = (unsigned long *)get_user_regs(tsk);
-
-	value = 0;
-	if (offset < sizeof(struct pt_regs))
-		value = regs[offset / sizeof(regs[0])];
-
-	return put_user(value, data);
+	return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				     regs, 0, -1);
 }
 
-/*
- * Write the word "value" to offset "offset" into the task's "struct
- * user". We actually access the pt_regs struct stored on the kernel
- * stack.
- */
-static int ptrace_write_user(struct task_struct *tsk, unsigned long offset,
-			     unsigned long value)
+static int genregs_set(struct task_struct *target,
+		       const struct utrace_regset *regset,
+		       unsigned int pos, unsigned int count,
+		       const void *kbuf, const void __user *ubuf)
 {
-	unsigned long *regs;
-
-	if (offset & 3 || offset >= sizeof(struct user)) {
-		printk("ptrace_write_user: invalid offset 0x%08lx\n", offset);
-		return -EIO;
-	}
-
-	if (offset >= sizeof(struct pt_regs))
-		return 0;
+	struct pt_regs *regs = get_user_regs(target);
 
-	regs = (unsigned long *)get_user_regs(tsk);
-	regs[offset / sizeof(regs[0])] = value;
-
-	return 0;
+	return utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				    regs, 0, -1);
 }
 
-static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
-{
-	struct pt_regs *regs = get_user_regs(tsk);
+static const struct utrace_regset native_regsets[] = {
+	{
+		.n	= ELF_NGREG,
+		.size	= sizeof(long),
+		.align	= sizeof(long),
+		.get	= genregs_get,
+		.set	= genregs_set,
+	},
+	/*
+	 * Other register sets that probably would make sense:
+	 *   - Coprocessor registers (8 coprocs with 16 registers each)
+	 *   - TLS stuff
+	 */
+};
 
-	return copy_to_user(uregs, regs, sizeof(*regs)) ? -EFAULT : 0;
-}
+static const struct utrace_regset_view utrace_avr32_native_view = {
+	.name		= UTS_MACHINE,
+	.e_machine	= ELF_ARCH,
+	.regsets	= native_regsets,
+	.n		= ARRAY_SIZE(native_regsets),
+};
 
-static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
+const struct utrace_regset_view *utrace_native_view(struct task_struct *tsk)
 {
-	struct pt_regs newregs;
-	int ret;
-
-	ret = -EFAULT;
-	if (copy_from_user(&newregs, uregs, sizeof(newregs)) == 0) {
-		struct pt_regs *regs = get_user_regs(tsk);
-
-		ret = -EINVAL;
-		if (valid_user_regs(&newregs)) {
-			*regs = newregs;
-			ret = 0;
-		}
-	}
-
-	return ret;
+	return &utrace_avr32_native_view;
 }
+#endif /* CONFIG_UTRACE */
+
 
+#if 0
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	unsigned long tmp;

linux-2.6-utrace-regset-ia64.patch:
 arch/ia64/ia32/sys_ia32.c    |  472 +++++++++++++++++++++++++
 arch/ia64/kernel/ptrace.c    |  804 +++++++++++++++++++++++++++++++++++++++++++
 include/asm-ia64/elf.h       |   24 +
 include/asm-ia64/tracehook.h |    7 
 4 files changed, 1305 insertions(+), 2 deletions(-)

--- NEW FILE linux-2.6-utrace-regset-ia64.patch ---
[PATCH 2a] utrace: ia64 regset support

This patch converts the machine-dependent ptrace code into utrace regset
support for ia64.

Signed-off-by: Roland McGrath <roland at redhat.com>
CC: Anil S Keshavamurthy <anil.s.keshavamurthy at intel.com>
Signed-off-by: Bibo Mao <bibo.mao at intel.com>

---

 arch/ia64/ia32/sys_ia32.c    |  472 +++++++++++++++++++++++++
 arch/ia64/kernel/ptrace.c    |  804 ++++++++++++++++++++++++++++++++++++++++++
 include/asm-ia64/tracehook.h |    7 
 include/asm-ia64/elf.h       |   24 +
 4 files changed, 1305 insertions(+), 2 deletions(-)

--- linux-2.6/arch/ia64/ia32/sys_ia32.c
+++ linux-2.6/arch/ia64/ia32/sys_ia32.c
@@ -44,6 +44,7 @@
 #include <linux/eventpoll.h>
 #include <linux/personality.h>
 #include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/stat.h>
 #include <linux/ipc.h>
 #include <linux/capability.h>
@@ -1868,6 +1869,477 @@ sys32_ptrace (int request, pid_t pid, un
 }
 #endif
 
+#ifdef CONFIG_UTRACE
+typedef struct utrace_get {
+	void *kbuf;
+	void __user *ubuf;
+} utrace_get_t;
+
+typedef struct utrace_set {
+	const void *kbuf;
+	const void __user *ubuf;
+} utrace_set_t;
+
+typedef struct utrace_getset {
+	struct task_struct *target;
+	const struct utrace_regset *regset;
+	union {
+		utrace_get_t get;
+		utrace_set_t set;
+	} u;
+	unsigned int pos;
+	unsigned int count;
+	int ret;
+} utrace_getset_t;
+
+static void getfpreg(struct task_struct *task, int regno,int *val)
+{
+	switch (regno / sizeof(int)) {
+		case 0: *val = task->thread.fcr & 0xffff; break;
+		case 1: *val = task->thread.fsr & 0xffff; break;
+		case 2: *val = (task->thread.fsr>>16) & 0xffff; break;
+		case 3: *val = task->thread.fir; break;
+		case 4: *val = (task->thread.fir>>32) & 0xffff; break;
+		case 5: *val = task->thread.fdr; break;
+		case 6: *val = (task->thread.fdr >> 32) & 0xffff; break;
+	}
+}
+
+static void setfpreg(struct task_struct *task, int regno, int val)
+{
+	switch (regno / sizeof(int)) {
+		case 0:
+			task->thread.fcr = (task->thread.fcr & (~0x1f3f))
+				| (val & 0x1f3f);
+			break;
+		case 1:
+			task->thread.fsr = (task->thread.fsr & (~0xffff)) | val;
+			break;
+		case 2:
+			task->thread.fsr = (task->thread.fsr & (~0xffff0000))
+				| (val << 16);
+			break;
+		case 3:
+			task->thread.fir = (task->thread.fir & (~0xffffffff)) | val;
+			break;
+		case 5:
+			task->thread.fdr = (task->thread.fdr & (~0xffffffff)) | val;
+			break;
+	}
+}
+
+static void access_fpreg_ia32(int regno, void *reg,
+		struct pt_regs *pt, struct switch_stack *sw,
+		int tos, int write)
+{
+	void *f;
+
+	if ((regno += tos) >= 8)
+		regno -= 8;
+	if (regno <= 4)
+		f = &pt->f8 + regno;
+	else if (regno <= 7)
+		f = &sw->f12 + (regno - 4);
+	else {
+		printk(" regno must be less than 7 \n");
+		 return;
+	}
+
+	if (write)
+		memcpy(f, reg, sizeof(struct _fpreg_ia32));
+	else
+		memcpy(reg, f, sizeof(struct _fpreg_ia32));
+}
+
+static void do_fpregs_get(struct unw_frame_info *info, void *arg)
+{
+	utrace_getset_t *dst = arg;
+	struct task_struct *task = dst->target;
+	struct pt_regs *pt;
+	int start, end, tos;
+	char buf[80];
+
+	if (dst->count == 0 || unw_unwind_to_user(info) < 0)
+		return;
+	if (dst->pos < 7 * sizeof(int)) {
+		end = min((dst->pos + dst->count), (unsigned int)(7 * sizeof(int)));
+		for (start = dst->pos; start < end; start += sizeof(int))
+			getfpreg(task, start,(int *)( buf + start));
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf, buf,
+				0, 7 * sizeof(int));
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+	if (dst->pos < sizeof(struct ia32_user_i387_struct)) {
+		pt = task_pt_regs(task);
+		tos = (task->thread.fsr >> 11) & 7;
+		end = min(dst->pos + dst->count,
+				(unsigned int)(sizeof(struct ia32_user_i387_struct)));
+		start = (dst->pos - 7 * sizeof(int)) / sizeof(struct _fpreg_ia32);
+		end = (end - 7 * sizeof(int)) / sizeof(struct _fpreg_ia32);
+		for (; start < end; start++)
+			access_fpreg_ia32(start, (struct _fpreg_ia32 *)buf + start,
+					pt, info->sw, tos, 0);
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf,
+				buf, 7 * sizeof(int),
+				sizeof(struct ia32_user_i387_struct));
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+}
+
+static void do_fpregs_set(struct unw_frame_info *info, void *arg)
+{
+	utrace_getset_t *dst = arg;
+	struct task_struct *task = dst->target;
+	struct pt_regs *pt;
+	char buf[80];
+	int end, start, tos;
+
+	if (dst->count == 0 || unw_unwind_to_user(info) < 0)
+		return;
+
+	if (dst->pos < 7 * sizeof(int)) {
+		start = dst->pos;
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf, buf,
+				0, 7 * sizeof(int));
+		if (dst->ret)
+			return;
+		for (; start < dst->pos; start += sizeof(int))
+			setfpreg(task, start, *((int*)(buf + start)));
+		if (dst->count == 0)
+			return;
+	}
+	if (dst->pos < sizeof(struct ia32_user_i387_struct)) {
+		start = (dst->pos - 7 * sizeof(int)) / sizeof(struct _fpreg_ia32);
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf,
+				buf, 7 * sizeof(int),
+				sizeof(struct ia32_user_i387_struct));
+		if (dst->ret)
+			return;
+		pt = task_pt_regs(task);
+		tos = (task->thread.fsr >> 11) & 7;
+		end = (dst->pos - 7 * sizeof(int)) / sizeof(struct _fpreg_ia32);
+		for (; start < end; start++)
+			access_fpreg_ia32(start, (struct _fpreg_ia32 *)buf + start,
+					pt, info->sw, tos, 0);
+		if (dst->count == 0)
+			return;
+	}
+}
+
+#define OFFSET(member) ((int)(offsetof(struct ia32_user_fxsr_struct, member)))
+static void getfpxreg(struct task_struct *task, int start, int end, char *buf)
+{
+	int min_val;
+
+	min_val = min(end, OFFSET(fop));
+	while (start < min_val) {
+		if (start == OFFSET(cwd))
+			*((short *)buf) = task->thread.fcr & 0xffff;
+		else if (start == OFFSET(swd))
+			*((short *)buf) = task->thread.fsr & 0xffff;
+		else if (start == OFFSET(twd))
+			*((short *)buf) = (task->thread.fsr>>16) & 0xffff;
+		buf += 2;
+		start += 2;
+	}
+	/* skip fop element */
+	if (start == OFFSET(fop)) {
+		start += 2;
+		buf += 2;
+	}
+	while (start < end) {
+		if (start == OFFSET(fip))
+			*((int *)buf) = task->thread.fir;
+		else if (start == OFFSET(fcs))
+			*((int *)buf) = (task->thread.fir>>32) & 0xffff;
+		else if (start == OFFSET(foo))
+			*((int *)buf) = task->thread.fdr;
+		else if (start == OFFSET(fos))
+			*((int *)buf) = (task->thread.fdr>>32) & 0xffff;
+		else if (start == OFFSET(mxcsr))
+			*((int *)buf) = ((task->thread.fcr>>32) & 0xff80)
+					 | ((task->thread.fsr>>32) & 0x3f);
+		buf += 4;
+		start += 4;
+	}
+}
+
+static void setfpxreg(struct task_struct *task, int start, int end, char *buf)
+{
+	int min_val, num32;
+	short num;
+	unsigned long num64;
+
+	min_val = min(end, OFFSET(fop));
+	while (start < min_val) {
+		num = *((short *)buf);
+		if (start == OFFSET(cwd)) {
+			task->thread.fcr = (task->thread.fcr & (~0x1f3f))
+						| (num & 0x1f3f);
+		} else if (start == OFFSET(swd)) {
+			task->thread.fsr = (task->thread.fsr & (~0xffff)) | num;
+		} else if (start == OFFSET(twd)) {
+			task->thread.fsr = (task->thread.fsr & (~0xffff0000)) | num;
+		}
+		buf += 2;
+		start += 2;
+	}
+	/* skip fop element */
+	if (start == OFFSET(fop)) {
+		start += 2;
+		buf += 2;
+	}
+	while (start < end) {
+		num32 = *((int *)buf);
+		if (start == OFFSET(fip))
+			task->thread.fir = (task->thread.fir & (~0xffffffff))
+						 | num32;
+		else if (start == OFFSET(foo))
+			task->thread.fdr = (task->thread.fdr & (~0xffffffff))
+						 | num32;
+		else if (start == OFFSET(mxcsr)) {
+			num64 = num32 & 0xff10;
+			task->thread.fcr = (task->thread.fcr & (~0xff1000000000UL))
+						 | (num64<<32);
+			num64 = num32 & 0x3f;
+			task->thread.fsr = (task->thread.fsr & (~0x3f00000000UL))
+						 | (num64<<32);
+		}
+		buf += 4;
+		start += 4;
+	}
+}
+
+static void do_fpxregs_get(struct unw_frame_info *info, void *arg)
+{
+	utrace_getset_t *dst = arg;
+	struct task_struct *task = dst->target;
+	struct pt_regs *pt;
+	char buf[128];
+	int start, end, tos;
+
+	if (dst->count == 0 || unw_unwind_to_user(info) < 0)
+		return;
+	if (dst->pos < OFFSET(st_space[0])) {
+		end = min(dst->pos + dst->count, (unsigned int)32);
+		getfpxreg(task, dst->pos, end, buf);
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf, buf,
+				0, OFFSET(st_space[0]));
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+	if (dst->pos < OFFSET(xmm_space[0])) {
+		pt = task_pt_regs(task);
+		tos = (task->thread.fsr >> 11) & 7;
+		end = min(dst->pos + dst->count,
+				(unsigned int)OFFSET(xmm_space[0]));
+		start = (dst->pos - OFFSET(st_space[0])) / 16;
+		end = (end - OFFSET(st_space[0])) / 16;
+		for (; start < end; start++)
+			access_fpreg_ia32(start, buf + 16 * start, pt,
+						info->sw, tos, 0);
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf,
+				buf, OFFSET(st_space[0]), OFFSET(xmm_space[0]));
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+	if (dst->pos < OFFSET(padding[0]))
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf,
+				&info->sw->f16, OFFSET(xmm_space[0]),
+				OFFSET(padding[0]));
+}
+
+static void do_fpxregs_set(struct unw_frame_info *info, void *arg)
+{
+	utrace_getset_t *dst = arg;
+	struct task_struct *task = dst->target;
+	char buf[128];
+	int start, end;
+
+	if (dst->count == 0 || unw_unwind_to_user(info) < 0)
+		return;
+
+	if (dst->pos < OFFSET(st_space[0])) {
+		start = dst->pos;
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf,
+				buf, 0, OFFSET(st_space[0]));
+		if (dst->ret)
+			return;
+		setfpxreg(task, start, dst->pos, buf);
+		if (dst->count == 0)
+			return;
+	}
+	if (dst->pos < OFFSET(xmm_space[0])) {
+		struct pt_regs *pt;
+		int tos;
+		pt = task_pt_regs(task);
+		tos = (task->thread.fsr >> 11) & 7;
+		start = (dst->pos - OFFSET(st_space[0])) / 16;
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf,
+				buf, OFFSET(st_space[0]), OFFSET(xmm_space[0]));
+		if (dst->ret)
+			return;
+		end = (dst->pos - OFFSET(st_space[0])) / 16;
+		for (; start < end; start++)
+			access_fpreg_ia32(start, buf + 16 * start, pt, info->sw,
+						 tos, 1);
+		if (dst->count == 0)
+			return;
+	}
+	if (dst->pos < OFFSET(padding[0]))
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf,
+				&info->sw->f16, OFFSET(xmm_space[0]),
+				 OFFSET(padding[0]));
+}
+#undef OFFSET
+
+static int do_regset_call(void (*call)(struct unw_frame_info *, void *),
+		struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	utrace_getset_t info = { .target = target, .regset = regset,
+		.pos = pos, .count = count,
+		.u.set = { .kbuf = kbuf, .ubuf = ubuf },
+		.ret = 0 };
+
+	if (target == current)
+		unw_init_running(call, &info);
+	else {
+		struct unw_frame_info ufi;
+		memset(&ufi, 0, sizeof(ufi));
+		unw_init_from_blocked_task(&ufi, target);
+		(*call)(&ufi, &info);
+	}
+
+	return info.ret;
+}
+
+static int ia32_fpregs_get(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		void *kbuf, void __user *ubuf)
+{
+	return do_regset_call(do_fpregs_get, target, regset, pos, count, kbuf, ubuf);
+}
+
+static int ia32_fpregs_set(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	return do_regset_call(do_fpregs_set, target, regset, pos, count, kbuf, ubuf);
+}
+
+static int ia32_fpxregs_get(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		void *kbuf, void __user *ubuf)
+{
+	return do_regset_call(do_fpxregs_get, target, regset, pos, count, kbuf, ubuf);
+}
+
+static int ia32_fpxregs_set(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	return do_regset_call(do_fpxregs_set, target, regset, pos, count, kbuf, ubuf);
+}
+
+static int ia32_genregs_get(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		void *kbuf, void __user *ubuf)
+{
+	if (kbuf) {
+		u32 *kp = kbuf;
+		while (count > 0) {
+			*kp++ = getreg(target, pos);
+			pos += 4;
+			count -= 4;
+		}
+	} else {
+		u32 __user *up = ubuf;
+		while (count > 0) {
+			if (__put_user(getreg(target, pos), up++))
+				return -EFAULT;
+			pos += 4;
+			count -= 4;
+		}
+	}
+	return 0;
+}
+
+static int ia32_genregs_set(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	int ret = 0;
+
+	if (kbuf) {
+		const u32 *kp = kbuf;
+		while (!ret && count > 0) {
+			putreg(target, pos, *kp++);
+			pos += 4;
+			count -= 4;
+		}
+	} else {
+		const u32 __user *up = ubuf;
+		u32 val;
+		while (!ret && count > 0) {
+			ret = __get_user(val, up++);
+			if (!ret)
+				putreg(target, pos, val);
+			pos += 4;
+			count -= 4;
+		}
+	}
+	return ret;
+}
+
+/*
+ * This should match arch/i386/kernel/ptrace.c:native_regsets.
+ * XXX ioperm? vm86?
+ */
+static const struct utrace_regset ia32_regsets[] = {
+	{
+		.n = sizeof(struct user_regs_struct32)/4,
+		.size = 4, .align = 4,
+		.get = ia32_genregs_get, .set = ia32_genregs_set
+	},
+	{
+		.n = sizeof(struct ia32_user_i387_struct) / 4,
+		.size = 4, .align = 4,
+		.get = ia32_fpregs_get, .set = ia32_fpregs_set
+	},
+	{
+		.n = sizeof(struct ia32_user_fxsr_struct) / 4,
+		.size = 4, .align = 4,
+		.get = ia32_fpxregs_get, .set = ia32_fpxregs_set
+	},
+};
+
+const struct utrace_regset_view utrace_ia32_view = {
+	.name = "i386", .e_machine = EM_386,
+	.regsets = ia32_regsets, .n = ARRAY_SIZE(ia32_regsets)
+};
+#endif
+
 typedef struct {
 	unsigned int	ss_sp;
 	unsigned int	ss_flags;
--- linux-2.6/arch/ia64/kernel/ptrace.c
+++ linux-2.6/arch/ia64/kernel/ptrace.c
@@ -3,6 +3,9 @@
  *
  * Copyright (C) 1999-2005 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm at hpl.hp.com>
+ * Copyright (C) 2006 Intel Co
+ *  2006-08-12	- IA64 Native Utrace implementation support added by
+ *	Anil S Keshavamurthy <anil.s.keshavamurthy at intel.com>
  *
  * Derived from the x86 and Alpha versions.
  */
@@ -18,13 +21,16 @@
 #include <linux/security.h>
 #include <linux/audit.h>
 #include <linux/signal.h>
+#include <linux/module.h>
 
+#include <asm/tracehook.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/ptrace_offsets.h>
 #include <asm/rse.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/elf.h>
 #include <asm/unwind.h>
 #ifdef CONFIG_PERFMON
 #include <asm/perfmon.h>
@@ -548,6 +554,7 @@ ia64_sync_user_rbs (struct task_struct *
 	return 0;
 }
 
+#if 0				/* XXX */
 static inline int
 thread_matches (struct task_struct *thread, unsigned long addr)
 {
@@ -620,6 +627,7 @@ find_thread_for_addr (struct task_struct
 	mmput(mm);
 	return child;
 }
+#endif
 
 /*
  * Write f32-f127 back to task->thread.fph if it has been modified.
@@ -664,6 +672,7 @@ ia64_sync_fph (struct task_struct *task)
 	psr->dfh = 1;
 }
 
+#if 0
 static int
 access_fr (struct unw_frame_info *info, int regnum, int hi,
 	   unsigned long *data, int write_access)
@@ -682,6 +691,7 @@ access_fr (struct unw_frame_info *info, 
 		*data = fpval.u.bits[hi];
 	return ret;
 }
+#endif /* access_fr() */
 
 /*
  * Change the machine-state of CHILD such that it will return via the normal
@@ -782,6 +792,7 @@ access_nat_bits (struct task_struct *chi
 	return 0;
 }
 
+#if 0
 static int
 access_uarea (struct task_struct *child, unsigned long addr,
 	      unsigned long *data, int write_access)
@@ -1248,7 +1259,9 @@ ptrace_getregs (struct task_struct *chil
 	ret = retval ? -EIO : 0;
 	return ret;
 }
+#endif /* ptrace_getregs() */
 
+#if 0
 static long
 ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
 {
@@ -1394,6 +1407,7 @@ ptrace_setregs (struct task_struct *chil
 	ret = retval ? -EIO : 0;
 	return ret;
 }
+#endif /* ptrace_setregs() */
 
 /*
  * Called by kernel/ptrace.c when detaching..
@@ -1411,6 +1425,7 @@ ptrace_disable (struct task_struct *chil
 	child_psr->tb = 0;
 }
 
+#if 0 				/* XXX */
 asmlinkage long
 sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
 {
@@ -1598,6 +1613,7 @@ sys_ptrace (long request, pid_t pid, uns
 	unlock_kernel();
 	return ret;
 }
+#endif
 
 /* "asmlinkage" so the input arguments are preserved... */
 
@@ -1650,3 +1666,791 @@ syscall_trace_leave (long arg0, long arg
 		tracehook_report_syscall_step(&regs);
 	}
 }
+
+/* Utrace implementation starts here */
+
+typedef struct utrace_get {
+	void *kbuf;
+	void __user *ubuf;
+} utrace_get_t;
+
+typedef struct utrace_set {
+	const void *kbuf;
+	const void __user *ubuf;
+} utrace_set_t;
+
+typedef struct utrace_getset {
+	struct task_struct *target;
+	const struct utrace_regset *regset;
+	union {
+		utrace_get_t get;
+		utrace_set_t set;
+	} u;
+	unsigned int pos;
+	unsigned int count;
+	int ret;
+} utrace_getset_t;
+
+static int
+access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info,
+		unsigned long addr, unsigned long *data, int write_access)
+{
+	struct pt_regs *pt;
+	unsigned long *ptr = NULL;
+	int ret;
+	char nat=0;
+
+	pt = task_pt_regs(target);
+	switch (addr) {
+		case ELF_GR_OFFSET(1):
+			ptr = &pt->r1;
+			break;
+		case ELF_GR_OFFSET(2):
+		case ELF_GR_OFFSET(3):
+			ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2));
+			break;
+		case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7):
+			if (write_access) {
+				/* read NaT bit first: */
+				unsigned long dummy;
+
+				ret = unw_get_gr(info, addr/8, &dummy, &nat);
+				if (ret < 0)
+					return ret;
+			}
+			return unw_access_gr(info, addr/8, data, &nat, write_access);
+		case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11):
+			ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8);
+			break;
+		case ELF_GR_OFFSET(12):
+		case ELF_GR_OFFSET(13):
+			ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12);
+			break;
+		case ELF_GR_OFFSET(14):
+			ptr = &pt->r14;
+			break;
+		case ELF_GR_OFFSET(15):
+			ptr = &pt->r15;
+	}
+	if (write_access)
+		*ptr = *data;
+	else
+		*data = *ptr;
+	return 0;
+}
+
+static int
+access_elf_breg(struct task_struct *target, struct unw_frame_info *info,
+		unsigned long addr, unsigned long *data, int write_access)
+{
+	struct pt_regs *pt;
+	unsigned long *ptr = NULL;
+
+	pt = task_pt_regs(target);
+	switch (addr) {
+		case ELF_BR_OFFSET(0):
+			ptr = &pt->b0;
+			break;
+		case ELF_BR_OFFSET(1) ... ELF_BR_OFFSET(5):
+			return unw_access_br(info, (addr - ELF_BR_OFFSET(0))/8,
+					data, write_access);
+		case ELF_BR_OFFSET(6):
+			ptr = &pt->b6;
+			break;
+		case ELF_BR_OFFSET(7):
+			ptr = &pt->b7;
+	}
+	if (write_access)
+		*ptr = *data;
+	else
+		*data = *ptr;
+	return 0;
+}
+
+static int
+access_elf_areg(struct task_struct *target, struct unw_frame_info *info,
+		unsigned long addr, unsigned long *data, int write_access)
+{
+	struct pt_regs *pt;
+	unsigned long cfm, urbs_end, rnat_addr;
+	unsigned long *ptr = NULL;
+
+	pt = task_pt_regs(target);
+	if (addr >= ELF_AR_RSC_OFFSET && addr <= ELF_AR_SSD_OFFSET) {
+		switch (addr) {
+			case ELF_AR_RSC_OFFSET:
+				/* force PL3 */
+				if (write_access)
+					pt->ar_rsc = *data | (3 << 2);
+				else
+					*data = pt->ar_rsc;
+				return 0;
+			case ELF_AR_BSP_OFFSET:
+				/*
+				 * By convention, we use PT_AR_BSP to refer to
+				 * the end of the user-level backing store.
+				 * Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof)
+				 * to get the real value of ar.bsp at the time
+				 * the kernel was entered.
+				 *
+				 * Furthermore, when changing the contents of
+				 * PT_AR_BSP (or PT_CFM) we MUST copy any
+				 * users-level stacked registers that are
+				 * stored on the kernel stack back to
+				 * user-space because otherwise, we might end
+				 * up clobbering kernel stacked registers.
+				 * Also, if this happens while the task is
+				 * blocked in a system call, which convert the
+				 * state such that the non-system-call exit
+				 * path is used.  This ensures that the proper
+				 * state will be picked up when resuming
+				 * execution.  However, it *also* means that
+				 * once we write PT_AR_BSP/PT_CFM, it won't be
+				 * possible to modify the syscall arguments of
+				 * the pending system call any longer.  This
+				 * shouldn't be an issue because modifying
+				 * PT_AR_BSP/PT_CFM generally implies that
+				 * we're either abandoning the pending system
+				 * call or that we defer it's re-execution
+				 * (e.g., due to GDB doing an inferior
+				 * function call).
+				 */
+				urbs_end = ia64_get_user_rbs_end(target, pt, &cfm);
+				if (write_access) {
+					if (*data != urbs_end) {
+						if (ia64_sync_user_rbs(target, info->sw,
+									pt->ar_bspstore,
+									urbs_end) < 0)
+							return -1;
+						if (in_syscall(pt))
+							convert_to_non_syscall(target,
+									pt,
+									cfm);
+						/*
+						 * Simulate user-level write
+						 * of ar.bsp:
+						 */
+						pt->loadrs = 0;
+						pt->ar_bspstore = *data;
+					}
+				} else
+					*data = urbs_end;
+				return 0;
+			case ELF_AR_BSPSTORE_OFFSET: // ar_bsp_store
+				ptr = &pt->ar_bspstore;
+				break;
+			case ELF_AR_RNAT_OFFSET:  // ar_rnat
+				urbs_end = ia64_get_user_rbs_end(target, pt, NULL);
+				rnat_addr = (long) ia64_rse_rnat_addr((long *)
+						urbs_end);
+				if (write_access)
+					return ia64_poke(target, info->sw, urbs_end,
+							rnat_addr, *data);
+				else
+					return ia64_peek(target, info->sw, urbs_end,
+							rnat_addr, data);
+			case ELF_AR_CCV_OFFSET:   // ar_ccv
+				ptr = &pt->ar_ccv;
+				break;
+			case ELF_AR_UNAT_OFFSET:	// ar_unat
+				ptr = &pt->ar_unat;
+				break;
+			case ELF_AR_FPSR_OFFSET:  // ar_fpsr
+				ptr = &pt->ar_fpsr;
+				break;
+			case ELF_AR_PFS_OFFSET:  // ar_pfs
+				ptr = &pt->ar_pfs;
+				break;
+			case ELF_AR_LC_OFFSET:   // ar_lc
+				return unw_access_ar(info, UNW_AR_LC, data,
+						write_access);
+			case ELF_AR_EC_OFFSET:    // ar_ec
+				return unw_access_ar(info, UNW_AR_EC, data,
+						write_access);
+			case ELF_AR_CSD_OFFSET:   // ar_csd
+				ptr = &pt->ar_csd;
+				break;
+			case ELF_AR_SSD_OFFSET:   // ar_ssd
+				ptr = &pt->ar_ssd;
+		}
+	} else if (addr >= ELF_CR_IIP_OFFSET && addr <= ELF_CR_IPSR_OFFSET) {
+		switch (addr) {
+			case ELF_CR_IIP_OFFSET:
+				ptr = &pt->cr_iip;
+				break;
+			case ELF_CFM_OFFSET:
+				urbs_end = ia64_get_user_rbs_end(target, pt, &cfm);
+				if (write_access) {
+					if (((cfm ^ *data) & PFM_MASK) != 0) {
+						if (ia64_sync_user_rbs(target, info->sw,
+									pt->ar_bspstore,
+									urbs_end) < 0)
+							return -1;
+						if (in_syscall(pt))
+							convert_to_non_syscall(target,
+									pt,
+									cfm);
+						pt->cr_ifs = ((pt->cr_ifs & ~PFM_MASK)
+								| (*data & PFM_MASK));
+					}
+				} else
+					*data = cfm;
+				return 0;
+			case ELF_CR_IPSR_OFFSET:
+				if (write_access)
+					pt->cr_ipsr = ((*data & IPSR_MASK)
+							| (pt->cr_ipsr & ~IPSR_MASK));
+				else
+					*data = (pt->cr_ipsr & IPSR_MASK);
+				return 0;
+		}
+	} else if (addr == ELF_NAT_OFFSET)
+			return access_nat_bits(target, pt, info,
+					data, write_access);
+	else if (addr == ELF_PR_OFFSET)
+			ptr = &pt->pr;
+	else
+		return -1;
+
+	if (write_access)
+		*ptr = *data;
+	else
+		*data = *ptr;
+
+	return 0;
+}
+
+static int
+access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
+		unsigned long addr, unsigned long *data, int write_access)
+{
+	if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15))
+		return access_elf_gpreg(target, info, addr, data, write_access);
+	else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7))
+		return access_elf_breg(target, info, addr, data, write_access);
+	else
+		return access_elf_areg(target, info, addr, data, write_access);
+}
+
+void do_gpregs_get(struct unw_frame_info *info, void *arg)
+{
+	struct pt_regs *pt;
+	utrace_getset_t *dst = arg;
+	elf_greg_t tmp[16];
+	unsigned int i, index, min_copy;
+
+	if (unw_unwind_to_user(info) < 0)
+		return;
+
+	/*
+	 * coredump format:
+	 *      r0-r31
+	 *      NaT bits (for r0-r31; bit N == 1 iff rN is a NaT)
+	 *      predicate registers (p0-p63)
+	 *      b0-b7
+	 *      ip cfm user-mask
+	 *      ar.rsc ar.bsp ar.bspstore ar.rnat
+	 *      ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec
+	 */
+
+
+	/* Skip r0 */
+	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) {
+		dst->ret = utrace_regset_copyout_zero(&dst->pos, &dst->count,
+						      &dst->u.get.kbuf,
+						      &dst->u.get.ubuf,
+						      0, ELF_GR_OFFSET(1));
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+
+	/* gr1 - gr15 */
+	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
+		index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
+		min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ?
+			 (dst->pos + dst->count) : ELF_GR_OFFSET(16);
+		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++)
+			if (access_elf_reg(dst->target, info, i,
+						&tmp[index], 0) < 0) {
+				dst->ret = -EIO;
+				return;
+			}
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
+				ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+
+	/* r16-r31 */
+	if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
+		pt = task_pt_regs(dst->target);
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16,
+				ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+
+	/* nat, pr, b0 - b7 */
+	if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
+		index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
+		min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ?
+			 (dst->pos + dst->count) : ELF_CR_IIP_OFFSET;
+		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++)
+			if (access_elf_reg(dst->target, info, i,
+						&tmp[index], 0) < 0) {
+				dst->ret = -EIO;
+				return;
+			}
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
+				ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+
+ 	/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
+	 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
+	 */
+	if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
+		index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
+		min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ?
+			 (dst->pos + dst->count) : ELF_AR_END_OFFSET;
+		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++)
+			if (access_elf_reg(dst->target, info, i,
+						&tmp[index], 0) < 0) {
+				dst->ret = -EIO;
+				return;
+			}
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
+				ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
+        }
+}
+
+void do_gpregs_set(struct unw_frame_info *info, void *arg)
+{
+	struct pt_regs *pt;
+	utrace_getset_t *dst = arg;
+	elf_greg_t tmp[16];
+	unsigned int i, index;
+
+	if (unw_unwind_to_user(info) < 0)
+		return;
+
+	/* Skip r0 */
+	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) {
+		dst->ret = utrace_regset_copyin_ignore(&dst->pos, &dst->count,
+						       &dst->u.set.kbuf,
+						       &dst->u.set.ubuf,
+						       0, ELF_GR_OFFSET(1));
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+
+	/* gr1-gr15 */
+	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
+		i = dst->pos;
+		index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
+				ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
+		if (dst->ret)
+			return;
+		for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
+			if (access_elf_reg(dst->target, info, i,
+						&tmp[index], 1) < 0) {
+				dst->ret = -EIO;
+				return;
+			}
+		if (dst->count == 0)
+			return;
+	}
+
+	/* gr16-gr31 */
+	if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
+		pt = task_pt_regs(dst->target);
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16,
+				ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+
+	/* nat, pr, b0 - b7 */
+	if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
+		i = dst->pos;
+		index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
+				ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
+		if (dst->ret)
+			return;
+		for (; i < dst->pos; i += sizeof(elf_greg_t), index++)
+			if (access_elf_reg(dst->target, info, i,
+						&tmp[index], 1) < 0) {
+				dst->ret = -EIO;
+				return;
+			}
+		if (dst->count == 0)
+			return;
+	}
+
+ 	/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
+	 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
+	 */
+	if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
+		i = dst->pos;
+		index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
+				ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
+		if (dst->ret)
+			return;
+		for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
+			if (access_elf_reg(dst->target, info, i,
+						&tmp[index], 1) < 0) {
+				dst->ret = -EIO;
+				return;
+			}
+	}
+}
+
+#define ELF_FP_OFFSET(i)	(i * sizeof(elf_fpreg_t))
+
+void do_fpregs_get(struct unw_frame_info *info, void *arg)
+{
+	utrace_getset_t *dst = arg;
+	struct task_struct *task = dst->target;
+	elf_fpreg_t tmp[30];
+	int index, min_copy, i;
+
+	if (unw_unwind_to_user(info) < 0)
+		return;
+
+	/* Skip pos 0 and 1 */
+	if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) {
+		dst->ret = utrace_regset_copyout_zero(&dst->pos, &dst->count,
+						      &dst->u.get.kbuf,
+						      &dst->u.get.ubuf,
+						      0, ELF_FP_OFFSET(2));
+		if (dst->count == 0 || dst->ret)
+			return;
+	}
+
+	/* fr2-fr31 */
+	if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) {
+		index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t);
+		min_copy = min(((unsigned int)ELF_FP_OFFSET(32)),
+				dst->pos + dst->count);
+		for (i = dst->pos; i < min_copy; i += sizeof(elf_fpreg_t), index++)
+			if (unw_get_fr(info, i / sizeof(elf_fpreg_t),
+					 &tmp[index])) {
+				dst->ret = -EIO;
+				return;
+			}
+		dst->ret = utrace_regset_copyout(&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
+				ELF_FP_OFFSET(2), ELF_FP_OFFSET(32));
+		if (dst->count == 0 || dst->ret)
+			return;
+	}
+
+	/* fph */
+	if (dst->count > 0) {
+		ia64_flush_fph(dst->target);
+		if (task->thread.flags & IA64_THREAD_FPH_VALID)
+			dst->ret = utrace_regset_copyout(
+				&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf,
+				&dst->target->thread.fph,
+				ELF_FP_OFFSET(32), -1);
+		else
+			/* Zero fill instead.  */
+			dst->ret = utrace_regset_copyout_zero(
+				&dst->pos, &dst->count,
+				&dst->u.get.kbuf, &dst->u.get.ubuf,
+				ELF_FP_OFFSET(32), -1);
+	}
+}
+
+void do_fpregs_set(struct unw_frame_info *info, void *arg)
+{
+	utrace_getset_t *dst = arg;
+	elf_fpreg_t fpreg, tmp[30];
+	int index, start, end;
+
+	if (unw_unwind_to_user(info) < 0)
+		return;
+
+	/* Skip pos 0 and 1 */
+	if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) {
+		dst->ret = utrace_regset_copyin_ignore(&dst->pos, &dst->count,
+						       &dst->u.set.kbuf,
+						       &dst->u.set.ubuf,
+						       0, ELF_FP_OFFSET(2));
+		if (dst->count == 0 || dst->ret)
+			return;
+	}
+
+	/* fr2-fr31 */
+	if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) {
+		start = dst->pos;
+		end = min(((unsigned int)ELF_FP_OFFSET(32)),
+			 dst->pos + dst->count);
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
+				ELF_FP_OFFSET(2), ELF_FP_OFFSET(32));
+		if (dst->ret)
+			return;
+
+		if (start & 0xF) { //  only write high part
+			if (unw_get_fr(info, start / sizeof(elf_fpreg_t),
+					 &fpreg)) {
+				dst->ret = -EIO;
+				return;
+			}
+			tmp[start / sizeof(elf_fpreg_t) - 2].u.bits[0]
+				= fpreg.u.bits[0];
+			start &= ~0xFUL;
+		}
+		if (end & 0xF) { // only write low part
+			if (unw_get_fr(info, end / sizeof(elf_fpreg_t), &fpreg)) {
+				dst->ret = -EIO;
+				return;
+                       	}
+			tmp[end / sizeof(elf_fpreg_t) -2].u.bits[1]
+				= fpreg.u.bits[1];
+			end = (end + 0xF) & ~0xFUL;
+		}
+
+		for ( ;	start < end ; start += sizeof(elf_fpreg_t)) {
+			index = start / sizeof(elf_fpreg_t);
+			if (unw_set_fr(info, index, tmp[index - 2])){
+				dst->ret = -EIO;
+				return;
+			}
+		}
+		if (dst->ret || dst->count == 0)
+			return;
+	}
+
+	/* fph */
+	if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(128)) {
+		ia64_sync_fph(dst->target);
+		dst->ret = utrace_regset_copyin(&dst->pos, &dst->count,
+						&dst->u.set.kbuf,
+						&dst->u.set.ubuf,
+						&dst->target->thread.fph,
+						ELF_FP_OFFSET(32), -1);
+	}
+}
+
+static int
+do_regset_call(void (*call)(struct unw_frame_info *, void *),
+	       struct task_struct *target,
+	       const struct utrace_regset *regset,
+	       unsigned int pos, unsigned int count,
+	       const void *kbuf, const void __user *ubuf)
+{
+	utrace_getset_t info = { .target = target, .regset = regset,
+				 .pos = pos, .count = count,
+				 .u.set = { .kbuf = kbuf, .ubuf = ubuf },
+				 .ret = 0 };
+
+	if (target == current)
+		unw_init_running(call, &info);
+	else {
+		struct unw_frame_info ufi;
+		memset(&ufi, 0, sizeof(ufi));
+		unw_init_from_blocked_task(&ufi, target);
+		(*call)(&ufi, &info);
+	}
+
+	return info.ret;
+}
+
+static int
+gpregs_get(struct task_struct *target,
+	   const struct utrace_regset *regset,
+	   unsigned int pos, unsigned int count,
+	   void *kbuf, void __user *ubuf)
+{
+	return do_regset_call(do_gpregs_get, target, regset, pos, count, kbuf, ubuf);
+}
+
+static int gpregs_set(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	return do_regset_call(do_gpregs_set, target, regset, pos, count, kbuf, ubuf);
+}
+
+static void do_gpregs_writeback(struct unw_frame_info *info, void *arg)
+{
+	struct pt_regs *pt;
+	utrace_getset_t *dst = arg;
+	unsigned long urbs_end;
+
+	if (unw_unwind_to_user(info) < 0)
+		return;
+	pt = task_pt_regs(dst->target);
+	urbs_end = ia64_get_user_rbs_end(dst->target, pt, NULL);
+	dst->ret = ia64_sync_user_rbs(dst->target, info->sw, pt->ar_bspstore, urbs_end);
+}
+/*
+ * This is called to write back the register backing store.
+ * ptrace does this before it stops, so that a tracer reading the user
+ * memory after the thread stops will get the current register data.
+ */
+static int
+gpregs_writeback(struct task_struct *target,
+		 const struct utrace_regset *regset,
+		 int now)
+{
+	return do_regset_call(do_gpregs_writeback, target, regset, 0, 0, NULL, NULL);
+}
+
+static int
+fpregs_active(struct task_struct *target, const struct utrace_regset *regset)
+{
+	return (target->thread.flags & IA64_THREAD_FPH_VALID) ? 128 : 32;
+}
+
+static int fpregs_get(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		void *kbuf, void __user *ubuf)
+{
+	return do_regset_call(do_fpregs_get, target, regset, pos, count, kbuf, ubuf);
+}
+
+static int fpregs_set(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	return do_regset_call(do_fpregs_set, target, regset, pos, count, kbuf, ubuf);
+}
+
+static int dbregs_get(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		void *kbuf, void __user *ubuf)
+{
+	int ret;
+
+#ifdef CONFIG_PERFMON
+	/*
+	 * Check if debug registers are used by perfmon. This
+	 * test must be done once we know that we can do the
+	 * operation, i.e. the arguments are all valid, but
+	 * before we start modifying the state.
+	 *
+	 * Perfmon needs to keep a count of how many processes
+	 * are trying to modify the debug registers for system
+	 * wide monitoring sessions.
+	 *
+	 * We also include read access here, because they may
+	 * cause the PMU-installed debug register state
+	 * (dbr[], ibr[]) to be reset. The two arrays are also
+	 * used by perfmon, but we do not use
+	 * IA64_THREAD_DBG_VALID. The registers are restored
+	 * by the PMU context switch code.
+	 */
+	if (pfm_use_debug_registers(target))
+		return -EIO;
+#endif
+
+	if (!(target->thread.flags & IA64_THREAD_DBG_VALID))
+		ret = utrace_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+						 0, -1);
+	else {
+		preempt_disable();
+		if (target == current)
+			ia64_load_debug_regs(&target->thread.dbr[0]);
+		preempt_enable_no_resched();
+		ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					    &target->thread.dbr, 0, -1);
+	}
+
+	return ret;
+}
+
+static int dbregs_set(struct task_struct *target,
+		const struct utrace_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	int i, ret;
+
+#ifdef CONFIG_PERFMON
+	if (pfm_use_debug_registers(target))
+		return -EIO;
+#endif
+
+	ret = 0;
+	if (!(target->thread.flags & IA64_THREAD_DBG_VALID)){
+		target->thread.flags |= IA64_THREAD_DBG_VALID;
+		memset(target->thread.dbr, 0, 2 * sizeof(target->thread.dbr));
+	} else if (target == current){
+		preempt_disable();
+		ia64_save_debug_regs(&target->thread.dbr[0]);
+		preempt_enable_no_resched();
+	}
+
+	ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				   &target->thread.dbr, 0, -1);
+
+	for (i = 1; i < IA64_NUM_DBG_REGS; i += 2) {
+		target->thread.dbr[i] &= ~(7UL << 56);
+		target->thread.ibr[i] &= ~(7UL << 56);
+	}
+
+	if (ret)
+		return ret;
+
+	if (target == current){
+		preempt_disable();
+		ia64_load_debug_regs(&target->thread.dbr[0]);
+		preempt_enable_no_resched();
+	}
+	return 0;
+}
+
+static const struct utrace_regset native_regsets[] = {
+	{
+		.n = ELF_NGREG,
+		.size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t),
+		.get = gpregs_get, .set = gpregs_set,
+		.writeback = gpregs_writeback
+	},
+	{
+		.n = ELF_NFPREG,
+		.size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t),
+		.get = fpregs_get, .set = fpregs_set, .active = fpregs_active
+	},
+	{
+		.n = 2 * IA64_NUM_DBG_REGS, .size = sizeof(long),
+		.align = sizeof(long),
+		.get = dbregs_get, .set = dbregs_set
+	}
+};
+
+static const struct utrace_regset_view utrace_ia64_native = {
+	.name = "ia64",
+	.e_machine = EM_IA_64,
+	.regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
+};
+
+const struct utrace_regset_view *utrace_native_view(struct task_struct *tsk)
+{
+#ifdef CONFIG_IA32_SUPPORT
+	extern const struct utrace_regset_view utrace_ia32_view;
+	if (IS_IA32_PROCESS(task_pt_regs(tsk)))
+		return &utrace_ia32_view;
+#endif
+	return &utrace_ia64_native;
+}
--- linux-2.6/include/asm-ia64/tracehook.h
+++ linux-2.6/include/asm-ia64/tracehook.h
@@ -67,7 +67,10 @@ static inline int tracehook_single_step_
 
 static inline void tracehook_abort_syscall(struct pt_regs *regs)
 {
-	regs->r15 = -1L;
+	if (IS_IA32_PROCESS(regs))
+		regs->r1 = -1UL;
+	else
+		regs->r15 = -1UL;
 }
 
-#endif
+#endif	/* asm/tracehook.h */
--- linux-2.6/include/asm-ia64/elf.h
+++ linux-2.6/include/asm-ia64/elf.h
@@ -154,6 +154,30 @@ extern void ia64_init_addr_space (void);
 #define ELF_NGREG	128	/* we really need just 72 but let's leave some headroom... */
 #define ELF_NFPREG	128	/* f0 and f1 could be omitted, but so what... */
 
+/* elf_gregset_t register offsets */
+#define ELF_GR_0_OFFSET     0
+#define ELF_NAT_OFFSET     (32 * sizeof(elf_greg_t))
+#define ELF_PR_OFFSET      (33 * sizeof(elf_greg_t))
+#define ELF_BR_0_OFFSET    (34 * sizeof(elf_greg_t))
+#define ELF_CR_IIP_OFFSET  (42 * sizeof(elf_greg_t))
+#define ELF_CFM_OFFSET     (43 * sizeof(elf_greg_t))
+#define ELF_CR_IPSR_OFFSET (44 * sizeof(elf_greg_t))
+#define ELF_GR_OFFSET(i)   (ELF_GR_0_OFFSET + i * sizeof(elf_greg_t))
+#define ELF_BR_OFFSET(i)   (ELF_BR_0_OFFSET + i * sizeof(elf_greg_t))
+#define ELF_AR_RSC_OFFSET  (45 * sizeof(elf_greg_t))
+#define ELF_AR_BSP_OFFSET  (46 * sizeof(elf_greg_t))
+#define ELF_AR_BSPSTORE_OFFSET (47 * sizeof(elf_greg_t))
+#define ELF_AR_RNAT_OFFSET (48 * sizeof(elf_greg_t))
+#define ELF_AR_CCV_OFFSET  (49 * sizeof(elf_greg_t))
+#define ELF_AR_UNAT_OFFSET (50 * sizeof(elf_greg_t))
+#define ELF_AR_FPSR_OFFSET (51 * sizeof(elf_greg_t))
+#define ELF_AR_PFS_OFFSET  (52 * sizeof(elf_greg_t))
+#define ELF_AR_LC_OFFSET   (53 * sizeof(elf_greg_t))
+#define ELF_AR_EC_OFFSET   (54 * sizeof(elf_greg_t))
+#define ELF_AR_CSD_OFFSET  (55 * sizeof(elf_greg_t))
+#define ELF_AR_SSD_OFFSET  (56 * sizeof(elf_greg_t))
+#define ELF_AR_END_OFFSET  (57 * sizeof(elf_greg_t))
+
 typedef unsigned long elf_fpxregset_t;
 
 typedef unsigned long elf_greg_t;

linux-2.6-utrace-regset-s390.patch:
 Makefile |    2 
 ptrace.c |  952 +++++++++++++++++++++++++--------------------------------------
 2 files changed, 390 insertions(+), 564 deletions(-)

--- NEW FILE linux-2.6-utrace-regset-s390.patch ---
[PATCH 2c] utrace: s390 regset support

This patch converts the machine-dependent ptrace code into utrace regset
support for s390.

Signed-off-by: Roland McGrath <roland at redhat.com>
CC: David Wilder <dwilder at us.ibm.com>

---

 arch/s390/kernel/Makefile |    2 
 arch/s390/kernel/ptrace.c |  952 ++++++++++++++++++---------------------------
 2 files changed, 390 insertions(+), 564 deletions(-)

--- linux-2.6/arch/s390/kernel/Makefile
+++ linux-2.6/arch/s390/kernel/Makefile
@@ -35,3 +35,5 @@ obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS
 # This is just to get the dependencies...
 #
 binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
+
+CFLAGS_ptrace.o		+= -DUTS_MACHINE='"$(UTS_MACHINE)"'
--- linux-2.6/arch/s390/kernel/ptrace.c
+++ linux-2.6/arch/s390/kernel/ptrace.c
@@ -30,6 +30,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/tracehook.h>
+#include <linux/module.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
@@ -42,6 +43,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/elf.h>
 
 #ifdef CONFIG_COMPAT
 #include "compat_ptrace.h"
@@ -116,640 +118,462 @@ tracehook_single_step_enabled(struct tas
 	return task->thread.per_info.single_step;
 }
 
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure single step bits etc are not set.
- */
-void
-ptrace_disable(struct task_struct *child)
-{
-	/* make sure the single step bit is not set. */
-	tracehook_disable_single_step(child);
-}
-
-#ifndef CONFIG_64BIT
-# define __ADDR_MASK 3
-#else
-# define __ADDR_MASK 7
-#endif
 
-/*
- * Read the word at offset addr from the user area of a process. The
- * trouble here is that the information is littered over different
- * locations. The process registers are found on the kernel stack,
- * the floating point stuff and the trace settings are stored in
- * the task structure. In addition the different structures in
- * struct user contain pad bytes that should be read as zeroes.
- * Lovely...
- */
 static int
-peek_user(struct task_struct *child, addr_t addr, addr_t data)
+genregs_get(struct task_struct *target,
+	    const struct utrace_regset *regset,
+	    unsigned int pos, unsigned int count,
+	    void *kbuf, void __user *ubuf)
 {
-	struct user *dummy = NULL;
-	addr_t offset, tmp, mask;
+	struct pt_regs *regs = task_pt_regs(target);
+	unsigned long pswmask;
+	int ret;
 
-	/*
-	 * Stupid gdb peeks/pokes the access registers in 64 bit with
-	 * an alignment of 4. Programmers from hell...
-	 */
-	mask = __ADDR_MASK;
-#ifdef CONFIG_64BIT
-	if (addr >= (addr_t) &dummy->regs.acrs &&
-	    addr < (addr_t) &dummy->regs.orig_gpr2)
-		mask = 3;
-#endif
-	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
-		return -EIO;
+	/* Remove per bit from user psw. */
+	pswmask = regs->psw.mask & ~PSW_MASK_PER;
+	ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				    &pswmask, PT_PSWMASK, PT_PSWADDR);
+
+	/* The rest of the PSW and the GPRs are directly on the stack. */
+	if (ret == 0)
+		ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					    &regs->psw.addr, PT_PSWADDR,
+					    PT_ACR0);
+
+	/* The ACRs are kept in the thread_struct.  */
+	if (ret == 0 && count > 0 && pos < PT_ORIGGPR2) {
+		if (target == current)
+			save_access_regs(target->thread.acrs);
+
+		ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					    target->thread.acrs,
+					    PT_ACR0, PT_ORIGGPR2);
+	}
 
-	if (addr < (addr_t) &dummy->regs.acrs) {
-		/*
-		 * psw and gprs are stored on the stack
-		 */
-		tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr);
-		if (addr == (addr_t) &dummy->regs.psw.mask)
-			/* Remove per bit from user psw. */
-			tmp &= ~PSW_MASK_PER;
+	/* Finally, the ORIG_GPR2 value.  */
+	if (ret == 0)
+		ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					    &regs->orig_gpr2, PT_ORIGGPR2, -1);
 
-	} else if (addr < (addr_t) &dummy->regs.orig_gpr2) {
-		/*
-		 * access registers are stored in the thread structure
-		 */
-		offset = addr - (addr_t) &dummy->regs.acrs;
-#ifdef CONFIG_64BIT
-		/*
-		 * Very special case: old & broken 64 bit gdb reading
-		 * from acrs[15]. Result is a 64 bit value. Read the
-		 * 32 bit acrs[15] value and shift it by 32. Sick...
-		 */
-		if (addr == (addr_t) &dummy->regs.acrs[15])
-			tmp = ((unsigned long) child->thread.acrs[15]) << 32;
-		else
-#endif
-		tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
+	return ret;
+}
 
-	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
-		/*
-		 * orig_gpr2 is stored on the kernel stack
-		 */
-		tmp = (addr_t) task_pt_regs(child)->orig_gpr2;
+static int
+genregs_set(struct task_struct *target,
+	    const struct utrace_regset *regset,
+	    unsigned int pos, unsigned int count,
+	    const void *kbuf, const void __user *ubuf)
+{
+	struct pt_regs *regs = task_pt_regs(target);
+	int ret = 0;
+
+	/* Check for an invalid PSW mask.  */
+	if (count > 0 && pos == PT_PSWMASK) {
+		unsigned long pswmask = regs->psw.mask;
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   &pswmask, PT_PSWMASK, PT_PSWADDR);
+		if (pswmask != PSW_MASK_MERGE(psw_user_bits, pswmask)
+#ifdef CONFIG_COMPAT
+		    && pswmask != PSW_MASK_MERGE(psw_user32_bits, pswmask)
+#endif
+			)
+			/* Invalid psw mask. */
+			return -EINVAL;
+		regs->psw.mask = pswmask;
+		FixPerRegisters(target);
+	}
 
-	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
-		/* 
-		 * floating point regs. are stored in the thread structure
-		 */
-		offset = addr - (addr_t) &dummy->regs.fp_regs;
-		tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
-		if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
-			tmp &= (unsigned long) FPC_VALID_MASK
-				<< (BITS_PER_LONG - 32);
+	/* The rest of the PSW and the GPRs are directly on the stack. */
+	if (ret == 0) {
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   &regs->psw.addr, PT_PSWADDR,
+					   PT_ACR0);
+#ifndef CONFIG_64BIT
+		/* I'd like to reject addresses without the
+		   high order bit but older gdb's rely on it */
+		regs->psw.addr |= PSW_ADDR_AMODE;
+#endif
+	}
 
-	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
-		/*
-		 * per_info is found in the thread structure
-		 */
-		offset = addr - (addr_t) &dummy->regs.per_info;
-		tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset);
+	/* The ACRs are kept in the thread_struct.  */
+	if (ret == 0 && count > 0 && pos < PT_ORIGGPR2) {
+		if (target == current
+		    && (pos != PT_ACR0 || count < sizeof(target->thread.acrs)))
+			save_access_regs(target->thread.acrs);
+
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   target->thread.acrs,
+					   PT_ACR0, PT_ORIGGPR2);
+		if (ret == 0 && target == current)
+			restore_access_regs(target->thread.acrs);
+	}
 
-	} else
-		tmp = 0;
+	/* Finally, the ORIG_GPR2 value.  */
+	if (ret == 0)
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   &regs->orig_gpr2, PT_ORIGGPR2, -1);
 
-	return put_user(tmp, (addr_t __user *) data);
+	return ret;
 }
 
-/*
- * Write a word to the user area of a process at location addr. This
- * operation does have an additional problem compared to peek_user.
- * Stores to the program status word and on the floating point
- * control register needs to get checked for validity.
- */
 static int
-poke_user(struct task_struct *child, addr_t addr, addr_t data)
+fpregs_get(struct task_struct *target,
+	   const struct utrace_regset *regset,
+	   unsigned int pos, unsigned int count,
+	   void *kbuf, void __user *ubuf)
 {
-	struct user *dummy = NULL;
-	addr_t offset, mask;
+	if (target == current)
+		save_fp_regs(&target->thread.fp_regs);
 
-	/*
-	 * Stupid gdb peeks/pokes the access registers in 64 bit with
-	 * an alignment of 4. Programmers from hell indeed...
-	 */
-	mask = __ADDR_MASK;
-#ifdef CONFIG_64BIT
-	if (addr >= (addr_t) &dummy->regs.acrs &&
-	    addr < (addr_t) &dummy->regs.orig_gpr2)
-		mask = 3;
-#endif
-	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
-		return -EIO;
+	return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				     &target->thread.fp_regs, 0, -1);
+}
 
-	if (addr < (addr_t) &dummy->regs.acrs) {
-		/*
-		 * psw and gprs are stored on the stack
-		 */
-		if (addr == (addr_t) &dummy->regs.psw.mask &&
-#ifdef CONFIG_COMPAT
-		    data != PSW_MASK_MERGE(psw_user32_bits, data) &&
-#endif
-		    data != PSW_MASK_MERGE(psw_user_bits, data))
-			/* Invalid psw mask. */
+static int
+fpregs_set(struct task_struct *target,
+	    const struct utrace_regset *regset,
+	    unsigned int pos, unsigned int count,
+	    const void *kbuf, const void __user *ubuf)
+{
+	int ret = 0;
+
+	if (target == current && (pos != 0 || count != sizeof(s390_fp_regs)))
+		save_fp_regs(&target->thread.fp_regs);
+
+	/* If setting FPC, must validate it first. */
+	if (count > 0 && pos == 0) {
+		unsigned long fpc;
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   &fpc, 0, sizeof(fpc));
+		if (ret)
+			return ret;
+
+		if ((fpc & ~((unsigned long) FPC_VALID_MASK
+			     << (BITS_PER_LONG - 32))) != 0)
 			return -EINVAL;
-#ifndef CONFIG_64BIT
-		if (addr == (addr_t) &dummy->regs.psw.addr)
-			/* I'd like to reject addresses without the
-			   high order bit but older gdb's rely on it */
-			data |= PSW_ADDR_AMODE;
-#endif
-		*(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data;
 
-	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
-		/*
-		 * access registers are stored in the thread structure
-		 */
-		offset = addr - (addr_t) &dummy->regs.acrs;
-#ifdef CONFIG_64BIT
-		/*
-		 * Very special case: old & broken 64 bit gdb writing
-		 * to acrs[15] with a 64 bit value. Ignore the lower
-		 * half of the value and write the upper 32 bit to
-		 * acrs[15]. Sick...
-		 */
-		if (addr == (addr_t) &dummy->regs.acrs[15])
-			child->thread.acrs[15] = (unsigned int) (data >> 32);
-		else
-#endif
-		*(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
+		memcpy(&target->thread.fp_regs, &fpc, sizeof(fpc));
+	}
 
-	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
-		/*
-		 * orig_gpr2 is stored on the kernel stack
-		 */
-		task_pt_regs(child)->orig_gpr2 = data;
+	if (ret == 0)
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   &target->thread.fp_regs, 0, -1);
 
-	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
-		/*
-		 * floating point regs. are stored in the thread structure
-		 */
-		if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
-		    (data & ~((unsigned long) FPC_VALID_MASK
-			      << (BITS_PER_LONG - 32))) != 0)
-			return -EINVAL;
-		offset = addr - (addr_t) &dummy->regs.fp_regs;
-		*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
+	if (ret == 0 && target == current)
+		restore_fp_regs(&target->thread.fp_regs);
 
-	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
-		/*
-		 * per_info is found in the thread structure 
-		 */
-		offset = addr - (addr_t) &dummy->regs.per_info;
-		*(addr_t *)((addr_t) &child->thread.per_info + offset) = data;
-
-	}
+	return ret;
+}
 
-	FixPerRegisters(child);
-	return 0;
+static int
+per_info_get(struct task_struct *target,
+	     const struct utrace_regset *regset,
+	     unsigned int pos, unsigned int count,
+	     void *kbuf, void __user *ubuf)
+{
+	return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				     &target->thread.per_info, 0, -1);
 }
 
 static int
-do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
+per_info_set(struct task_struct *target,
+	     const struct utrace_regset *regset,
+	     unsigned int pos, unsigned int count,
+	     const void *kbuf, const void __user *ubuf)
 {
-	unsigned long tmp;
-	ptrace_area parea; 
-	int copied, ret;
-
-	switch (request) {
-	case PTRACE_PEEKTEXT:
-	case PTRACE_PEEKDATA:
-		/* Remove high order bit from address (only for 31 bit). */
-		addr &= PSW_ADDR_INSN;
-		/* read word at location addr. */
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		if (copied != sizeof(tmp))
-			return -EIO;
-		return put_user(tmp, (unsigned long __force __user *) data);
-
-	case PTRACE_PEEKUSR:
-		/* read the word at location addr in the USER area. */
-		return peek_user(child, addr, data);
-
-	case PTRACE_POKETEXT:
-	case PTRACE_POKEDATA:
-		/* Remove high order bit from address (only for 31 bit). */
-		addr &= PSW_ADDR_INSN;
-		/* write the word at location addr. */
-		copied = access_process_vm(child, addr, &data, sizeof(data),1);
-		if (copied != sizeof(data))
-			return -EIO;
-		return 0;
-
-	case PTRACE_POKEUSR:
-		/* write the word at location addr in the USER area */
-		return poke_user(child, addr, data);
-
-	case PTRACE_PEEKUSR_AREA:
-	case PTRACE_POKEUSR_AREA:
-		if (copy_from_user(&parea, (void __force __user *) addr,
-							sizeof(parea)))
-			return -EFAULT;
-		addr = parea.kernel_addr;
-		data = parea.process_addr;
-		copied = 0;
-		while (copied < parea.len) {
-			if (request == PTRACE_PEEKUSR_AREA)
-				ret = peek_user(child, addr, data);
-			else {
-				addr_t utmp;
-				if (get_user(utmp,
-					     (addr_t __force __user *) data))
-					return -EFAULT;
-				ret = poke_user(child, addr, utmp);
-			}
-			if (ret)
-				return ret;
-			addr += sizeof(unsigned long);
-			data += sizeof(unsigned long);
-			copied += sizeof(unsigned long);
-		}
-		return 0;
-	}
-	return ptrace_request(child, request, addr, data);
+	int ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				       &target->thread.per_info, 0, -1);
+
+	FixPerRegisters(target);
+
+	return ret;
 }
 
-#ifdef CONFIG_COMPAT
-/*
- * Now the fun part starts... a 31 bit program running in the
- * 31 bit emulation tracing another program. PTRACE_PEEKTEXT,
- * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy
- * to handle, the difference to the 64 bit versions of the requests
- * is that the access is done in multiples of 4 byte instead of
- * 8 bytes (sizeof(unsigned long) on 31/64 bit).
- * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA,
- * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program
- * is a 31 bit program too, the content of struct user can be
- * emulated. A 31 bit program peeking into the struct user of
- * a 64 bit program is a no-no.
- */
 
 /*
- * Same as peek_user but for a 31 bit program.
+ * These are our native regset flavors.
  */
-static int
-peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
-{
-	struct user32 *dummy32 = NULL;
-	per_struct32 *dummy_per32 = NULL;
-	addr_t offset;
-	__u32 tmp;
-
-	if (!test_thread_flag(TIF_31BIT) ||
-	    (addr & 3) || addr > sizeof(struct user) - 3)
-		return -EIO;
+static const struct utrace_regset native_regsets[] = {
+	{
+		.size = sizeof(long), .align = sizeof(long),
+		.n = sizeof(s390_regs) / sizeof(long),
+		.get = genregs_get, .set = genregs_set
+	},
+	{
+		.size = sizeof(long), .align = sizeof(long),
+		.n = sizeof(s390_fp_regs) / sizeof(long),
+		.get = fpregs_get, .set = fpregs_set
+	},
+	{
+		.size = sizeof(long), .align = sizeof(long),
+		.n = sizeof(per_struct) / sizeof(long),
+		.get = per_info_get, .set = per_info_set
+	},
+};
+
+static const struct utrace_regset_view utrace_s390_native_view = {
+	.name = UTS_MACHINE, .e_machine = ELF_ARCH,
+	.regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
+};
 
-	if (addr < (addr_t) &dummy32->regs.acrs) {
-		/*
-		 * psw and gprs are stored on the stack
-		 */
-		if (addr == (addr_t) &dummy32->regs.psw.mask) {
-			/* Fake a 31 bit psw mask. */
-			tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
-			tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
-		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
-			/* Fake a 31 bit psw address. */
-			tmp = (__u32) task_pt_regs(child)->psw.addr |
-				PSW32_ADDR_AMODE31;
-		} else {
-			/* gpr 0-15 */
-			tmp = *(__u32 *)((addr_t) &task_pt_regs(child)->psw +
-					 addr*2 + 4);
-		}
-	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
-		/*
-		 * access registers are stored in the thread structure
-		 */
-		offset = addr - (addr_t) &dummy32->regs.acrs;
-		tmp = *(__u32*)((addr_t) &child->thread.acrs + offset);
 
-	} else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
-		/*
-		 * orig_gpr2 is stored on the kernel stack
-		 */
-		tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4);
+#ifdef CONFIG_COMPAT
+static int
+s390_genregs_get(struct task_struct *target,
+		 const struct utrace_regset *regset,
+		 unsigned int pos, unsigned int count,
+		 void *kbuf, void __user *ubuf)
+{
+	struct pt_regs *regs = task_pt_regs(target);
+	int ret = 0;
+
+	/* Fake a 31 bit psw mask. */
+	if (count > 0 && pos == PT_PSWMASK / 2) {
+		u32 pswmask = PSW32_MASK_MERGE(psw32_user_bits,
+					       (u32) (regs->psw.mask >> 32));
+		ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					    &pswmask, PT_PSWMASK / 2,
+					    PT_PSWADDR / 2);
+	}
 
-	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
-		/*
-		 * floating point regs. are stored in the thread structure 
-		 */
-	        offset = addr - (addr_t) &dummy32->regs.fp_regs;
-		tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
+	/* Fake a 31 bit psw address. */
+	if (ret == 0 && count > 0 && pos == PT_PSWADDR / 2) {
+		u32 pswaddr = (u32) regs->psw.addr | PSW32_ADDR_AMODE31;
+		ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					    &pswaddr, PT_PSWADDR / 2,
+					    PT_GPR0 / 2);
+	}
 
-	} else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
-		/*
-		 * per_info is found in the thread structure
-		 */
-		offset = addr - (addr_t) &dummy32->regs.per_info;
-		/* This is magic. See per_struct and per_struct32. */
-		if ((offset >= (addr_t) &dummy_per32->control_regs &&
-		     offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
-		    (offset >= (addr_t) &dummy_per32->starting_addr &&
-		     offset <= (addr_t) &dummy_per32->ending_addr) ||
-		    offset == (addr_t) &dummy_per32->lowcore.words.address)
-			offset = offset*2 + 4;
+	/* The GPRs are directly on the stack.  Just truncate them.  */
+	while (ret == 0 && count > 0 && pos < PT_ACR0 / 2) {
+		u32 value = regs->gprs[(pos - PT_GPR0 / 2) / sizeof(u32)];
+		if (kbuf) {
+			*(u32 *) kbuf = value;
+			kbuf += sizeof(u32);
+		}
+		else if (put_user(value, (u32 __user *) ubuf))
+			ret = -EFAULT;
 		else
-			offset = offset*2;
-		tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset);
+			ubuf += sizeof(u32);
+		pos += sizeof(u32);
+		count -= sizeof(u32);
+	}
 
-	} else
-		tmp = 0;
+	/* The ACRs are kept in the thread_struct.  */
+	if (ret == 0 && count > 0 && pos < PT_ACR0 / 2 + NUM_ACRS * ACR_SIZE) {
+		if (target == current)
+			save_access_regs(target->thread.acrs);
+
+		ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					    target->thread.acrs,
+					    PT_ACR0 / 2,
+					    PT_ACR0 / 2 + NUM_ACRS * ACR_SIZE);
+	}
 
-	return put_user(tmp, (__u32 __user *) data);
+	/* Finally, the ORIG_GPR2 value.  */
+	if (count > 0) {
+		if (kbuf)
+			*(u32 *) kbuf = regs->orig_gpr2;
+		else if (put_user((u32) regs->orig_gpr2,
+				  (u32 __user *) ubuf))
+			return -EFAULT;
+	}
+
+	return 0;
 }
 
-/*
- * Same as poke_user but for a 31 bit program.
- */
 static int
-poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
-{
-	struct user32 *dummy32 = NULL;
-	per_struct32 *dummy_per32 = NULL;
-	addr_t offset;
-	__u32 tmp;
+s390_genregs_set(struct task_struct *target,
+		 const struct utrace_regset *regset,
+		 unsigned int pos, unsigned int count,
+		 const void *kbuf, const void __user *ubuf)
+{
+	struct pt_regs *regs = task_pt_regs(target);
+	int ret = 0;
+
+	/* Check for an invalid PSW mask.  */
+	if (count > 0 && pos == PT_PSWMASK / 2) {
+		u32 pswmask;
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   &pswmask, PT_PSWMASK / 2,
+					   PT_PSWADDR / 2);
+		if (ret)
+			return ret;
 
-	if (!test_thread_flag(TIF_31BIT) ||
-	    (addr & 3) || addr > sizeof(struct user32) - 3)
-		return -EIO;
+		if (pswmask != PSW_MASK_MERGE(psw_user32_bits, pswmask))
+			/* Invalid psw mask. */
+			return -EINVAL;
 
-	tmp = (__u32) data;
+		/* Build a 64 bit psw mask from 31 bit mask. */
+		regs->psw.mask = PSW_MASK_MERGE(psw_user32_bits,
+						(u64) pswmask << 32);
+		FixPerRegisters(target);
+	}
 
-	if (addr < (addr_t) &dummy32->regs.acrs) {
-		/*
-		 * psw, gprs, acrs and orig_gpr2 are stored on the stack
-		 */
-		if (addr == (addr_t) &dummy32->regs.psw.mask) {
+	/* Build a 64 bit psw address from 31 bit address. */
+	if (count > 0 && pos == PT_PSWADDR / 2) {
+		u32 pswaddr;
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   &pswaddr, PT_PSWADDR / 2,
+					   PT_GPR0 / 2);
+		if (ret == 0)
 			/* Build a 64 bit psw mask from 31 bit mask. */
-			if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
-				/* Invalid psw mask. */
-				return -EINVAL;
-			task_pt_regs(child)->psw.mask =
-				PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
-		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
-			/* Build a 64 bit psw address from 31 bit address. */
-			task_pt_regs(child)->psw.addr =
-				(__u64) tmp & PSW32_ADDR_INSN;
-		} else {
-			/* gpr 0-15 */
-			*(__u32*)((addr_t) &task_pt_regs(child)->psw
-				  + addr*2 + 4) = tmp;
+			regs->psw.addr = pswaddr & PSW32_ADDR_INSN;
+	}
+
+	/* The GPRs are directly onto the stack. */
+	while (ret == 0 && count > 0 && pos < PT_ACR0 / 2) {
+		u32 value;
+
+		if (kbuf) {
+			value = *(const u32 *) kbuf;
+			kbuf += sizeof(u32);
 		}
-	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
-		/*
-		 * access registers are stored in the thread structure
-		 */
-		offset = addr - (addr_t) &dummy32->regs.acrs;
-		*(__u32*)((addr_t) &child->thread.acrs + offset) = tmp;
+		else if (get_user(value, (const u32 __user *) ubuf))
+			return -EFAULT;
+		else
+			ubuf += sizeof(u32);
+		pos += sizeof(u32);
+		count -= sizeof(u32);
 
-	} else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
-		/*
-		 * orig_gpr2 is stored on the kernel stack
-		 */
-		*(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp;
+		regs->gprs[(pos - PT_GPR0 / 2) / sizeof(u32)] = value;
+	}
 
-	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
-		/*
-		 * floating point regs. are stored in the thread structure 
-		 */
-		if (addr == (addr_t) &dummy32->regs.fp_regs.fpc &&
-		    (tmp & ~FPC_VALID_MASK) != 0)
-			/* Invalid floating point control. */
-			return -EINVAL;
-	        offset = addr - (addr_t) &dummy32->regs.fp_regs;
-		*(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp;
+	/* The ACRs are kept in the thread_struct.  */
+	if (count > 0 && pos < PT_ORIGGPR2 / 2) {
+		if (target == current
+		    && (pos != PT_ACR0 / 2
+			|| count < sizeof(target->thread.acrs)))
+			save_access_regs(target->thread.acrs);
+
+		ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					   target->thread.acrs,
+					   PT_ACR0 / 2,
+					   PT_ACR0 / 2 + NUM_ACRS * ACR_SIZE);
 
-	} else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
-		/*
-		 * per_info is found in the thread structure.
-		 */
-		offset = addr - (addr_t) &dummy32->regs.per_info;
-		/*
-		 * This is magic. See per_struct and per_struct32.
-		 * By incident the offsets in per_struct are exactly
-		 * twice the offsets in per_struct32 for all fields.
-		 * The 8 byte fields need special handling though,
-		 * because the second half (bytes 4-7) is needed and
-		 * not the first half.
-		 */
-		if ((offset >= (addr_t) &dummy_per32->control_regs &&
-		     offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
-		    (offset >= (addr_t) &dummy_per32->starting_addr &&
-		     offset <= (addr_t) &dummy_per32->ending_addr) ||
-		    offset == (addr_t) &dummy_per32->lowcore.words.address)
-			offset = offset*2 + 4;
-		else
-			offset = offset*2;
-		*(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp;
+		if (ret == 0 && target == current)
+			restore_access_regs(target->thread.acrs);
+	}
 
+	/* Finally, the ORIG_GPR2 value.  */
+	if (ret == 0 && count > 0) {
+		u32 value;
+		if (kbuf)
+			value = *(const u32 *) kbuf;
+		else if (get_user(value, (const u32 __user *) ubuf))
+			return -EFAULT;
+		regs->orig_gpr2 = value;
 	}
 
-	FixPerRegisters(child);
-	return 0;
+	return ret;
 }
 
-static int
-do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
+
+/*
+ * This is magic. See per_struct and per_struct32.
+ * By incident the offsets in per_struct are exactly
+ * twice the offsets in per_struct32 for all fields.
+ * The 8 byte fields need special handling though,
+ * because the second half (bytes 4-7) is needed and
+ * not the first half.
+ */
+static unsigned int
+offset_from_per32(unsigned int offset)
 {
-	unsigned int tmp;  /* 4 bytes !! */
-	ptrace_area_emu31 parea; 
-	int copied, ret;
-
-	switch (request) {
-	case PTRACE_PEEKTEXT:
-	case PTRACE_PEEKDATA:
-		/* read word at location addr. */
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		if (copied != sizeof(tmp))
-			return -EIO;
-		return put_user(tmp, (unsigned int __force __user *) data);
-
-	case PTRACE_PEEKUSR:
-		/* read the word at location addr in the USER area. */
-		return peek_user_emu31(child, addr, data);
-
-	case PTRACE_POKETEXT:
-	case PTRACE_POKEDATA:
-		/* write the word at location addr. */
-		tmp = data;
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
-		if (copied != sizeof(tmp))
-			return -EIO;
-		return 0;
-
-	case PTRACE_POKEUSR:
-		/* write the word at location addr in the USER area */
-		return poke_user_emu31(child, addr, data);
-
-	case PTRACE_PEEKUSR_AREA:
-	case PTRACE_POKEUSR_AREA:
-		if (copy_from_user(&parea, (void __force __user *) addr,
-							sizeof(parea)))
-			return -EFAULT;
-		addr = parea.kernel_addr;
-		data = parea.process_addr;
-		copied = 0;
-		while (copied < parea.len) {
-			if (request == PTRACE_PEEKUSR_AREA)
-				ret = peek_user_emu31(child, addr, data);
-			else {
-				__u32 utmp;
-				if (get_user(utmp,
-					     (__u32 __force __user *) data))
-					return -EFAULT;
-				ret = poke_user_emu31(child, addr, utmp);
-			}
-			if (ret)
-				return ret;
-			addr += sizeof(unsigned int);
-			data += sizeof(unsigned int);
-			copied += sizeof(unsigned int);
+	BUILD_BUG_ON(offsetof(per_struct32, control_regs) != 0);
+	if (offset - offsetof(per_struct32, control_regs) < 3*sizeof(u32)
+	    || (offset >= offsetof(per_struct32, starting_addr) &&
+		offset <= offsetof(per_struct32, ending_addr))
+	    || offset == offsetof(per_struct32, lowcore.words.address))
+		offset = offset*2 + 4;
+	else
+		offset = offset*2;
+	return offset;
+}
+
+static int
+s390_per_info_get(struct task_struct *target,
+		  const struct utrace_regset *regset,
+		  unsigned int pos, unsigned int count,
+		  void *kbuf, void __user *ubuf)
+{
+	while (count > 0) {
+		u32 val = *(u32 *) ((char *) &target->thread.per_info
+				    + offset_from_per32 (pos));
+		if (kbuf) {
+			*(u32 *) kbuf = val;
+			kbuf += sizeof(u32);
 		}
-		return 0;
-#if 0				/* XXX */
-	case PTRACE_GETEVENTMSG:
-		return put_user((__u32) child->ptrace_message,
-				(unsigned int __force __user *) data);
-	case PTRACE_GETSIGINFO:
-		if (child->last_siginfo == NULL)
-			return -EINVAL;
-		return copy_siginfo_to_user32((compat_siginfo_t
-					       __force __user *) data,
-					      child->last_siginfo);
-	case PTRACE_SETSIGINFO:
-		if (child->last_siginfo == NULL)
-			return -EINVAL;
-		return copy_siginfo_from_user32(child->last_siginfo,
-						(compat_siginfo_t
-						 __force __user *) data);
+		else if (put_user(val, (u32 __user *) ubuf))
+			return -EFAULT;
+		else
+			ubuf += sizeof(u32);
+		pos += sizeof(u32);
+		count -= sizeof(u32);
 	}
-	return ptrace_request(child, request, addr, data);
+	return 0;
 }
-#endif
-
-#define PT32_IEEE_IP 0x13c
 
 static int
-do_ptrace(struct task_struct *child, long request, long addr, long data)
-{
-	int ret;
-
-	if (request == PTRACE_ATTACH)
-		return ptrace_attach(child);
+s390_per_info_set(struct task_struct *target,
+		  const struct utrace_regset *regset,
+		  unsigned int pos, unsigned int count,
+		  const void *kbuf, const void __user *ubuf)
+{
+	while (count > 0) {
+		u32 val;
+
+		if (kbuf) {
+			val = *(const u32 *) kbuf;
+			kbuf += sizeof(u32);
+		}
+		else if (get_user(val, (const u32 __user *) ubuf))
+			return -EFAULT;
+		else
+			ubuf += sizeof(u32);
+		pos += sizeof(u32);
+		count -= sizeof(u32);
 
-	/*
-	 * Special cases to get/store the ieee instructions pointer.
-	 */
-	if (child == current) {
-		if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP)
-			return peek_user(child, addr, data);
-		if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP)
-			return poke_user(child, addr, data);
-#ifdef CONFIG_COMPAT
-		if (request == PTRACE_PEEKUSR &&
-		    addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
-			return peek_user_emu31(child, addr, data);
-		if (request == PTRACE_POKEUSR &&
-		    addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
-			return poke_user_emu31(child, addr, data);
-#endif
+		*(u32 *) ((char *) &target->thread.per_info
+			  + offset_from_per32 (pos)) = val;
 	}
+	return 0;
+}
 
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		return ret;
-
-	switch (request) {
-	case PTRACE_SYSCALL:
-		/* continue and stop at next (return from) syscall */
-	case PTRACE_CONT:
-		/* restart after signal. */
-		if (!valid_signal(data))
-			return -EIO;
-		if (request == PTRACE_SYSCALL)
-			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		else
-			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		child->exit_code = data;
-		/* make sure the single step bit is not set. */
-		tracehook_disable_single_step(child);
-		wake_up_process(child);
-		return 0;
-
-	case PTRACE_KILL:
-		/*
-		 * make the child exit.  Best I can do is send it a sigkill. 
-		 * perhaps it should be put in the status that it wants to 
-		 * exit.
-		 */
-		if (child->exit_state == EXIT_ZOMBIE) /* already dead */
-			return 0;
-		child->exit_code = SIGKILL;
-		/* make sure the single step bit is not set. */
-		tracehook_disable_single_step(child);
-		wake_up_process(child);
-		return 0;
-
-	case PTRACE_SINGLESTEP:
-		/* set the trap flag. */
-		if (!valid_signal(data))
-			return -EIO;
-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		child->exit_code = data;
-		if (data)
-			set_tsk_thread_flag(child, TIF_SINGLE_STEP);
-		else
-			tracehook_enable_single_step(child);
-		/* give it a chance to run. */
-		wake_up_process(child);
-		return 0;
-
-	case PTRACE_DETACH:
-		/* detach a process that was attached. */
-		return ptrace_detach(child, data);
 
+static const struct utrace_regset s390_compat_regsets[] = {
+	{
+		.size = sizeof(u32), .align = sizeof(u32),
+		.n = sizeof(s390_regs) / sizeof(long),
+		.get = s390_genregs_get, .set = s390_genregs_set
+	},
+	{
+		.size = sizeof(u32), .align = sizeof(u32),
+		.n = sizeof(s390_fp_regs) / sizeof(u32),
+		.get = fpregs_get, .set = fpregs_set
+	},
+	{
+		.size = sizeof(u32), .align = sizeof(u32),
+		.n = sizeof(per_struct) / sizeof(u32),
+		.get = s390_per_info_get, .set = s390_per_info_set
+	},
+};
+
+static const struct utrace_regset_view utrace_s390_compat_view = {
+	.name = "s390", .e_machine = EM_S390,
+	.regsets = s390_compat_regsets, .n = ARRAY_SIZE(s390_compat_regsets)
+};
+#endif	/* CONFIG_COMPAT */
 
-	/* Do requests that differ for 31/64 bit */
-	default:
+const struct utrace_regset_view *utrace_native_view(struct task_struct *tsk)
+{
 #ifdef CONFIG_COMPAT
-		if (test_thread_flag(TIF_31BIT))
-			return do_ptrace_emu31(child, request, addr, data);
+        if (test_tsk_thread_flag(tsk, TIF_31BIT))
+                return &utrace_s390_compat_view;
 #endif
-		return do_ptrace_normal(child, request, addr, data);
-	}
-	/* Not reached.  */
-	return -EIO;
+        return &utrace_s390_native_view;
 }
 
-asmlinkage long
-sys_ptrace(long request, long pid, long addr, long data)
-{
-	struct task_struct *child;
-	int ret;
-
-	lock_kernel();
-	if (request == PTRACE_TRACEME) {
-		 ret = ptrace_traceme();
-		 goto out;
-	}
-
-	child = ptrace_get_task_struct(pid);
-	if (IS_ERR(child)) {
-		ret = PTR_ERR(child);
-		goto out;
-	}
-
-	ret = do_ptrace(child, request, addr, data);
-	put_task_struct(child);
-out:
-	unlock_kernel();
-	return ret;
-}
 
 asmlinkage void
 syscall_trace(struct pt_regs *regs, int entryexit)

linux-2.6-utrace-regset-sparc64.patch:
 Makefile  |    2 
 ptrace.c  |  631 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 systbls.S |    4 
 3 files changed, 568 insertions(+), 69 deletions(-)

Index: linux-2.6-utrace-regset-sparc64.patch
===================================================================
RCS file: linux-2.6-utrace-regset-sparc64.patch
diff -N linux-2.6-utrace-regset-sparc64.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-regset-sparc64.patch	19 Jul 2007 17:46:36 -0000	1.3
@@ -0,0 +1,726 @@
+[PATCH 2b] utrace: sparc64 regset support
+
+This patch converts the machine-dependent ptrace code into utrace regset
+support for sparc64.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+
+---
+
+ arch/sparc64/kernel/Makefile  |    2 
+ arch/sparc64/kernel/ptrace.c  |  631 +++++++++++++++++++++++++++++++++++++----
+ arch/sparc64/kernel/systbls.S |    4 
+ 3 files changed, 568 insertions(+), 69 deletions(-)
+
+--- linux-2.6/arch/sparc64/kernel/Makefile
++++ linux-2.6/arch/sparc64/kernel/Makefile
+@@ -5,6 +5,8 @@
+ EXTRA_AFLAGS := -ansi
+ EXTRA_CFLAGS := -Werror
+ 
++CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
++
+ extra-y		:= head.o init_task.o vmlinux.lds
+ 
+ obj-y		:= process.o setup.o cpu.o idprom.o \
+--- linux-2.6/arch/sparc64/kernel/ptrace.c
++++ linux-2.6/arch/sparc64/kernel/ptrace.c
+@@ -1,6 +1,6 @@
+-/* ptrace.c: Sparc process tracing support.
++/* ptrace.c: Sparc64 process tracing support.
+  *
+- * Copyright (C) 1996 David S. Miller (davem at caipfs.rutgers.edu)
++ * Copyright (C) 1996, 2006 David S. Miller (davem at davemloft.net)
+  * Copyright (C) 1997 Jakub Jelinek (jj at sunsite.mff.cuni.cz)
+  *
+  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
+@@ -11,106 +11,603 @@
+  */
+ 
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+-#include <linux/errno.h>
+-#include <linux/ptrace.h>
+-#include <linux/user.h>
+-#include <linux/smp.h>
+-#include <linux/smp_lock.h>
+ #include <linux/security.h>
+ #include <linux/seccomp.h>
+ #include <linux/audit.h>
+-#include <linux/signal.h>
+ #include <linux/tracehook.h>
++#include <linux/elf.h>
++#include <linux/ptrace.h>
+ 
+ #include <asm/asi.h>
+ #include <asm/pgtable.h>
+ #include <asm/system.h>
+-#include <asm/uaccess.h>
+-#include <asm/psrcompat.h>
+-#include <asm/visasm.h>
+ #include <asm/spitfire.h>
+ #include <asm/page.h>
+ #include <asm/cpudata.h>
++#include <asm/psrcompat.h>
+ 
+-#if 0				/* XXX */
+-/* Returning from ptrace is a bit tricky because the syscall return
+- * low level code assumes any value returned which is negative and
+- * is a valid errno will mean setting the condition codes to indicate
+- * an error return.  This doesn't work, so we have this hook.
++#define GENREG_G0	0
++#define GENREG_O0	8
++#define GENREG_L0	16
++#define GENREG_I0	24
++#define GENREG_TSTATE	32
++#define GENREG_TPC	33
++#define GENREG_TNPC	34
++#define GENREG_Y	35
++
++#define SPARC64_NGREGS	36
++
++static int genregs_get(struct task_struct *target,
++		       const struct utrace_regset *regset,
++		       unsigned int pos, unsigned int count,
++		       void *kbuf, void __user *ubuf)
++{
++	struct pt_regs *regs = task_pt_regs(target);
++	int err;
++
++	err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->u_regs,
++				    GENREG_G0 * 8, GENREG_L0 * 8);
++
++	if (err == 0 && count > 0 && pos < (GENREG_TSTATE * 8)) {
++		struct thread_info *t = task_thread_info(target);
++		unsigned long rwindow[16], fp, *win;
++		int wsaved;
++
++		if (target == current)
++			flushw_user();
++
++		wsaved = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_WSAVED];
++		fp = regs->u_regs[UREG_FP] + STACK_BIAS;
++		if (wsaved && t->rwbuf_stkptrs[wsaved - 1] == fp)
++			win = &t->reg_window[wsaved - 1].locals[0];
++		else {
++			if (target == current) {
++				if (copy_from_user(rwindow,
++						   (void __user *) fp,
++						   16 * sizeof(long)))
++					err = -EFAULT;
++			} else
++				err = access_process_vm(target, fp, rwindow,
++							16 * sizeof(long), 0);
++			if (err)
++				return err;
++			win = rwindow;
++		}
++
++		err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
++					    win, GENREG_L0 * 8,
++					    GENREG_TSTATE * 8);
++	}
++
++	if (err == 0)
++		err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
++					    &regs->tstate, GENREG_TSTATE * 8,
++					    GENREG_Y * 8);
++	if (err == 0 && count > 0) {
++		if (kbuf)
++			*(unsigned long *) kbuf = regs->y;
++		else if (put_user(regs->y, (unsigned long __user *) ubuf))
++			return -EFAULT;
++	}
++
++	return err;
++}
++
++/* Consistent with signal handling, we only allow userspace to
++ * modify the %asi, %icc, and %xcc fields of the %tstate register.
+  */
+-static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
++#define TSTATE_DEBUGCHANGE	(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)
++
++static int genregs_set(struct task_struct *target,
++		       const struct utrace_regset *regset,
++		       unsigned int pos, unsigned int count,
++		       const void *kbuf, const void __user *ubuf)
+ {
+-	regs->u_regs[UREG_I0] = error;
+-	regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY);
+-	regs->tpc = regs->tnpc;
+-	regs->tnpc += 4;
++	struct pt_regs *regs = task_pt_regs(target);
++	unsigned long tstate_save;
++	int err;
++
++	err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, regs->u_regs,
++				   GENREG_G0 * 8, GENREG_L0 * 8);
++
++	if (err == 0 && count > 0 && pos < (GENREG_TSTATE * 8)) {
++		unsigned long fp = regs->u_regs[UREG_FP] + STACK_BIAS;
++		unsigned long rwindow[16], *winbuf;
++		unsigned int copy = (GENREG_TSTATE * 8) - pos;
++		unsigned int off;
++		int err;
++
++		if (target == current)
++			flushw_user();
++
++		if (count < copy)
++			copy = count;
++		off = pos - (GENREG_L0 * 8);
++
++		if (kbuf) {
++			winbuf = (unsigned long *) kbuf;
++			kbuf += copy;
++		}
++		else {
++			winbuf = rwindow;
++			if (copy_from_user(winbuf, ubuf, copy))
++				return -EFAULT;
++			ubuf += copy;
++		}
++		count -= copy;
++		pos += copy;
++
++		if (target == current)
++			err = copy_to_user((void __user *) fp + off,
++					   winbuf, copy);
++		else
++			err = access_process_vm(target, fp + off,
++						winbuf, copy, 1);
++	}
++
++	tstate_save = regs->tstate &~ TSTATE_DEBUGCHANGE;
++
++	if (err == 0)
++		err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
++					    &regs->tstate, GENREG_TSTATE * 8,
++					    GENREG_Y * 8);
++
++	regs->tstate &= TSTATE_DEBUGCHANGE;
++	regs->tstate |= tstate_save;
++
++	if (err == 0 && count > 0) {
++		if (kbuf)
++			regs->y = *(unsigned long *) kbuf;
++		else if (get_user(regs->y, (unsigned long __user *) ubuf))
++			return -EFAULT;
++	}
++
++	return err;
++}
++
++#define FPREG_F0	0
++#define FPREG_FSR	32
++#define FPREG_GSR	33
++#define FPREG_FPRS	34
++
++#define SPARC64_NFPREGS	35
++
++static int fpregs_get(struct task_struct *target,
++		      const struct utrace_regset *regset,
++		      unsigned int pos, unsigned int count,
++		      void *kbuf, void __user *ubuf)
++{
++	struct thread_info *t = task_thread_info(target);
++	int err;
++
++	err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
++				    t->fpregs, FPREG_F0 * 8, FPREG_FSR * 8);
++
++	if (err == 0)
++		err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
++					    &t->xfsr[0], FPREG_FSR * 8,
++					    FPREG_GSR * 8);
++
++	if (err == 0)
++		err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
++					    &t->gsr[0], FPREG_GSR * 8,
++					    FPREG_FPRS * 8);
++
++	if (err == 0 && count > 0) {
++		struct pt_regs *regs = task_pt_regs(target);
++
++		if (kbuf)
++			*(unsigned long *) kbuf = regs->fprs;
++		else if (put_user(regs->fprs, (unsigned long __user *) ubuf))
++			return -EFAULT;
++	}
++
++	return err;
+ }
+ 
+-static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
++static int fpregs_set(struct task_struct *target,
++		      const struct utrace_regset *regset,
++		      unsigned int pos, unsigned int count,
++		      const void *kbuf, const void __user *ubuf)
+ {
+-	regs->u_regs[UREG_I0] = value;
+-	regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
+-	regs->tpc = regs->tnpc;
+-	regs->tnpc += 4;
++	struct thread_info *t = task_thread_info(target);
++	int err;
++
++	err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
++				   t->fpregs, FPREG_F0 * 8, FPREG_FSR * 8);
++
++	if (err == 0)
++		err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
++					   &t->xfsr[0], FPREG_FSR * 8,
++					   FPREG_GSR * 8);
++
++	if (err == 0)
++		err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
++					   &t->gsr[0], FPREG_GSR * 8,
++					   FPREG_FPRS * 8);
++
++	if (err == 0 && count > 0) {
++		struct pt_regs *regs = task_pt_regs(target);
++
++		if (kbuf)
++			regs->fprs = *(unsigned long *) kbuf;
++		else if (get_user(regs->fprs, (unsigned long __user *) ubuf))
++			return -EFAULT;
++	}
++
++	return err;
+ }
+ 
+-static inline void
+-pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr)
++static const struct utrace_regset native_regsets[] = {
++	{
++		.n = SPARC64_NGREGS,
++		.size = sizeof(long), .align = sizeof(long),
++		.get = genregs_get, .set = genregs_set
++	},
++	{
++		.n = SPARC64_NFPREGS,
++		.size = sizeof(long), .align = sizeof(long),
++		.get = fpregs_get, .set = fpregs_set
++	},
++};
++
++static const struct utrace_regset_view utrace_sparc64_native_view = {
++	.name = UTS_MACHINE, .e_machine = ELF_ARCH,
++	.regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
++};
++
++#ifdef CONFIG_COMPAT
++
++#define GENREG32_G0	0
++#define GENREG32_O0	8
++#define GENREG32_L0	16
++#define GENREG32_I0	24
++#define GENREG32_PSR	32
++#define GENREG32_PC	33
++#define GENREG32_NPC	34
++#define GENREG32_Y	35
++#define GENREG32_WIM	36
++#define GENREG32_TBR	37
++
++#define SPARC32_NGREGS	38
++
++static int genregs32_get(struct task_struct *target,
++			 const struct utrace_regset *regset,
++			 unsigned int pos, unsigned int count,
++			 void *kbuf, void __user *ubuf)
+ {
+-	if (test_thread_flag(TIF_32BIT)) {
+-		if (put_user(value, (unsigned int __user *) addr)) {
+-			pt_error_return(regs, EFAULT);
+-			return;
+-		}
+-	} else {
+-		if (put_user(value, (long __user *) addr)) {
+-			pt_error_return(regs, EFAULT);
+-			return;
++	struct pt_regs *regs = task_pt_regs(target);
++
++	while (count > 0 && pos < (GENREG32_L0 * 4)) {
++		u32 val = regs->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)];
++		if (kbuf) {
++			*(u32 *) kbuf = val;
++			kbuf += sizeof(u32);
++		} else if (put_user(val, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0 && pos < (GENREG32_PSR * 4)) {
++		struct thread_info *t = task_thread_info(target);
++		unsigned long fp;
++		u32 rwindow[16];
++		int wsaved;
++
++		if (target == current)
++			flushw_user();
++
++		wsaved = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_WSAVED];
++		fp = regs->u_regs[UREG_FP] & 0xffffffffUL;
++		if (wsaved && t->rwbuf_stkptrs[wsaved - 1] == fp) {
++			int i;
++			for (i = 0; i < 8; i++)
++				rwindow[i + 0] =
++					t->reg_window[wsaved-1].locals[i];
++			for (i = 0; i < 8; i++)
++				rwindow[i + 8] =
++					t->reg_window[wsaved-1].ins[i];
++		} else {
++			int err;
++
++			if (target == current) {
++				err = 0;
++				if (copy_from_user(rwindow, (void __user *) fp,
++						   16 * sizeof(u32)))
++					err = -EFAULT;
++			} else
++				err = access_process_vm(target, fp, rwindow,
++							16 * sizeof(u32), 0);
++			if (err)
++				return err;
++		}
++
++		while (count > 0 && pos < (GENREG32_PSR * 4)) {
++			u32 val = rwindow[(pos - (GENREG32_L0*4))/sizeof(u32)];
++
++			if (kbuf) {
++				*(u32 *) kbuf = val;
++				kbuf += sizeof(u32);
++			} else if (put_user(val, (u32 __user *) ubuf))
++				return -EFAULT;
++			else
++				ubuf += sizeof(u32);
++			pos += sizeof(u32);
++			count -= sizeof(u32);
+ 		}
+ 	}
+-	regs->u_regs[UREG_I0] = 0;
+-	regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
+-	regs->tpc = regs->tnpc;
+-	regs->tnpc += 4;
++
++	if (count > 0 && pos == (GENREG32_PSR * 4)) {
++		u32 psr = tstate_to_psr(regs->tstate);
++
++		if (kbuf) {
++			*(u32 *) kbuf = psr;
++			kbuf += sizeof(u32);
++		} else if (put_user(psr, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0 && pos == (GENREG32_PC * 4)) {
++		u32 val = regs->tpc;
++
++		if (kbuf) {
++			*(u32 *) kbuf = val;
++			kbuf += sizeof(u32);
++		} else if (put_user(val, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0 && pos == (GENREG32_NPC * 4)) {
++		u32 val = regs->tnpc;
++
++		if (kbuf) {
++			*(u32 *) kbuf = val;
++			kbuf += sizeof(u32);
++		} else if (put_user(val, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0 && pos == (GENREG32_Y * 4)) {
++		if (kbuf) {
++			*(u32 *) kbuf = regs->y;
++			kbuf += sizeof(u32);
++		} else if (put_user(regs->y, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0) {
++		if (kbuf)
++			memset(kbuf, 0, count);
++		else if (clear_user(ubuf, count))
++			return -EFAULT;
++	}
++
++	return 0;
++}
++
++static int genregs32_set(struct task_struct *target,
++			 const struct utrace_regset *regset,
++			 unsigned int pos, unsigned int count,
++			 const void *kbuf, const void __user *ubuf)
++{
++	struct pt_regs *regs = task_pt_regs(target);
++
++	while (count > 0 && pos < (GENREG32_L0 * 4)) {
++		unsigned long *loc;
++		loc = &regs->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)];
++		if (kbuf) {
++			*loc = *(u32 *) kbuf;
++			kbuf += sizeof(u32);
++		} else if (get_user(*loc, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0 && pos < (GENREG32_PSR * 4)) {
++		unsigned long fp;
++		u32 regbuf[16];
++		unsigned int off, copy;
++		int err;
++
++		if (target == current)
++			flushw_user();
++
++		copy = (GENREG32_PSR * 4) - pos;
++		if (count < copy)
++			copy = count;
++		BUG_ON(copy > 16 * sizeof(u32));
++
++		fp = regs->u_regs[UREG_FP] & 0xffffffffUL;
++		off = pos - (GENREG32_L0 * 4);
++		if (kbuf) {
++			memcpy(regbuf, kbuf, copy);
++			kbuf += copy;
++		} else if (copy_from_user(regbuf, ubuf, copy))
++			return -EFAULT;
++		else
++			ubuf += copy;
++		pos += copy;
++		count -= copy;
++
++		if (target == current) {
++			err = 0;
++			if (copy_to_user((void __user *) fp + off,
++					 regbuf, count))
++				err = -EFAULT;
++		} else
++			err = access_process_vm(target, fp + off,
++						regbuf, count, 1);
++		if (err)
++			return err;
++	}
++
++	if (count > 0 && pos == (GENREG32_PSR * 4)) {
++		unsigned long tstate, tstate_save;
++		u32 psr;
++
++		tstate_save = regs->tstate&~(TSTATE_ICC|TSTATE_XCC);
++
++		if (kbuf) {
++			psr = *(u32 *) kbuf;
++			kbuf += sizeof(u32);
++		} else if (get_user(psr, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++
++		tstate = psr_to_tstate_icc(psr);
++		regs->tstate = tstate_save | tstate;
++	}
++
++	if (count > 0 && pos == (GENREG32_PC * 4)) {
++		if (kbuf) {
++			regs->tpc = *(u32 *) kbuf;
++			kbuf += sizeof(u32);
++		} else if (get_user(regs->tpc, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0 && pos == (GENREG32_NPC * 4)) {
++		if (kbuf) {
++			regs->tnpc = *(u32 *) kbuf;
++			kbuf += sizeof(u32);
++		} else if (get_user(regs->tnpc, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	if (count > 0 && pos == (GENREG32_Y * 4)) {
++		if (kbuf) {
++			regs->y = *(u32 *) kbuf;
++			kbuf += sizeof(u32);
++		} else if (get_user(regs->y, (u32 __user *) ubuf))
++			return -EFAULT;
++		else
++			ubuf += sizeof(u32);
++		pos += sizeof(u32);
++		count -= sizeof(u32);
++	}
++
++	/* Ignore WIM and TBR */
++
++	return 0;
+ }
+ 
+-static void
+-pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr)
++#define FPREG32_F0	0
++#define FPREG32_FSR	32
++
++#define SPARC32_NFPREGS	33
++
++static int fpregs32_get(struct task_struct *target,
++			const struct utrace_regset *regset,
++			unsigned int pos, unsigned int count,
++			void *kbuf, void __user *ubuf)
+ {
+-	if (current->personality == PER_SUNOS)
+-		pt_succ_return (regs, val);
+-	else
+-		pt_succ_return_linux (regs, val, addr);
++	struct thread_info *t = task_thread_info(target);
++	int err;
++
++	err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf,
++				    t->fpregs, FPREG32_F0 * 4,
++				    FPREG32_FSR * 4);
++
++	if (err == 0 && count > 0) {
++		if (kbuf) {
++			*(u32 *) kbuf = t->xfsr[0];
++		} else if (put_user(t->xfsr[0], (u32 __user *) ubuf))
++			return -EFAULT;
++	}
++
++	return err;
+ }
+-#endif
+ 
+-/* #define ALLOW_INIT_TRACING */
+-/* #define DEBUG_PTRACE */
++static int fpregs32_set(struct task_struct *target,
++			const struct utrace_regset *regset,
++			unsigned int pos, unsigned int count,
++			const void *kbuf, const void __user *ubuf)
++{
++	struct thread_info *t = task_thread_info(target);
++	int err;
+ 
+-#ifdef DEBUG_PTRACE
+-char *pt_rq [] = {
+-	/* 0  */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
+-	/* 4  */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
+-	/* 8  */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
+-	/* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
+-	/* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
+-	/* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
+-	/* 24 */ "SYSCALL", ""
++	err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf,
++				   t->fpregs, FPREG32_F0 * 4,
++				   FPREG32_FSR * 4);
++
++	if (err == 0 && count > 0) {
++		u32 fsr;
++		if (kbuf) {
++			fsr = *(u32 *) kbuf;
++		} else if (get_user(fsr, (u32 __user *) ubuf))
++			return -EFAULT;
++		t->xfsr[0] = (t->xfsr[0] & 0xffffffff00000000UL) | fsr;
++	}
++
++	return 0;
++}
++
++static const struct utrace_regset sparc32_regsets[] = {
++	{
++		.n = SPARC32_NGREGS,
++		.size = sizeof(u32), .align = sizeof(u32),
++		.get = genregs32_get, .set = genregs32_set
++	},
++	{
++		.n = SPARC32_NFPREGS,
++		.size = sizeof(u32), .align = sizeof(u32),
++		.get = fpregs32_get, .set = fpregs32_set
++	},
+ };
+-#endif
+ 
+-/*
+- * Called by kernel/ptrace.c when detaching..
+- *
+- * Make sure single step bits etc are not set.
+- */
+-void ptrace_disable(struct task_struct *child)
++static const struct utrace_regset_view utrace_sparc32_view = {
++	.name = "sparc", .e_machine = EM_SPARC,
++	.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
++};
++
++#endif	/* CONFIG_COMPAT */
++
++const struct utrace_regset_view *utrace_native_view(struct task_struct *tsk)
+ {
+-	/* nothing to do */
++#ifdef CONFIG_COMPAT
++	if (test_tsk_thread_flag(tsk, TIF_32BIT))
++		return &utrace_sparc32_view;
++#endif
++	return &utrace_sparc64_native_view;
+ }
+ 
++
+ /* To get the necessary page struct, access_process_vm() first calls
+  * get_user_pages().  This has done a flush_dcache_page() on the
+  * accessed page.  Then our caller (copy_{to,from}_user_page()) did
+--- linux-2.6/arch/sparc64/kernel/systbls.S
++++ linux-2.6/arch/sparc64/kernel/systbls.S
+@@ -24,7 +24,7 @@ sys_call_table32:
+ /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod
+ /*15*/	.word sys_chmod, sys32_lchown16, sparc_brk, sys32_perfctr, sys32_lseek
+ /*20*/	.word sys_getpid, sys_capget, sys_capset, sys32_setuid16, sys32_getuid16
+-/*25*/	.word sys32_vmsplice, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
++/*25*/	.word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
+ /*30*/	.word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice
+ 	.word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile
+ /*40*/	.word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid
+@@ -170,7 +170,7 @@ sunos_sys_table:
+ 	.word sys_chmod, sys32_lchown16, sunos_brk
+ 	.word sunos_nosys, sys32_lseek, sunos_getpid
+ 	.word sunos_nosys, sunos_nosys, sunos_nosys
+-	.word sunos_getuid, sunos_nosys, sys_ptrace
++	.word sunos_getuid, sunos_nosys, compat_sys_ptrace
+ 	.word sunos_nosys, sunos_nosys, sunos_nosys
+ 	.word sunos_nosys, sunos_nosys, sunos_nosys
+ 	.word sys_access, sunos_nosys, sunos_nosys

linux-2.6-utrace-regset.patch:
 arch/i386/kernel/i387.c             |  143 +++---
 arch/i386/kernel/ptrace.c           |  822 ++++++++++++++++++++----------------
 arch/powerpc/kernel/Makefile        |    4 
 arch/powerpc/kernel/ptrace-common.h |  145 ------
 arch/powerpc/kernel/ptrace.c        |  718 +++++++++++++++----------------
 arch/powerpc/kernel/ptrace32.c      |  443 -------------------
 arch/x86_64/ia32/fpu32.c            |   92 +++-
 arch/x86_64/ia32/ptrace32.c         |  719 ++++++++++++++++++++-----------
 arch/x86_64/kernel/ptrace.c         |  730 +++++++++++++++++++------------
 include/asm-i386/i387.h             |   13 
 include/asm-x86_64/fpu32.h          |    3 
 include/asm-x86_64/tracehook.h      |    8 
 include/linux/tracehook.h           |  244 ++++++++++
 kernel/ptrace.c                     |    8 
 14 files changed, 2124 insertions(+), 1968 deletions(-)

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.2 -r 1.3 linux-2.6-utrace-regset.patch
Index: linux-2.6-utrace-regset.patch
===================================================================
RCS file: linux-2.6-utrace-regset.patch
diff -N linux-2.6-utrace-regset.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-regset.patch	19 Jul 2007 17:46:36 -0000	1.3
@@ -0,0 +1,4713 @@
+[PATCH 2] utrace: register sets
+
+This provides a new uniform interface in <linux/tracehook.h> for accessing
+registers and similar per-thread machine resources.  The old architecture
+ptrace code for accessing register state is rolled into new functions to
+flesh out the utrace_regset interface.  Nothing yet uses this interface.
+The hope is that this interface can cover most of the machine-dependent
+issues for any higher-level tracing/debugging interface.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+
+---
+
+ arch/i386/kernel/i387.c             |  143 +++---
+ arch/i386/kernel/ptrace.c           |  822 ++++++++++++++++++++---------------
+ arch/x86_64/ia32/ptrace32.c         |  719 ++++++++++++++++++++-----------
+ arch/x86_64/ia32/fpu32.c            |   92 +++-
+ arch/x86_64/kernel/ptrace.c         |  730 +++++++++++++++++++------------
+ arch/powerpc/kernel/Makefile        |    4 
+ arch/powerpc/kernel/ptrace32.c      |  443 -------------------
+ arch/powerpc/kernel/ptrace.c        |  718 +++++++++++++++----------------
+ arch/powerpc/kernel/ptrace-common.h |  145 ------
+ kernel/ptrace.c                     |    8 
+ include/linux/tracehook.h           |  244 ++++++++++
+ include/asm-i386/i387.h             |   13 -
+ include/asm-x86_64/fpu32.h          |    3 
+ include/asm-x86_64/tracehook.h      |    8 
+ 14 files changed, 2124 insertions(+), 1968 deletions(-)
+ delete arch/powerpc/kernel/ptrace32.c
+ delete arch/powerpc/kernel/ptrace-common.h
+
+--- linux-2.6/arch/i386/kernel/i387.c
++++ linux-2.6/arch/i386/kernel/i387.c
+@@ -222,14 +222,10 @@ void set_fpu_twd( struct task_struct *ts
+  * FXSR floating point environment conversions.
+  */
+ 
+-static int convert_fxsr_to_user( struct _fpstate __user *buf,
+-					struct i387_fxsave_struct *fxsave )
++static inline void
++convert_fxsr_env_to_i387(unsigned long env[7],
++			 struct i387_fxsave_struct *fxsave)
+ {
+-	unsigned long env[7];
+-	struct _fpreg __user *to;
+-	struct _fpxreg *from;
+-	int i;
+-
+ 	env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul;
+ 	env[1] = (unsigned long)fxsave->swd | 0xffff0000ul;
+ 	env[2] = twd_fxsr_to_i387(fxsave);
+@@ -237,7 +233,17 @@ static int convert_fxsr_to_user( struct 
+ 	env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
+ 	env[5] = fxsave->foo;
+ 	env[6] = fxsave->fos;
++}
++
++static int convert_fxsr_to_user(struct _fpstate __user *buf,
++				struct i387_fxsave_struct *fxsave)
++{
++	unsigned long env[7];
++	struct _fpreg __user *to;
++	struct _fpxreg *from;
++	int i;
+ 
++	convert_fxsr_env_to_i387(env, fxsave);
+ 	if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
+ 		return 1;
+ 
+@@ -255,6 +261,20 @@ static int convert_fxsr_to_user( struct 
+ 	return 0;
+ }
+ 
++static inline void
++convert_fxsr_env_from_i387(struct i387_fxsave_struct *fxsave,
++			   const unsigned long env[7])
++{
++	fxsave->cwd = (unsigned short)(env[0] & 0xffff);
++	fxsave->swd = (unsigned short)(env[1] & 0xffff);
++	fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
++	fxsave->fip = env[3];
++	fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
++	fxsave->fcs = (env[4] & 0xffff);
++	fxsave->foo = env[5];
++	fxsave->fos = env[6];
++}
++
+ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
+ 					  struct _fpstate __user *buf )
+ {
+@@ -266,14 +286,7 @@ static int convert_fxsr_from_user( struc
+ 	if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
+ 		return 1;
+ 
+-	fxsave->cwd = (unsigned short)(env[0] & 0xffff);
+-	fxsave->swd = (unsigned short)(env[1] & 0xffff);
+-	fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
+-	fxsave->fip = env[3];
+-	fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
+-	fxsave->fcs = (env[4] & 0xffff);
+-	fxsave->foo = env[5];
+-	fxsave->fos = env[6];
++	convert_fxsr_env_from_i387(fxsave, env);
+ 
+ 	to = (struct _fpxreg *) &fxsave->st_space[0];
+ 	from = &buf->_st[0];
+@@ -388,88 +401,82 @@ int restore_i387( struct _fpstate __user
+  * ptrace request handlers.
+  */
+ 
+-static inline int get_fpregs_fsave( struct user_i387_struct __user *buf,
+-				    struct task_struct *tsk )
++static inline void get_fpregs_fsave(struct user_i387_struct *buf,
++				    struct task_struct *tsk)
+ {
+-	return __copy_to_user( buf, &tsk->thread.i387.fsave,
+-			       sizeof(struct user_i387_struct) );
++	memcpy(buf, &tsk->thread.i387.fsave, sizeof(struct user_i387_struct));
+ }
+ 
+-static inline int get_fpregs_fxsave( struct user_i387_struct __user *buf,
+-				     struct task_struct *tsk )
++static inline void get_fpregs_fxsave(struct user_i387_struct *buf,
++				     struct task_struct *tsk)
+ {
+-	return convert_fxsr_to_user( (struct _fpstate __user *)buf,
+-				     &tsk->thread.i387.fxsave );
++	struct _fpreg *to;
++	const struct _fpxreg *from;
++	unsigned int i;
++
++	convert_fxsr_env_to_i387((unsigned long *) buf,
++				 &tsk->thread.i387.fxsave);
++
++	to = (struct _fpreg *) buf->st_space;
++	from = (const struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0];
++	for (i = 0; i < 8; i++, to++, from++)
++		*to = *(const struct _fpreg *) from;
+ }
+ 
+-int get_fpregs( struct user_i387_struct __user *buf, struct task_struct *tsk )
++int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk)
+ {
+ 	if ( HAVE_HWFP ) {
+-		if ( cpu_has_fxsr ) {
+-			return get_fpregs_fxsave( buf, tsk );
+-		} else {
+-			return get_fpregs_fsave( buf, tsk );
+-		}
++		if (cpu_has_fxsr)
++			get_fpregs_fxsave(buf, tsk);
++		else
++			get_fpregs_fsave(buf, tsk);
++		return 0;
+ 	} else {
+ 		return save_i387_soft( &tsk->thread.i387.soft,
+ 				       (struct _fpstate __user *)buf );
+ 	}
+ }
+ 
+-static inline int set_fpregs_fsave( struct task_struct *tsk,
+-				    struct user_i387_struct __user *buf )
++static inline void set_fpregs_fsave(struct task_struct *tsk,
++				    const struct user_i387_struct *buf)
+ {
+-	return __copy_from_user( &tsk->thread.i387.fsave, buf,
+-				 sizeof(struct user_i387_struct) );
++	memcpy(&tsk->thread.i387.fsave, buf, sizeof(struct user_i387_struct));
+ }
+ 
+-static inline int set_fpregs_fxsave( struct task_struct *tsk,
+-				     struct user_i387_struct __user *buf )
++static inline void set_fpregs_fxsave(struct task_struct *tsk,
++				     const struct user_i387_struct *buf)
+ {
+-	return convert_fxsr_from_user( &tsk->thread.i387.fxsave,
+-				       (struct _fpstate __user *)buf );
++	struct _fpxreg *to;
++	const struct _fpreg *from;
++	unsigned int i;
++
++	convert_fxsr_env_from_i387(&tsk->thread.i387.fxsave,
++				   (unsigned long *) buf);
++
++	to = (struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0];
++	from = (const struct _fpreg *) buf->st_space;
++	for (i = 0; i < 8; i++, to++, from++)
++		*(struct _fpreg *) to = *from;
+ }
+ 
+-int set_fpregs( struct task_struct *tsk, struct user_i387_struct __user *buf )
++int set_fpregs(struct task_struct *tsk, const struct user_i387_struct *buf)
+ {
[...4320 lines suppressed...]
++ * @e_machine:	ELF %EM_* value for which this is the native view, if any.
++ *
++ * A regset view is a collection of regsets (&struct utrace_regset,
++ * above).  This describes all the state of a thread that can be seen
++ * from a given architecture/ABI environment.  More than one view might
++ * refer to the same &struct utrace_regset, or more than one regset
++ * might refer to the same machine-specific state in the thread.  For
++ * example, a 32-bit thread's state could be examined from the 32-bit
++ * view or from the 64-bit view.  Either method reaches the same thread
++ * register state, doing appropriate widening or truncation.
++ */
++struct utrace_regset_view {
++	const char *name;
++	const struct utrace_regset *regsets;
++	unsigned int n;
++	u16 e_machine;
++};
++
++/*
++ * This is documented here rather than at the definition sites because its
++ * implementation is machine-dependent but its interface is universal.
++ */
++/**
++ * utrace_native_view - Return the process's native regset view.
++ * @tsk: a thread of the process in question
++ *
++ * Return the &struct utrace_regset_view that is native for the given process.
++ * For example, what it would access when it called ptrace().
++ * Throughout the life of the process, this only changes at exec.
++ */
++const struct utrace_regset_view *utrace_native_view(struct task_struct *tsk);
++
++
++/*
++ * These are helpers for writing regset get/set functions in arch code.
++ * Because @start_pos and @end_pos are always compile-time constants,
++ * these are inlined into very little code though they look large.
++ *
++ * Use one or more calls sequentially for each chunk of regset data stored
++ * contiguously in memory.  Call with constants for @start_pos and @end_pos,
++ * giving the range of byte positions in the regset that data corresponds
++ * to; @end_pos can be -1 if this chunk is at the end of the regset layout.
++ * Each call updates the arguments to point past its chunk.
++ */
++
++static inline int
++utrace_regset_copyout(unsigned int *pos, unsigned int *count,
++		      void **kbuf, void __user **ubuf,
++		      const void *data, int start_pos, int end_pos)
++{
++	if (*count == 0)
++		return 0;
++	BUG_ON(*pos < start_pos);
++	if (end_pos < 0 || *pos < end_pos) {
++		unsigned int copy = (end_pos < 0 ? *count
++				     : min(*count, end_pos - *pos));
++		data += *pos - start_pos;
++		if (*kbuf) {
++			memcpy(*kbuf, data, copy);
++			*kbuf += copy;
++		}
++		else if (copy_to_user(*ubuf, data, copy))
++			return -EFAULT;
++		else
++			*ubuf += copy;
++		*pos += copy;
++		*count -= copy;
++	}
++	return 0;
++}
++
++static inline int
++utrace_regset_copyin(unsigned int *pos, unsigned int *count,
++		     const void **kbuf, const void __user **ubuf,
++		     void *data, int start_pos, int end_pos)
++{
++	if (*count == 0)
++		return 0;
++	BUG_ON(*pos < start_pos);
++	if (end_pos < 0 || *pos < end_pos) {
++		unsigned int copy = (end_pos < 0 ? *count
++				     : min(*count, end_pos - *pos));
++		data += *pos - start_pos;
++		if (*kbuf) {
++			memcpy(data, *kbuf, copy);
++			*kbuf += copy;
++		}
++		else if (copy_from_user(data, *ubuf, copy))
++			return -EFAULT;
++		else
++			*ubuf += copy;
++		*pos += copy;
++		*count -= copy;
++	}
++	return 0;
++}
++
++/*
++ * These two parallel the two above, but for portions of a regset layout
++ * that always read as all-zero or for which writes are ignored.
++ */
++static inline int
++utrace_regset_copyout_zero(unsigned int *pos, unsigned int *count,
++			   void **kbuf, void __user **ubuf,
++			   int start_pos, int end_pos)
++{
++	if (*count == 0)
++		return 0;
++	BUG_ON(*pos < start_pos);
++	if (end_pos < 0 || *pos < end_pos) {
++		unsigned int copy = (end_pos < 0 ? *count
++				     : min(*count, end_pos - *pos));
++		if (*kbuf) {
++			memset(*kbuf, 0, copy);
++			*kbuf += copy;
++		}
++		else if (clear_user(*ubuf, copy))
++			return -EFAULT;
++		else
++			*ubuf += copy;
++		*pos += copy;
++		*count -= copy;
++	}
++	return 0;
++}
++
++static inline int
++utrace_regset_copyin_ignore(unsigned int *pos, unsigned int *count,
++			    const void **kbuf, const void __user **ubuf,
++			    int start_pos, int end_pos)
++{
++	if (*count == 0)
++		return 0;
++	BUG_ON(*pos < start_pos);
++	if (end_pos < 0 || *pos < end_pos) {
++		unsigned int copy = (end_pos < 0 ? *count
++				     : min(*count, end_pos - *pos));
++		if (*kbuf)
++			*kbuf += copy;
++		else
++			*ubuf += copy;
++		*pos += copy;
++		*count -= copy;
++	}
++	return 0;
++}
++
++
+ /*
+  * Following are entry points from core code, where the user debugging
+  * support can affect the normal behavior.  The locking situation is
+--- linux-2.6/include/asm-i386/i387.h
++++ linux-2.6/include/asm-i386/i387.h
+@@ -130,17 +130,12 @@ extern int save_i387( struct _fpstate __
+ extern int restore_i387( struct _fpstate __user *buf );
+ 
+ /*
+- * ptrace request handers...
++ * ptrace request handlers...
+  */
+-extern int get_fpregs( struct user_i387_struct __user *buf,
+-		       struct task_struct *tsk );
+-extern int set_fpregs( struct task_struct *tsk,
+-		       struct user_i387_struct __user *buf );
++extern int get_fpregs(struct user_i387_struct *, struct task_struct *);
++extern int set_fpregs(struct task_struct *, const struct user_i387_struct *);
++extern void updated_fpxregs(struct task_struct *tsk);
+ 
+-extern int get_fpxregs( struct user_fxsr_struct __user *buf,
+-			struct task_struct *tsk );
+-extern int set_fpxregs( struct task_struct *tsk,
+-			struct user_fxsr_struct __user *buf );
+ 
+ /*
+  * FPU state for core dumps...
+--- linux-2.6/include/asm-x86_64/fpu32.h
++++ linux-2.6/include/asm-x86_64/fpu32.h
+@@ -7,4 +7,7 @@ int restore_i387_ia32(struct task_struct
+ int save_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, 
+ 		   struct pt_regs *regs, int fsave);
+ 
++int get_fpregs32(struct user_i387_ia32_struct *, struct task_struct *);
++int set_fpregs32(struct task_struct *, const struct user_i387_ia32_struct *);
++
+ #endif
+--- linux-2.6/include/asm-x86_64/tracehook.h
++++ linux-2.6/include/asm-x86_64/tracehook.h
+@@ -48,4 +48,12 @@ static inline void tracehook_abort_sysca
+ 	regs->orig_rax = -1L;
+ }
+ 
++/*
++ * These are used directly by some of the regset code.
++ */
++extern const struct utrace_regset_view utrace_x86_64_native;
++#ifdef CONFIG_IA32_EMULATION
++extern const struct utrace_regset_view utrace_ia32_view;
++#endif
++
+ #endif

linux-2.6-utrace-tracehook-avr32.patch:
 arch/avr32/kernel/entry-avr32b.S |   10 +++
 arch/avr32/kernel/process.c      |    2 
 arch/avr32/kernel/ptrace.c       |  102 +++++++++------------------------------
 include/asm-avr32/tracehook.h    |   62 +++++++++++++++++++++++
 4 files changed, 96 insertions(+), 80 deletions(-)

--- NEW FILE linux-2.6-utrace-tracehook-avr32.patch ---
[PATCH 1e] utrace: tracehook for AVR32

From: Haavard Skinnemoen <hskinnemoen at atmel.com>

This patch does the initial tracehook conversion for AVR32.

Signed-off-by: Haavard Skinnemoen <hskinnemoen at atmel.com>
Signed-off-by: Roland McGrath <roland at redhat.com>

---

 arch/avr32/kernel/ptrace.c       |  102 ++++++++++----------------------------
 arch/avr32/kernel/process.c      |    2 -
 arch/avr32/kernel/entry-avr32b.S |   10 +++-
 include/asm-avr32/tracehook.h    |   62 +++++++++++++++++++++++
 4 files changed, 96 insertions(+), 80 deletions(-)
 create include/asm-avr32/tracehook.h

--- linux-2.6/arch/avr32/kernel/ptrace.c
+++ linux-2.6/arch/avr32/kernel/ptrace.c
@@ -5,20 +5,16 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#undef DEBUG
+#include <linux/compile.h>
+#include <linux/elf.h>
+#include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/user.h>
-#include <linux/security.h>
-#include <linux/unistd.h>
-#include <linux/notifier.h>
-
-#include <asm/traps.h>
-#include <asm/uaccess.h>
-#include <asm/ocd.h>
+
 #include <asm/mmu_context.h>
 #include <linux/kdebug.h>
 
@@ -28,52 +24,7 @@ static struct pt_regs *get_user_regs(str
 				  THREAD_SIZE - sizeof(struct pt_regs));
 }
 
-static void ptrace_single_step(struct task_struct *tsk)
-{
-	pr_debug("ptrace_single_step: pid=%u, SR=0x%08lx\n",
-		 tsk->pid, tsk->thread.cpu_context.sr);
-	if (!(tsk->thread.cpu_context.sr & SR_D)) {
-		/*
-		 * Set a breakpoint at the current pc to force the
-		 * process into debug mode.  The syscall/exception
-		 * exit code will set a breakpoint at the return
-		 * address when this flag is set.
-		 */
-		pr_debug("ptrace_single_step: Setting TIF_BREAKPOINT\n");
-		set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
-	}
-
-	/* The monitor code will do the actual step for us */
-	set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
-}
-
-/*
- * Called by kernel/ptrace.c when detaching
- *
- * Make sure any single step bits, etc. are not set
- */
-void ptrace_disable(struct task_struct *child)
-{
-	clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
-}
-
-/*
- * Handle hitting a breakpoint
- */
-static void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
-{
-	siginfo_t info;
-
-	info.si_signo = SIGTRAP;
-	info.si_errno = 0;
-	info.si_code  = TRAP_BRKPT;
-	info.si_addr  = (void __user *)instruction_pointer(regs);
-
-	pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n",
-		 tsk->pid, info.si_addr);
-	force_sig_info(SIGTRAP, &info, tsk);
-}
-
+#if 0
 /*
  * Read the word at offset "offset" into the task's "struct user". We
  * actually access the pt_regs struct stored on the kernel stack.
@@ -257,32 +208,31 @@ long arch_ptrace(struct task_struct *chi
 	pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC));
 	return ret;
 }
+#endif
 
-asmlinkage void syscall_trace(void)
+asmlinkage void syscall_trace(struct pt_regs *regs, int is_exit)
 {
-	pr_debug("syscall_trace called\n");
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return;
-	if (!(current->ptrace & PT_PTRACED))
-		return;
 
-	pr_debug("syscall_trace: notifying parent\n");
-	/* 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)
-				 ? 0x80 : 0));
+	tracehook_report_syscall(regs, is_exit);
+}
 
-	/*
-	 * 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) {
-		pr_debug("syscall_trace: sending signal %d to PID %u\n",
-			 current->exit_code, current->pid);
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
+/*
+ * Handle hitting a breakpoint
+ */
+static void do_breakpoint(struct task_struct *tsk, struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code  = TRAP_BRKPT;
+	info.si_addr  = (void __user *)instruction_pointer(regs);
+
+	pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n",
+		 tsk->pid, info.si_addr);
+	force_sig_info(SIGTRAP, &info, tsk);
 }
 
 asmlinkage void do_debug_priv(struct pt_regs *regs)
@@ -361,10 +311,10 @@ asmlinkage void do_debug(struct pt_regs 
 			__mtdr(DBGREG_DC, dc);
 
 			clear_thread_flag(TIF_SINGLE_STEP);
-			ptrace_break(current, regs);
+			do_breakpoint(current, regs);
 		}
 	} else {
 		/* regular breakpoint */
-		ptrace_break(current, regs);
+		do_breakpoint(current, regs);
 	}
 }
--- linux-2.6/arch/avr32/kernel/process.c
+++ linux-2.6/arch/avr32/kernel/process.c
@@ -382,8 +382,6 @@ asmlinkage int sys_execve(char __user *u
 		goto out;
 
 	error = do_execve(filename, uargv, uenvp, regs);
-	if (error == 0)
-		current->ptrace &= ~PT_DTRACE;
 	putname(filename);
 
 out:
--- linux-2.6/arch/avr32/kernel/entry-avr32b.S
+++ linux-2.6/arch/avr32/kernel/entry-avr32b.S
@@ -223,15 +223,21 @@ ret_from_fork:
 	rjmp    syscall_exit_cont
 
 syscall_trace_enter:
-	pushm	r8-r12
+	mov	r12, sp		/* regs		*/
+	mov	r11, 0		/* is_exit	*/
 	rcall	syscall_trace
-	popm	r8-r12
+
+	/* syscall_trace may update r8, so reload r8-r12 from regs. */
+	sub	lr, sp, -REG_R12
+	ldm	lr, r8-r12
 	rjmp	syscall_trace_cont
 
 syscall_exit_work:
 	bld	r1, TIF_SYSCALL_TRACE
 	brcc	1f
 	unmask_interrupts
+	mov	r12, sp
+	mov	r11, 1
 	rcall	syscall_trace
 	mask_interrupts
 	ld.w	r1, r0[TI_flags]
--- linux-2.6/include/asm-avr32/tracehook.h
+++ linux-2.6/include/asm-avr32/tracehook.h
@@ -0,0 +1,62 @@
+/*
+ * Tracing hooks for AVR32
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_AVR32_TRACEHOOK_H
+#define _ASM_AVR32_TRACEHOOK_H
+
+#include <linux/sched.h>
+
+#define ARCH_HAS_SINGLE_STEP	1
+
+static inline void tracehook_enable_single_step(struct task_struct *tsk)
+{
+	/*
+	 * If the process is stopped in debug mode, simply set
+	 * TIF_SINGLE_STEP to tell the monitor code to set the single
+	 * step bit in DC before returning.
+	 *
+	 * Otherwise, we need to set a breakpoint at the return
+	 * address before returning to userspace. TIF_BREAKPOINT will
+	 * tell the syscall/exception exit code to do this.
+	 */
+	if (!(tsk->thread.cpu_context.sr & SR_D))
+		set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
+
+	set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
+}
+
+static inline void tracehook_disable_single_step(struct task_struct *tsk)
+{
+	clear_tsk_thread_flag(tsk, TIF_BREAKPOINT);
+	clear_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
+}
+
+static inline int tracehook_single_step_enabled(struct task_struct *tsk)
+{
+	return test_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
+}
+
+static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
+{
+	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
+{
+	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline void tracehook_abort_syscall(struct pt_regs *regs)
+{
+	/* Invalid system call number => return -ENOSYS */
+	regs->r8 = -1;
+}
+
+
+#endif /* _ASM_AVR32_TRACEHOOK_H */

linux-2.6-utrace-tracehook-ia64.patch:
 arch/ia64/ia32/ia32_entry.S  |    2 -
 arch/ia64/ia32/sys_ia32.c    |   23 ++-----------
 arch/ia64/kernel/ptrace.c    |   39 +++++-----------------
 arch/ia64/kernel/signal.c    |    4 +-
 include/asm-ia64/tracehook.h |   73 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 91 insertions(+), 50 deletions(-)

--- NEW FILE linux-2.6-utrace-tracehook-ia64.patch ---
[PATCH 1a] utrace: tracehook for ia64

This patch does the initial tracehook conversion for ia64.

Signed-off-by: Roland McGrath <roland at redhat.com>
Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy at intel.com>
Signed-off-by: Bibo mao <bibo.mao at intel.com>

---

 arch/ia64/ia32/ia32_entry.S  |    2 +
 arch/ia64/ia32/sys_ia32.c    |   23 ++-----------
 arch/ia64/kernel/ptrace.c    |   39 ++++++----------------
 arch/ia64/kernel/signal.c    |    4 ++
 include/asm-ia64/tracehook.h |   73 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 91 insertions(+), 50 deletions(-)
 create include/asm-ia64/tracehook.h

--- linux-2.6/arch/ia64/ia32/ia32_entry.S
+++ linux-2.6/arch/ia64/ia32/ia32_entry.S
@@ -199,7 +199,7 @@ ia32_syscall_table:
 	data8 sys_setuid	/* 16-bit version */
 	data8 sys_getuid	/* 16-bit version */
 	data8 compat_sys_stime    /* 25 */
-	data8 sys32_ptrace
+	data8 compat_sys_ptrace
 	data8 sys32_alarm
 	data8 sys_ni_syscall
 	data8 sys32_pause
--- linux-2.6/arch/ia64/ia32/sys_ia32.c
+++ linux-2.6/arch/ia64/ia32/sys_ia32.c
@@ -1436,25 +1436,6 @@ sys32_waitpid (int pid, unsigned int *st
 	return compat_sys_wait4(pid, stat_addr, options, NULL);
 }
 
-static unsigned int
-ia32_peek (struct task_struct *child, unsigned long addr, unsigned int *val)
-{
-	size_t copied;
-	unsigned int ret;
-
-	copied = access_process_vm(child, addr, val, sizeof(*val), 0);
-	return (copied != sizeof(ret)) ? -EIO : 0;
-}
-
-static unsigned int
-ia32_poke (struct task_struct *child, unsigned long addr, unsigned int val)
-{
-
-	if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val))
-		return -EIO;
-	return 0;
-}
-
 /*
  *  The order in which registers are stored in the ptrace regs structure
  */
@@ -1752,6 +1733,7 @@ restore_ia32_fpxstate (struct task_struc
 	return 0;
 }
 
+#if 0				/* XXX */
 asmlinkage long
 sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data)
 {
@@ -1859,9 +1841,11 @@ sys32_ptrace (int request, pid_t pid, un
 					    compat_ptr(data));
 		break;
 
+#if 0				/* XXX */
 	      case PTRACE_GETEVENTMSG:   
 		ret = put_user(child->ptrace_message, (unsigned int __user *) compat_ptr(data));
 		break;
+#endif
 
 	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
 	      case PTRACE_CONT:		/* restart after signal. */
@@ -1882,6 +1866,7 @@ sys32_ptrace (int request, pid_t pid, un
 	unlock_kernel();
 	return ret;
 }
+#endif
 
 typedef struct {
 	unsigned int	ss_sp;
--- linux-2.6/arch/ia64/kernel/ptrace.c
+++ linux-2.6/arch/ia64/kernel/ptrace.c
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
@@ -1598,28 +1599,6 @@ sys_ptrace (long request, pid_t pid, uns
 	return ret;
 }
 
-
-static void
-syscall_trace (void)
-{
-	/*
-	 * 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) ? 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;
-	}
-}
-
 /* "asmlinkage" so the input arguments are preserved... */
 
 asmlinkage void
@@ -1627,9 +1606,8 @@ syscall_trace_enter (long arg0, long arg
 		     long arg4, long arg5, long arg6, long arg7,
 		     struct pt_regs regs)
 {
-	if (test_thread_flag(TIF_SYSCALL_TRACE) 
-	    && (current->ptrace & PT_PTRACED))
-		syscall_trace();
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall(&regs, 0);
 
 	if (unlikely(current->audit_context)) {
 		long syscall;
@@ -1664,8 +1642,11 @@ syscall_trace_leave (long arg0, long arg
 		audit_syscall_exit(success, result);
 	}
 
-	if ((test_thread_flag(TIF_SYSCALL_TRACE)
-	    || test_thread_flag(TIF_SINGLESTEP))
-	    && (current->ptrace & PT_PTRACED))
-		syscall_trace();
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall(&regs, 1);
+
+	if (test_thread_flag(TIF_SINGLESTEP)) {
+		force_sig(SIGTRAP, current); /* XXX */
+		tracehook_report_syscall_step(&regs);
+	}
 }
--- linux-2.6/arch/ia64/kernel/signal.c
+++ linux-2.6/arch/ia64/kernel/signal.c
@@ -10,7 +10,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
@@ -429,6 +429,8 @@ handle_signal (unsigned long sig, struct
 		sigaddset(&current->blocked, sig);
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
+
+	tracehook_report_handle_signal(sig, ka, oldset, &scr->pt);
 	return 1;
 }
 
--- linux-2.6/include/asm-ia64/tracehook.h
+++ linux-2.6/include/asm-ia64/tracehook.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C)2006 Intel Co
+ *	Anil S Keshavamurthy <anil.s.keshavamurthy at intel.com>
+ *	and Bibo Mao <bibo.mao at intel.com> adapted from i386.
+ *
+ * 	Tracing hooks, ia64 CPU support
+ */
+
+#ifndef _ASM_TRACEHOOK_H
+#define _ASM_TRACEHOOK_H	1
+
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+/*
+ * See linux/tracehook.h for the descriptions of what these need to do.
+ */
+
+#define ARCH_HAS_SINGLE_STEP	(1)
+#define ARCH_HAS_BLOCK_STEP	(1)
+
+static inline void tracehook_enable_single_step(struct task_struct *tsk)
+{
+	struct pt_regs *pt = task_pt_regs(tsk);
+	ia64_psr(pt)->ss = 1;
+	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+}
+
+static inline void tracehook_disable_single_step(struct task_struct *tsk)
+{
+	struct pt_regs *pt = task_pt_regs(tsk);
+	ia64_psr(pt)->ss = 0;
+	if (ia64_psr(pt)->tb == 0)
+		clear_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+}
+
+static inline void tracehook_enable_block_step(struct task_struct *tsk)
+{
+	struct pt_regs *pt = task_pt_regs(tsk);
+	ia64_psr(pt)->tb = 1;
+	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+}
+
+static inline void tracehook_disable_block_step(struct task_struct *tsk)
+{
+	struct pt_regs *pt = task_pt_regs(tsk);
+	ia64_psr(pt)->tb = 0;
+	if (ia64_psr(pt)->ss == 0)
+		clear_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+}
+
+static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
+{
+	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
+{
+	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline int tracehook_single_step_enabled(struct task_struct *tsk)
+{
+	struct pt_regs *pt = task_pt_regs(tsk);
+	return ia64_psr(pt)->ss;
+}
+
+static inline void tracehook_abort_syscall(struct pt_regs *regs)
+{
+	regs->r15 = -1L;
+}
+
+#endif

linux-2.6-utrace-tracehook-s390.patch:
 arch/s390/kernel/compat_signal.c |    5 ++-
 arch/s390/kernel/ptrace.c        |   62 +++++++++++++++++++++------------------
 arch/s390/kernel/signal.c        |    3 +
 arch/s390/kernel/traps.c         |    6 +--
 include/asm-s390/tracehook.h     |   46 ++++++++++++++++++++++++++++
 5 files changed, 90 insertions(+), 32 deletions(-)

--- NEW FILE linux-2.6-utrace-tracehook-s390.patch ---
[PATCH 1c] utrace: tracehook for s390

This patch does the initial tracehook conversion for s390.

Signed-off-by: Roland McGrath <roland at redhat.com>
Signed-off-by: David Wilder <dwilder at us.ibm.com>

---

 arch/s390/kernel/traps.c         |    6 ++--
 arch/s390/kernel/compat_signal.c |    5 ++-
 arch/s390/kernel/ptrace.c        |   62 +++++++++++++++++++++-----------------
 arch/s390/kernel/signal.c        |    3 ++
 include/asm-s390/tracehook.h     |   46 ++++++++++++++++++++++++++++
 5 files changed, 90 insertions(+), 32 deletions(-)
 create include/asm-s390/tracehook.h

--- linux-2.6/arch/s390/kernel/traps.c
+++ linux-2.6/arch/s390/kernel/traps.c
@@ -18,7 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -338,7 +338,7 @@ void __kprobes do_single_step(struct pt_
 					SIGTRAP) == NOTIFY_STOP){
 		return;
 	}
-	if ((current->ptrace & PT_PTRACED) != 0)
+	if (tracehook_consider_fatal_signal(current, SIGTRAP))
 		force_sig(SIGTRAP, current);
 }
 
@@ -439,7 +439,7 @@ static void illegal_op(struct pt_regs * 
 		if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
 			return;
 		if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
-			if (current->ptrace & PT_PTRACED)
+			if (tracehook_consider_fatal_signal(current, SIGTRAP))
 				force_sig(SIGTRAP, current);
 			else
 				signal = SIGILL;
--- linux-2.6/arch/s390/kernel/compat_signal.c
+++ linux-2.6/arch/s390/kernel/compat_signal.c
@@ -27,6 +27,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
+#include <linux/tracehook.h>
 #include "compat_linux.h"
 #include "compat_ptrace.h"
 
@@ -580,7 +581,9 @@ handle_signal32(unsigned long sig, struc
 			sigaddset(&current->blocked,sig);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
+
+		tracehook_report_handle_signal(sig, ka, oldset, regs);
 	}
+
 	return ret;
 }
-
--- linux-2.6/arch/s390/kernel/ptrace.c
+++ linux-2.6/arch/s390/kernel/ptrace.c
@@ -29,6 +29,7 @@
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/audit.h>
@@ -84,18 +85,35 @@ FixPerRegisters(struct task_struct *task
 		per_info->control_regs.bits.storage_alt_space_ctl = 1;
 	else
 		per_info->control_regs.bits.storage_alt_space_ctl = 0;
+
+	if (task == current)
+		/*
+		 * These registers are loaded in __switch_to on
+		 * context switch.  We must load them now if
+		 * touching the current thread.
+		 */
+		__ctl_load(per_info->control_regs.words.cr, 9, 11);
 }
 
-static void set_single_step(struct task_struct *task)
+void
+tracehook_enable_single_step(struct task_struct *task)
 {
 	task->thread.per_info.single_step = 1;
 	FixPerRegisters(task);
 }
 
-static void clear_single_step(struct task_struct *task)
+void
+tracehook_disable_single_step(struct task_struct *task)
 {
 	task->thread.per_info.single_step = 0;
 	FixPerRegisters(task);
+	clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
+}
+
+int
+tracehook_single_step_enabled(struct task_struct *task)
+{
+	return task->thread.per_info.single_step;
 }
 
 /*
@@ -107,7 +125,7 @@ void
 ptrace_disable(struct task_struct *child)
 {
 	/* make sure the single step bit is not set. */
-	clear_single_step(child);
+	tracehook_disable_single_step(child);
 }
 
 #ifndef CONFIG_64BIT
@@ -593,6 +611,7 @@ do_ptrace_emu31(struct task_struct *chil
 			copied += sizeof(unsigned int);
 		}
 		return 0;
+#if 0				/* XXX */
 	case PTRACE_GETEVENTMSG:
 		return put_user((__u32) child->ptrace_message,
 				(unsigned int __force __user *) data);
@@ -658,7 +677,7 @@ do_ptrace(struct task_struct *child, lon
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
 		/* make sure the single step bit is not set. */
-		clear_single_step(child);
+		tracehook_disable_single_step(child);
 		wake_up_process(child);
 		return 0;
 
@@ -672,7 +691,7 @@ do_ptrace(struct task_struct *child, lon
 			return 0;
 		child->exit_code = SIGKILL;
 		/* make sure the single step bit is not set. */
-		clear_single_step(child);
+		tracehook_disable_single_step(child);
 		wake_up_process(child);
 		return 0;
 
@@ -685,7 +704,7 @@ do_ptrace(struct task_struct *child, lon
 		if (data)
 			set_tsk_thread_flag(child, TIF_SINGLE_STEP);
 		else
-			set_single_step(child);
+			tracehook_enable_single_step(child);
 		/* give it a chance to run. */
 		wake_up_process(child);
 		return 0;
@@ -738,30 +757,17 @@ syscall_trace(struct pt_regs *regs, int 
 	if (unlikely(current->audit_context) && entryexit)
 		audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
 
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		goto out;
-	if (!(current->ptrace & PT_PTRACED))
-		goto out;
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				 ? 0x80 : 0));
-
-	/*
-	 * If the debuffer has set an invalid system call number,
-	 * we prepare to skip the system call restart handling.
-	 */
-	if (!entryexit && regs->gprs[2] >= NR_syscalls)
-		regs->trap = -1;
+	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
+		tracehook_report_syscall(regs, entryexit);
 
-	/*
-	 * 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;
+		/*
+		 * If the debugger has set an invalid system call number,
+		 * we prepare to skip the system call restart handling.
+		 */
+		if (!entryexit && regs->gprs[2] >= NR_syscalls)
+			regs->trap = -1;
 	}
- out:
+
 	if (unlikely(current->audit_context) && !entryexit)
 		audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
 				    regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
--- linux-2.6/arch/s390/kernel/signal.c
+++ linux-2.6/arch/s390/kernel/signal.c
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
+#include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
@@ -396,6 +397,8 @@ handle_signal(unsigned long sig, struct 
 			sigaddset(&current->blocked,sig);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
+
+		tracehook_report_handle_signal(sig, ka, oldset, regs);
 	}
 
 	return ret;
--- linux-2.6/include/asm-s390/tracehook.h
+++ linux-2.6/include/asm-s390/tracehook.h
@@ -0,0 +1,46 @@
+/*
+ * Tracing hooks, s390/s390x support.
+ *
+ * Copyright (C) 2006, 2007 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.
+ *
+ * Red Hat Author: Roland McGrath.
+ */
+
+#ifndef _ASM_TRACEHOOK_H
+#define _ASM_TRACEHOOK_H	1
+
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+/*
+ * See linux/tracehook.h for the descriptions of what these need to do.
+ */
+
+#define ARCH_HAS_SINGLE_STEP	(1)
+
+/* These three are defined in arch/s390/kernel/ptrace.c.  */
+void tracehook_enable_single_step(struct task_struct *tsk);
+void tracehook_disable_single_step(struct task_struct *tsk);
+int tracehook_single_step_enabled(struct task_struct *tsk);
+
+
+static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
+{
+	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
+{
+	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline void tracehook_abort_syscall(struct pt_regs *regs)
+{
+	regs->gprs[2] = -1L;
+}
+
+#endif

linux-2.6-utrace-tracehook-sparc64.patch:
 arch/sparc64/kernel/entry.S     |    6 ------
 arch/sparc64/kernel/ptrace.c    |   29 +++++++++--------------------
 arch/sparc64/kernel/signal.c    |    2 ++
 arch/sparc64/kernel/signal32.c  |    2 ++
 include/asm-sparc64/tracehook.h |   40 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 53 insertions(+), 26 deletions(-)

Index: linux-2.6-utrace-tracehook-sparc64.patch
===================================================================
RCS file: linux-2.6-utrace-tracehook-sparc64.patch
diff -N linux-2.6-utrace-tracehook-sparc64.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-tracehook-sparc64.patch	19 Jul 2007 17:46:36 -0000	1.3
@@ -0,0 +1,196 @@
+[PATCH 1b] utrace: tracehook for sparc64
+
+This patch does the initial tracehook conversion for sparc64.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+
+---
+
+ arch/sparc64/kernel/ptrace.c    |   29 +++++++++-------------------
+ arch/sparc64/kernel/signal.c    |    2 ++
+ arch/sparc64/kernel/signal32.c  |    2 ++
+ arch/sparc64/kernel/entry.S     |    6 ------
+ include/asm-sparc64/tracehook.h |   40 +++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 53 insertions(+), 26 deletions(-)
+ create include/asm-sparc64/tracehook.h
+
+--- linux-2.6/arch/sparc64/kernel/ptrace.c
++++ linux-2.6/arch/sparc64/kernel/ptrace.c
+@@ -22,6 +22,7 @@
+ #include <linux/seccomp.h>
+ #include <linux/audit.h>
+ #include <linux/signal.h>
++#include <linux/tracehook.h>
+ 
+ #include <asm/asi.h>
+ #include <asm/pgtable.h>
+@@ -33,6 +34,7 @@
+ #include <asm/page.h>
+ #include <asm/cpudata.h>
+ 
++#if 0				/* XXX */
+ /* Returning from ptrace is a bit tricky because the syscall return
+  * low level code assumes any value returned which is negative and
+  * is a valid errno will mean setting the condition codes to indicate
+@@ -82,6 +84,7 @@ pt_os_succ_return (struct pt_regs *regs,
+ 	else
+ 		pt_succ_return_linux (regs, val, addr);
+ }
++#endif
+ 
+ /* #define ALLOW_INIT_TRACING */
+ /* #define DEBUG_PTRACE */
+@@ -167,6 +170,7 @@ void flush_ptrace_access(struct vm_area_
+ 	}
+ }
+ 
++#if 0				/* XXX */
+ asmlinkage void do_ptrace(struct pt_regs *regs)
+ {
+ 	int request = regs->u_regs[UREG_I0];
+@@ -643,11 +647,13 @@ out_tsk:
+ out:
+ 	unlock_kernel();
+ }
++#endif
+ 
+ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+ {
+ 	/* do the secure computing check first */
+-	secure_computing(regs->u_regs[UREG_G1]);
++	if (!syscall_exit_p)
++		secure_computing(regs->u_regs[UREG_G1]);
+ 
+ 	if (unlikely(current->audit_context) && syscall_exit_p) {
+ 		unsigned long tstate = regs->tstate;
+@@ -659,26 +665,9 @@ asmlinkage void syscall_trace(struct pt_
+ 		audit_syscall_exit(result, regs->u_regs[UREG_I0]);
+ 	}
+ 
+-	if (!(current->ptrace & PT_PTRACED))
+-		goto out;
+-
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+-		goto out;
+-
+-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+-				 ? 0x80 : 0));
++	if (test_thread_flag(TIF_SYSCALL_TRACE))
++		tracehook_report_syscall(regs, syscall_exit_p);
+ 
+-	/*
+-	 * 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;
+-	}
+-
+-out:
+ 	if (unlikely(current->audit_context) && !syscall_exit_p)
+ 		audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
+ 				     AUDIT_ARCH_SPARC :
+--- linux-2.6/arch/sparc64/kernel/signal.c
++++ linux-2.6/arch/sparc64/kernel/signal.c
+@@ -22,6 +22,7 @@
+ #include <linux/tty.h>
+ #include <linux/binfmts.h>
+ #include <linux/bitops.h>
++#include <linux/tracehook.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ptrace.h>
+@@ -490,6 +491,7 @@ static inline void handle_signal(unsigne
+ 		sigaddset(&current->blocked,signr);
+ 	recalc_sigpending();
+ 	spin_unlock_irq(&current->sighand->siglock);
++	tracehook_report_handle_signal(signr, ka, oldset, regs);
+ }
+ 
+ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
+--- linux-2.6/arch/sparc64/kernel/signal32.c
++++ linux-2.6/arch/sparc64/kernel/signal32.c
+@@ -20,6 +20,7 @@
+ #include <linux/binfmts.h>
+ #include <linux/compat.h>
+ #include <linux/bitops.h>
++#include <linux/tracehook.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ptrace.h>
+@@ -1236,6 +1237,7 @@ static inline void handle_signal32(unsig
+ 		sigaddset(&current->blocked,signr);
+ 	recalc_sigpending();
+ 	spin_unlock_irq(&current->sighand->siglock);
++	tracehook_report_handle_signal(signr, ka, oldset, regs);
+ }
+ 
+ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
+--- linux-2.6/arch/sparc64/kernel/entry.S
++++ linux-2.6/arch/sparc64/kernel/entry.S
+@@ -1434,7 +1434,6 @@ execve_merge:
+ 
+ 	.globl	sys_pipe, sys_sigpause, sys_nis_syscall
+ 	.globl	sys_rt_sigreturn
+-	.globl	sys_ptrace
+ 	.globl	sys_sigaltstack
+ 	.align	32
+ sys_pipe:	ba,pt		%xcc, sparc_pipe
+@@ -1477,11 +1476,6 @@ sys32_rt_sigreturn:
+ 		 add		%o7, 1f-.-4, %o7
+ 		nop
+ #endif
+-sys_ptrace:	add		%sp, PTREGS_OFF, %o0
+-		call		do_ptrace
+-		 add		%o7, 1f-.-4, %o7
+-		nop
+-		.align		32
+ 1:		ldx		[%curptr + TI_FLAGS], %l5
+ 		andcc		%l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
+ 		be,pt		%icc, rtrap
+--- linux-2.6/include/asm-sparc64/tracehook.h
++++ linux-2.6/include/asm-sparc64/tracehook.h
+@@ -0,0 +1,40 @@
++/*
++ * Tracing hooks, SPARC64 CPU support
++ *
++ * Copyright (C) 2006, 2007 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.
++ *
++ * Red Hat Author: Roland McGrath.
++ */
++
++#ifndef _ASM_TRACEHOOK_H
++#define _ASM_TRACEHOOK_H	1
++
++
++#include <linux/sched.h>
++#include <asm/ptrace.h>
++
++/*
++ * See linux/tracehook.h for the descriptions of what these need to do.
++ */
++
++
++static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
++{
++	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
++{
++	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++static inline void tracehook_abort_syscall(struct pt_regs *regs)
++{
++	regs->u_regs[UREG_G1] = -1L;
++}
++
++#endif

linux-2.6-utrace-tracehook-um.patch:
 arch/um/kernel/exec.c           |    1 
 arch/um/kernel/process.c        |    6 
 arch/um/kernel/ptrace.c         |  327 ++++------------------------------------
 arch/um/kernel/signal.c         |    5 
 arch/um/kernel/skas/syscall.c   |    4 
 arch/um/sys-i386/signal.c       |    4 
 include/asm-um/ptrace-generic.h |    3 
 include/asm-um/ptrace-i386.h    |    2 
 include/asm-um/ptrace-x86_64.h  |    2 
 include/asm-um/thread_info.h    |    3 
 include/asm-um/tracehook.h      |   57 ++++++
 11 files changed, 106 insertions(+), 308 deletions(-)

Index: linux-2.6-utrace-tracehook-um.patch
===================================================================
RCS file: linux-2.6-utrace-tracehook-um.patch
diff -N linux-2.6-utrace-tracehook-um.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-tracehook-um.patch	19 Jul 2007 17:46:36 -0000	1.3
@@ -0,0 +1,596 @@
+[PATCH 1d] utrace: tracehook for UML
+
+From: Jeff Dike <jdike at addtoit.com>
+
+This is the tracehook part of the UML utrace work, enough to get UML
+building with the utrace prep patches applied.
+
+Checks of task->ptrace & PT_DTRACE were replaced with
+test_thread_flag(TIF_SINGLESTEP, or removed, in the case of execve.
+
+Most of arch/um/kernel/ptrace.c is gone, to be reinstated in future
+utrace work.
+
+Similarly, calls to syscall_trace and ptrace notifications in the
+signal delivery code are gone.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+Signed-off-by: Jeff Dike <jdike at linux.intel.com>
+
+---
+
+ arch/um/kernel/ptrace.c         |  327 ++++-----------------------------------
+ arch/um/kernel/skas/syscall.c   |    4 
+ arch/um/kernel/signal.c         |    5 -
+ arch/um/kernel/exec.c           |    1 
+ arch/um/kernel/process.c        |    6 -
+ arch/um/sys-i386/signal.c       |    4 
+ include/asm-um/ptrace-x86_64.h  |    2 
+ include/asm-um/ptrace-generic.h |    3 
+ include/asm-um/ptrace-i386.h    |    2 
+ include/asm-um/tracehook.h      |   57 +++++++
+ include/asm-um/thread_info.h    |    3 
+ 11 files changed, 106 insertions(+), 308 deletions(-)
+ create include/asm-um/tracehook.h
+
+--- linux-2.6/arch/um/kernel/ptrace.c
++++ linux-2.6/arch/um/kernel/ptrace.c
+@@ -3,261 +3,21 @@
+  * Licensed under the GPL
+  */
+ 
+-#include "linux/sched.h"
+-#include "linux/mm.h"
+-#include "linux/errno.h"
+-#include "linux/smp_lock.h"
+-#include "linux/security.h"
+-#include "linux/ptrace.h"
+-#include "linux/audit.h"
+-#ifdef CONFIG_PROC_MM
+-#include "linux/proc_mm.h"
+-#endif
+-#include "asm/ptrace.h"
+-#include "asm/uaccess.h"
+-#include "kern_util.h"
+-#include "skas_ptrace.h"
+-#include "sysdep/ptrace.h"
+-#include "os.h"
+-
+-static inline void set_singlestepping(struct task_struct *child, int on)
+-{
+-        if (on)
+-                child->ptrace |= PT_DTRACE;
+-        else
+-                child->ptrace &= ~PT_DTRACE;
+-        child->thread.singlestep_syscall = 0;
+-
+-#ifdef SUBARCH_SET_SINGLESTEPPING
+-        SUBARCH_SET_SINGLESTEPPING(child, on);
+-#endif
+-}
++#include <linux/audit.h>
++#include <linux/elf.h>
++#include <linux/module.h>
++#include <linux/ptrace.h>
++#include <linux/tracehook.h>
+ 
+ /*
+  * Called by kernel/ptrace.c when detaching..
+  */
+ void ptrace_disable(struct task_struct *child)
+ { 
+-        set_singlestepping(child,0);
+-}
+-
+-extern int peek_user(struct task_struct * child, long addr, long data);
+-extern int poke_user(struct task_struct * child, long addr, long data);
+-
+-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+-{
+-	int i, ret;
+-	unsigned long __user *p = (void __user *)(unsigned long)data;
+-
+-	switch (request) {
+-		/* when I and D space are separate, these will need to be fixed. */
+-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+-	case PTRACE_PEEKDATA: {
+-		unsigned long tmp;
+-		int copied;
+-
+-		ret = -EIO;
+-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+-		if (copied != sizeof(tmp))
+-			break;
+-		ret = put_user(tmp, p);
+-		break;
+-	}
+-
+-	/* read the word at location addr in the USER area. */
+-        case PTRACE_PEEKUSR:
+-                ret = peek_user(child, addr, data);
+-                break;
+-
+-	/* when I and D space are separate, this will have to be fixed. */
+-	case PTRACE_POKETEXT: /* write the word at location addr. */
+-	case PTRACE_POKEDATA:
+-		ret = -EIO;
+-		if (access_process_vm(child, addr, &data, sizeof(data), 
+-				      1) != sizeof(data))
+-			break;
+-		ret = 0;
+-		break;
+-
+-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+-                ret = poke_user(child, addr, data);
+-                break;
+-
+-	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+-	case PTRACE_CONT: { /* restart after signal. */
+-		ret = -EIO;
+-		if (!valid_signal(data))
+-			break;
+-
+-                set_singlestepping(child, 0);
+-		if (request == PTRACE_SYSCALL) {
+-			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-		else {
+-			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-		child->exit_code = data;
+-		wake_up_process(child);
+-		ret = 0;
+-		break;
+-	}
+-
+-/*
+- * make the child exit.  Best I can do is send it a sigkill. 
+- * perhaps it should be put in the status that it wants to 
+- * exit.
+- */
+-	case PTRACE_KILL: {
+-		ret = 0;
+-		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+-			break;
+-
+-                set_singlestepping(child, 0);
+-		child->exit_code = SIGKILL;
+-		wake_up_process(child);
+-		break;
+-	}
+-
+-	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+-		ret = -EIO;
+-		if (!valid_signal(data))
+-			break;
+-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-                set_singlestepping(child, 1);
+-		child->exit_code = data;
+-		/* give it a chance to run. */
+-		wake_up_process(child);
+-		ret = 0;
+-		break;
+-	}
+-
+-	case PTRACE_DETACH:
+-		/* detach a process that was attached. */
+-		ret = ptrace_detach(child, data);
+- 		break;
+-
+-#ifdef PTRACE_GETREGS
+-	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+-		if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
+-			ret = -EIO;
+-			break;
+-		}
+-		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
+-			__put_user(getreg(child, i), p);
+-			p++;
+-		}
+-		ret = 0;
+-		break;
+-	}
+-#endif
+-#ifdef PTRACE_SETREGS
+-	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+-		unsigned long tmp = 0;
+-		if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
+-			ret = -EIO;
+-			break;
+-		}
+-		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
+-			__get_user(tmp, p);
+-			putreg(child, i, tmp);
+-			p++;
+-		}
+-		ret = 0;
+-		break;
+-	}
+-#endif
+-#ifdef PTRACE_GETFPREGS
+-	case PTRACE_GETFPREGS: /* Get the child FPU state. */
+-		ret = get_fpregs(data, child);
+-		break;
+-#endif
+-#ifdef PTRACE_SETFPREGS
+-	case PTRACE_SETFPREGS: /* Set the child FPU state. */
+-	        ret = set_fpregs(data, child);
+-		break;
+-#endif
+-#ifdef PTRACE_GETFPXREGS
+-	case PTRACE_GETFPXREGS: /* Get the child FPU state. */
+-		ret = get_fpxregs(data, child);
+-		break;
+-#endif
+-#ifdef PTRACE_SETFPXREGS
+-	case PTRACE_SETFPXREGS: /* Set the child FPU state. */
+-		ret = set_fpxregs(data, child);
+-		break;
+-#endif
+-	case PTRACE_GET_THREAD_AREA:
+-		ret = ptrace_get_thread_area(child, addr,
+-					     (struct user_desc __user *) data);
+-		break;
+-
+-	case PTRACE_SET_THREAD_AREA:
+-		ret = ptrace_set_thread_area(child, addr,
+-					     (struct user_desc __user *) data);
+-		break;
+-
+-	case PTRACE_FAULTINFO: {
+-		/* Take the info from thread->arch->faultinfo,
+-		 * but transfer max. sizeof(struct ptrace_faultinfo).
+-		 * On i386, ptrace_faultinfo is smaller!
+-		 */
+-		ret = copy_to_user(p, &child->thread.arch.faultinfo,
+-				   sizeof(struct ptrace_faultinfo));
+-		if(ret)
+-			break;
+-		break;
+-	}
+-
+-#ifdef PTRACE_LDT
+-	case PTRACE_LDT: {
+-		struct ptrace_ldt ldt;
+-
+-		if(copy_from_user(&ldt, p, sizeof(ldt))){
+-			ret = -EIO;
+-			break;
+-		}
+-
+-		/* This one is confusing, so just punt and return -EIO for 
+-		 * now
+-		 */
+-		ret = -EIO;
+-		break;
+-	}
+-#endif
+-#ifdef CONFIG_PROC_MM
+-	case PTRACE_SWITCH_MM: {
+-		struct mm_struct *old = child->mm;
+-		struct mm_struct *new = proc_mm_get_mm(data);
+-
+-		if(IS_ERR(new)){
+-			ret = PTR_ERR(new);
+-			break;
+-		}
+-
+-		atomic_inc(&new->mm_users);
+-		child->mm = new;
+-		child->active_mm = new;
+-		mmput(old);
+-		ret = 0;
+-		break;
+-	}
+-#endif
+-#ifdef PTRACE_ARCH_PRCTL
+-        case PTRACE_ARCH_PRCTL:
+-                /* XXX Calls ptrace on the host - needs some SMP thinking */
+-                ret = arch_prctl_skas(child, data, (void *) addr);
+-                break;
+-#endif
+-	default:
+-		ret = ptrace_request(child, request, addr, data);
+-		break;
+-	}
+-
+-	return ret;
+ }
+ 
+-void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
+-		  int error_code)
++static void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
++			 int error_code)
+ {
+ 	struct siginfo info;
+ 
+@@ -266,56 +26,39 @@ void send_sigtrap(struct task_struct *ts
+ 	info.si_code = TRAP_BRKPT;
+ 
+ 	/* User-mode eip? */
+-	info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
++	info.si_addr = UPT_IS_USER(&regs->regs) ?
++		(void __user *) UPT_IP(&regs->regs) : NULL;
+ 
+ 	/* Send us the fakey SIGTRAP */
+ 	force_sig_info(SIGTRAP, &info, tsk);
+ }
+ 
+-/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
+- * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
++/* notification of system call entry/exit
++ * - triggered by current->work.syscall_trace
+  */
+-void syscall_trace(union uml_pt_regs *regs, int entryexit)
++void do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
+-	int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
+-	int tracesysgood;
+-
+-	if (unlikely(current->audit_context)) {
+-		if (!entryexit)
+-			audit_syscall_entry(HOST_AUDIT_ARCH,
+-					    UPT_SYSCALL_NR(regs),
+-					    UPT_SYSCALL_ARG1(regs),
+-					    UPT_SYSCALL_ARG2(regs),
+-					    UPT_SYSCALL_ARG3(regs),
+-					    UPT_SYSCALL_ARG4(regs));
+-		else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
+-                                        UPT_SYSCALL_RET(regs));
+-	}
+-
+-	/* Fake a debug trap */
+-	if (is_singlestep)
+-		send_sigtrap(current, regs, 0);
+-
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+-		return;
+-
+-	if (!(current->ptrace & PT_PTRACED))
+-		return;
+-
+-	/* the 0x80 provides a way for the tracing parent to distinguish
+-	   between a syscall stop and SIGTRAP delivery */
+-	tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
+-	ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
+-
+-	if (entryexit) /* force do_signal() --> is_syscall() */
+-		set_thread_flag(TIF_SIGPENDING);
+-
+-	/* 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;
+-	}
++	/* do the secure computing check first */
++	if (!entryexit)
++		secure_computing(PT_REGS_SYSCALL_NR(regs));
++
++	if (unlikely(current->audit_context) && entryexit)
++		audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(&regs->regs)),
++				   UPT_SYSCALL_RET(&regs->regs));
++
++	if (test_thread_flag(TIF_SYSCALL_TRACE))
++		tracehook_report_syscall(regs, entryexit);
++
++	if (test_thread_flag(TIF_SINGLESTEP) && entryexit) {
++		send_sigtrap(current, regs, 0);	/* XXX */
++		tracehook_report_syscall_step(regs);
++	}
++
++	if (unlikely(current->audit_context) && !entryexit)
++		audit_syscall_entry(HOST_AUDIT_ARCH,
++				    UPT_SYSCALL_NR(&regs->regs),
++				    UPT_SYSCALL_ARG1(&regs->regs),
++				    UPT_SYSCALL_ARG2(&regs->regs),
++				    UPT_SYSCALL_ARG3(&regs->regs),
++				    UPT_SYSCALL_ARG4(&regs->regs));
+ }
+--- linux-2.6/arch/um/kernel/skas/syscall.c
++++ linux-2.6/arch/um/kernel/skas/syscall.c
+@@ -19,8 +19,6 @@ void handle_syscall(union uml_pt_regs *r
+ 	long result;
+ 	int syscall;
+ 
+-	syscall_trace(r, 0);
+-
+ 	current->thread.nsyscalls++;
+ 	nsyscalls++;
+ 
+@@ -38,6 +36,4 @@ void handle_syscall(union uml_pt_regs *r
+ 	else result = EXECUTE_SYSCALL(syscall, regs);
+ 
+ 	REGS_SET_SYSCALL_RETURN(r->skas.regs, result);
+-
+-	syscall_trace(r, 1);
+ }
+--- linux-2.6/arch/um/kernel/signal.c
++++ linux-2.6/arch/um/kernel/signal.c
+@@ -14,6 +14,7 @@
+ #include "linux/tty.h"
+ #include "linux/binfmts.h"
+ #include "linux/ptrace.h"
++#include "linux/tracehook.h"
+ #include "asm/signal.h"
+ #include "asm/uaccess.h"
+ #include "asm/unistd.h"
+@@ -92,6 +93,8 @@ static int handle_signal(struct pt_regs 
+ 			sigaddset(&current->blocked, signr);
+ 		recalc_sigpending();
+ 		spin_unlock_irq(&current->sighand->siglock);
++
++		tracehook_report_handle_signal(signr, ka, oldset, regs);
+ 	}
+ 
+ 	return err;
+@@ -147,7 +150,7 @@ static int kern_do_signal(struct pt_regs
+ 	 * on the host.  The tracing thread will check this flag and
+ 	 * PTRACE_SYSCALL if necessary.
+ 	 */
+-	if(current->ptrace & PT_DTRACE)
++	if(test_thread_flag(TIF_SYSCALL_TRACE))
+ 		current->thread.singlestep_syscall =
+ 			is_syscall(PT_REGS_IP(&current->thread.regs));
+ 
+--- linux-2.6/arch/um/kernel/exec.c
++++ linux-2.6/arch/um/kernel/exec.c
+@@ -51,7 +51,6 @@ static long execve1(char *file, char __u
+         error = do_execve(file, argv, env, &current->thread.regs);
+         if (error == 0){
+ 		task_lock(current);
+-                current->ptrace &= ~PT_DTRACE;
+ #ifdef SUBARCH_EXECVE1
+ 		SUBARCH_EXECVE1(&current->thread.regs.regs);
+ #endif
+--- linux-2.6/arch/um/kernel/process.c
++++ linux-2.6/arch/um/kernel/process.c
+@@ -403,11 +403,11 @@ int singlestepping(void * t)
+ {
+ 	struct task_struct *task = t ? t : current;
+ 
+-	if ( ! (task->ptrace & PT_DTRACE) )
+-		return(0);
++	if (!test_thread_flag(TIF_SINGLESTEP))
++		return 0;
+ 
+ 	if (task->thread.singlestep_syscall)
+-		return(1);
++		return 1;
+ 
+ 	return 2;
+ }
+--- linux-2.6/arch/um/sys-i386/signal.c
++++ linux-2.6/arch/um/sys-i386/signal.c
+@@ -274,8 +274,6 @@ int setup_signal_stack_sc(unsigned long 
+ 	PT_REGS_EDX(regs) = (unsigned long) 0;
+ 	PT_REGS_ECX(regs) = (unsigned long) 0;
+ 
+-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+-		ptrace_notify(SIGTRAP);
+ 	return 0;
+ 
+ err:
+@@ -331,8 +329,6 @@ int setup_signal_stack_si(unsigned long 
+ 	PT_REGS_EDX(regs) = (unsigned long) &frame->info;
+ 	PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
+ 
+-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+-		ptrace_notify(SIGTRAP);
+ 	return 0;
+ 
+ err:
+--- linux-2.6/include/asm-um/ptrace-x86_64.h
++++ linux-2.6/include/asm-um/ptrace-x86_64.h
+@@ -14,6 +14,8 @@
+ #define __FRAME_OFFSETS /* Needed to get the R* macros */
+ #include "asm/ptrace-generic.h"
+ 
++#define ARCH_HAS_SINGLE_STEP	(1)
++
+ #define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
+ 
+ /* Also defined in sysdep/ptrace.h, so may already be defined. */
+--- linux-2.6/include/asm-um/ptrace-generic.h
++++ linux-2.6/include/asm-um/ptrace-generic.h
+@@ -44,9 +44,6 @@ extern int set_fpxregs(unsigned long buf
+ 
+ extern void show_regs(struct pt_regs *regs);
+ 
+-extern void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
+-			 int error_code);
+-
+ extern int arch_copy_tls(struct task_struct *new);
+ extern void clear_flushed_tls(struct task_struct *task);
+ 
+--- linux-2.6/include/asm-um/ptrace-i386.h
++++ linux-2.6/include/asm-um/ptrace-i386.h
+@@ -6,6 +6,8 @@
+ #ifndef __UM_PTRACE_I386_H
+ #define __UM_PTRACE_I386_H
+ 
++#define ARCH_HAS_SINGLE_STEP	(1)
++
+ #define HOST_AUDIT_ARCH AUDIT_ARCH_I386
+ 
+ #include "linux/compiler.h"
+--- linux-2.6/include/asm-um/tracehook.h
++++ linux-2.6/include/asm-um/tracehook.h
+@@ -0,0 +1,57 @@
++/*
++ * Tracing hooks, i386 CPU support
++ *
++ * Copyright (C) 2006, 2007 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.
++ *
++ * Red Hat Author: Roland McGrath.
++ *
++ * Munged for UML - jdike@{addtoit,linux.intel}.com
++ */
++
++#ifndef _ASM_TRACEHOOK_H
++#define _ASM_TRACEHOOK_H	1
++
++#include <linux/sched.h>
++#include <asm/ptrace.h>
++#include <asm/thread_info.h>
++
++/*
++ * See linux/tracehook.h for the descriptions of what these need to do.
++ */
++
++static inline void tracehook_enable_single_step(struct task_struct *tsk)
++{
++	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
++}
++
++static inline void tracehook_disable_single_step(struct task_struct *tsk)
++{
++	clear_tsk_thread_flag(tsk, TIF_SINGLESTEP);
++}
++
++static inline int tracehook_single_step_enabled(struct task_struct *tsk)
++{
++	return test_tsk_thread_flag(tsk, TIF_SINGLESTEP);
++}
++
++static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
++{
++	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
++{
++	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++static inline void tracehook_abort_syscall(struct pt_regs *regs)
++{
++	PT_REGS_SYSCALL_NR(regs) = -1;
++}
++
++
++#endif
+--- linux-2.6/include/asm-um/thread_info.h
++++ linux-2.6/include/asm-um/thread_info.h
+@@ -71,6 +71,8 @@ static inline struct thread_info *curren
+ #define TIF_MEMDIE	 	5
+ #define TIF_SYSCALL_AUDIT	6
+ #define TIF_RESTORE_SIGMASK	7
++#define TIF_SINGLESTEP          8       /* restore singlestep on return to user
++                                         * mode */
+ 
+ #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
+ #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
+@@ -79,5 +81,6 @@ static inline struct thread_info *curren
+ #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
+ #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
+ #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
++#define _TIF_SINGLESTEP         (1 << TIF_SINGLESTEP)
+ 
+ #endif

linux-2.6-utrace-tracehook.patch:
 arch/alpha/kernel/asm-offsets.c     |    2 
 arch/alpha/kernel/entry.S           |    4 
 arch/arm/kernel/ptrace.c            |   17 -
 arch/arm26/kernel/ptrace.c          |   32 --
 arch/frv/kernel/ptrace.c            |   15 -
 arch/i386/kernel/entry.S            |    7 
 arch/i386/kernel/process.c          |    3 
 arch/i386/kernel/ptrace.c           |  104 +--------
 arch/i386/kernel/signal.c           |   37 +--
 arch/i386/kernel/vm86.c             |    7 
 arch/i386/math-emu/fpu_entry.c      |    6 
 arch/ia64/kernel/asm-offsets.c      |    2 
 arch/ia64/kernel/fsys.S             |   16 -
 arch/ia64/kernel/mca.c              |    2 
 arch/mips/kernel/ptrace.c           |   21 -
 arch/mips/kernel/sysirix.c          |    2 
 arch/powerpc/kernel/asm-offsets.c   |    2 
 arch/powerpc/kernel/process.c       |    5 
 arch/powerpc/kernel/ptrace-common.h |   16 -
 arch/powerpc/kernel/ptrace.c        |   76 +-----
 arch/powerpc/kernel/ptrace32.c      |   13 -
 arch/powerpc/kernel/signal_32.c     |    3 
 arch/powerpc/kernel/signal_64.c     |    3 
 arch/powerpc/kernel/sys_ppc32.c     |    5 
 arch/ppc/kernel/asm-offsets.c       |    2 
 arch/s390/kernel/compat_linux.c     |    3 
 arch/s390/kernel/process.c          |    3 
 arch/sparc64/kernel/binfmt_aout32.c |    2 
 arch/sparc64/kernel/process.c       |    3 
 arch/sparc64/kernel/sys_sparc32.c   |    3 
 arch/x86_64/ia32/ia32_aout.c        |    6 
 arch/x86_64/ia32/ia32_signal.c      |    7 
 arch/x86_64/ia32/ia32entry.S        |    4 
 arch/x86_64/ia32/ptrace32.c         |    2 
 arch/x86_64/ia32/sys_ia32.c         |    5 
 arch/x86_64/kernel/entry.S          |    8 
 arch/x86_64/kernel/process.c        |    5 
 arch/x86_64/kernel/ptrace.c         |   57 +---
 arch/x86_64/kernel/signal.c         |   28 +-
 arch/x86_64/kernel/traps.c          |    8 
 arch/x86_64/mm/fault.c              |    4 
 drivers/connector/cn_proc.c         |    4 
 fs/binfmt_aout.c                    |    6 
 fs/binfmt_elf.c                     |    6 
 fs/binfmt_elf_fdpic.c               |    7 
 fs/binfmt_flat.c                    |    3 
 fs/binfmt_som.c                     |    2 
 fs/exec.c                           |   11 
 fs/proc/array.c                     |   12 -
 fs/proc/base.c                      |   17 -
 include/asm-i386/signal.h           |    4 
 include/asm-i386/thread_info.h      |    7 
 include/asm-i386/tracehook.h        |   52 ++++
 include/asm-powerpc/tracehook.h     |   74 ++++++
 include/asm-x86_64/thread_info.h    |    3 
 include/asm-x86_64/tracehook.h      |   51 ++++
 include/linux/init_task.h           |    3 
 include/linux/ptrace.h              |   18 -
 include/linux/sched.h               |   16 -
 include/linux/tracehook.h           |  414 ++++++++++++++++++++++++++++++++++++
 kernel/exit.c                       |  244 +++++----------------
 kernel/fork.c                       |   66 +----
 kernel/ptrace.c                     |  299 +-------------------------
 kernel/signal.c                     |  212 +++---------------
 kernel/sys.c                        |    2 
 kernel/timer.c                      |    6 
 kernel/tsacct.c                     |    2 
 mm/nommu.c                          |    4 
 security/selinux/hooks.c            |   54 ++--
 security/selinux/include/objsec.h   |    1 
 70 files changed, 934 insertions(+), 1216 deletions(-)

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.2 -r 1.3 linux-2.6-utrace-tracehook.patch
Index: linux-2.6-utrace-tracehook.patch
===================================================================
RCS file: linux-2.6-utrace-tracehook.patch
diff -N linux-2.6-utrace-tracehook.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-utrace-tracehook.patch	19 Jul 2007 17:46:36 -0000	1.3
@@ -0,0 +1,4000 @@
+[PATCH 1] utrace: tracehook (die, ptrace, die)
+
+This patch rips out the old ptrace implementation.  It leaves behind stubs
+so ptrace just fails with ENOSYS.  This is not really a useful kernel tree
+to build, but it's a clean removal of the old code before adding the new.
+Some dead code is left behind especially in architecture ptrace.c files;
+this is left in to be reused under new interfaces by later patches,
+reducing the total disruption to the code.
+
+The "real_parent" member in task_struct is renamed "parent", and the old
+"parent" member is gone.  That is to say, nothing interferes in the normal
+parent/child links any more.  The fact that ptrace could cause these links
+to change was the source of numerous race conditions and similar bugs
+uncovered and worked around (often contortedly) in the core task management
+code under the old ptrace implementation.
+
+In each place in core code that referred to the old ptrace stuff, we now
+have the tracehook interface.  These declarations are in <linux/tracehook.h>,
+and use "tracehook_*" function names.  This centralizes all the hooks
+that a thread tracing facility needs into core code, and the file
+documents the calling environment (locking conditions, etc.) and meaning
+of each hook.  The definitions here are all stubs doing nothing, so
+there are no user debugging features in the kernel at all.  They provide
+the placeholders for where a tracing interface can tie into the kernel.
+
+The architecture support for single-step (and block-step) from the old
+ptrace support is moved into tracehook_* function interfaces.  Nothing
+yet calls these, but this provides the clean interface that user
+debugging support can use for the architecture-specific single-step
+control code.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+
+---
+
+ fs/binfmt_flat.c                    |    3 
+ fs/binfmt_som.c                     |    2 
+ fs/proc/base.c                      |   17 +
+ fs/proc/array.c                     |   12 +
+ fs/binfmt_elf_fdpic.c               |    7 -
+ fs/exec.c                           |   11 -
+ fs/binfmt_elf.c                     |    6 -
+ fs/binfmt_aout.c                    |    6 -
+ security/selinux/hooks.c            |   54 +++--
+ security/selinux/include/objsec.h   |    1 
+ arch/s390/kernel/compat_linux.c     |    3 
+ arch/s390/kernel/process.c          |    3 
+ arch/frv/kernel/ptrace.c            |   15 -
+ arch/i386/math-emu/fpu_entry.c      |    6 -
+ arch/i386/kernel/ptrace.c           |  104 ++-------
+ arch/i386/kernel/signal.c           |   37 +--
+ arch/i386/kernel/process.c          |    3 
+ arch/i386/kernel/vm86.c             |    7 -
+ arch/i386/kernel/entry.S            |    7 -
+ arch/x86_64/ia32/sys_ia32.c         |    5 
+ arch/x86_64/ia32/ptrace32.c         |    2 
+ arch/x86_64/ia32/ia32_aout.c        |    6 -
+ arch/x86_64/ia32/ia32_signal.c      |    7 -
+ arch/x86_64/ia32/ia32entry.S        |    4 
+ arch/x86_64/kernel/traps.c          |    8 -
+ arch/x86_64/kernel/ptrace.c         |   57 ++---
+ arch/x86_64/kernel/signal.c         |   28 +-
+ arch/x86_64/kernel/process.c        |    5 
+ arch/x86_64/kernel/entry.S          |    8 -
+ arch/x86_64/mm/fault.c              |    4 
+ arch/arm/kernel/ptrace.c            |   17 -
+ arch/mips/kernel/sysirix.c          |    2 
+ arch/mips/kernel/ptrace.c           |   21 --
+ arch/powerpc/kernel/sys_ppc32.c     |    5 
+ arch/powerpc/kernel/ptrace-common.h |   16 -
+ arch/powerpc/kernel/ptrace32.c      |   13 +
+ arch/powerpc/kernel/ptrace.c        |   76 +-----
+ arch/powerpc/kernel/asm-offsets.c   |    2 
+ arch/powerpc/kernel/signal_64.c     |    3 
+ arch/powerpc/kernel/process.c       |    5 
+ arch/powerpc/kernel/signal_32.c     |    3 
+ arch/arm26/kernel/ptrace.c          |   32 +--
+ arch/alpha/kernel/asm-offsets.c     |    2 
+ arch/alpha/kernel/entry.S           |    4 
+ arch/sparc64/kernel/binfmt_aout32.c |    2 
+ arch/sparc64/kernel/process.c       |    3 
+ arch/sparc64/kernel/sys_sparc32.c   |    3 
+ arch/ppc/kernel/asm-offsets.c       |    2 
+ arch/ia64/kernel/mca.c              |    2 
+ arch/ia64/kernel/asm-offsets.c      |    2 
+ arch/ia64/kernel/fsys.S             |   16 +
+ kernel/exit.c                       |  244 +++++----------------
+ kernel/ptrace.c                     |  299 +------------------------
+ kernel/timer.c                      |    6 -
+ kernel/signal.c                     |  212 ++++--------------
+ kernel/tsacct.c                     |    2 
+ kernel/sys.c                        |    2 
+ kernel/fork.c                       |   66 ++----
+ include/linux/ptrace.h              |   18 --
+ include/linux/sched.h               |   16 -
+ include/linux/init_task.h           |    3 
+ include/linux/tracehook.h           |  414 +++++++++++++++++++++++++++++++++++
+ include/asm-i386/tracehook.h        |   52 ++++
+ include/asm-i386/thread_info.h      |    7 -
+ include/asm-i386/signal.h           |    4 
+ include/asm-powerpc/tracehook.h     |   74 ++++++
+ include/asm-x86_64/tracehook.h      |   51 ++++
+ include/asm-x86_64/thread_info.h    |    3 
+ drivers/connector/cn_proc.c         |    4 
+ mm/nommu.c                          |    4 
+ 70 files changed, 934 insertions(+), 1216 deletions(-)
+ create include/linux/tracehook.h
+ create include/asm-i386/tracehook.h
+ create include/asm-powerpc/tracehook.h
+ create include/asm-x86_64/tracehook.h
+
+--- linux-2.6/fs/binfmt_flat.c
++++ linux-2.6/fs/binfmt_flat.c
+@@ -914,9 +914,6 @@ static int load_flat_binary(struct linux
+ 	
+ 	start_thread(regs, start_addr, current->mm->start_stack);
+ 
+-	if (current->ptrace & PT_PTRACED)
+-		send_sig(SIGTRAP, current, 0);
+-
+ 	return 0;
+ }
+ 
+--- linux-2.6/fs/binfmt_som.c
++++ linux-2.6/fs/binfmt_som.c
+@@ -285,8 +285,6 @@ load_som_binary(struct linux_binprm * bp
+ 	map_hpux_gateway_page(current,current->mm);
+ 
+ 	start_thread_som(regs, som_entry, bprm->p);
+-	if (current->ptrace & PT_PTRACED)
+-		send_sig(SIGTRAP, current, 0);
+ 	return 0;
+ 
+ 	/* error cleanup */
+--- linux-2.6/fs/proc/base.c
++++ linux-2.6/fs/proc/base.c
+@@ -67,6 +67,7 @@
+ #include <linux/mount.h>
+ #include <linux/security.h>
+ #include <linux/ptrace.h>
++#include <linux/tracehook.h>
+ #include <linux/seccomp.h>
+ #include <linux/cpuset.h>
+ #include <linux/audit.h>
+@@ -192,13 +193,6 @@ static int proc_root_link(struct inode *
+ 	return result;
+ }
+ 
+-#define MAY_PTRACE(task) \
+-	(task == current || \
+-	(task->parent == current && \
+-	(task->ptrace & PT_PTRACED) && \
+-	 (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
+-	 security_ptrace(current,task) == 0))
+-
+ static int proc_pid_environ(struct task_struct *task, char * buffer)
+ {
+ 	int res = 0;
+@@ -523,7 +517,8 @@ static ssize_t mem_read(struct file * fi
+ 	if (!task)
+ 		goto out_no_task;
+ 
+-	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
++	if (!tracehook_allow_access_process_vm(task)
++	    || !ptrace_may_attach(task))
+ 		goto out;
+ 
+ 	ret = -ENOMEM;
+@@ -549,7 +544,8 @@ static ssize_t mem_read(struct file * fi
+ 
+ 		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ 		retval = access_process_vm(task, src, page, this_len, 0);
+-		if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
++		if (!retval || !tracehook_allow_access_process_vm(task)
++		    || !ptrace_may_attach(task)) {
+ 			if (!ret)
+ 				ret = -EIO;
+ 			break;
+@@ -593,7 +589,8 @@ static ssize_t mem_write(struct file * f
+ 	if (!task)
+ 		goto out_no_task;
+ 
+-	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
++	if (!tracehook_allow_access_process_vm(task)
++	    || !ptrace_may_attach(task))
+ 		goto out;
+ 
+ 	copied = -ENOMEM;
+--- linux-2.6/fs/proc/array.c
++++ linux-2.6/fs/proc/array.c
+@@ -73,6 +73,7 @@
+ #include <linux/file.h>
+ #include <linux/times.h>
[...3607 lines suppressed...]
+ /* work to do on any return to u-space */
+ #define _TIF_ALLWORK_MASK	(0x0000FFFF & ~_TIF_SECCOMP)
+ 
+--- linux-2.6/include/asm-i386/signal.h
++++ linux-2.6/include/asm-i386/signal.h
+@@ -221,10 +221,8 @@ struct pt_regs;
+ 
+ #define ptrace_signal_deliver(regs, cookie)		\
+ 	do {						\
+-		if (current->ptrace & PT_DTRACE) {	\
+-			current->ptrace &= ~PT_DTRACE;	\
++		if (test_and_clear_thread_flag(TIF_FORCED_TF)) \
+ 			(regs)->eflags &= ~TF_MASK;	\
+-		}					\
+ 	} while (0)
+ 
+ #endif /* __KERNEL__ */
+--- linux-2.6/include/asm-powerpc/tracehook.h
++++ linux-2.6/include/asm-powerpc/tracehook.h
+@@ -0,0 +1,74 @@
++/*
++ * Tracing hooks, PowerPC CPU support
++ *
++ * Copyright (C) 2006, 2007 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.
++ *
++ * Red Hat Author: Roland McGrath.
++ */
++
++#ifndef _ASM_TRACEHOOK_H
++#define _ASM_TRACEHOOK_H	1
++
++#include <linux/sched.h>
++#include <asm/ptrace.h>
++
++/*
++ * See linux/tracehook.h for the descriptions of what these need to do.
++ */
++
++#define ARCH_HAS_SINGLE_STEP	(1)
++
++static inline void tracehook_enable_single_step(struct task_struct *task)
++{
++	struct pt_regs *regs = task->thread.regs;
++	if (regs != NULL) {
++#if defined(CONFIG_PPC32) && (defined(CONFIG_40x) || defined(CONFIG_BOOKE))
++		task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
++		regs->msr |= MSR_DE;
++#else
++		regs->msr |= MSR_SE;
++#endif
++	}
++	set_tsk_thread_flag(task, TIF_SINGLESTEP);
++}
++
++static inline void tracehook_disable_single_step(struct task_struct *task)
++{
++	struct pt_regs *regs = task->thread.regs;
++	if (regs != NULL) {
++#if defined(CONFIG_PPC32) && (defined(CONFIG_40x) || defined(CONFIG_BOOKE))
++		task->thread.dbcr0 = 0;
++		regs->msr &= ~MSR_DE;
++#else
++		regs->msr &= ~MSR_SE;
++#endif
++	}
++	clear_tsk_thread_flag(task, TIF_SINGLESTEP);
++}
++
++static inline int tracehook_single_step_enabled(struct task_struct *tsk)
++{
++	return test_tsk_thread_flag(tsk, TIF_SINGLESTEP);
++}
++
++static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
++{
++	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
++{
++	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++static inline void tracehook_abort_syscall(struct pt_regs *regs)
++{
++	regs->orig_gpr3 = -1L;
++}
++
++
++#endif
+--- linux-2.6/include/asm-x86_64/tracehook.h
++++ linux-2.6/include/asm-x86_64/tracehook.h
+@@ -0,0 +1,51 @@
++/*
++ * Tracing hooks, x86-64 CPU support
++ *
++ * Copyright (C) 2006, 2007 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.
++ *
++ * Red Hat Author: Roland McGrath.
++ */
++
++#ifndef _ASM_TRACEHOOK_H
++#define _ASM_TRACEHOOK_H	1
++
++#include <linux/sched.h>
++#include <asm/ptrace.h>
++
++/*
++ * See linux/tracehook.h for the descriptions of what these need to do.
++ */
++
++#define ARCH_HAS_SINGLE_STEP	(1)
++
++/* These two are defined in arch/x86_64/kernel/ptrace.c.  */
++void tracehook_enable_single_step(struct task_struct *tsk);
++void tracehook_disable_single_step(struct task_struct *tsk);
++
++static inline int tracehook_single_step_enabled(struct task_struct *tsk)
++{
++	return test_tsk_thread_flag(tsk, TIF_SINGLESTEP);
++}
++
++static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
++{
++	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
++{
++	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
++}
++
++#define tracehook_syscall_callno(regs)	(&(regs)->orig_rax)
++#define tracehook_syscall_retval(regs)	(&(regs)->rax)
++static inline void tracehook_abort_syscall(struct pt_regs *regs)
++{
++	regs->orig_rax = -1L;
++}
++
++#endif
+--- linux-2.6/include/asm-x86_64/thread_info.h
++++ linux-2.6/include/asm-x86_64/thread_info.h
+@@ -115,7 +115,7 @@ static inline struct thread_info *stack_
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_SECCOMP		8	/* secure computing */
+ #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal */
+-/* 16 free */
++#define TIF_FORCED_TF		16	/* true if TF in eflags artificially */
+ #define TIF_IA32		17	/* 32bit process */ 
+ #define TIF_FORK		18	/* ret_from_fork */
+ #define TIF_ABI_PENDING		19
+@@ -133,6 +133,7 @@ static inline struct thread_info *stack_
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+ #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
++#define _TIF_FORCED_TF		(1<<TIF_FORCED_TF)
+ #define _TIF_IA32		(1<<TIF_IA32)
+ #define _TIF_FORK		(1<<TIF_FORK)
+ #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
+--- linux-2.6/drivers/connector/cn_proc.c
++++ linux-2.6/drivers/connector/cn_proc.c
+@@ -63,8 +63,8 @@ void proc_fork_connector(struct task_str
+ 	ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ 	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+ 	ev->what = PROC_EVENT_FORK;
+-	ev->event_data.fork.parent_pid = task->real_parent->pid;
+-	ev->event_data.fork.parent_tgid = task->real_parent->tgid;
++	ev->event_data.fork.parent_pid = task->parent->pid;
++	ev->event_data.fork.parent_tgid = task->parent->tgid;
+ 	ev->event_data.fork.child_pid = task->pid;
+ 	ev->event_data.fork.child_tgid = task->tgid;
+ 
+--- linux-2.6/mm/nommu.c
++++ linux-2.6/mm/nommu.c
+@@ -20,7 +20,7 @@
+ #include <linux/pagemap.h>
+ #include <linux/slab.h>
+ #include <linux/vmalloc.h>
+-#include <linux/ptrace.h>
++#include <linux/tracehook.h>
+ #include <linux/blkdev.h>
+ #include <linux/backing-dev.h>
+ #include <linux/mount.h>
+@@ -682,7 +682,7 @@ static unsigned long determine_vm_flags(
+ 	 * it's being traced - otherwise breakpoints set in it may interfere
+ 	 * with another untraced process
+ 	 */
+-	if ((flags & MAP_PRIVATE) && (current->ptrace & PT_PTRACED))
++	if ((flags & MAP_PRIVATE) && tracehook_expect_breakpoints(current))
+ 		vm_flags &= ~VM_MAYSHARE;
+ 
+ 	return vm_flags;


Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/dist/rpms/kernel/FC-6/kernel-2.6.spec,v
retrieving revision 1.2991
retrieving revision 1.2992
diff -u -r1.2991 -r1.2992
--- kernel-2.6.spec	17 Jul 2007 20:01:52 -0000	1.2991
+++ kernel-2.6.spec	19 Jul 2007 17:46:35 -0000	1.2992
@@ -506,7 +506,24 @@
 
 %if !%{nopatches}
 
-Patch10: linux-2.6-utrace.patch
+Patch10: linux-2.6-utrace-tracehook.patch
+Patch11: linux-2.6-utrace-tracehook-ia64.patch
+Patch12: linux-2.6-utrace-tracehook-sparc64.patch
+Patch13: linux-2.6-utrace-tracehook-s390.patch
+Patch14: linux-2.6-utrace-tracehook-um.patch
+Patch15: linux-2.6-utrace-tracehook-avr32.patch
+Patch16: linux-2.6-utrace-regset.patch
+Patch17: linux-2.6-utrace-regset-ia64.patch
+Patch18: linux-2.6-utrace-regset-sparc64.patch
+Patch19: linux-2.6-utrace-regset-s390.patch
+Patch20: linux-2.6-utrace-regset-avr32.patch
+Patch21: linux-2.6-utrace-core.patch
+Patch22: linux-2.6-utrace-ptrace-compat.patch
+Patch23: linux-2.6-utrace-ptrace-compat-ia64.patch
+Patch24: linux-2.6-utrace-ptrace-compat-sparc64.patch
+Patch25: linux-2.6-utrace-ptrace-compat-s390.patch
+Patch26: linux-2.6-utrace-ptrace-compat-avr32.patch
+
 Patch30: linux-2.6-sysrq-c.patch
 Patch40: linux-2.6-x86-tune-generic.patch
 Patch50: linux-2.6-x86-vga-vidfail.patch
@@ -570,6 +587,7 @@
 Patch666: linux-2.6-libata-unbreak-smart-2.patch
 Patch667: linux-2.6-libata-ata_piix_fix_pio-mwdma-programming.patch
 Patch668: linux-2.6-libata_pata_atiixp_add_ati_sb700.patch
+Patch669: linux-2.6-libata-restore-combined-mode.patch
 Patch680: git-wireless-dev.patch
 Patch690: linux-2.6-e1000-ich9.patch
 Patch710: linux-2.6-bcm43xx-pci-neuter.patch
@@ -1040,7 +1058,24 @@
 ApplyPatch linux-2.6-sched-cfs.patch
 
 # Roland's utrace ptrace replacement.
-ApplyPatch linux-2.6-utrace.patch -F2
+ApplyPatch linux-2.6-utrace-tracehook.patch
+ApplyPatch linux-2.6-utrace-tracehook-ia64.patch
+ApplyPatch linux-2.6-utrace-tracehook-sparc64.patch
+ApplyPatch linux-2.6-utrace-tracehook-s390.patch
+ApplyPatch linux-2.6-utrace-tracehook-um.patch
+ApplyPatch linux-2.6-utrace-tracehook-avr32.patch
+ApplyPatch linux-2.6-utrace-regset.patch
+ApplyPatch linux-2.6-utrace-regset-ia64.patch
+ApplyPatch linux-2.6-utrace-regset-sparc64.patch
+ApplyPatch linux-2.6-utrace-regset-s390.patch
+ApplyPatch linux-2.6-utrace-regset-avr32.patch
+ApplyPatch linux-2.6-utrace-core.patch
+ApplyPatch linux-2.6-utrace-ptrace-compat.patch
+ApplyPatch linux-2.6-utrace-ptrace-compat-ia64.patch
+ApplyPatch linux-2.6-utrace-ptrace-compat-sparc64.patch
+ApplyPatch linux-2.6-utrace-ptrace-compat-s390.patch
+ApplyPatch linux-2.6-utrace-ptrace-compat-avr32.patch
+
 # setuid /proc/self/maps fix. (dependent on utrace)
 ApplyPatch linux-2.6-proc-self-maps-fix.patch
 
@@ -1214,6 +1249,8 @@
 ApplyPatch linux-2.6-libata-ata_piix_fix_pio-mwdma-programming.patch
 # add ID for sb700 to the pata driver
 ApplyPatch linux-2.6-libata_pata_atiixp_add_ati_sb700.patch
+# restore the ugly libata COMBINED_MODE hacks
+ApplyPatch linux-2.6-libata-restore-combined-mode.patch
 
 # Add the new wireless stack and drivers from wireless-dev
 ApplyPatch git-wireless-dev.patch
@@ -2181,6 +2218,12 @@
 %endif
 
 %changelog
+* Thu Jul 19 2007 Chuck Ebbert <cebbert at redhat.com>
+- restore the libata COMBINED_MODE hacks
+- set CONFIG_NF_CONNTRACK_PROC_COMPAT
+- restore the old firewire stack
+- new utrace backport
+
 * Tue Jul 17 2007 Chuck Ebbert <cebbert at redhat.com>
 - disable the nohz and highres kernel options
   by default -- enable with 'nohz=yes highres=yes'




More information about the fedora-cvs-commits mailing list