1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/kprobes.h> 4 5 /* Ftrace callback handler for kprobes -- called under preepmt disabed */ 6 void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, 7 struct ftrace_ops *ops, struct ftrace_regs *regs) 8 { 9 struct kprobe *p; 10 struct kprobe_ctlblk *kcb; 11 12 p = get_kprobe((kprobe_opcode_t *)ip); 13 if (unlikely(!p) || kprobe_disabled(p)) 14 return; 15 16 kcb = get_kprobe_ctlblk(); 17 if (kprobe_running()) { 18 kprobes_inc_nmissed_count(p); 19 } else { 20 unsigned long orig_ip = instruction_pointer(&(regs->regs)); 21 22 instruction_pointer_set(&(regs->regs), ip); 23 24 __this_cpu_write(current_kprobe, p); 25 kcb->kprobe_status = KPROBE_HIT_ACTIVE; 26 if (!p->pre_handler || !p->pre_handler(p, &(regs->regs))) { 27 /* 28 * Emulate singlestep (and also recover regs->pc) 29 * as if there is a nop 30 */ 31 instruction_pointer_set(&(regs->regs), 32 (unsigned long)p->addr + MCOUNT_INSN_SIZE); 33 if (unlikely(p->post_handler)) { 34 kcb->kprobe_status = KPROBE_HIT_SSDONE; 35 p->post_handler(p, &(regs->regs), 0); 36 } 37 instruction_pointer_set(&(regs->regs), orig_ip); 38 } 39 40 /* 41 * If pre_handler returns !0, it changes regs->pc. We have to 42 * skip emulating post_handler. 43 */ 44 __this_cpu_write(current_kprobe, NULL); 45 } 46 } 47 NOKPROBE_SYMBOL(kprobe_ftrace_handler); 48 49 int arch_prepare_kprobe_ftrace(struct kprobe *p) 50 { 51 p->ainsn.api.insn = NULL; 52 return 0; 53 } 54