aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r--arch/s390/kernel/ptrace.c73
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 @@
57enum s390_regset { 57enum 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
641asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) 650asmlinkage 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
677asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) 685asmlinkage 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
811static 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
801static const struct user_regset s390_regsets[] = { 831static 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
820static const struct user_regset_view user_s390_view = { 859static 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
991static 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
952static const struct user_regset s390_compat_regsets[] = { 1012static 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),