aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r--arch/powerpc/kernel/ptrace.c325
1 files changed, 218 insertions, 107 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index bf76562167c3..0fb53950da43 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -35,11 +35,11 @@
35#include <asm/pgtable.h> 35#include <asm/pgtable.h>
36#include <asm/system.h> 36#include <asm/system.h>
37 37
38#ifdef CONFIG_PPC64 38/*
39#include "ptrace-common.h" 39 * does not yet catch signals sent when the child dies.
40#endif 40 * in exit.c or in signal.c.
41 */
41 42
42#ifdef CONFIG_PPC32
43/* 43/*
44 * Set of msr bits that gdb can change on behalf of a process. 44 * Set of msr bits that gdb can change on behalf of a process.
45 */ 45 */
@@ -48,65 +48,117 @@
48#else 48#else
49#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE) 49#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
50#endif 50#endif
51#endif /* CONFIG_PPC32 */
52 51
53/* 52/*
54 * does not yet catch signals sent when the child dies. 53 * Max register writeable via put_reg
55 * in exit.c or in signal.c.
56 */ 54 */
57
58#ifdef CONFIG_PPC32 55#ifdef CONFIG_PPC32
56#define PT_MAX_PUT_REG PT_MQ
57#else
58#define PT_MAX_PUT_REG PT_CCR
59#endif
60
59/* 61/*
60 * Get contents of register REGNO in task TASK. 62 * Get contents of register REGNO in task TASK.
61 */ 63 */
62static inline unsigned long get_reg(struct task_struct *task, int regno) 64unsigned long ptrace_get_reg(struct task_struct *task, int regno)
63{ 65{
64 if (regno < sizeof(struct pt_regs) / sizeof(unsigned long) 66 unsigned long tmp = 0;
65 && task->thread.regs != NULL) 67
68 if (task->thread.regs == NULL)
69 return -EIO;
70
71 if (regno == PT_MSR) {
72 tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
73 return tmp | task->thread.fpexc_mode;
74 }
75
76 if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
66 return ((unsigned long *)task->thread.regs)[regno]; 77 return ((unsigned long *)task->thread.regs)[regno];
67 return (0); 78
79 return -EIO;
68} 80}
69 81
70/* 82/*
71 * Write contents of register REGNO in task TASK. 83 * Write contents of register REGNO in task TASK.
72 */ 84 */
73static inline int put_reg(struct task_struct *task, int regno, 85int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
74 unsigned long data)
75{ 86{
76 if (regno <= PT_MQ && task->thread.regs != NULL) { 87 if (task->thread.regs == NULL)
88 return -EIO;
89
90 if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
77 if (regno == PT_MSR) 91 if (regno == PT_MSR)
78 data = (data & MSR_DEBUGCHANGE) 92 data = (data & MSR_DEBUGCHANGE)
79 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); 93 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
94 /* We prevent mucking around with the reserved area of trap
95 * which are used internally by the kernel
96 */
97 if (regno == PT_TRAP)
98 data &= 0xfff0;
80 ((unsigned long *)task->thread.regs)[regno] = data; 99 ((unsigned long *)task->thread.regs)[regno] = data;
81 return 0; 100 return 0;
82 } 101 }
83 return -EIO; 102 return -EIO;
84} 103}
85 104
105
106static int get_fpregs(void __user *data, struct task_struct *task,
107 int has_fpscr)
108{
109 unsigned int count = has_fpscr ? 33 : 32;
110
111 if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
112 return -EFAULT;
113 return 0;
114}
115
116static int set_fpregs(void __user *data, struct task_struct *task,
117 int has_fpscr)
118{
119 unsigned int count = has_fpscr ? 33 : 32;
120
121 if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
122 return -EFAULT;
123 return 0;
124}
125
126
86#ifdef CONFIG_ALTIVEC 127#ifdef CONFIG_ALTIVEC
87/* 128/*
129 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
130 * The transfer totals 34 quadword. Quadwords 0-31 contain the
131 * corresponding vector registers. Quadword 32 contains the vscr as the
132 * last word (offset 12) within that quadword. Quadword 33 contains the
133 * vrsave as the first word (offset 0) within the quadword.
134 *
135 * This definition of the VMX state is compatible with the current PPC32
136 * ptrace interface. This allows signal handling and ptrace to use the
137 * same structures. This also simplifies the implementation of a bi-arch
138 * (combined (32- and 64-bit) gdb.
139 */
140
141/*
88 * Get contents of AltiVec register state in task TASK 142 * Get contents of AltiVec register state in task TASK
89 */ 143 */
90static inline int get_vrregs(unsigned long __user *data, struct task_struct *task) 144static int get_vrregs(unsigned long __user *data, struct task_struct *task)
91{ 145{
92 int i, j; 146 unsigned long regsize;
93
94 if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
95 return -EFAULT;
96 147
97 /* copy AltiVec registers VR[0] .. VR[31] */ 148 /* copy AltiVec registers VR[0] .. VR[31] */
98 for (i = 0; i < 32; i++) 149 regsize = 32 * sizeof(vector128);
99 for (j = 0; j < 4; j++, data++) 150 if (copy_to_user(data, task->thread.vr, regsize))
100 if (__put_user(task->thread.vr[i].u[j], data)) 151 return -EFAULT;
101 return -EFAULT; 152 data += (regsize / sizeof(unsigned long));
102 153
103 /* copy VSCR */ 154 /* copy VSCR */
104 for (i = 0; i < 4; i++, data++) 155 regsize = 1 * sizeof(vector128);
105 if (__put_user(task->thread.vscr.u[i], data)) 156 if (copy_to_user(data, &task->thread.vscr, regsize))
106 return -EFAULT; 157 return -EFAULT;
158 data += (regsize / sizeof(unsigned long));
107 159
108 /* copy VRSAVE */ 160 /* copy VRSAVE */
109 if (__put_user(task->thread.vrsave, data)) 161 if (put_user(task->thread.vrsave, (u32 __user *)data))
110 return -EFAULT; 162 return -EFAULT;
111 163
112 return 0; 164 return 0;
@@ -115,31 +167,29 @@ static inline int get_vrregs(unsigned long __user *data, struct task_struct *tas
115/* 167/*
116 * Write contents of AltiVec register state into task TASK. 168 * Write contents of AltiVec register state into task TASK.
117 */ 169 */
118static inline int set_vrregs(struct task_struct *task, unsigned long __user *data) 170static int set_vrregs(struct task_struct *task, unsigned long __user *data)
119{ 171{
120 int i, j; 172 unsigned long regsize;
121
122 if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
123 return -EFAULT;
124 173
125 /* copy AltiVec registers VR[0] .. VR[31] */ 174 /* copy AltiVec registers VR[0] .. VR[31] */
126 for (i = 0; i < 32; i++) 175 regsize = 32 * sizeof(vector128);
127 for (j = 0; j < 4; j++, data++) 176 if (copy_from_user(task->thread.vr, data, regsize))
128 if (__get_user(task->thread.vr[i].u[j], data)) 177 return -EFAULT;
129 return -EFAULT; 178 data += (regsize / sizeof(unsigned long));
130 179
131 /* copy VSCR */ 180 /* copy VSCR */
132 for (i = 0; i < 4; i++, data++) 181 regsize = 1 * sizeof(vector128);
133 if (__get_user(task->thread.vscr.u[i], data)) 182 if (copy_from_user(&task->thread.vscr, data, regsize))
134 return -EFAULT; 183 return -EFAULT;
184 data += (regsize / sizeof(unsigned long));
135 185
136 /* copy VRSAVE */ 186 /* copy VRSAVE */
137 if (__get_user(task->thread.vrsave, data)) 187 if (get_user(task->thread.vrsave, (u32 __user *)data))
138 return -EFAULT; 188 return -EFAULT;
139 189
140 return 0; 190 return 0;
141} 191}
142#endif 192#endif /* CONFIG_ALTIVEC */
143 193
144#ifdef CONFIG_SPE 194#ifdef CONFIG_SPE
145 195
@@ -156,7 +206,7 @@ static inline int set_vrregs(struct task_struct *task, unsigned long __user *dat
156/* 206/*
157 * Get contents of SPE register state in task TASK. 207 * Get contents of SPE register state in task TASK.
158 */ 208 */
159static inline int get_evrregs(unsigned long *data, struct task_struct *task) 209static int get_evrregs(unsigned long *data, struct task_struct *task)
160{ 210{
161 int i; 211 int i;
162 212
@@ -182,7 +232,7 @@ static inline int get_evrregs(unsigned long *data, struct task_struct *task)
182/* 232/*
183 * Write contents of SPE register state into task TASK. 233 * Write contents of SPE register state into task TASK.
184 */ 234 */
185static inline int set_evrregs(struct task_struct *task, unsigned long *data) 235static int set_evrregs(struct task_struct *task, unsigned long *data)
186{ 236{
187 int i; 237 int i;
188 238
@@ -205,8 +255,8 @@ static inline int set_evrregs(struct task_struct *task, unsigned long *data)
205} 255}
206#endif /* CONFIG_SPE */ 256#endif /* CONFIG_SPE */
207 257
208static inline void 258
209set_single_step(struct task_struct *task) 259static void set_single_step(struct task_struct *task)
210{ 260{
211 struct pt_regs *regs = task->thread.regs; 261 struct pt_regs *regs = task->thread.regs;
212 262
@@ -221,8 +271,7 @@ set_single_step(struct task_struct *task)
221 set_tsk_thread_flag(task, TIF_SINGLESTEP); 271 set_tsk_thread_flag(task, TIF_SINGLESTEP);
222} 272}
223 273
224static inline void 274static void clear_single_step(struct task_struct *task)
225clear_single_step(struct task_struct *task)
226{ 275{
227 struct pt_regs *regs = task->thread.regs; 276 struct pt_regs *regs = task->thread.regs;
228 277
@@ -236,7 +285,25 @@ clear_single_step(struct task_struct *task)
236 } 285 }
237 clear_tsk_thread_flag(task, TIF_SINGLESTEP); 286 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
238} 287}
239#endif /* CONFIG_PPC32 */ 288
289static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
290 unsigned long data)
291{
292 /* We only support one DABR and no IABRS at the moment */
293 if (addr > 0)
294 return -EINVAL;
295
296 /* The bottom 3 bits are flags */
297 if ((data & ~0x7UL) >= TASK_SIZE)
298 return -EIO;
299
300 /* Ensure translation is on */
301 if (data && !(data & DABR_TRANSLATION))
302 return -EIO;
303
304 task->thread.dabr = data;
305 return 0;
306}
240 307
241/* 308/*
242 * Called by kernel/ptrace.c when detaching.. 309 * Called by kernel/ptrace.c when detaching..
@@ -249,6 +316,62 @@ void ptrace_disable(struct task_struct *child)
249 clear_single_step(child); 316 clear_single_step(child);
250} 317}
251 318
319/*
320 * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
321 * we mark them as obsolete now, they will be removed in a future version
322 */
323static long arch_ptrace_old(struct task_struct *child, long request, long addr,
324 long data)
325{
326 int ret = -EPERM;
327
328 switch(request) {
329 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
330 int i;
331 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
332 unsigned long __user *tmp = (unsigned long __user *)addr;
333
334 for (i = 0; i < 32; i++) {
335 ret = put_user(*reg, tmp);
336 if (ret)
337 break;
338 reg++;
339 tmp++;
340 }
341 break;
342 }
343
344 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
345 int i;
346 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
347 unsigned long __user *tmp = (unsigned long __user *)addr;
348
349 for (i = 0; i < 32; i++) {
350 ret = get_user(*reg, tmp);
351 if (ret)
352 break;
353 reg++;
354 tmp++;
355 }
356 break;
357 }
358
359 case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
360 flush_fp_to_thread(child);
361 ret = get_fpregs((void __user *)addr, child, 0);
362 break;
363 }
364
365 case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
366 flush_fp_to_thread(child);
367 ret = set_fpregs((void __user *)addr, child, 0);
368 break;
369 }
370
371 }
372 return ret;
373}
374
252long arch_ptrace(struct task_struct *child, long request, long addr, long data) 375long arch_ptrace(struct task_struct *child, long request, long addr, long data)
253{ 376{
254 int ret = -EPERM; 377 int ret = -EPERM;
@@ -284,11 +407,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
284#endif 407#endif
285 break; 408 break;
286 409
287#ifdef CONFIG_PPC32
288 CHECK_FULL_REGS(child->thread.regs); 410 CHECK_FULL_REGS(child->thread.regs);
289#endif
290 if (index < PT_FPR0) { 411 if (index < PT_FPR0) {
291 tmp = get_reg(child, (int) index); 412 tmp = ptrace_get_reg(child, (int) index);
292 } else { 413 } else {
293 flush_fp_to_thread(child); 414 flush_fp_to_thread(child);
294 tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; 415 tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
@@ -323,13 +444,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
323#endif 444#endif
324 break; 445 break;
325 446
326#ifdef CONFIG_PPC32
327 CHECK_FULL_REGS(child->thread.regs); 447 CHECK_FULL_REGS(child->thread.regs);
328#endif
329 if (index == PT_ORIG_R3)
330 break;
331 if (index < PT_FPR0) { 448 if (index < PT_FPR0) {
332 ret = put_reg(child, index, data); 449 ret = ptrace_put_reg(child, index, data);
333 } else { 450 } else {
334 flush_fp_to_thread(child); 451 flush_fp_to_thread(child);
335 ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; 452 ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
@@ -384,7 +501,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
384 break; 501 break;
385 } 502 }
386 503
387#ifdef CONFIG_PPC64
388 case PTRACE_GET_DEBUGREG: { 504 case PTRACE_GET_DEBUGREG: {
389 ret = -EINVAL; 505 ret = -EINVAL;
390 /* We only support one DABR and no IABRS at the moment */ 506 /* We only support one DABR and no IABRS at the moment */
@@ -398,73 +514,61 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
398 case PTRACE_SET_DEBUGREG: 514 case PTRACE_SET_DEBUGREG:
399 ret = ptrace_set_debugreg(child, addr, data); 515 ret = ptrace_set_debugreg(child, addr, data);
400 break; 516 break;
401#endif
402 517
403 case PTRACE_DETACH: 518 case PTRACE_DETACH:
404 ret = ptrace_detach(child, data); 519 ret = ptrace_detach(child, data);
405 break; 520 break;
406 521
407 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ 522#ifdef CONFIG_PPC64
408 int i; 523 case PTRACE_GETREGS64:
409 unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; 524#endif
410 unsigned long __user *tmp = (unsigned long __user *)addr; 525 case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
411 526 int ui;
412 for (i = 0; i < 32; i++) { 527 if (!access_ok(VERIFY_WRITE, (void __user *)data,
413 ret = put_user(*reg, tmp); 528 sizeof(struct pt_regs))) {
414 if (ret) 529 ret = -EIO;
415 break; 530 break;
416 reg++; 531 }
417 tmp++; 532 ret = 0;
533 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
534 ret |= __put_user(ptrace_get_reg(child, ui),
535 (unsigned long __user *) data);
536 data += sizeof(long);
418 } 537 }
419 break; 538 break;
420 } 539 }
421 540
422 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ 541#ifdef CONFIG_PPC64
423 int i; 542 case PTRACE_SETREGS64:
424 unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; 543#endif
425 unsigned long __user *tmp = (unsigned long __user *)addr; 544 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
426 545 unsigned long tmp;
427 for (i = 0; i < 32; i++) { 546 int ui;
428 ret = get_user(*reg, tmp); 547 if (!access_ok(VERIFY_READ, (void __user *)data,
548 sizeof(struct pt_regs))) {
549 ret = -EIO;
550 break;
551 }
552 ret = 0;
553 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
554 ret = __get_user(tmp, (unsigned long __user *) data);
429 if (ret) 555 if (ret)
430 break; 556 break;
431 reg++; 557 ptrace_put_reg(child, ui, tmp);
432 tmp++; 558 data += sizeof(long);
433 } 559 }
434 break; 560 break;
435 } 561 }
436 562
437 case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ 563 case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
438 int i;
439 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
440 unsigned long __user *tmp = (unsigned long __user *)addr;
441
442 flush_fp_to_thread(child); 564 flush_fp_to_thread(child);
443 565 ret = get_fpregs((void __user *)data, child, 1);
444 for (i = 0; i < 32; i++) {
445 ret = put_user(*reg, tmp);
446 if (ret)
447 break;
448 reg++;
449 tmp++;
450 }
451 break; 566 break;
452 } 567 }
453 568
454 case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ 569 case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
455 int i;
456 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
457 unsigned long __user *tmp = (unsigned long __user *)addr;
458
459 flush_fp_to_thread(child); 570 flush_fp_to_thread(child);
460 571 ret = set_fpregs((void __user *)data, child, 1);
461 for (i = 0; i < 32; i++) {
462 ret = get_user(*reg, tmp);
463 if (ret)
464 break;
465 reg++;
466 tmp++;
467 }
468 break; 572 break;
469 } 573 }
470 574
@@ -499,11 +603,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
499 break; 603 break;
500#endif 604#endif
501 605
606 /* Old reverse args ptrace callss */
607 case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
608 case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
609 case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
610 case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
611 ret = arch_ptrace_old(child, request, addr, data);
612 break;
613
502 default: 614 default:
503 ret = ptrace_request(child, request, addr, data); 615 ret = ptrace_request(child, request, addr, data);
504 break; 616 break;
505 } 617 }
506
507 return ret; 618 return ret;
508} 619}
509 620