| From e4cc58944c1e2ce41e3079d4eb60c95e7ce04b2b Mon Sep 17 00:00:00 2001 |
| From: Andreas Schwab <schwab@suse.de> |
| Date: Sun, 20 Apr 2008 02:25:13 +1000 |
| Subject: [PATCH] [POWERPC] Add compat handler for PTRACE_GETSIGINFO |
| |
| From: Andreas Schwab <schwab@suse.de> |
| |
| commit e4cc58944c1e2ce41e3079d4eb60c95e7ce04b2b upstream |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| arch/powerpc/kernel/ppc32.h | 2 ++ |
| arch/powerpc/kernel/ptrace32.c | 27 +++++++++++++++++++++++++++ |
| 2 files changed, 29 insertions(+) |
| |
| --- a/arch/powerpc/kernel/ppc32.h |
| +++ b/arch/powerpc/kernel/ppc32.h |
| @@ -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 */ |
| --- a/arch/powerpc/kernel/ptrace32.c |
| +++ b/arch/powerpc/kernel/ptrace32.c |
| @@ -29,12 +29,15 @@ |
| #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 tas |
| 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_stru |
| 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: |