Skip to content

Commit

Permalink
[XTENSA] Allow debugger to modify the WINDOWBASE register.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chris Zankel committed Feb 14, 2008
1 parent bdd362f commit 42086ce
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 32 deletions.
66 changes: 35 additions & 31 deletions arch/xtensa/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,61 +43,65 @@ 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)
{
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;
}


Expand Down
3 changes: 2 additions & 1 deletion include/asm-xtensa/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 42086ce

Please sign in to comment.