diff options
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 33fdc5a7976..83339d33c4b 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -57,6 +57,7 @@ | |||
57 | enum s390_regset { | 57 | enum s390_regset { |
58 | REGSET_GENERAL, | 58 | REGSET_GENERAL, |
59 | REGSET_FP, | 59 | REGSET_FP, |
60 | REGSET_LAST_BREAK, | ||
60 | REGSET_GENERAL_EXTENDED, | 61 | REGSET_GENERAL_EXTENDED, |
61 | }; | 62 | }; |
62 | 63 | ||
@@ -381,6 +382,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
381 | copied += sizeof(unsigned long); | 382 | copied += sizeof(unsigned long); |
382 | } | 383 | } |
383 | return 0; | 384 | return 0; |
385 | case PTRACE_GET_LAST_BREAK: | ||
386 | put_user(task_thread_info(child)->last_break, | ||
387 | (unsigned long __user *) data); | ||
388 | return 0; | ||
384 | default: | 389 | default: |
385 | /* Removing high order bit from addr (only for 31 bit). */ | 390 | /* Removing high order bit from addr (only for 31 bit). */ |
386 | addr &= PSW_ADDR_INSN; | 391 | addr &= PSW_ADDR_INSN; |
@@ -633,6 +638,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
633 | copied += sizeof(unsigned int); | 638 | copied += sizeof(unsigned int); |
634 | } | 639 | } |
635 | return 0; | 640 | return 0; |
641 | case PTRACE_GET_LAST_BREAK: | ||
642 | put_user(task_thread_info(child)->last_break, | ||
643 | (unsigned int __user *) data); | ||
644 | return 0; | ||
636 | } | 645 | } |
637 | return compat_ptrace_request(child, request, addr, data); | 646 | return compat_ptrace_request(child, request, addr, data); |
638 | } | 647 | } |
@@ -640,7 +649,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
640 | 649 | ||
641 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | 650 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) |
642 | { | 651 | { |
643 | long ret; | 652 | long ret = 0; |
644 | 653 | ||
645 | /* Do the secure computing check first. */ | 654 | /* Do the secure computing check first. */ |
646 | secure_computing(regs->gprs[2]); | 655 | secure_computing(regs->gprs[2]); |
@@ -649,7 +658,6 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
649 | * The sysc_tracesys code in entry.S stored the system | 658 | * The sysc_tracesys code in entry.S stored the system |
650 | * call number to gprs[2]. | 659 | * call number to gprs[2]. |
651 | */ | 660 | */ |
652 | ret = regs->gprs[2]; | ||
653 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | 661 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
654 | (tracehook_report_syscall_entry(regs) || | 662 | (tracehook_report_syscall_entry(regs) || |
655 | regs->gprs[2] >= NR_syscalls)) { | 663 | regs->gprs[2] >= NR_syscalls)) { |
@@ -671,7 +679,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
671 | regs->gprs[2], regs->orig_gpr2, | 679 | regs->gprs[2], regs->orig_gpr2, |
672 | regs->gprs[3], regs->gprs[4], | 680 | regs->gprs[3], regs->gprs[4], |
673 | regs->gprs[5]); | 681 | regs->gprs[5]); |
674 | return ret; | 682 | return ret ?: regs->gprs[2]; |
675 | } | 683 | } |
676 | 684 | ||
677 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) | 685 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) |
@@ -798,6 +806,28 @@ static int s390_fpregs_set(struct task_struct *target, | |||
798 | return rc; | 806 | return rc; |
799 | } | 807 | } |
800 | 808 | ||
809 | #ifdef CONFIG_64BIT | ||
810 | |||
811 | static int s390_last_break_get(struct task_struct *target, | ||
812 | const struct user_regset *regset, | ||
813 | unsigned int pos, unsigned int count, | ||
814 | void *kbuf, void __user *ubuf) | ||
815 | { | ||
816 | if (count > 0) { | ||
817 | if (kbuf) { | ||
818 | unsigned long *k = kbuf; | ||
819 | *k = task_thread_info(target)->last_break; | ||
820 | } else { | ||
821 | unsigned long __user *u = ubuf; | ||
822 | if (__put_user(task_thread_info(target)->last_break, u)) | ||
823 | return -EFAULT; | ||
824 | } | ||
825 | } | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | #endif | ||
830 | |||
801 | static const struct user_regset s390_regsets[] = { | 831 | static const struct user_regset s390_regsets[] = { |
802 | [REGSET_GENERAL] = { | 832 | [REGSET_GENERAL] = { |
803 | .core_note_type = NT_PRSTATUS, | 833 | .core_note_type = NT_PRSTATUS, |
@@ -815,6 +845,15 @@ static const struct user_regset s390_regsets[] = { | |||
815 | .get = s390_fpregs_get, | 845 | .get = s390_fpregs_get, |
816 | .set = s390_fpregs_set, | 846 | .set = s390_fpregs_set, |
817 | }, | 847 | }, |
848 | #ifdef CONFIG_64BIT | ||
849 | [REGSET_LAST_BREAK] = { | ||
850 | .core_note_type = NT_S390_LAST_BREAK, | ||
851 | .n = 1, | ||
852 | .size = sizeof(long), | ||
853 | .align = sizeof(long), | ||
854 | .get = s390_last_break_get, | ||
855 | }, | ||
856 | #endif | ||
818 | }; | 857 | }; |
819 | 858 | ||
820 | static const struct user_regset_view user_s390_view = { | 859 | static const struct user_regset_view user_s390_view = { |
@@ -949,6 +988,27 @@ static int s390_compat_regs_high_set(struct task_struct *target, | |||
949 | return rc; | 988 | return rc; |
950 | } | 989 | } |
951 | 990 | ||
991 | static int s390_compat_last_break_get(struct task_struct *target, | ||
992 | const struct user_regset *regset, | ||
993 | unsigned int pos, unsigned int count, | ||
994 | void *kbuf, void __user *ubuf) | ||
995 | { | ||
996 | compat_ulong_t last_break; | ||
997 | |||
998 | if (count > 0) { | ||
999 | last_break = task_thread_info(target)->last_break; | ||
1000 | if (kbuf) { | ||
1001 | unsigned long *k = kbuf; | ||
1002 | *k = last_break; | ||
1003 | } else { | ||
1004 | unsigned long __user *u = ubuf; | ||
1005 | if (__put_user(last_break, u)) | ||
1006 | return -EFAULT; | ||
1007 | } | ||
1008 | } | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
952 | static const struct user_regset s390_compat_regsets[] = { | 1012 | static const struct user_regset s390_compat_regsets[] = { |
953 | [REGSET_GENERAL] = { | 1013 | [REGSET_GENERAL] = { |
954 | .core_note_type = NT_PRSTATUS, | 1014 | .core_note_type = NT_PRSTATUS, |
@@ -966,6 +1026,13 @@ static const struct user_regset s390_compat_regsets[] = { | |||
966 | .get = s390_fpregs_get, | 1026 | .get = s390_fpregs_get, |
967 | .set = s390_fpregs_set, | 1027 | .set = s390_fpregs_set, |
968 | }, | 1028 | }, |
1029 | [REGSET_LAST_BREAK] = { | ||
1030 | .core_note_type = NT_S390_LAST_BREAK, | ||
1031 | .n = 1, | ||
1032 | .size = sizeof(long), | ||
1033 | .align = sizeof(long), | ||
1034 | .get = s390_compat_last_break_get, | ||
1035 | }, | ||
969 | [REGSET_GENERAL_EXTENDED] = { | 1036 | [REGSET_GENERAL_EXTENDED] = { |
970 | .core_note_type = NT_S390_HIGH_GPRS, | 1037 | .core_note_type = NT_S390_HIGH_GPRS, |
971 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), | 1038 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), |