|
6 | 6 | */
|
7 | 7 |
|
8 | 8 | #include <linux/ftrace.h>
|
| 9 | +#include <linux/kprobes.h> |
9 | 10 | #include <linux/uaccess.h>
|
10 | 11 |
|
11 | 12 | #include <asm/inst.h>
|
@@ -271,3 +272,66 @@ int ftrace_disable_ftrace_graph_caller(void)
|
271 | 272 | }
|
272 | 273 | #endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
|
273 | 274 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
| 275 | + |
| 276 | +#ifdef CONFIG_KPROBES_ON_FTRACE |
| 277 | +/* Ftrace callback handler for kprobes -- called under preepmt disabled */ |
| 278 | +void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, |
| 279 | + struct ftrace_ops *ops, struct ftrace_regs *fregs) |
| 280 | +{ |
| 281 | + int bit; |
| 282 | + struct pt_regs *regs; |
| 283 | + struct kprobe *p; |
| 284 | + struct kprobe_ctlblk *kcb; |
| 285 | + |
| 286 | + bit = ftrace_test_recursion_trylock(ip, parent_ip); |
| 287 | + if (bit < 0) |
| 288 | + return; |
| 289 | + |
| 290 | + p = get_kprobe((kprobe_opcode_t *)ip); |
| 291 | + if (unlikely(!p) || kprobe_disabled(p)) |
| 292 | + goto out; |
| 293 | + |
| 294 | + regs = ftrace_get_regs(fregs); |
| 295 | + if (!regs) |
| 296 | + goto out; |
| 297 | + |
| 298 | + kcb = get_kprobe_ctlblk(); |
| 299 | + if (kprobe_running()) { |
| 300 | + kprobes_inc_nmissed_count(p); |
| 301 | + } else { |
| 302 | + unsigned long orig_ip = instruction_pointer(regs); |
| 303 | + |
| 304 | + instruction_pointer_set(regs, ip); |
| 305 | + |
| 306 | + __this_cpu_write(current_kprobe, p); |
| 307 | + kcb->kprobe_status = KPROBE_HIT_ACTIVE; |
| 308 | + if (!p->pre_handler || !p->pre_handler(p, regs)) { |
| 309 | + /* |
| 310 | + * Emulate singlestep (and also recover regs->csr_era) |
| 311 | + * as if there is a nop |
| 312 | + */ |
| 313 | + instruction_pointer_set(regs, (unsigned long)p->addr + MCOUNT_INSN_SIZE); |
| 314 | + if (unlikely(p->post_handler)) { |
| 315 | + kcb->kprobe_status = KPROBE_HIT_SSDONE; |
| 316 | + p->post_handler(p, regs, 0); |
| 317 | + } |
| 318 | + instruction_pointer_set(regs, orig_ip); |
| 319 | + } |
| 320 | + |
| 321 | + /* |
| 322 | + * If pre_handler returns !0, it changes regs->csr_era. We have to |
| 323 | + * skip emulating post_handler. |
| 324 | + */ |
| 325 | + __this_cpu_write(current_kprobe, NULL); |
| 326 | + } |
| 327 | +out: |
| 328 | + ftrace_test_recursion_unlock(bit); |
| 329 | +} |
| 330 | +NOKPROBE_SYMBOL(kprobe_ftrace_handler); |
| 331 | + |
| 332 | +int arch_prepare_kprobe_ftrace(struct kprobe *p) |
| 333 | +{ |
| 334 | + p->ainsn.insn = NULL; |
| 335 | + return 0; |
| 336 | +} |
| 337 | +#endif /* CONFIG_KPROBES_ON_FTRACE */ |
0 commit comments