aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-12-20 06:58:08 -0500
committerPaul Mackerras <paulus@samba.org>2008-02-07 04:40:16 -0500
commitfa8f5cb0c980e9fe3e04bc937fbd13417b52c046 (patch)
tree22bb8496ac654e57b134223e23ea899fbb5cfb6e /arch/powerpc/kernel/ptrace.c
parent80fdf4709497a276a826c9d8426ef1effc8f8e33 (diff)
[POWERPC] Add user_regset compat support
This extends task_user_regset_view CONFIG_PPC64 with support for the 32-bit view of register state, compatible with what a CONFIG_PPC32 kernel provides. This will enable generic machine-independent code to access user-mode threads' registers for debugging and dumping. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r--arch/powerpc/kernel/ptrace.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index eb00274e84ba..60de9ee3701d 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -501,8 +501,170 @@ static const struct user_regset_view user_ppc_native_view = {
501 .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) 501 .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
502}; 502};
503 503
504#ifdef CONFIG_PPC64
505#include <linux/compat.h>
506
507static int gpr32_get(struct task_struct *target,
508 const struct user_regset *regset,
509 unsigned int pos, unsigned int count,
510 void *kbuf, void __user *ubuf)
511{
512 const unsigned long *regs = &target->thread.regs->gpr[0];
513 compat_ulong_t *k = kbuf;
514 compat_ulong_t __user *u = ubuf;
515 compat_ulong_t reg;
516
517 if (target->thread.regs == NULL)
518 return -EIO;
519
520 CHECK_FULL_REGS(target->thread.regs);
521
522 pos /= sizeof(reg);
523 count /= sizeof(reg);
524
525 if (kbuf)
526 for (; count > 0 && pos < PT_MSR; --count)
527 *k++ = regs[pos++];
528 else
529 for (; count > 0 && pos < PT_MSR; --count)
530 if (__put_user((compat_ulong_t) regs[pos++], u++))
531 return -EFAULT;
532
533 if (count > 0 && pos == PT_MSR) {
534 reg = get_user_msr(target);
535 if (kbuf)
536 *k++ = reg;
537 else if (__put_user(reg, u++))
538 return -EFAULT;
539 ++pos;
540 --count;
541 }
542
543 if (kbuf)
544 for (; count > 0 && pos < PT_REGS_COUNT; --count)
545 *k++ = regs[pos++];
546 else
547 for (; count > 0 && pos < PT_REGS_COUNT; --count)
548 if (__put_user((compat_ulong_t) regs[pos++], u++))
549 return -EFAULT;
550
551 kbuf = k;
552 ubuf = u;
553 pos *= sizeof(reg);
554 count *= sizeof(reg);
555 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
556 PT_REGS_COUNT * sizeof(reg), -1);
557}
558
559static int gpr32_set(struct task_struct *target,
560 const struct user_regset *regset,
561 unsigned int pos, unsigned int count,
562 const void *kbuf, const void __user *ubuf)
563{
564 unsigned long *regs = &target->thread.regs->gpr[0];
565 const compat_ulong_t *k = kbuf;
566 const compat_ulong_t __user *u = ubuf;
567 compat_ulong_t reg;
568
569 if (target->thread.regs == NULL)
570 return -EIO;
571
572 CHECK_FULL_REGS(target->thread.regs);
573
574 pos /= sizeof(reg);
575 count /= sizeof(reg);
576
577 if (kbuf)
578 for (; count > 0 && pos < PT_MSR; --count)
579 regs[pos++] = *k++;
580 else
581 for (; count > 0 && pos < PT_MSR; --count) {
582 if (__get_user(reg, u++))
583 return -EFAULT;
584 regs[pos++] = reg;
585 }
586
587
588 if (count > 0 && pos == PT_MSR) {
589 if (kbuf)
590 reg = *k++;
591 else if (__get_user(reg, u++))
592 return -EFAULT;
593 set_user_msr(target, reg);
594 ++pos;
595 --count;
596 }
597
598 if (kbuf)
599 for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
600 regs[pos++] = *k++;
601 else
602 for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
603 if (__get_user(reg, u++))
604 return -EFAULT;
605 regs[pos++] = reg;
606 }
607
608 if (count > 0 && pos == PT_TRAP) {
609 if (kbuf)
610 reg = *k++;
611 else if (__get_user(reg, u++))
612 return -EFAULT;
613 set_user_trap(target, reg);
614 ++pos;
615 --count;
616 }
617
618 kbuf = k;
619 ubuf = u;
620 pos *= sizeof(reg);
621 count *= sizeof(reg);
622 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
623 (PT_TRAP + 1) * sizeof(reg), -1);
624}
625
626/*
627 * These are the regset flavors matching the CONFIG_PPC32 native set.
628 */
629static const struct user_regset compat_regsets[] = {
630 [REGSET_GPR] = {
631 .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
632 .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
633 .get = gpr32_get, .set = gpr32_set
634 },
635 [REGSET_FPR] = {
636 .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
637 .size = sizeof(double), .align = sizeof(double),
638 .get = fpr_get, .set = fpr_set
639 },
640#ifdef CONFIG_ALTIVEC
641 [REGSET_VMX] = {
642 .core_note_type = NT_PPC_VMX, .n = 34,
643 .size = sizeof(vector128), .align = sizeof(vector128),
644 .active = vr_active, .get = vr_get, .set = vr_set
645 },
646#endif
647#ifdef CONFIG_SPE
648 [REGSET_SPE] = {
649 .n = 35,
650 .size = sizeof(u32), .align = sizeof(u32),
651 .active = evr_active, .get = evr_get, .set = evr_set
652 },
653#endif
654};
655
656static const struct user_regset_view user_ppc_compat_view = {
657 .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
658 .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
659};
660#endif /* CONFIG_PPC64 */
661
504const struct user_regset_view *task_user_regset_view(struct task_struct *task) 662const struct user_regset_view *task_user_regset_view(struct task_struct *task)
505{ 663{
664#ifdef CONFIG_PPC64
665 if (test_tsk_thread_flag(task, TIF_32BIT))
666 return &user_ppc_compat_view;
667#endif
506 return &user_ppc_native_view; 668 return &user_ppc_native_view;
507} 669}
508 670