Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e7dbfe34 MH |
2 | /* |
3 | * Dynamic Ftrace based Kprobes Optimization | |
4 | * | |
e7dbfe34 MH |
5 | * Copyright (C) Hitachi Ltd., 2012 |
6 | */ | |
7 | #include <linux/kprobes.h> | |
8 | #include <linux/ptrace.h> | |
9 | #include <linux/hardirq.h> | |
10 | #include <linux/preempt.h> | |
11 | #include <linux/ftrace.h> | |
12 | ||
f684199f | 13 | #include "common.h" |
e7dbfe34 | 14 | |
5bb4fc2d | 15 | /* Ftrace callback handler for kprobes -- called under preepmt disabed */ |
9326638c MH |
16 | void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, |
17 | struct ftrace_ops *ops, struct pt_regs *regs) | |
e7dbfe34 MH |
18 | { |
19 | struct kprobe *p; | |
20 | struct kprobe_ctlblk *kcb; | |
e7dbfe34 | 21 | |
a19b2e3d | 22 | /* Preempt is disabled by ftrace */ |
e7dbfe34 MH |
23 | p = get_kprobe((kprobe_opcode_t *)ip); |
24 | if (unlikely(!p) || kprobe_disabled(p)) | |
a19b2e3d | 25 | return; |
e7dbfe34 MH |
26 | |
27 | kcb = get_kprobe_ctlblk(); | |
28 | if (kprobe_running()) { | |
29 | kprobes_inc_nmissed_count(p); | |
30 | } else { | |
a017784f | 31 | unsigned long orig_ip = regs->ip; |
e7dbfe34 MH |
32 | /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */ |
33 | regs->ip = ip + sizeof(kprobe_opcode_t); | |
34 | ||
35 | __this_cpu_write(current_kprobe, p); | |
36 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | |
5bb4fc2d | 37 | if (!p->pre_handler || !p->pre_handler(p, regs)) { |
e704e34c MH |
38 | /* |
39 | * Emulate singlestep (and also recover regs->ip) | |
40 | * as if there is a 5byte nop | |
41 | */ | |
42 | regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE; | |
43 | if (unlikely(p->post_handler)) { | |
44 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | |
45 | p->post_handler(p, regs, 0); | |
46 | } | |
47 | regs->ip = orig_ip; | |
5bb4fc2d | 48 | } |
e7dbfe34 | 49 | /* |
cce188bd MH |
50 | * If pre_handler returns !0, it changes regs->ip. We have to |
51 | * skip emulating post_handler. | |
e7dbfe34 | 52 | */ |
cce188bd | 53 | __this_cpu_write(current_kprobe, NULL); |
e7dbfe34 | 54 | } |
e7dbfe34 | 55 | } |
9326638c | 56 | NOKPROBE_SYMBOL(kprobe_ftrace_handler); |
e7dbfe34 | 57 | |
7ec8a97a | 58 | int arch_prepare_kprobe_ftrace(struct kprobe *p) |
e7dbfe34 MH |
59 | { |
60 | p->ainsn.insn = NULL; | |
490154bc | 61 | p->ainsn.boostable = false; |
e7dbfe34 MH |
62 | return 0; |
63 | } |