diff options
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index ae0e14b8880..bae1cc49fe9 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -42,6 +42,7 @@ enum s390_regset { | |||
42 | REGSET_GENERAL, | 42 | REGSET_GENERAL, |
43 | REGSET_FP, | 43 | REGSET_FP, |
44 | REGSET_LAST_BREAK, | 44 | REGSET_LAST_BREAK, |
45 | REGSET_SYSTEM_CALL, | ||
45 | REGSET_GENERAL_EXTENDED, | 46 | REGSET_GENERAL_EXTENDED, |
46 | }; | 47 | }; |
47 | 48 | ||
@@ -303,6 +304,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
303 | high order bit but older gdb's rely on it */ | 304 | high order bit but older gdb's rely on it */ |
304 | data |= PSW_ADDR_AMODE; | 305 | data |= PSW_ADDR_AMODE; |
305 | #endif | 306 | #endif |
307 | if (addr == (addr_t) &dummy->regs.psw.addr) | ||
308 | /* | ||
309 | * The debugger changed the instruction address, | ||
310 | * reset system call restart, see signal.c:do_signal | ||
311 | */ | ||
312 | task_thread_info(child)->system_call = 0; | ||
313 | |||
306 | *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; | 314 | *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; |
307 | 315 | ||
308 | } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { | 316 | } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { |
@@ -610,6 +618,11 @@ static int __poke_user_compat(struct task_struct *child, | |||
610 | /* Build a 64 bit psw address from 31 bit address. */ | 618 | /* Build a 64 bit psw address from 31 bit address. */ |
611 | task_pt_regs(child)->psw.addr = | 619 | task_pt_regs(child)->psw.addr = |
612 | (__u64) tmp & PSW32_ADDR_INSN; | 620 | (__u64) tmp & PSW32_ADDR_INSN; |
621 | /* | ||
622 | * The debugger changed the instruction address, | ||
623 | * reset system call restart, see signal.c:do_signal | ||
624 | */ | ||
625 | task_thread_info(child)->system_call = 0; | ||
613 | } else { | 626 | } else { |
614 | /* gpr 0-15 */ | 627 | /* gpr 0-15 */ |
615 | *(__u32*)((addr_t) &task_pt_regs(child)->psw | 628 | *(__u32*)((addr_t) &task_pt_regs(child)->psw |
@@ -737,7 +750,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
737 | * debugger stored an invalid system call number. Skip | 750 | * debugger stored an invalid system call number. Skip |
738 | * the system call and the system call restart handling. | 751 | * the system call and the system call restart handling. |
739 | */ | 752 | */ |
740 | regs->svcnr = 0; | 753 | regs->svc_code = 0; |
741 | ret = -1; | 754 | ret = -1; |
742 | } | 755 | } |
743 | 756 | ||
@@ -899,6 +912,26 @@ static int s390_last_break_get(struct task_struct *target, | |||
899 | 912 | ||
900 | #endif | 913 | #endif |
901 | 914 | ||
915 | static int s390_system_call_get(struct task_struct *target, | ||
916 | const struct user_regset *regset, | ||
917 | unsigned int pos, unsigned int count, | ||
918 | void *kbuf, void __user *ubuf) | ||
919 | { | ||
920 | unsigned int *data = &task_thread_info(target)->system_call; | ||
921 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
922 | data, 0, sizeof(unsigned int)); | ||
923 | } | ||
924 | |||
925 | static int s390_system_call_set(struct task_struct *target, | ||
926 | const struct user_regset *regset, | ||
927 | unsigned int pos, unsigned int count, | ||
928 | const void *kbuf, const void __user *ubuf) | ||
929 | { | ||
930 | unsigned int *data = &task_thread_info(target)->system_call; | ||
931 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
932 | data, 0, sizeof(unsigned int)); | ||
933 | } | ||
934 | |||
902 | static const struct user_regset s390_regsets[] = { | 935 | static const struct user_regset s390_regsets[] = { |
903 | [REGSET_GENERAL] = { | 936 | [REGSET_GENERAL] = { |
904 | .core_note_type = NT_PRSTATUS, | 937 | .core_note_type = NT_PRSTATUS, |
@@ -925,6 +958,14 @@ static const struct user_regset s390_regsets[] = { | |||
925 | .get = s390_last_break_get, | 958 | .get = s390_last_break_get, |
926 | }, | 959 | }, |
927 | #endif | 960 | #endif |
961 | [REGSET_SYSTEM_CALL] = { | ||
962 | .core_note_type = NT_S390_SYSTEM_CALL, | ||
963 | .n = 1, | ||
964 | .size = sizeof(unsigned int), | ||
965 | .align = sizeof(unsigned int), | ||
966 | .get = s390_system_call_get, | ||
967 | .set = s390_system_call_set, | ||
968 | }, | ||
928 | }; | 969 | }; |
929 | 970 | ||
930 | static const struct user_regset_view user_s390_view = { | 971 | static const struct user_regset_view user_s390_view = { |
@@ -1104,6 +1145,14 @@ static const struct user_regset s390_compat_regsets[] = { | |||
1104 | .align = sizeof(long), | 1145 | .align = sizeof(long), |
1105 | .get = s390_compat_last_break_get, | 1146 | .get = s390_compat_last_break_get, |
1106 | }, | 1147 | }, |
1148 | [REGSET_SYSTEM_CALL] = { | ||
1149 | .core_note_type = NT_S390_SYSTEM_CALL, | ||
1150 | .n = 1, | ||
1151 | .size = sizeof(compat_uint_t), | ||
1152 | .align = sizeof(compat_uint_t), | ||
1153 | .get = s390_system_call_get, | ||
1154 | .set = s390_system_call_set, | ||
1155 | }, | ||
1107 | [REGSET_GENERAL_EXTENDED] = { | 1156 | [REGSET_GENERAL_EXTENDED] = { |
1108 | .core_note_type = NT_S390_HIGH_GPRS, | 1157 | .core_note_type = NT_S390_HIGH_GPRS, |
1109 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), | 1158 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), |