diff options
author | Chris Zankel <chris@zankel.net> | 2008-01-28 18:55:01 -0500 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2008-02-13 20:45:36 -0500 |
commit | 42086cec3263b8c015ca3faa01e8190f0e3ff445 (patch) | |
tree | c28564042c13ee09e652dc176b6f8cd87ce10359 /arch/xtensa | |
parent | bdd362ff4ff8dc0c697ce87dbb337f3b7341fc46 (diff) |
[XTENSA] Allow debugger to modify the WINDOWBASE register.
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>
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/kernel/ptrace.c | 66 |
1 files changed, 35 insertions, 31 deletions
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index f6669d605125..9486882ef0af 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c | |||
@@ -43,32 +43,29 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs) | |||
43 | { | 43 | { |
44 | struct pt_regs *regs = task_pt_regs(child); | 44 | struct pt_regs *regs = task_pt_regs(child); |
45 | xtensa_gregset_t __user *gregset = uregs; | 45 | xtensa_gregset_t __user *gregset = uregs; |
46 | unsigned long wb = regs->windowbase; | ||
47 | unsigned long ws = regs->windowstart; | ||
48 | unsigned long wm = regs->wmask; | 46 | unsigned long wm = regs->wmask; |
49 | int ret = 0; | 47 | unsigned long wb = regs->windowbase; |
50 | int live, last; | 48 | int live, i; |
51 | 49 | ||
52 | if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) | 50 | if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) |
53 | return -EIO; | 51 | return -EIO; |
54 | 52 | ||
55 | /* Norm windowstart to a windowbase of 0. */ | 53 | __put_user(regs->pc, &gregset->pc); |
56 | 54 | __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); | |
57 | ws = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1); | 55 | __put_user(regs->lbeg, &gregset->lbeg); |
58 | 56 | __put_user(regs->lend, &gregset->lend); | |
59 | ret |= __put_user(regs->pc, &gregset->pc); | 57 | __put_user(regs->lcount, &gregset->lcount); |
60 | ret |= __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); | 58 | __put_user(regs->windowstart, &gregset->windowstart); |
61 | ret |= __put_user(regs->lbeg, &gregset->lbeg); | 59 | __put_user(regs->windowbase, &gregset->windowbase); |
62 | ret |= __put_user(regs->lend, &gregset->lend); | ||
63 | ret |= __put_user(regs->lcount, &gregset->lcount); | ||
64 | ret |= __put_user(ws, &gregset->windowstart); | ||
65 | 60 | ||
66 | live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; | 61 | live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; |
67 | last = XCHAL_NUM_AREGS - (wm >> 4) * 4; | ||
68 | ret |= __copy_to_user(gregset->a, regs->areg, live * 4); | ||
69 | ret |= __copy_to_user(gregset->a + last, regs->areg + last, (wm>>4)*16); | ||
70 | 62 | ||
71 | return ret ? -EFAULT : 0; | 63 | for (i = 0; i < live; i++) |
64 | __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); | ||
65 | for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++) | ||
66 | __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); | ||
67 | |||
68 | return 0; | ||
72 | } | 69 | } |
73 | 70 | ||
74 | int ptrace_setregs(struct task_struct *child, void __user *uregs) | 71 | int ptrace_setregs(struct task_struct *child, void __user *uregs) |
@@ -76,28 +73,35 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs) | |||
76 | struct pt_regs *regs = task_pt_regs(child); | 73 | struct pt_regs *regs = task_pt_regs(child); |
77 | xtensa_gregset_t *gregset = uregs; | 74 | xtensa_gregset_t *gregset = uregs; |
78 | const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; | 75 | const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; |
79 | unsigned long wm = regs->wmask; | ||
80 | unsigned long ps; | 76 | unsigned long ps; |
81 | int ret = 0; | 77 | unsigned long wb; |
82 | int live, last; | ||
83 | 78 | ||
84 | if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) | 79 | if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) |
85 | return -EIO; | 80 | return -EIO; |
86 | 81 | ||
87 | ret |= __get_user(regs->pc, &gregset->pc); | 82 | __get_user(regs->pc, &gregset->pc); |
88 | ret |= __get_user(ps, &gregset->ps); | 83 | __get_user(ps, &gregset->ps); |
89 | ret |= __get_user(regs->lbeg, &gregset->lbeg); | 84 | __get_user(regs->lbeg, &gregset->lbeg); |
90 | ret |= __get_user(regs->lend, &gregset->lend); | 85 | __get_user(regs->lend, &gregset->lend); |
91 | ret |= __get_user(regs->lcount, &gregset->lcount); | 86 | __get_user(regs->lcount, &gregset->lcount); |
87 | __get_user(regs->windowstart, &gregset->windowstart); | ||
88 | __get_user(wb, &gregset->windowbase); | ||
92 | 89 | ||
93 | regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); | 90 | regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); |
94 | 91 | ||
95 | live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; | 92 | if (wb >= XCHAL_NUM_AREGS / 4) |
96 | last = XCHAL_NUM_AREGS - (wm >> 4) * 4; | 93 | return -EFAULT; |
97 | ret |= __copy_from_user(regs->areg, gregset->a, live * 4); | ||
98 | ret |= __copy_from_user(regs->areg+last, gregset->a+last, (wm>>4)*16); | ||
99 | 94 | ||
100 | return ret ? -EFAULT : 0; | 95 | regs->windowbase = wb; |
96 | |||
97 | if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4, | ||
98 | gregset->a, wb * 16)) | ||
99 | return -EFAULT; | ||
100 | |||
101 | if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16)) | ||
102 | return -EFAULT; | ||
103 | |||
104 | return 0; | ||
101 | } | 105 | } |
102 | 106 | ||
103 | 107 | ||