[POWERPC] Add compat handler for PTRACE_GETSIGINFO
authorAndreas Schwab <schwab@suse.de>
Sat, 19 Apr 2008 16:25:13 +0000 (02:25 +1000)
committerPaul Mackerras <paulus@samba.org>
Sun, 20 Apr 2008 03:03:36 +0000 (13:03 +1000)
Current versions of gdb require a working implementation of
PTRACE_GETSIGINFO for proper watchpoint support.  Since struct siginfo
contains pointers it must be converted when passed to a 32-bit debugger.

Signed-off-by: Andreas Schwab <schwab@suse.de>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/kernel/ppc32.h
arch/powerpc/kernel/ptrace32.c

index 90e5627..fda05e2 100644 (file)
@@ -135,4 +135,6 @@ struct ucontext32 {
        struct mcontext32       uc_mcontext;
 };
 
+extern int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s);
+
 #endif  /* _PPC64_PPC32_H */
index 4c1de6a..9d30e10 100644 (file)
 #include <linux/security.h>
 #include <linux/signal.h>
 #include <linux/compat.h>
+#include <linux/elf.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
+#include "ppc32.h"
+
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
@@ -64,6 +67,27 @@ static long compat_ptrace_old(struct task_struct *child, long request,
        return -EPERM;
 }
 
+static int compat_ptrace_getsiginfo(struct task_struct *child, compat_siginfo_t __user *data)
+{
+       siginfo_t lastinfo;
+       int error = -ESRCH;
+
+       read_lock(&tasklist_lock);
+       if (likely(child->sighand != NULL)) {
+               error = -EINVAL;
+               spin_lock_irq(&child->sighand->siglock);
+               if (likely(child->last_siginfo != NULL)) {
+                       lastinfo = *child->last_siginfo;
+                       error = 0;
+               }
+               spin_unlock_irq(&child->sighand->siglock);
+       }
+       read_unlock(&tasklist_lock);
+       if (!error)
+               return copy_siginfo_to_user32(data, &lastinfo);
+       return error;
+}
+
 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        compat_ulong_t caddr, compat_ulong_t cdata)
 {
@@ -282,6 +306,9 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        0, PT_REGS_COUNT * sizeof(compat_long_t),
                        compat_ptr(data));
 
+       case PTRACE_GETSIGINFO:
+               return compat_ptrace_getsiginfo(child, compat_ptr(data));
+
        case PTRACE_GETFPREGS:
        case PTRACE_SETFPREGS:
        case PTRACE_GETVRREGS: