Blame view
arch/xtensa/kernel/ptrace.c
8.07 KB
5a0015d62 [PATCH] xtensa: A... |
1 2 3 4 5 6 |
// TODO some minor issues /* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * |
c658eac62 [XTENSA] Add supp... |
7 |
* Copyright (C) 2001 - 2007 Tensilica Inc. |
5a0015d62 [PATCH] xtensa: A... |
8 9 10 11 12 13 14 |
* * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> * Chris Zankel <chris@zankel.net> * Scott Foehner<sfoehner@yahoo.com>, * Kevin Chea * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> */ |
5a0015d62 [PATCH] xtensa: A... |
15 16 17 18 19 20 |
#include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/smp.h> |
5a0015d62 [PATCH] xtensa: A... |
21 |
#include <linux/security.h> |
0ee23b50f [PATCH] xtensa: u... |
22 |
#include <linux/signal.h> |
5a0015d62 [PATCH] xtensa: A... |
23 24 25 26 27 28 29 |
#include <asm/pgtable.h> #include <asm/page.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/ptrace.h> #include <asm/elf.h> |
c658eac62 [XTENSA] Add supp... |
30 |
#include <asm/coprocessor.h> |
5a0015d62 [PATCH] xtensa: A... |
31 |
|
6d75ca102 xtensa: use gener... |
32 33 34 35 36 37 38 39 40 41 |
void user_enable_single_step(struct task_struct *child) { child->ptrace |= PT_SINGLESTEP; } void user_disable_single_step(struct task_struct *child) { child->ptrace &= ~PT_SINGLESTEP; } |
5a0015d62 [PATCH] xtensa: A... |
42 |
/* |
c658eac62 [XTENSA] Add supp... |
43 |
* Called by kernel/ptrace.c when detaching to disable single stepping. |
5a0015d62 [PATCH] xtensa: A... |
44 45 46 47 48 49 |
*/ void ptrace_disable(struct task_struct *child) { /* Nothing to do.. */ } |
c658eac62 [XTENSA] Add supp... |
50 |
int ptrace_getregs(struct task_struct *child, void __user *uregs) |
5a0015d62 [PATCH] xtensa: A... |
51 |
{ |
c658eac62 [XTENSA] Add supp... |
52 53 |
struct pt_regs *regs = task_pt_regs(child); xtensa_gregset_t __user *gregset = uregs; |
c658eac62 [XTENSA] Add supp... |
54 |
unsigned long wm = regs->wmask; |
42086cec3 [XTENSA] Allow de... |
55 56 |
unsigned long wb = regs->windowbase; int live, i; |
c658eac62 [XTENSA] Add supp... |
57 58 59 |
if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) return -EIO; |
42086cec3 [XTENSA] Allow de... |
60 61 62 63 64 65 66 |
__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); |
c658eac62 [XTENSA] Add supp... |
67 68 |
live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; |
c658eac62 [XTENSA] Add supp... |
69 |
|
42086cec3 [XTENSA] Allow de... |
70 71 72 73 74 75 |
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; |
c658eac62 [XTENSA] Add supp... |
76 |
} |
5a0015d62 [PATCH] xtensa: A... |
77 |
|
c658eac62 [XTENSA] Add supp... |
78 79 80 81 82 |
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; |
c658eac62 [XTENSA] Add supp... |
83 |
unsigned long ps; |
42086cec3 [XTENSA] Allow de... |
84 |
unsigned long wb; |
c658eac62 [XTENSA] Add supp... |
85 86 87 |
if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) return -EIO; |
42086cec3 [XTENSA] Allow de... |
88 89 90 91 92 93 94 |
__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); |
c658eac62 [XTENSA] Add supp... |
95 96 |
regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); |
42086cec3 [XTENSA] Allow de... |
97 98 |
if (wb >= XCHAL_NUM_AREGS / 4) return -EFAULT; |
c658eac62 [XTENSA] Add supp... |
99 |
|
42086cec3 [XTENSA] Allow de... |
100 101 102 103 104 105 106 107 108 109 |
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; |
c658eac62 [XTENSA] Add supp... |
110 |
} |
5a0015d62 [PATCH] xtensa: A... |
111 |
|
5a0015d62 [PATCH] xtensa: A... |
112 |
|
c658eac62 [XTENSA] Add supp... |
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
int ptrace_getxregs(struct task_struct *child, void __user *uregs) { struct pt_regs *regs = task_pt_regs(child); struct thread_info *ti = task_thread_info(child); elf_xtregs_t __user *xtregs = uregs; int ret = 0; if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t))) return -EIO; #if XTENSA_HAVE_COPROCESSORS /* Flush all coprocessor registers to memory. */ coprocessor_flush_all(ti); ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp, sizeof(xtregs_coprocessor_t)); #endif ret |= __copy_to_user(&xtregs->opt, ®s->xtregs_opt, sizeof(xtregs->opt)); ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user, sizeof(xtregs->user)); |
5a0015d62 [PATCH] xtensa: A... |
133 |
|
c658eac62 [XTENSA] Add supp... |
134 135 136 137 138 139 140 141 142 |
return ret ? -EFAULT : 0; } int ptrace_setxregs(struct task_struct *child, void __user *uregs) { struct thread_info *ti = task_thread_info(child); struct pt_regs *regs = task_pt_regs(child); elf_xtregs_t *xtregs = uregs; int ret = 0; |
0d0138ebe xtensa: prevent a... |
143 144 |
if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t))) return -EFAULT; |
c658eac62 [XTENSA] Add supp... |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
#if XTENSA_HAVE_COPROCESSORS /* Flush all coprocessors before we overwrite them. */ coprocessor_flush_all(ti); coprocessor_release_all(ti); ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, sizeof(xtregs_coprocessor_t)); #endif ret |= __copy_from_user(®s->xtregs_opt, &xtregs->opt, sizeof(xtregs->opt)); ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user, sizeof(xtregs->user)); return ret ? -EFAULT : 0; } int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret) { struct pt_regs *regs; unsigned long tmp; regs = task_pt_regs(child); tmp = 0; /* Default return value. */ |
5a0015d62 [PATCH] xtensa: A... |
168 |
|
c658eac62 [XTENSA] Add supp... |
169 |
switch(regno) { |
5a0015d62 [PATCH] xtensa: A... |
170 171 |
case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: |
c658eac62 [XTENSA] Add supp... |
172 |
tmp = regs->areg[regno - REG_AR_BASE]; |
5a0015d62 [PATCH] xtensa: A... |
173 |
break; |
c658eac62 [XTENSA] Add supp... |
174 |
|
5a0015d62 [PATCH] xtensa: A... |
175 |
case REG_A_BASE ... REG_A_BASE + 15: |
c658eac62 [XTENSA] Add supp... |
176 |
tmp = regs->areg[regno - REG_A_BASE]; |
5a0015d62 [PATCH] xtensa: A... |
177 |
break; |
c658eac62 [XTENSA] Add supp... |
178 |
|
5a0015d62 [PATCH] xtensa: A... |
179 180 181 |
case REG_PC: tmp = regs->pc; break; |
c658eac62 [XTENSA] Add supp... |
182 |
|
5a0015d62 [PATCH] xtensa: A... |
183 184 185 186 |
case REG_PS: /* Note: PS.EXCM is not set while user task is running; * its being set in regs is for exception handling * convenience. */ |
173d66813 [PATCH] xtensa: r... |
187 |
tmp = (regs->ps & ~(1 << PS_EXCM_BIT)); |
5a0015d62 [PATCH] xtensa: A... |
188 |
break; |
c658eac62 [XTENSA] Add supp... |
189 |
|
5a0015d62 [PATCH] xtensa: A... |
190 |
case REG_WB: |
c658eac62 [XTENSA] Add supp... |
191 |
break; /* tmp = 0 */ |
5a0015d62 [PATCH] xtensa: A... |
192 |
case REG_WS: |
c658eac62 [XTENSA] Add supp... |
193 194 195 196 |
{ unsigned long wb = regs->windowbase; unsigned long ws = regs->windowstart; tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1); |
5a0015d62 [PATCH] xtensa: A... |
197 |
break; |
c658eac62 [XTENSA] Add supp... |
198 |
} |
5a0015d62 [PATCH] xtensa: A... |
199 200 201 |
case REG_LBEG: tmp = regs->lbeg; break; |
c658eac62 [XTENSA] Add supp... |
202 |
|
5a0015d62 [PATCH] xtensa: A... |
203 204 205 |
case REG_LEND: tmp = regs->lend; break; |
c658eac62 [XTENSA] Add supp... |
206 |
|
5a0015d62 [PATCH] xtensa: A... |
207 208 209 |
case REG_LCOUNT: tmp = regs->lcount; break; |
c658eac62 [XTENSA] Add supp... |
210 |
|
5a0015d62 [PATCH] xtensa: A... |
211 212 213 |
case REG_SAR: tmp = regs->sar; break; |
c658eac62 [XTENSA] Add supp... |
214 |
|
5a0015d62 [PATCH] xtensa: A... |
215 216 217 |
case SYSCALL_NR: tmp = regs->syscall; break; |
5a0015d62 [PATCH] xtensa: A... |
218 |
|
c658eac62 [XTENSA] Add supp... |
219 220 221 222 223 |
default: return -EIO; } return put_user(tmp, ret); } |
5a0015d62 [PATCH] xtensa: A... |
224 |
|
c658eac62 [XTENSA] Add supp... |
225 226 227 228 |
int ptrace_pokeusr(struct task_struct *child, long regno, long val) { struct pt_regs *regs; regs = task_pt_regs(child); |
5a0015d62 [PATCH] xtensa: A... |
229 |
|
c658eac62 [XTENSA] Add supp... |
230 |
switch (regno) { |
5a0015d62 [PATCH] xtensa: A... |
231 |
case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: |
c658eac62 [XTENSA] Add supp... |
232 |
regs->areg[regno - REG_AR_BASE] = val; |
5a0015d62 [PATCH] xtensa: A... |
233 |
break; |
c658eac62 [XTENSA] Add supp... |
234 |
|
5a0015d62 [PATCH] xtensa: A... |
235 |
case REG_A_BASE ... REG_A_BASE + 15: |
c658eac62 [XTENSA] Add supp... |
236 |
regs->areg[regno - REG_A_BASE] = val; |
5a0015d62 [PATCH] xtensa: A... |
237 |
break; |
c658eac62 [XTENSA] Add supp... |
238 |
|
5a0015d62 [PATCH] xtensa: A... |
239 |
case REG_PC: |
c658eac62 [XTENSA] Add supp... |
240 |
regs->pc = val; |
5a0015d62 [PATCH] xtensa: A... |
241 |
break; |
c658eac62 [XTENSA] Add supp... |
242 |
|
5a0015d62 [PATCH] xtensa: A... |
243 |
case SYSCALL_NR: |
c658eac62 [XTENSA] Add supp... |
244 |
regs->syscall = val; |
5a0015d62 [PATCH] xtensa: A... |
245 |
break; |
5a0015d62 [PATCH] xtensa: A... |
246 247 |
default: |
c658eac62 [XTENSA] Add supp... |
248 249 250 251 |
return -EIO; } return 0; } |
9b05a69e0 ptrace: change si... |
252 253 |
long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) |
c658eac62 [XTENSA] Add supp... |
254 255 |
{ int ret = -EPERM; |
5ef45079d ptrace: cleanup a... |
256 |
void __user *datap = (void __user *) data; |
c658eac62 [XTENSA] Add supp... |
257 258 259 260 261 262 263 264 |
switch (request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: ret = generic_ptrace_peekdata(child, addr, data); break; case PTRACE_PEEKUSR: /* read register specified by addr. */ |
5ef45079d ptrace: cleanup a... |
265 |
ret = ptrace_peekusr(child, addr, datap); |
c658eac62 [XTENSA] Add supp... |
266 267 268 269 270 271 272 273 274 |
break; case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = generic_ptrace_pokedata(child, addr, data); break; case PTRACE_POKEUSR: /* write register specified by addr. */ ret = ptrace_pokeusr(child, addr, data); |
5a0015d62 [PATCH] xtensa: A... |
275 |
break; |
5a0015d62 [PATCH] xtensa: A... |
276 |
|
5a0015d62 [PATCH] xtensa: A... |
277 |
case PTRACE_GETREGS: |
5ef45079d ptrace: cleanup a... |
278 |
ret = ptrace_getregs(child, datap); |
5a0015d62 [PATCH] xtensa: A... |
279 |
break; |
5a0015d62 [PATCH] xtensa: A... |
280 281 |
case PTRACE_SETREGS: |
5ef45079d ptrace: cleanup a... |
282 |
ret = ptrace_setregs(child, datap); |
5a0015d62 [PATCH] xtensa: A... |
283 |
break; |
5a0015d62 [PATCH] xtensa: A... |
284 |
|
c658eac62 [XTENSA] Add supp... |
285 |
case PTRACE_GETXTREGS: |
5ef45079d ptrace: cleanup a... |
286 |
ret = ptrace_getxregs(child, datap); |
5a0015d62 [PATCH] xtensa: A... |
287 |
break; |
5a0015d62 [PATCH] xtensa: A... |
288 |
|
c658eac62 [XTENSA] Add supp... |
289 |
case PTRACE_SETXTREGS: |
5ef45079d ptrace: cleanup a... |
290 |
ret = ptrace_setxregs(child, datap); |
5a0015d62 [PATCH] xtensa: A... |
291 |
break; |
5a0015d62 [PATCH] xtensa: A... |
292 293 |
default: ret = ptrace_request(child, request, addr, data); |
c658eac62 [XTENSA] Add supp... |
294 |
break; |
5a0015d62 [PATCH] xtensa: A... |
295 |
} |
c658eac62 [XTENSA] Add supp... |
296 |
|
5a0015d62 [PATCH] xtensa: A... |
297 298 299 300 301 |
return ret; } void do_syscall_trace(void) { |
5a0015d62 [PATCH] xtensa: A... |
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
/* * The 0x80 provides a way for the tracing parent to distinguish * between a syscall stop and SIGTRAP delivery */ ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ if (current->exit_code) { send_sig(current->exit_code, current, 1); current->exit_code = 0; } } |
fc4fb2adf [PATCH] xtensa: f... |
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
void do_syscall_trace_enter(struct pt_regs *regs) { if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) do_syscall_trace(); #if 0 if (unlikely(current->audit_context)) audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); #endif } void do_syscall_trace_leave(struct pt_regs *regs) { if ((test_thread_flag(TIF_SYSCALL_TRACE)) && (current->ptrace & PT_PTRACED)) do_syscall_trace(); } |