diff options
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 130 |
1 files changed, 128 insertions, 2 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 509804957f5f..d56aa18309f8 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -215,14 +215,14 @@ static int set_segment_reg(struct task_struct *task, | |||
215 | #ifdef CONFIG_IA32_EMULATION | 215 | #ifdef CONFIG_IA32_EMULATION |
216 | if (test_tsk_thread_flag(task, TIF_IA32)) | 216 | if (test_tsk_thread_flag(task, TIF_IA32)) |
217 | task_pt_regs(task)->cs = value; | 217 | task_pt_regs(task)->cs = value; |
218 | break; | ||
219 | #endif | 218 | #endif |
219 | break; | ||
220 | case offsetof(struct user_regs_struct,ss): | 220 | case offsetof(struct user_regs_struct,ss): |
221 | #ifdef CONFIG_IA32_EMULATION | 221 | #ifdef CONFIG_IA32_EMULATION |
222 | if (test_tsk_thread_flag(task, TIF_IA32)) | 222 | if (test_tsk_thread_flag(task, TIF_IA32)) |
223 | task_pt_regs(task)->ss = value; | 223 | task_pt_regs(task)->ss = value; |
224 | break; | ||
225 | #endif | 224 | #endif |
225 | break; | ||
226 | } | 226 | } |
227 | 227 | ||
228 | return 0; | 228 | return 0; |
@@ -634,6 +634,132 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
634 | return ret; | 634 | return ret; |
635 | } | 635 | } |
636 | 636 | ||
637 | #ifdef CONFIG_IA32_EMULATION | ||
638 | |||
639 | #include <asm/user32.h> | ||
640 | |||
641 | #define R32(l,q) \ | ||
642 | case offsetof(struct user32, regs.l): \ | ||
643 | regs->q = value; break | ||
644 | |||
645 | #define SEG32(rs) \ | ||
646 | case offsetof(struct user32, regs.rs): \ | ||
647 | return set_segment_reg(child, \ | ||
648 | offsetof(struct user_regs_struct, rs), \ | ||
649 | value); \ | ||
650 | break | ||
651 | |||
652 | static int putreg32(struct task_struct *child, unsigned regno, u32 value) | ||
653 | { | ||
654 | struct pt_regs *regs = task_pt_regs(child); | ||
655 | |||
656 | switch (regno) { | ||
657 | |||
658 | SEG32(cs); | ||
659 | SEG32(ds); | ||
660 | SEG32(es); | ||
661 | SEG32(fs); | ||
662 | SEG32(gs); | ||
663 | SEG32(ss); | ||
664 | |||
665 | R32(ebx, bx); | ||
666 | R32(ecx, cx); | ||
667 | R32(edx, dx); | ||
668 | R32(edi, di); | ||
669 | R32(esi, si); | ||
670 | R32(ebp, bp); | ||
671 | R32(eax, ax); | ||
672 | R32(orig_eax, orig_ax); | ||
673 | R32(eip, ip); | ||
674 | R32(esp, sp); | ||
675 | |||
676 | case offsetof(struct user32, regs.eflags): | ||
677 | return set_flags(child, value); | ||
678 | |||
679 | case offsetof(struct user32, u_debugreg[0]) ... | ||
680 | offsetof(struct user32, u_debugreg[7]): | ||
681 | regno -= offsetof(struct user32, u_debugreg[0]); | ||
682 | return ptrace_set_debugreg(child, regno / 4, value); | ||
683 | |||
684 | default: | ||
685 | if (regno > sizeof(struct user32) || (regno & 3)) | ||
686 | return -EIO; | ||
687 | |||
688 | /* | ||
689 | * Other dummy fields in the virtual user structure | ||
690 | * are ignored | ||
691 | */ | ||
692 | break; | ||
693 | } | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | #undef R32 | ||
698 | #undef SEG32 | ||
699 | |||
700 | #define R32(l,q) \ | ||
701 | case offsetof(struct user32, regs.l): \ | ||
702 | *val = regs->q; break | ||
703 | |||
704 | #define SEG32(rs) \ | ||
705 | case offsetof(struct user32, regs.rs): \ | ||
706 | *val = get_segment_reg(child, \ | ||
707 | offsetof(struct user_regs_struct, rs)); \ | ||
708 | break | ||
709 | |||
710 | static int getreg32(struct task_struct *child, unsigned regno, u32 *val) | ||
711 | { | ||
712 | struct pt_regs *regs = task_pt_regs(child); | ||
713 | |||
714 | switch (regno) { | ||
715 | |||
716 | SEG32(ds); | ||
717 | SEG32(es); | ||
718 | SEG32(fs); | ||
719 | SEG32(gs); | ||
720 | |||
721 | R32(cs, cs); | ||
722 | R32(ss, ss); | ||
723 | R32(ebx, bx); | ||
724 | R32(ecx, cx); | ||
725 | R32(edx, dx); | ||
726 | R32(edi, di); | ||
727 | R32(esi, si); | ||
728 | R32(ebp, bp); | ||
729 | R32(eax, ax); | ||
730 | R32(orig_eax, orig_ax); | ||
731 | R32(eip, ip); | ||
732 | R32(esp, sp); | ||
733 | |||
734 | case offsetof(struct user32, regs.eflags): | ||
735 | *val = get_flags(child); | ||
736 | break; | ||
737 | |||
738 | case offsetof(struct user32, u_debugreg[0]) ... | ||
739 | offsetof(struct user32, u_debugreg[7]): | ||
740 | regno -= offsetof(struct user32, u_debugreg[0]); | ||
741 | *val = ptrace_get_debugreg(child, regno / 4); | ||
742 | break; | ||
743 | |||
744 | default: | ||
745 | if (regno > sizeof(struct user32) || (regno & 3)) | ||
746 | return -EIO; | ||
747 | |||
748 | /* | ||
749 | * Other dummy fields in the virtual user structure | ||
750 | * are ignored | ||
751 | */ | ||
752 | *val = 0; | ||
753 | break; | ||
754 | } | ||
755 | return 0; | ||
756 | } | ||
757 | |||
758 | #undef R32 | ||
759 | #undef SEG32 | ||
760 | |||
761 | #endif /* CONFIG_IA32_EMULATION */ | ||
762 | |||
637 | #ifdef CONFIG_X86_32 | 763 | #ifdef CONFIG_X86_32 |
638 | 764 | ||
639 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | 765 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) |