[XTENSA] Allow debugger to modify the WINDOWBASE register.
authorChris Zankel <chris@zankel.net>
Mon, 28 Jan 2008 23:55:01 +0000 (15:55 -0800)
committerChris Zankel <chris@zankel.net>
Thu, 14 Feb 2008 01:45:36 +0000 (17:45 -0800)
For the 'return' command, GDB needs to adjust WINDOWBASE.
In case WB is different from 0, we need to rotate the
window register file and update WINDOWSTART and WMASK.
This patch also removes some ret|= statements for
__get_user/__put_user as the address range was alrady
checked a couple of lines earlier.

Signed-off-by: Chris Zankel <chris@zankel.net>
arch/xtensa/kernel/ptrace.c
include/asm-xtensa/elf.h

index f6669d605125a6d6d824b07308dbf6fc48675a92..9486882ef0afa8318fca682d24ff3c382c18997b 100644 (file)
@@ -43,32 +43,29 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs)
 {
        struct pt_regs *regs = task_pt_regs(child);
        xtensa_gregset_t __user *gregset = uregs;
-       unsigned long wb = regs->windowbase;
-       unsigned long ws = regs->windowstart;
        unsigned long wm = regs->wmask;
-       int ret = 0;
-       int live, last;
+       unsigned long wb = regs->windowbase;
+       int live, i;
 
        if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
                return -EIO;
 
-       /* Norm windowstart to a windowbase of 0. */
-
-       ws = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1);
-
-       ret |= __put_user(regs->pc, &gregset->pc);
-       ret |= __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
-       ret |= __put_user(regs->lbeg, &gregset->lbeg);
-       ret |= __put_user(regs->lend, &gregset->lend);
-       ret |= __put_user(regs->lcount, &gregset->lcount);
-       ret |= __put_user(ws, &gregset->windowstart);
+       __put_user(regs->pc, &gregset->pc);
+       __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
+       __put_user(regs->lbeg, &gregset->lbeg);
+       __put_user(regs->lend, &gregset->lend);
+       __put_user(regs->lcount, &gregset->lcount);
+       __put_user(regs->windowstart, &gregset->windowstart);
+       __put_user(regs->windowbase, &gregset->windowbase);
 
        live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
-       last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
-       ret |= __copy_to_user(gregset->a, regs->areg, live * 4);
-       ret |= __copy_to_user(gregset->a + last, regs->areg + last, (wm>>4)*16);
 
-       return ret ? -EFAULT : 0;
+       for (i = 0; i < live; i++)
+               __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
+       for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++)
+               __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
+
+       return 0;
 }
 
 int ptrace_setregs(struct task_struct *child, void __user *uregs)
@@ -76,28 +73,35 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs)
        struct pt_regs *regs = task_pt_regs(child);
        xtensa_gregset_t *gregset = uregs;
        const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
-       unsigned long wm = regs->wmask;
        unsigned long ps;
-       int ret = 0;
-       int live, last;
+       unsigned long wb;
 
        if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
                return -EIO;
 
-       ret |= __get_user(regs->pc, &gregset->pc);
-       ret |= __get_user(ps, &gregset->ps);
-       ret |= __get_user(regs->lbeg, &gregset->lbeg);
-       ret |= __get_user(regs->lend, &gregset->lend);
-       ret |= __get_user(regs->lcount, &gregset->lcount);
+       __get_user(regs->pc, &gregset->pc);
+       __get_user(ps, &gregset->ps);
+       __get_user(regs->lbeg, &gregset->lbeg);
+       __get_user(regs->lend, &gregset->lend);
+       __get_user(regs->lcount, &gregset->lcount);
+       __get_user(regs->windowstart, &gregset->windowstart);
+       __get_user(wb, &gregset->windowbase);
 
        regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT);
 
-       live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
-       last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
-       ret |= __copy_from_user(regs->areg, gregset->a, live * 4);
-       ret |= __copy_from_user(regs->areg+last, gregset->a+last, (wm>>4)*16);
+       if (wb >= XCHAL_NUM_AREGS / 4)
+               return -EFAULT;
 
-       return ret ? -EFAULT : 0;
+       regs->windowbase = wb;
+
+       if (wb != 0 &&  __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
+                                        gregset->a, wb * 16))
+               return -EFAULT;
+
+       if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16))
+               return -EFAULT;
+
+       return 0;
 }
 
 
index 11103e07d028b233fa6560b32d0fb99c5a0f2522..ca6e5101a2cba6fb021fec6891193653660ecd64 100644 (file)
@@ -82,7 +82,8 @@ typedef struct {
        elf_greg_t lcount;
        elf_greg_t sar;
        elf_greg_t windowstart;
-       elf_greg_t reserved[9+48];
+       elf_greg_t windowbase;
+       elf_greg_t reserved[8+48];
        elf_greg_t a[64];
 } xtensa_gregset_t;