aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/traps.c
diff options
context:
space:
mode:
authorJan Willeke <willeke@de.ibm.com>2014-09-22 10:39:06 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2014-09-25 04:52:17 -0400
commit2a0a5b2299b9bef76123fac91e68d39cb361c33e (patch)
treefa8872070bf295dbbc57e7063db6e6baf739f543 /arch/s390/kernel/traps.c
parent975fab17399a2b29985166181ad80e5f50fa42e9 (diff)
s390/uprobes: architecture backend for uprobes
Signed-off-by: Jan Willeke <willeke@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r--arch/s390/kernel/traps.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index c5762324d9ee..e3e06a4fdfce 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -58,15 +58,10 @@ int is_valid_bugaddr(unsigned long addr)
58 return 1; 58 return 1;
59} 59}
60 60
61static void __kprobes do_trap(struct pt_regs *regs, 61void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
62 int si_signo, int si_code, char *str)
63{ 62{
64 siginfo_t info; 63 siginfo_t info;
65 64
66 if (notify_die(DIE_TRAP, str, regs, 0,
67 regs->int_code, si_signo) == NOTIFY_STOP)
68 return;
69
70 if (user_mode(regs)) { 65 if (user_mode(regs)) {
71 info.si_signo = si_signo; 66 info.si_signo = si_signo;
72 info.si_errno = 0; 67 info.si_errno = 0;
@@ -90,6 +85,15 @@ static void __kprobes do_trap(struct pt_regs *regs,
90 } 85 }
91} 86}
92 87
88static void __kprobes do_trap(struct pt_regs *regs, int si_signo, int si_code,
89 char *str)
90{
91 if (notify_die(DIE_TRAP, str, regs, 0,
92 regs->int_code, si_signo) == NOTIFY_STOP)
93 return;
94 do_report_trap(regs, si_signo, si_code, str);
95}
96
93void __kprobes do_per_trap(struct pt_regs *regs) 97void __kprobes do_per_trap(struct pt_regs *regs)
94{ 98{
95 siginfo_t info; 99 siginfo_t info;
@@ -178,6 +182,7 @@ void __kprobes illegal_op(struct pt_regs *regs)
178 siginfo_t info; 182 siginfo_t info;
179 __u8 opcode[6]; 183 __u8 opcode[6];
180 __u16 __user *location; 184 __u16 __user *location;
185 int is_uprobe_insn = 0;
181 int signal = 0; 186 int signal = 0;
182 187
183 location = get_trap_ip(regs); 188 location = get_trap_ip(regs);
@@ -194,6 +199,10 @@ void __kprobes illegal_op(struct pt_regs *regs)
194 force_sig_info(SIGTRAP, &info, current); 199 force_sig_info(SIGTRAP, &info, current);
195 } else 200 } else
196 signal = SIGILL; 201 signal = SIGILL;
202#ifdef CONFIG_UPROBES
203 } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) {
204 is_uprobe_insn = 1;
205#endif
197#ifdef CONFIG_MATHEMU 206#ifdef CONFIG_MATHEMU
198 } else if (opcode[0] == 0xb3) { 207 } else if (opcode[0] == 0xb3) {
199 if (get_user(*((__u16 *) (opcode+2)), location+1)) 208 if (get_user(*((__u16 *) (opcode+2)), location+1))
@@ -219,11 +228,13 @@ void __kprobes illegal_op(struct pt_regs *regs)
219#endif 228#endif
220 } else 229 } else
221 signal = SIGILL; 230 signal = SIGILL;
222 } else { 231 }
223 /* 232 /*
224 * If we get an illegal op in kernel mode, send it through the 233 * We got either an illegal op in kernel mode, or user space trapped
225 * kprobes notifier. If kprobes doesn't pick it up, SIGILL 234 * on a uprobes illegal instruction. See if kprobes or uprobes picks
226 */ 235 * it up. If not, SIGILL.
236 */
237 if (is_uprobe_insn || !user_mode(regs)) {
227 if (notify_die(DIE_BPT, "bpt", regs, 0, 238 if (notify_die(DIE_BPT, "bpt", regs, 0,
228 3, SIGTRAP) != NOTIFY_STOP) 239 3, SIGTRAP) != NOTIFY_STOP)
229 signal = SIGILL; 240 signal = SIGILL;