Commit | Line | Data |
---|---|---|
a17ae4c3 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
4ba069b8 MG |
2 | /* |
3 | * Kernel Probes (KProbes) | |
4 | * | |
a53c8fab | 5 | * Copyright IBM Corp. 2002, 2006 |
4ba069b8 MG |
6 | * |
7 | * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com> | |
8 | */ | |
9 | ||
9c89bb8e MH |
10 | #define pr_fmt(fmt) "kprobes: " fmt |
11 | ||
4ba069b8 MG |
12 | #include <linux/kprobes.h> |
13 | #include <linux/ptrace.h> | |
14 | #include <linux/preempt.h> | |
15 | #include <linux/stop_machine.h> | |
1eeb66a1 | 16 | #include <linux/kdebug.h> |
a2b53673 | 17 | #include <linux/uaccess.h> |
dcc096c5 | 18 | #include <linux/extable.h> |
4ba069b8 | 19 | #include <linux/module.h> |
5a0e3ad6 | 20 | #include <linux/slab.h> |
adb45839 | 21 | #include <linux/hardirq.h> |
c933146a | 22 | #include <linux/ftrace.h> |
12af2b83 | 23 | #include <linux/execmem.h> |
e6c7c630 | 24 | #include <asm/set_memory.h> |
a882b3b0 HC |
25 | #include <asm/sections.h> |
26 | #include <asm/dis.h> | |
b61e1f32 | 27 | #include "entry.h" |
4ba069b8 | 28 | |
4a188635 | 29 | DEFINE_PER_CPU(struct kprobe *, current_kprobe); |
4ba069b8 MG |
30 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); |
31 | ||
4a188635 | 32 | struct kretprobe_blackpoint kretprobe_blacklist[] = { }; |
f438d914 | 33 | |
6c6687a4 HC |
34 | void *alloc_insn_page(void) |
35 | { | |
36 | void *page; | |
37 | ||
12af2b83 | 38 | page = execmem_alloc(EXECMEM_KPROBES, PAGE_SIZE); |
6c6687a4 HC |
39 | if (!page) |
40 | return NULL; | |
f9b2d96c | 41 | set_memory_rox((unsigned long)page, 1); |
6c6687a4 HC |
42 | return page; |
43 | } | |
44 | ||
7a5388de | 45 | static void copy_instruction(struct kprobe *p) |
63c40436 | 46 | { |
6c6687a4 | 47 | kprobe_opcode_t insn[MAX_INSN_SIZE]; |
63c40436 HC |
48 | s64 disp, new_disp; |
49 | u64 addr, new_addr; | |
6c6687a4 | 50 | unsigned int len; |
63c40436 | 51 | |
6c6687a4 HC |
52 | len = insn_length(*p->addr >> 8); |
53 | memcpy(&insn, p->addr, len); | |
54 | p->opcode = insn[0]; | |
55 | if (probe_is_insn_relative_long(&insn[0])) { | |
56 | /* | |
57 | * For pc-relative instructions in RIL-b or RIL-c format patch | |
d890e6af HC |
58 | * the RI2 displacement field. The insn slot for the to be |
59 | * patched instruction is within the same 4GB area like the | |
60 | * original instruction. Therefore the new displacement will | |
61 | * always fit. | |
6c6687a4 HC |
62 | */ |
63 | disp = *(s32 *)&insn[1]; | |
64 | addr = (u64)(unsigned long)p->addr; | |
65 | new_addr = (u64)(unsigned long)p->ainsn.insn; | |
66 | new_disp = ((addr + (disp * 2)) - new_addr) / 2; | |
67 | *(s32 *)&insn[1] = new_disp; | |
68 | } | |
69 | s390_kernel_write(p->ainsn.insn, &insn, len); | |
63c40436 | 70 | } |
7a5388de | 71 | NOKPROBE_SYMBOL(copy_instruction); |
63c40436 | 72 | |
4df898dc SS |
73 | /* Check if paddr is at an instruction boundary */ |
74 | static bool can_probe(unsigned long paddr) | |
75 | { | |
76 | unsigned long addr, offset = 0; | |
77 | kprobe_opcode_t insn; | |
78 | struct kprobe *kp; | |
79 | ||
80 | if (paddr & 0x01) | |
81 | return false; | |
82 | ||
83 | if (!kallsyms_lookup_size_offset(paddr, NULL, &offset)) | |
84 | return false; | |
85 | ||
86 | /* Decode instructions */ | |
87 | addr = paddr - offset; | |
88 | while (addr < paddr) { | |
89 | if (copy_from_kernel_nofault(&insn, (void *)addr, sizeof(insn))) | |
90 | return false; | |
91 | ||
92 | if (insn >> 8 == 0) { | |
93 | if (insn != BREAKPOINT_INSTRUCTION) { | |
94 | /* | |
95 | * Note that QEMU inserts opcode 0x0000 to implement | |
96 | * software breakpoints for guests. Since the size of | |
97 | * the original instruction is unknown, stop following | |
98 | * instructions and prevent setting a kprobe. | |
99 | */ | |
100 | return false; | |
101 | } | |
102 | /* | |
103 | * Check if the instruction has been modified by another | |
104 | * kprobe, in which case the original instruction is | |
105 | * decoded. | |
106 | */ | |
107 | kp = get_kprobe((void *)addr); | |
108 | if (!kp) { | |
109 | /* not a kprobe */ | |
110 | return false; | |
111 | } | |
112 | insn = kp->opcode; | |
113 | } | |
114 | addr += insn_length(insn >> 8); | |
115 | } | |
116 | return addr == paddr; | |
117 | } | |
118 | ||
7a5388de | 119 | int arch_prepare_kprobe(struct kprobe *p) |
ba640a59 | 120 | { |
4df898dc | 121 | if (!can_probe((unsigned long)p->addr)) |
ba640a59 | 122 | return -EINVAL; |
ba640a59 | 123 | /* Make sure the probe isn't going on a difficult instruction */ |
975fab17 | 124 | if (probe_is_prohibited_opcode(p->addr)) |
ba640a59 | 125 | return -EINVAL; |
d890e6af HC |
126 | p->ainsn.insn = get_insn_slot(); |
127 | if (!p->ainsn.insn) | |
63c40436 | 128 | return -ENOMEM; |
63c40436 | 129 | copy_instruction(p); |
ba640a59 | 130 | return 0; |
4ba069b8 | 131 | } |
7a5388de | 132 | NOKPROBE_SYMBOL(arch_prepare_kprobe); |
4ba069b8 | 133 | |
c933146a HC |
134 | struct swap_insn_args { |
135 | struct kprobe *p; | |
136 | unsigned int arm_kprobe : 1; | |
5a8b589f MS |
137 | }; |
138 | ||
7a5388de | 139 | static int swap_instruction(void *data) |
4ba069b8 | 140 | { |
c933146a | 141 | struct swap_insn_args *args = data; |
c933146a | 142 | struct kprobe *p = args->p; |
657480d9 SS |
143 | u16 opc; |
144 | ||
145 | opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode; | |
146 | s390_kernel_write(p->addr, &opc, sizeof(opc)); | |
5a8b589f | 147 | return 0; |
4ba069b8 | 148 | } |
7a5388de | 149 | NOKPROBE_SYMBOL(swap_instruction); |
4ba069b8 | 150 | |
7a5388de | 151 | void arch_arm_kprobe(struct kprobe *p) |
4ba069b8 | 152 | { |
c933146a | 153 | struct swap_insn_args args = {.p = p, .arm_kprobe = 1}; |
4ba069b8 | 154 | |
5d5dbc4e | 155 | stop_machine_cpuslocked(swap_instruction, &args, NULL); |
4ba069b8 | 156 | } |
7a5388de | 157 | NOKPROBE_SYMBOL(arch_arm_kprobe); |
4ba069b8 | 158 | |
7a5388de | 159 | void arch_disarm_kprobe(struct kprobe *p) |
4ba069b8 | 160 | { |
c933146a | 161 | struct swap_insn_args args = {.p = p, .arm_kprobe = 0}; |
4ba069b8 | 162 | |
5d5dbc4e | 163 | stop_machine_cpuslocked(swap_instruction, &args, NULL); |
4ba069b8 | 164 | } |
7a5388de | 165 | NOKPROBE_SYMBOL(arch_disarm_kprobe); |
4ba069b8 | 166 | |
7a5388de | 167 | void arch_remove_kprobe(struct kprobe *p) |
4ba069b8 | 168 | { |
d890e6af HC |
169 | if (!p->ainsn.insn) |
170 | return; | |
171 | free_insn_slot(p->ainsn.insn, 0); | |
172 | p->ainsn.insn = NULL; | |
4ba069b8 | 173 | } |
7a5388de | 174 | NOKPROBE_SYMBOL(arch_remove_kprobe); |
4ba069b8 | 175 | |
7a5388de HC |
176 | static void enable_singlestep(struct kprobe_ctlblk *kcb, |
177 | struct pt_regs *regs, | |
178 | unsigned long ip) | |
4ba069b8 | 179 | { |
4b440e01 | 180 | union { |
527618ab | 181 | struct ctlreg regs[3]; |
4b440e01 | 182 | struct { |
527618ab HC |
183 | struct ctlreg control; |
184 | struct ctlreg start; | |
185 | struct ctlreg end; | |
4b440e01 HC |
186 | }; |
187 | } per_kprobe; | |
4ba069b8 | 188 | |
5e9a2692 | 189 | /* Set up the PER control registers %cr9-%cr11 */ |
527618ab HC |
190 | per_kprobe.control.val = PER_EVENT_IFETCH; |
191 | per_kprobe.start.val = ip; | |
192 | per_kprobe.end.val = ip; | |
4ba069b8 | 193 | |
fc0a1fea | 194 | /* Save control regs and psw mask */ |
80725978 | 195 | __local_ctl_store(9, 11, kcb->kprobe_saved_ctl); |
fc0a1fea MS |
196 | kcb->kprobe_saved_imask = regs->psw.mask & |
197 | (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT); | |
198 | ||
199 | /* Set PER control regs, turns on single step for the given address */ | |
4b440e01 | 200 | __local_ctl_load(9, 11, per_kprobe.regs); |
4ba069b8 | 201 | regs->psw.mask |= PSW_MASK_PER; |
adb45839 | 202 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); |
fecc868a | 203 | regs->psw.addr = ip; |
4ba069b8 | 204 | } |
7a5388de | 205 | NOKPROBE_SYMBOL(enable_singlestep); |
4ba069b8 | 206 | |
7a5388de HC |
207 | static void disable_singlestep(struct kprobe_ctlblk *kcb, |
208 | struct pt_regs *regs, | |
209 | unsigned long ip) | |
fc0a1fea MS |
210 | { |
211 | /* Restore control regs and psw mask, set new psw address */ | |
80725978 | 212 | __local_ctl_load(9, 11, kcb->kprobe_saved_ctl); |
fc0a1fea MS |
213 | regs->psw.mask &= ~PSW_MASK_PER; |
214 | regs->psw.mask |= kcb->kprobe_saved_imask; | |
fecc868a | 215 | regs->psw.addr = ip; |
fc0a1fea | 216 | } |
7a5388de | 217 | NOKPROBE_SYMBOL(disable_singlestep); |
fc0a1fea | 218 | |
b9599798 MS |
219 | /* |
220 | * Activate a kprobe by storing its pointer to current_kprobe. The | |
221 | * previous kprobe is stored in kcb->prev_kprobe. A stack of up to | |
222 | * two kprobes can be active, see KPROBE_REENTER. | |
223 | */ | |
7a5388de | 224 | static void push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) |
4ba069b8 | 225 | { |
eb7e7d76 | 226 | kcb->prev_kprobe.kp = __this_cpu_read(current_kprobe); |
4ba069b8 | 227 | kcb->prev_kprobe.status = kcb->kprobe_status; |
eb7e7d76 | 228 | __this_cpu_write(current_kprobe, p); |
4ba069b8 | 229 | } |
7a5388de | 230 | NOKPROBE_SYMBOL(push_kprobe); |
4ba069b8 | 231 | |
b9599798 MS |
232 | /* |
233 | * Deactivate a kprobe by backing up to the previous state. If the | |
234 | * current state is KPROBE_REENTER prev_kprobe.kp will be non-NULL, | |
235 | * for any other state prev_kprobe.kp will be NULL. | |
236 | */ | |
7a5388de | 237 | static void pop_kprobe(struct kprobe_ctlblk *kcb) |
4ba069b8 | 238 | { |
eb7e7d76 | 239 | __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); |
4ba069b8 | 240 | kcb->kprobe_status = kcb->prev_kprobe.status; |
cd579539 | 241 | kcb->prev_kprobe.kp = NULL; |
4ba069b8 | 242 | } |
7a5388de | 243 | NOKPROBE_SYMBOL(pop_kprobe); |
4ba069b8 | 244 | |
7a5388de | 245 | static void kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p) |
0e917cc3 MS |
246 | { |
247 | switch (kcb->kprobe_status) { | |
248 | case KPROBE_HIT_SSDONE: | |
249 | case KPROBE_HIT_ACTIVE: | |
250 | kprobes_inc_nmissed_count(p); | |
251 | break; | |
252 | case KPROBE_HIT_SS: | |
253 | case KPROBE_REENTER: | |
254 | default: | |
255 | /* | |
256 | * A kprobe on the code path to single step an instruction | |
257 | * is a BUG. The code path resides in the .kprobes.text | |
258 | * section and is executed with interrupts disabled. | |
259 | */ | |
9c89bb8e | 260 | pr_err("Failed to recover from reentered kprobes.\n"); |
0e917cc3 MS |
261 | dump_kprobe(p); |
262 | BUG(); | |
263 | } | |
264 | } | |
7a5388de | 265 | NOKPROBE_SYMBOL(kprobe_reenter_check); |
0e917cc3 | 266 | |
7a5388de | 267 | static int kprobe_handler(struct pt_regs *regs) |
4ba069b8 | 268 | { |
4ba069b8 | 269 | struct kprobe_ctlblk *kcb; |
0e917cc3 | 270 | struct kprobe *p; |
4ba069b8 MG |
271 | |
272 | /* | |
0e917cc3 MS |
273 | * We want to disable preemption for the entire duration of kprobe |
274 | * processing. That includes the calls to the pre/post handlers | |
275 | * and single stepping the kprobe instruction. | |
4ba069b8 MG |
276 | */ |
277 | preempt_disable(); | |
278 | kcb = get_kprobe_ctlblk(); | |
9cb1ccec | 279 | p = get_kprobe((void *)(regs->psw.addr - 2)); |
4ba069b8 | 280 | |
0e917cc3 MS |
281 | if (p) { |
282 | if (kprobe_running()) { | |
b9599798 MS |
283 | /* |
284 | * We have hit a kprobe while another is still | |
285 | * active. This can happen in the pre and post | |
286 | * handler. Single step the instruction of the | |
287 | * new probe but do not call any handler function | |
288 | * of this secondary kprobe. | |
289 | * push_kprobe and pop_kprobe saves and restores | |
290 | * the currently active kprobe. | |
4ba069b8 | 291 | */ |
0e917cc3 | 292 | kprobe_reenter_check(kcb, p); |
b9599798 | 293 | push_kprobe(kcb, p); |
4ba069b8 | 294 | kcb->kprobe_status = KPROBE_REENTER; |
4ba069b8 | 295 | } else { |
0e917cc3 MS |
296 | /* |
297 | * If we have no pre-handler or it returned 0, we | |
298 | * continue with single stepping. If we have a | |
299 | * pre-handler and it returned non-zero, it prepped | |
fc682f7b MH |
300 | * for changing execution path, so get out doing |
301 | * nothing more here. | |
0e917cc3 MS |
302 | */ |
303 | push_kprobe(kcb, p); | |
304 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | |
cce188bd MH |
305 | if (p->pre_handler && p->pre_handler(p, regs)) { |
306 | pop_kprobe(kcb); | |
307 | preempt_enable_no_resched(); | |
0e917cc3 | 308 | return 1; |
cce188bd | 309 | } |
0e917cc3 | 310 | kcb->kprobe_status = KPROBE_HIT_SS; |
4ba069b8 | 311 | } |
0e917cc3 | 312 | enable_singlestep(kcb, regs, (unsigned long) p->ainsn.insn); |
4ba069b8 | 313 | return 1; |
0e917cc3 MS |
314 | } /* else: |
315 | * No kprobe at this address and no active kprobe. The trap has | |
316 | * not been caused by a kprobe breakpoint. The race of breakpoint | |
317 | * vs. kprobe remove does not exist because on s390 as we use | |
318 | * stop_machine to arm/disarm the breakpoints. | |
319 | */ | |
4ba069b8 | 320 | preempt_enable_no_resched(); |
0e917cc3 | 321 | return 0; |
4ba069b8 | 322 | } |
7a5388de | 323 | NOKPROBE_SYMBOL(kprobe_handler); |
4ba069b8 | 324 | |
4ba069b8 MG |
325 | /* |
326 | * Called after single-stepping. p->addr is the address of the | |
327 | * instruction whose first byte has been replaced by the "breakpoint" | |
328 | * instruction. To avoid the SMP problems that can occur when we | |
329 | * temporarily put back the original opcode to single-step, we | |
330 | * single-stepped a copy of the instruction. The address of this | |
331 | * copy is p->ainsn.insn. | |
332 | */ | |
7a5388de | 333 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) |
4ba069b8 MG |
334 | { |
335 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | |
9cb1ccec | 336 | unsigned long ip = regs->psw.addr; |
975fab17 | 337 | int fixup = probe_get_fixup_type(p->ainsn.insn); |
4ba069b8 | 338 | |
ba640a59 | 339 | if (fixup & FIXUP_PSW_NORMAL) |
fc0a1fea | 340 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; |
4ba069b8 | 341 | |
ba640a59 | 342 | if (fixup & FIXUP_BRANCH_NOT_TAKEN) { |
a882b3b0 | 343 | int ilen = insn_length(p->ainsn.insn[0] >> 8); |
ba640a59 MS |
344 | if (ip - (unsigned long) p->ainsn.insn == ilen) |
345 | ip = (unsigned long) p->addr + ilen; | |
346 | } | |
4ba069b8 | 347 | |
ba640a59 MS |
348 | if (fixup & FIXUP_RETURN_REGISTER) { |
349 | int reg = (p->ainsn.insn[0] & 0xf0) >> 4; | |
350 | regs->gprs[reg] += (unsigned long) p->addr - | |
351 | (unsigned long) p->ainsn.insn; | |
352 | } | |
4ba069b8 | 353 | |
fc0a1fea | 354 | disable_singlestep(kcb, regs, ip); |
4ba069b8 | 355 | } |
7a5388de | 356 | NOKPROBE_SYMBOL(resume_execution); |
4ba069b8 | 357 | |
7a5388de | 358 | static int post_kprobe_handler(struct pt_regs *regs) |
4ba069b8 | 359 | { |
4ba069b8 | 360 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
4a188635 | 361 | struct kprobe *p = kprobe_running(); |
4ba069b8 | 362 | |
4a188635 | 363 | if (!p) |
4ba069b8 MG |
364 | return 0; |
365 | ||
42e19e6f | 366 | resume_execution(p, regs); |
4a188635 | 367 | if (kcb->kprobe_status != KPROBE_REENTER && p->post_handler) { |
4ba069b8 | 368 | kcb->kprobe_status = KPROBE_HIT_SSDONE; |
4a188635 | 369 | p->post_handler(p, regs, 0); |
4ba069b8 | 370 | } |
b9599798 | 371 | pop_kprobe(kcb); |
4ba069b8 MG |
372 | preempt_enable_no_resched(); |
373 | ||
374 | /* | |
375 | * if somebody else is singlestepping across a probe point, psw mask | |
376 | * will have PER set, in which case, continue the remaining processing | |
377 | * of do_single_step, as if this is not a probe hit. | |
378 | */ | |
4a188635 | 379 | if (regs->psw.mask & PSW_MASK_PER) |
4ba069b8 | 380 | return 0; |
4ba069b8 MG |
381 | |
382 | return 1; | |
383 | } | |
7a5388de | 384 | NOKPROBE_SYMBOL(post_kprobe_handler); |
4ba069b8 | 385 | |
7a5388de | 386 | static int kprobe_trap_handler(struct pt_regs *regs, int trapnr) |
4ba069b8 | 387 | { |
4ba069b8 | 388 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
4a188635 | 389 | struct kprobe *p = kprobe_running(); |
4ba069b8 MG |
390 | |
391 | switch(kcb->kprobe_status) { | |
4ba069b8 MG |
392 | case KPROBE_HIT_SS: |
393 | case KPROBE_REENTER: | |
394 | /* | |
395 | * We are here because the instruction being single | |
396 | * stepped caused a page fault. We reset the current | |
397 | * kprobe and the nip points back to the probe address | |
398 | * and allow the page fault handler to continue as a | |
399 | * normal page fault. | |
400 | */ | |
4a188635 | 401 | disable_singlestep(kcb, regs, (unsigned long) p->addr); |
b9599798 | 402 | pop_kprobe(kcb); |
4ba069b8 MG |
403 | preempt_enable_no_resched(); |
404 | break; | |
405 | case KPROBE_HIT_ACTIVE: | |
406 | case KPROBE_HIT_SSDONE: | |
4ba069b8 MG |
407 | /* |
408 | * In case the user-specified fault handler returned | |
409 | * zero, try to fix up. | |
410 | */ | |
46fee16f | 411 | if (fixup_exception(regs)) |
4ba069b8 | 412 | return 1; |
4ba069b8 MG |
413 | /* |
414 | * fixup_exception() could not handle it, | |
415 | * Let do_page_fault() fix it. | |
416 | */ | |
417 | break; | |
418 | default: | |
419 | break; | |
420 | } | |
421 | return 0; | |
422 | } | |
7a5388de | 423 | NOKPROBE_SYMBOL(kprobe_trap_handler); |
4ba069b8 | 424 | |
7a5388de | 425 | int kprobe_fault_handler(struct pt_regs *regs, int trapnr) |
adb45839 MS |
426 | { |
427 | int ret; | |
428 | ||
429 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | |
430 | local_irq_disable(); | |
431 | ret = kprobe_trap_handler(regs, trapnr); | |
432 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | |
433 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | |
434 | return ret; | |
435 | } | |
7a5388de | 436 | NOKPROBE_SYMBOL(kprobe_fault_handler); |
adb45839 | 437 | |
4ba069b8 MG |
438 | /* |
439 | * Wrapper routine to for handling exceptions. | |
440 | */ | |
7a5388de HC |
441 | int kprobe_exceptions_notify(struct notifier_block *self, |
442 | unsigned long val, void *data) | |
4ba069b8 | 443 | { |
4a188635 | 444 | struct die_args *args = (struct die_args *) data; |
adb45839 | 445 | struct pt_regs *regs = args->regs; |
4ba069b8 MG |
446 | int ret = NOTIFY_DONE; |
447 | ||
adb45839 MS |
448 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) |
449 | local_irq_disable(); | |
450 | ||
4ba069b8 MG |
451 | switch (val) { |
452 | case DIE_BPT: | |
4a188635 | 453 | if (kprobe_handler(regs)) |
4ba069b8 MG |
454 | ret = NOTIFY_STOP; |
455 | break; | |
456 | case DIE_SSTEP: | |
4a188635 | 457 | if (post_kprobe_handler(regs)) |
4ba069b8 MG |
458 | ret = NOTIFY_STOP; |
459 | break; | |
460 | case DIE_TRAP: | |
adb45839 | 461 | if (!preemptible() && kprobe_running() && |
4a188635 | 462 | kprobe_trap_handler(regs, args->trapnr)) |
4ba069b8 | 463 | ret = NOTIFY_STOP; |
4ba069b8 MG |
464 | break; |
465 | default: | |
466 | break; | |
467 | } | |
adb45839 MS |
468 | |
469 | if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT)) | |
470 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | |
471 | ||
4ba069b8 MG |
472 | return ret; |
473 | } | |
7a5388de | 474 | NOKPROBE_SYMBOL(kprobe_exceptions_notify); |
4ba069b8 | 475 | |
4ba069b8 MG |
476 | int __init arch_init_kprobes(void) |
477 | { | |
63bf38ff | 478 | return 0; |
4ba069b8 | 479 | } |
bf8f6e5b | 480 | |
7a5388de | 481 | int arch_trampoline_kprobe(struct kprobe *p) |
bf8f6e5b | 482 | { |
63bf38ff | 483 | return 0; |
bf8f6e5b | 484 | } |
7a5388de | 485 | NOKPROBE_SYMBOL(arch_trampoline_kprobe); |