aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ptrace.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-01-30 07:31:01 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:01 -0500
commite9c86c789f067f75211cedb3f13aa58369b0d14a (patch)
treefd32ac00326835f9200dc3b886efc926ed7aa07b /arch/x86/kernel/ptrace.c
parent2047b08be67b70875d8765fc81d34ce28041bec3 (diff)
x86: x86 ptrace arch merge
This adds 64-bit support to arch_ptrace in arch/x86/kernel/ptrace.c, so this function can be used for native ptrace on both 32 and 64. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r--arch/x86/kernel/ptrace.c65
1 files changed, 35 insertions, 30 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index c709868d28a5..7161d60e152d 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -463,12 +463,13 @@ static int ptrace_set_debugreg(struct task_struct *child,
463void ptrace_disable(struct task_struct *child) 463void ptrace_disable(struct task_struct *child)
464{ 464{
465 user_disable_single_step(child); 465 user_disable_single_step(child);
466#ifdef TIF_SYSCALL_EMU
466 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); 467 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
468#endif
467} 469}
468 470
469long arch_ptrace(struct task_struct *child, long request, long addr, long data) 471long arch_ptrace(struct task_struct *child, long request, long addr, long data)
470{ 472{
471 struct user * dummy = NULL;
472 int i, ret; 473 int i, ret;
473 unsigned long __user *datap = (unsigned long __user *)data; 474 unsigned long __user *datap = (unsigned long __user *)data;
474 475
@@ -484,18 +485,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
484 unsigned long tmp; 485 unsigned long tmp;
485 486
486 ret = -EIO; 487 ret = -EIO;
487 if ((addr & 3) || addr < 0 || 488 if ((addr & (sizeof(data) - 1)) || addr < 0 ||
488 addr > sizeof(struct user) - 3) 489 addr >= sizeof(struct user))
489 break; 490 break;
490 491
491 tmp = 0; /* Default return condition */ 492 tmp = 0; /* Default return condition */
492 if(addr < FRAME_SIZE*sizeof(long)) 493 if (addr < sizeof(struct user_regs_struct))
493 tmp = getreg(child, addr); 494 tmp = getreg(child, addr);
494 if(addr >= (long) &dummy->u_debugreg[0] && 495 else if (addr >= offsetof(struct user, u_debugreg[0]) &&
495 addr <= (long) &dummy->u_debugreg[7]){ 496 addr <= offsetof(struct user, u_debugreg[7])) {
496 addr -= (long) &dummy->u_debugreg[0]; 497 addr -= offsetof(struct user, u_debugreg[0]);
497 addr = addr >> 2; 498 tmp = ptrace_get_debugreg(child, addr / sizeof(data));
498 tmp = ptrace_get_debugreg(child, addr);
499 } 499 }
500 ret = put_user(tmp, datap); 500 ret = put_user(tmp, datap);
501 break; 501 break;
@@ -509,34 +509,26 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
509 509
510 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 510 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
511 ret = -EIO; 511 ret = -EIO;
512 if ((addr & 3) || addr < 0 || 512 if ((addr & (sizeof(data) - 1)) || addr < 0 ||
513 addr > sizeof(struct user) - 3) 513 addr >= sizeof(struct user))
514 break; 514 break;
515 515
516 if (addr < FRAME_SIZE*sizeof(long)) { 516 if (addr < sizeof(struct user_regs_struct))
517 ret = putreg(child, addr, data); 517 ret = putreg(child, addr, data);
518 break; 518 else if (addr >= offsetof(struct user, u_debugreg[0]) &&
519 addr <= offsetof(struct user, u_debugreg[7])) {
520 addr -= offsetof(struct user, u_debugreg[0]);
521 ret = ptrace_set_debugreg(child,
522 addr / sizeof(data), data);
519 } 523 }
520 /* We need to be very careful here. We implicitly 524 break;
521 want to modify a portion of the task_struct, and we
522 have to be selective about what portions we allow someone
523 to modify. */
524
525 ret = -EIO;
526 if(addr >= (long) &dummy->u_debugreg[0] &&
527 addr <= (long) &dummy->u_debugreg[7]){
528 addr -= (long) &dummy->u_debugreg;
529 addr = addr >> 2;
530 ret = ptrace_set_debugreg(child, addr, data);
531 }
532 break;
533 525
534 case PTRACE_GETREGS: { /* Get all gp regs from the child. */ 526 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
535 if (!access_ok(VERIFY_WRITE, datap, FRAME_SIZE*sizeof(long))) { 527 if (!access_ok(VERIFY_WRITE, datap, sizeof(struct user_regs_struct))) {
536 ret = -EIO; 528 ret = -EIO;
537 break; 529 break;
538 } 530 }
539 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { 531 for (i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long)) {
540 __put_user(getreg(child, i), datap); 532 __put_user(getreg(child, i), datap);
541 datap++; 533 datap++;
542 } 534 }
@@ -546,11 +538,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
546 538
547 case PTRACE_SETREGS: { /* Set all gp regs in the child. */ 539 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
548 unsigned long tmp; 540 unsigned long tmp;
549 if (!access_ok(VERIFY_READ, datap, FRAME_SIZE*sizeof(long))) { 541 if (!access_ok(VERIFY_READ, datap, sizeof(struct user_regs_struct))) {
550 ret = -EIO; 542 ret = -EIO;
551 break; 543 break;
552 } 544 }
553 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { 545 for (i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long)) {
554 __get_user(tmp, datap); 546 __get_user(tmp, datap);
555 putreg(child, i, tmp); 547 putreg(child, i, tmp);
556 datap++; 548 datap++;
@@ -584,6 +576,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
584 break; 576 break;
585 } 577 }
586 578
579#ifdef CONFIG_X86_32
587 case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */ 580 case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
588 if (!access_ok(VERIFY_WRITE, datap, 581 if (!access_ok(VERIFY_WRITE, datap,
589 sizeof(struct user_fxsr_struct))) { 582 sizeof(struct user_fxsr_struct))) {
@@ -606,7 +599,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
606 ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data); 599 ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data);
607 break; 600 break;
608 } 601 }
602#endif
609 603
604#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
610 case PTRACE_GET_THREAD_AREA: 605 case PTRACE_GET_THREAD_AREA:
611 if (addr < 0) 606 if (addr < 0)
612 return -EIO; 607 return -EIO;
@@ -620,6 +615,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
620 ret = do_set_thread_area(child, addr, 615 ret = do_set_thread_area(child, addr,
621 (struct user_desc __user *) data, 0); 616 (struct user_desc __user *) data, 0);
622 break; 617 break;
618#endif
619
620#ifdef CONFIG_X86_64
621 /* normal 64bit interface to access TLS data.
622 Works just like arch_prctl, except that the arguments
623 are reversed. */
624 case PTRACE_ARCH_PRCTL:
625 ret = do_arch_prctl(child, data, addr);
626 break;
627#endif
623 628
624 default: 629 default:
625 ret = ptrace_request(child, request, addr, data); 630 ret = ptrace_request(child, request, addr, data);