aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/ptrace32.c')
-rw-r--r--arch/powerpc/kernel/ptrace32.c239
1 files changed, 104 insertions, 135 deletions
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 9b9a230349bc..9e6baeac0fb1 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -33,13 +33,55 @@
33#include <asm/pgtable.h> 33#include <asm/pgtable.h>
34#include <asm/system.h> 34#include <asm/system.h>
35 35
36#include "ptrace-common.h"
37
38/* 36/*
39 * does not yet catch signals sent when the child dies. 37 * does not yet catch signals sent when the child dies.
40 * in exit.c or in signal.c. 38 * in exit.c or in signal.c.
41 */ 39 */
42 40
41/*
42 * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
43 * we mark them as obsolete now, they will be removed in a future version
44 */
45static long compat_ptrace_old(struct task_struct *child, long request,
46 long addr, long data)
47{
48 int ret = -EPERM;
49
50 switch(request) {
51 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
52 int i;
53 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
54 unsigned int __user *tmp = (unsigned int __user *)addr;
55
56 for (i = 0; i < 32; i++) {
57 ret = put_user(*reg, tmp);
58 if (ret)
59 break;
60 reg++;
61 tmp++;
62 }
63 break;
64 }
65
66 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
67 int i;
68 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
69 unsigned int __user *tmp = (unsigned int __user *)addr;
70
71 for (i = 0; i < 32; i++) {
72 ret = get_user(*reg, tmp);
73 if (ret)
74 break;
75 reg++;
76 tmp++;
77 }
78 break;
79 }
80
81 }
82 return ret;
83}
84
43long compat_sys_ptrace(int request, int pid, unsigned long addr, 85long compat_sys_ptrace(int request, int pid, unsigned long addr,
44 unsigned long data) 86 unsigned long data)
45{ 87{
@@ -123,7 +165,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
123 break; 165 break;
124 166
125 if (index < PT_FPR0) { 167 if (index < PT_FPR0) {
126 tmp = get_reg(child, index); 168 tmp = ptrace_get_reg(child, index);
127 } else { 169 } else {
128 flush_fp_to_thread(child); 170 flush_fp_to_thread(child);
129 /* 171 /*
@@ -162,7 +204,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
162 else 204 else
163 part = 0; /* want the 1st half of the register (left-most). */ 205 part = 0; /* want the 1st half of the register (left-most). */
164 206
165 /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */ 207 /* Validate the input - check to see if address is on the wrong boundary
208 * or beyond the end of the user area
209 */
166 if ((addr & 3) || numReg > PT_FPSCR) 210 if ((addr & 3) || numReg > PT_FPSCR)
167 break; 211 break;
168 212
@@ -170,7 +214,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
170 flush_fp_to_thread(child); 214 flush_fp_to_thread(child);
171 tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0]; 215 tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
172 } else { /* register within PT_REGS struct */ 216 } else { /* register within PT_REGS struct */
173 tmp = get_reg(child, numReg); 217 tmp = ptrace_get_reg(child, numReg);
174 } 218 }
175 reg32bits = ((u32*)&tmp)[part]; 219 reg32bits = ((u32*)&tmp)[part];
176 ret = put_user(reg32bits, (u32 __user *)data); 220 ret = put_user(reg32bits, (u32 __user *)data);
@@ -226,10 +270,8 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
226 if ((addr & 3) || (index > PT_FPSCR32)) 270 if ((addr & 3) || (index > PT_FPSCR32))
227 break; 271 break;
228 272
229 if (index == PT_ORIG_R3)
230 break;
231 if (index < PT_FPR0) { 273 if (index < PT_FPR0) {
232 ret = put_reg(child, index, data); 274 ret = ptrace_put_reg(child, index, data);
233 } else { 275 } else {
234 flush_fp_to_thread(child); 276 flush_fp_to_thread(child);
235 /* 277 /*
@@ -258,70 +300,25 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
258 /* Determine which register the user wants */ 300 /* Determine which register the user wants */
259 index = (u64)addr >> 2; 301 index = (u64)addr >> 2;
260 numReg = index / 2; 302 numReg = index / 2;
303
261 /* 304 /*
262 * Validate the input - check to see if address is on the 305 * Validate the input - check to see if address is on the
263 * wrong boundary or beyond the end of the user area 306 * wrong boundary or beyond the end of the user area
264 */ 307 */
265 if ((addr & 3) || (numReg > PT_FPSCR)) 308 if ((addr & 3) || (numReg > PT_FPSCR))
266 break; 309 break;
267 /* Insure it is a register we let them change */ 310 if (numReg < PT_FPR0) {
268 if ((numReg == PT_ORIG_R3) 311 unsigned long freg = ptrace_get_reg(child, numReg);
269 || ((numReg > PT_CCR) && (numReg < PT_FPR0))) 312 if (index % 2)
270 break; 313 freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
271 if (numReg >= PT_FPR0) { 314 else
315 freg = (freg & 0xfffffffful) | (data << 32);
316 ret = ptrace_put_reg(child, numReg, freg);
317 } else {
272 flush_fp_to_thread(child); 318 flush_fp_to_thread(child);
319 ((unsigned int *)child->thread.regs)[index] = data;
320 ret = 0;
273 } 321 }
274 if (numReg == PT_MSR)
275 data = (data & MSR_DEBUGCHANGE)
276 | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
277 ((u32*)child->thread.regs)[index] = data;
278 ret = 0;
279 break;
280 }
281
282 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
283 case PTRACE_CONT: { /* restart after signal. */
284 ret = -EIO;
285 if (!valid_signal(data))
286 break;
287 if (request == PTRACE_SYSCALL)
288 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
289 else
290 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
291 child->exit_code = data;
292 /* make sure the single step bit is not set. */
293 clear_single_step(child);
294 wake_up_process(child);
295 ret = 0;
296 break;
297 }
298
299 /*
300 * make the child exit. Best I can do is send it a sigkill.
301 * perhaps it should be put in the status that it wants to
302 * exit.
303 */
304 case PTRACE_KILL: {
305 ret = 0;
306 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
307 break;
308 child->exit_code = SIGKILL;
309 /* make sure the single step bit is not set. */
310 clear_single_step(child);
311 wake_up_process(child);
312 break;
313 }
314
315 case PTRACE_SINGLESTEP: { /* set the trap flag. */
316 ret = -EIO;
317 if (!valid_signal(data))
318 break;
319 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
320 set_single_step(child);
321 child->exit_code = data;
322 /* give it a chance to run. */
323 wake_up_process(child);
324 ret = 0;
325 break; 322 break;
326 } 323 }
327 324
@@ -334,95 +331,67 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
334 break; 331 break;
335 } 332 }
336 333
337 case PTRACE_SET_DEBUGREG: 334 case PTRACE_GETEVENTMSG:
338 ret = ptrace_set_debugreg(child, addr, data); 335 ret = put_user(child->ptrace_message, (unsigned int __user *) data);
339 break;
340
341 case PTRACE_DETACH:
342 ret = ptrace_detach(child, data);
343 break; 336 break;
344 337
345 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ 338 case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
346 int i; 339 int ui;
347 unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; 340 if (!access_ok(VERIFY_WRITE, (void __user *)data,
348 unsigned int __user *tmp = (unsigned int __user *)addr; 341 PT_REGS_COUNT * sizeof(int))) {
349 342 ret = -EIO;
350 for (i = 0; i < 32; i++) { 343 break;
351 ret = put_user(*reg, tmp);
352 if (ret)
353 break;
354 reg++;
355 tmp++;
356 } 344 }
357 break; 345 ret = 0;
358 } 346 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
359 347 ret |= __put_user(ptrace_get_reg(child, ui),
360 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ 348 (unsigned int __user *) data);
361 int i; 349 data += sizeof(int);
362 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
363 unsigned int __user *tmp = (unsigned int __user *)addr;
364
365 for (i = 0; i < 32; i++) {
366 ret = get_user(*reg, tmp);
367 if (ret)
368 break;
369 reg++;
370 tmp++;
371 } 350 }
372 break; 351 break;
373 } 352 }
374 353
375 case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ 354 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
376 int i; 355 unsigned long tmp;
377 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; 356 int ui;
378 unsigned int __user *tmp = (unsigned int __user *)addr; 357 if (!access_ok(VERIFY_READ, (void __user *)data,
379 358 PT_REGS_COUNT * sizeof(int))) {
380 flush_fp_to_thread(child); 359 ret = -EIO;
381 360 break;
382 for (i = 0; i < 32; i++) {
383 ret = put_user(*reg, tmp);
384 if (ret)
385 break;
386 reg++;
387 tmp++;
388 } 361 }
389 break; 362 ret = 0;
390 } 363 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
391 364 ret = __get_user(tmp, (unsigned int __user *) data);
392 case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
393 int i;
394 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
395 unsigned int __user *tmp = (unsigned int __user *)addr;
396
397 flush_fp_to_thread(child);
398
399 for (i = 0; i < 32; i++) {
400 ret = get_user(*reg, tmp);
401 if (ret) 365 if (ret)
402 break; 366 break;
403 reg++; 367 ptrace_put_reg(child, ui, tmp);
404 tmp++; 368 data += sizeof(int);
405 } 369 }
406 break; 370 break;
407 } 371 }
408 372
409 case PTRACE_GETEVENTMSG: 373 case PTRACE_GETFPREGS:
410 ret = put_user(child->ptrace_message, (unsigned int __user *) data); 374 case PTRACE_SETFPREGS:
411 break;
412
413#ifdef CONFIG_ALTIVEC
414 case PTRACE_GETVRREGS: 375 case PTRACE_GETVRREGS:
415 /* Get the child altivec register state. */ 376 case PTRACE_SETVRREGS:
416 flush_altivec_to_thread(child); 377 case PTRACE_GETREGS64:
417 ret = get_vrregs((unsigned long __user *)data, child); 378 case PTRACE_SETREGS64:
379 case PPC_PTRACE_GETFPREGS:
380 case PPC_PTRACE_SETFPREGS:
381 case PTRACE_KILL:
382 case PTRACE_SINGLESTEP:
383 case PTRACE_DETACH:
384 case PTRACE_SET_DEBUGREG:
385 case PTRACE_SYSCALL:
386 case PTRACE_CONT:
387 ret = arch_ptrace(child, request, addr, data);
418 break; 388 break;
419 389
420 case PTRACE_SETVRREGS: 390 /* Old reverse args ptrace callss */
421 /* Set the child altivec register state. */ 391 case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
422 flush_altivec_to_thread(child); 392 case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
423 ret = set_vrregs(child, (unsigned long __user *)data); 393 ret = compat_ptrace_old(child, request, addr, data);
424 break; 394 break;
425#endif
426 395
427 default: 396 default:
428 ret = ptrace_request(child, request, addr, data); 397 ret = ptrace_request(child, request, addr, data);