aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/ptrace-common.h23
-rw-r--r--arch/powerpc/kernel/ptrace.c148
-rw-r--r--arch/powerpc/kernel/ptrace32.c204
3 files changed, 209 insertions, 166 deletions
diff --git a/arch/powerpc/kernel/ptrace-common.h b/arch/powerpc/kernel/ptrace-common.h
index f0746eca8f44..21884535fee6 100644
--- a/arch/powerpc/kernel/ptrace-common.h
+++ b/arch/powerpc/kernel/ptrace-common.h
@@ -52,6 +52,29 @@ static inline int put_reg(struct task_struct *task, int regno,
52} 52}
53 53
54 54
55static inline int get_fpregs(void __user *data,
56 struct task_struct *task,
57 int has_fpscr)
58{
59 unsigned int count = has_fpscr ? 33 : 32;
60
61 if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
62 return -EFAULT;
63 return 0;
64}
65
66static inline int set_fpregs(void __user *data,
67 struct task_struct *task,
68 int has_fpscr)
69{
70 unsigned int count = has_fpscr ? 33 : 32;
71
72 if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
73 return -EFAULT;
74 return 0;
75}
76
77
55#ifdef CONFIG_ALTIVEC 78#ifdef CONFIG_ALTIVEC
56/* 79/*
57 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. 80 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index da53b0d4114b..230d5f5bfab6 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -59,6 +59,62 @@ void ptrace_disable(struct task_struct *child)
59 clear_single_step(child); 59 clear_single_step(child);
60} 60}
61 61
62/*
63 * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
64 * we mark them as obsolete now, they will be removed in a future version
65 */
66static long arch_ptrace_old(struct task_struct *child, long request, long addr,
67 long data)
68{
69 int ret = -EPERM;
70
71 switch(request) {
72 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
73 int i;
74 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
75 unsigned long __user *tmp = (unsigned long __user *)addr;
76
77 for (i = 0; i < 32; i++) {
78 ret = put_user(*reg, tmp);
79 if (ret)
80 break;
81 reg++;
82 tmp++;
83 }
84 break;
85 }
86
87 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
88 int i;
89 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
90 unsigned long __user *tmp = (unsigned long __user *)addr;
91
92 for (i = 0; i < 32; i++) {
93 ret = get_user(*reg, tmp);
94 if (ret)
95 break;
96 reg++;
97 tmp++;
98 }
99 break;
100 }
101
102 case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
103 flush_fp_to_thread(child);
104 ret = get_fpregs((void __user *)addr, child, 0);
105 break;
106 }
107
108 case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
109 flush_fp_to_thread(child);
110 ret = set_fpregs((void __user *)addr, child, 0);
111 break;
112 }
113
114 }
115 return ret;
116}
117
62long arch_ptrace(struct task_struct *child, long request, long addr, long data) 118long arch_ptrace(struct task_struct *child, long request, long addr, long data)
63{ 119{
64 int ret = -EPERM; 120 int ret = -EPERM;
@@ -214,71 +270,58 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
214 ret = ptrace_detach(child, data); 270 ret = ptrace_detach(child, data);
215 break; 271 break;
216 272
217 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ 273#ifdef CONFIG_PPC64
218 int i; 274 case PTRACE_GETREGS64:
219 unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; 275#endif
220 unsigned long __user *tmp = (unsigned long __user *)addr; 276 case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
221 277 int ui;
222 for (i = 0; i < 32; i++) { 278 if (!access_ok(VERIFY_WRITE, (void __user *)data,
223 ret = put_user(*reg, tmp); 279 sizeof(struct pt_regs))) {
224 if (ret) 280 ret = -EIO;
225 break; 281 break;
226 reg++; 282 }
227 tmp++; 283 ret = 0;
284 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
285 ret |= __put_user(get_reg(child, ui),
286 (unsigned long __user *) data);
287 data += sizeof(long);
228 } 288 }
229 break; 289 break;
230 } 290 }
231 291
232 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ 292#ifdef CONFIG_PPC64
233 int i; 293 case PTRACE_SETREGS64:
234 unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; 294#endif
235 unsigned long __user *tmp = (unsigned long __user *)addr; 295 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
236 296 unsigned long tmp;
237 for (i = 0; i < 32; i++) { 297 int ui;
238 ret = get_user(*reg, tmp); 298 if (!access_ok(VERIFY_READ, (void __user *)data,
299 sizeof(struct pt_regs))) {
300 ret = -EIO;
301 break;
302 }
303 ret = 0;
304 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
305 ret = __get_user(tmp, (unsigned long __user *) data);
239 if (ret) 306 if (ret)
240 break; 307 break;
241 reg++; 308 put_reg(child, ui, tmp);
242 tmp++; 309 data += sizeof(long);
243 } 310 }
244 break; 311 break;
245 } 312 }
246 313
247#ifdef CONFIG_PPC64 314 case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
248 case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
249 int i;
250 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
251 unsigned long __user *tmp = (unsigned long __user *)addr;
252
253 flush_fp_to_thread(child); 315 flush_fp_to_thread(child);
254 316 ret = get_fpregs((void __user *)data, child, 1);
255 for (i = 0; i < 32; i++) {
256 ret = put_user(*reg, tmp);
257 if (ret)
258 break;
259 reg++;
260 tmp++;
261 }
262 break; 317 break;
263 } 318 }
264 319
265 case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ 320 case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
266 int i;
267 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
268 unsigned long __user *tmp = (unsigned long __user *)addr;
269
270 flush_fp_to_thread(child); 321 flush_fp_to_thread(child);
271 322 ret = set_fpregs((void __user *)data, child, 1);
272 for (i = 0; i < 32; i++) {
273 ret = get_user(*reg, tmp);
274 if (ret)
275 break;
276 reg++;
277 tmp++;
278 }
279 break; 323 break;
280 } 324 }
281#endif /* CONFIG_PPC64 */
282 325
283#ifdef CONFIG_ALTIVEC 326#ifdef CONFIG_ALTIVEC
284 case PTRACE_GETVRREGS: 327 case PTRACE_GETVRREGS:
@@ -311,11 +354,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
311 break; 354 break;
312#endif 355#endif
313 356
357 /* Old reverse args ptrace callss */
358 case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
359 case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
360 case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
361 case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
362 ret = arch_ptrace_old(child, request, addr, data);
363 break;
364
314 default: 365 default:
315 ret = ptrace_request(child, request, addr, data); 366 ret = ptrace_request(child, request, addr, data);
316 break; 367 break;
317 } 368 }
318
319 return ret; 369 return ret;
320} 370}
321 371
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 1bf1f450e1ab..98b1580a2bc2 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -41,6 +41,50 @@
41 * in exit.c or in signal.c. 41 * in exit.c or in signal.c.
42 */ 42 */
43 43
44/*
45 * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
46 * we mark them as obsolete now, they will be removed in a future version
47 */
48static long compat_ptrace_old(struct task_struct *child, long request,
49 long addr, long data)
50{
51 int ret = -EPERM;
52
53 switch(request) {
54 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
55 int i;
56 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
57 unsigned int __user *tmp = (unsigned int __user *)addr;
58
59 for (i = 0; i < 32; i++) {
60 ret = put_user(*reg, tmp);
61 if (ret)
62 break;
63 reg++;
64 tmp++;
65 }
66 break;
67 }
68
69 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
70 int i;
71 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
72 unsigned int __user *tmp = (unsigned int __user *)addr;
73
74 for (i = 0; i < 32; i++) {
75 ret = get_user(*reg, tmp);
76 if (ret)
77 break;
78 reg++;
79 tmp++;
80 }
81 break;
82 }
83
84 }
85 return ret;
86}
87
44long compat_sys_ptrace(int request, int pid, unsigned long addr, 88long compat_sys_ptrace(int request, int pid, unsigned long addr,
45 unsigned long data) 89 unsigned long data)
46{ 90{
@@ -280,52 +324,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
280 break; 324 break;
281 } 325 }
282 326
283 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
284 case PTRACE_CONT: { /* restart after signal. */
285 ret = -EIO;
286 if (!valid_signal(data))
287 break;
288 if (request == PTRACE_SYSCALL)
289 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
290 else
291 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
292 child->exit_code = data;
293 /* make sure the single step bit is not set. */
294 clear_single_step(child);
295 wake_up_process(child);
296 ret = 0;
297 break;
298 }
299
300 /*
301 * make the child exit. Best I can do is send it a sigkill.
302 * perhaps it should be put in the status that it wants to
303 * exit.
304 */
305 case PTRACE_KILL: {
306 ret = 0;
307 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
308 break;
309 child->exit_code = SIGKILL;
310 /* make sure the single step bit is not set. */
311 clear_single_step(child);
312 wake_up_process(child);
313 break;
314 }
315
316 case PTRACE_SINGLESTEP: { /* set the trap flag. */
317 ret = -EIO;
318 if (!valid_signal(data))
319 break;
320 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
321 set_single_step(child);
322 child->exit_code = data;
323 /* give it a chance to run. */
324 wake_up_process(child);
325 ret = 0;
326 break;
327 }
328
329 case PTRACE_GET_DEBUGREG: { 327 case PTRACE_GET_DEBUGREG: {
330 ret = -EINVAL; 328 ret = -EINVAL;
331 /* We only support one DABR and no IABRS at the moment */ 329 /* We only support one DABR and no IABRS at the moment */
@@ -335,95 +333,67 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
335 break; 333 break;
336 } 334 }
337 335
338 case PTRACE_SET_DEBUGREG: 336 case PTRACE_GETEVENTMSG:
339 ret = ptrace_set_debugreg(child, addr, data); 337 ret = put_user(child->ptrace_message, (unsigned int __user *) data);
340 break;
341
342 case PTRACE_DETACH:
343 ret = ptrace_detach(child, data);
344 break; 338 break;
345 339
346 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ 340 case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
347 int i; 341 int ui;
348 unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; 342 if (!access_ok(VERIFY_WRITE, (void __user *)data,
349 unsigned int __user *tmp = (unsigned int __user *)addr; 343 PT_REGS_COUNT * sizeof(int))) {
350 344 ret = -EIO;
351 for (i = 0; i < 32; i++) { 345 break;
352 ret = put_user(*reg, tmp);
353 if (ret)
354 break;
355 reg++;
356 tmp++;
357 } 346 }
358 break; 347 ret = 0;
359 } 348 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
360 349 ret |= __put_user(get_reg(child, ui),
361 case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ 350 (unsigned int __user *) data);
362 int i; 351 data += sizeof(int);
363 unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
364 unsigned int __user *tmp = (unsigned int __user *)addr;
365
366 for (i = 0; i < 32; i++) {
367 ret = get_user(*reg, tmp);
368 if (ret)
369 break;
370 reg++;
371 tmp++;
372 } 352 }
373 break; 353 break;
374 } 354 }
375 355
376 case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ 356 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
377 int i; 357 unsigned long tmp;
378 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; 358 int ui;
379 unsigned int __user *tmp = (unsigned int __user *)addr; 359 if (!access_ok(VERIFY_READ, (void __user *)data,
380 360 PT_REGS_COUNT * sizeof(int))) {
381 flush_fp_to_thread(child); 361 ret = -EIO;
382 362 break;
383 for (i = 0; i < 32; i++) {
384 ret = put_user(*reg, tmp);
385 if (ret)
386 break;
387 reg++;
388 tmp++;
389 } 363 }
390 break; 364 ret = 0;
391 } 365 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
392 366 ret = __get_user(tmp, (unsigned int __user *) data);
393 case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
394 int i;
395 unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
396 unsigned int __user *tmp = (unsigned int __user *)addr;
397
398 flush_fp_to_thread(child);
399
400 for (i = 0; i < 32; i++) {
401 ret = get_user(*reg, tmp);
402 if (ret) 367 if (ret)
403 break; 368 break;
404 reg++; 369 put_reg(child, ui, tmp);
405 tmp++; 370 data += sizeof(int);
406 } 371 }
407 break; 372 break;
408 } 373 }
409 374
410 case PTRACE_GETEVENTMSG: 375 case PTRACE_GETFPREGS:
411 ret = put_user(child->ptrace_message, (unsigned int __user *) data); 376 case PTRACE_SETFPREGS:
412 break;
413
414#ifdef CONFIG_ALTIVEC
415 case PTRACE_GETVRREGS: 377 case PTRACE_GETVRREGS:
416 /* Get the child altivec register state. */ 378 case PTRACE_SETVRREGS:
417 flush_altivec_to_thread(child); 379 case PTRACE_GETREGS64:
418 ret = get_vrregs((unsigned long __user *)data, child); 380 case PTRACE_SETREGS64:
381 case PPC_PTRACE_GETFPREGS:
382 case PPC_PTRACE_SETFPREGS:
383 case PTRACE_KILL:
384 case PTRACE_SINGLESTEP:
385 case PTRACE_DETACH:
386 case PTRACE_SET_DEBUGREG:
387 case PTRACE_SYSCALL:
388 case PTRACE_CONT:
389 ret = arch_ptrace(child, request, addr, data);
419 break; 390 break;
420 391
421 case PTRACE_SETVRREGS: 392 /* Old reverse args ptrace callss */
422 /* Set the child altivec register state. */ 393 case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
423 flush_altivec_to_thread(child); 394 case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
424 ret = set_vrregs(child, (unsigned long __user *)data); 395 ret = compat_ptrace_old(child, request, addr, data);
425 break; 396 break;
426#endif
427 397
428 default: 398 default:
429 ret = ptrace_request(child, request, addr, data); 399 ret = ptrace_request(child, request, addr, data);