diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2010-05-17 04:00:05 -0400 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-05-17 04:00:15 -0400 |
commit | 86f2552bbd0e17b19bb5e9881042533eaea553c7 (patch) | |
tree | f520909d953f5d8c7db3dd4c4f2582bd7f7473aa /arch/s390/kernel/ptrace.c | |
parent | cd3b70f5d4d82f85d1e1d6e822f38ae098cf7c72 (diff) |
[S390] add breaking event address for user space
Copy the last breaking event address from the lowcore to a new
field in the thread_struct on each system entry. Add a new
ptrace request PTRACE_GET_LAST_BREAK and a new utrace regset
REGSET_LAST_BREAK to query the last breaking event.
This is useful for debugging wild branches in user space code.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/ptrace.c')
-rw-r--r-- | arch/s390/kernel/ptrace.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 9f654da4cecc..83339d33c4b1 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 | } |
@@ -797,6 +806,28 @@ static int s390_fpregs_set(struct task_struct *target, | |||
797 | return rc; | 806 | return rc; |
798 | } | 807 | } |
799 | 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 | |||
800 | static const struct user_regset s390_regsets[] = { | 831 | static const struct user_regset s390_regsets[] = { |
801 | [REGSET_GENERAL] = { | 832 | [REGSET_GENERAL] = { |
802 | .core_note_type = NT_PRSTATUS, | 833 | .core_note_type = NT_PRSTATUS, |
@@ -814,6 +845,15 @@ static const struct user_regset s390_regsets[] = { | |||
814 | .get = s390_fpregs_get, | 845 | .get = s390_fpregs_get, |
815 | .set = s390_fpregs_set, | 846 | .set = s390_fpregs_set, |
816 | }, | 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 | ||
817 | }; | 857 | }; |
818 | 858 | ||
819 | static const struct user_regset_view user_s390_view = { | 859 | static const struct user_regset_view user_s390_view = { |
@@ -948,6 +988,27 @@ static int s390_compat_regs_high_set(struct task_struct *target, | |||
948 | return rc; | 988 | return rc; |
949 | } | 989 | } |
950 | 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 | |||
951 | static const struct user_regset s390_compat_regsets[] = { | 1012 | static const struct user_regset s390_compat_regsets[] = { |
952 | [REGSET_GENERAL] = { | 1013 | [REGSET_GENERAL] = { |
953 | .core_note_type = NT_PRSTATUS, | 1014 | .core_note_type = NT_PRSTATUS, |
@@ -965,6 +1026,13 @@ static const struct user_regset s390_compat_regsets[] = { | |||
965 | .get = s390_fpregs_get, | 1026 | .get = s390_fpregs_get, |
966 | .set = s390_fpregs_set, | 1027 | .set = s390_fpregs_set, |
967 | }, | 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 | }, | ||
968 | [REGSET_GENERAL_EXTENDED] = { | 1036 | [REGSET_GENERAL_EXTENDED] = { |
969 | .core_note_type = NT_S390_HIGH_GPRS, | 1037 | .core_note_type = NT_S390_HIGH_GPRS, |
970 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), | 1038 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), |