Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=912000e73ee8fcb97831b123c9c3a7274b71cab7
Commit:     912000e73ee8fcb97831b123c9c3a7274b71cab7
Parent:     1b6610d6fcb8dc23631cf48f09aa02e6649e379d
Author:     Benjamin Herrenschmidt <[EMAIL PROTECTED]>
AuthorDate: Mon Jun 4 15:15:46 2007 +1000
Committer:  Paul Mackerras <[EMAIL PROTECTED]>
CommitDate: Thu Jun 14 22:29:57 2007 +1000

    [POWERPC] Allow ptrace write to pt_regs trap and orig_r3
    
    This patch allows a ptracer to write to the "trap" and "orig_r3" words
    of the pt_regs.
    
    This, along with a subsequent patch to the signal restart code, should
    enable gdb to properly handle syscall restarting after executing a separate
    function (at least when there's no restart block).
    
    This patch also removes ptrace32.c code toying directly with the registers
    and makes it use the ptrace_get/put_reg() accessors for everything so that
    the logic for checking what is permitted is in only one place.
    
    Signed-off-by: Benjamin Herrenschmidt <[EMAIL PROTECTED]>
    Signed-off-by: Paul Mackerras <[EMAIL PROTECTED]>
---
 arch/powerpc/kernel/ptrace.c   |    9 ++++++---
 arch/powerpc/kernel/ptrace32.c |   27 ++++++++++++++-------------
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index c9c330d..dd4837c 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -75,10 +75,15 @@ int ptrace_put_reg(struct task_struct *task, int regno, 
unsigned long data)
        if (task->thread.regs == NULL)
                return -EIO;
 
-       if (regno <= PT_MAX_PUT_REG) {
+       if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
                if (regno == PT_MSR)
                        data = (data & MSR_DEBUGCHANGE)
                                | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
+               /* We prevent mucking around with the reserved area of trap
+                * which are used internally by the kernel
+                */
+               if (regno == PT_TRAP)
+                       data &= 0xfff0;
                ((unsigned long *)task->thread.regs)[regno] = data;
                return 0;
        }
@@ -409,8 +414,6 @@ long arch_ptrace(struct task_struct *child, long request, 
long addr, long data)
                        break;
 
                CHECK_FULL_REGS(child->thread.regs);
-               if (index == PT_ORIG_R3)
-                       break;
                if (index < PT_FPR0) {
                        ret = ptrace_put_reg(child, index, data);
                } else {
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 4511b42..aae6a98 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -206,7 +206,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long 
addr,
                else
                        part = 0;  /* want the 1st half of the register 
(left-most). */
 
-               /* Validate the input - check to see if address is on the wrong 
boundary or beyond the end of the user area */
+               /* Validate the input - check to see if address is on the wrong 
boundary
+                * or beyond the end of the user area
+                */
                if ((addr & 3) || numReg > PT_FPSCR)
                        break;
 
@@ -270,8 +272,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long 
addr,
                if ((addr & 3) || (index > PT_FPSCR32))
                        break;
 
-               if (index == PT_ORIG_R3)
-                       break;
                if (index < PT_FPR0) {
                        ret = ptrace_put_reg(child, index, data);
                } else {
@@ -302,24 +302,25 @@ long compat_sys_ptrace(int request, int pid, unsigned 
long addr,
                /* Determine which register the user wants */
                index = (u64)addr >> 2;
                numReg = index / 2;
+
                /*
                 * Validate the input - check to see if address is on the
                 * wrong boundary or beyond the end of the user area
                 */
                if ((addr & 3) || (numReg > PT_FPSCR))
                        break;
-               /* Insure it is a register we let them change */
-               if ((numReg == PT_ORIG_R3)
-                               || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
-                       break;
-               if (numReg >= PT_FPR0) {
+               if (numReg < PT_FPR0) {
+                       unsigned long freg = ptrace_get_reg(child, numReg);
+                       if (index % 2)
+                               freg = (freg & ~0xfffffffful) | (data & 
0xfffffffful);
+                       else
+                               freg = (freg & 0xfffffffful) | (data << 32);
+                       ret = ptrace_put_reg(child, numReg, freg);
+               } else {
                        flush_fp_to_thread(child);
+                       ((unsigned int *)child->thread.regs)[index] = data;
+                       ret = 0;
                }
-               if (numReg == PT_MSR)
-                       data = (data & MSR_DEBUGCHANGE)
-                               | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
-               ((u32*)child->thread.regs)[index] = data;
-               ret = 0;
                break;
        }
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to