xref: /openbmc/linux/arch/s390/kernel/ftrace.c (revision 57904291176fa16a981cefca5cbe1a0b50196792)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2dfd9f7abSHeiko Carstens /*
3dfd9f7abSHeiko Carstens  * Dynamic function tracer architecture backend.
4dfd9f7abSHeiko Carstens  *
53d1e220dSHeiko Carstens  * Copyright IBM Corp. 2009,2014
6dfd9f7abSHeiko Carstens  *
7f36e7c98SHeiko Carstens  *   Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
8dfd9f7abSHeiko Carstens  */
9dfd9f7abSHeiko Carstens 
10c933146aSHeiko Carstens #include <linux/moduleloader.h>
1188dbd203SHeiko Carstens #include <linux/hardirq.h>
12dfd9f7abSHeiko Carstens #include <linux/uaccess.h>
13dfd9f7abSHeiko Carstens #include <linux/ftrace.h>
14dfd9f7abSHeiko Carstens #include <linux/kernel.h>
15dfd9f7abSHeiko Carstens #include <linux/types.h>
164cc9bed0SMartin Schwidefsky #include <linux/kprobes.h>
179bf1226bSHeiko Carstens #include <trace/syscall.h>
18cbb870c8SHeiko Carstens #include <asm/asm-offsets.h>
19ae2b9a11SHeiko Carstens #include <asm/text-patching.h>
20c933146aSHeiko Carstens #include <asm/cacheflush.h>
21de5012b4SIlya Leoshkevich #include <asm/ftrace.lds.h>
22de5012b4SIlya Leoshkevich #include <asm/nospec-branch.h>
23e6c7c630SLaura Abbott #include <asm/set_memory.h>
2463df41d6SHeiko Carstens #include "entry.h"
25de5012b4SIlya Leoshkevich #include "ftrace.h"
26dfd9f7abSHeiko Carstens 
274cc9bed0SMartin Schwidefsky /*
28c9343637SVasily Gorbik  * To generate function prologue either gcc's hotpatch feature (since gcc 4.8)
29c9343637SVasily Gorbik  * or a combination of -pg -mrecord-mcount -mnop-mcount -mfentry flags
30c9343637SVasily Gorbik  * (since gcc 9 / clang 10) is used.
31c9343637SVasily Gorbik  * In both cases the original and also the disabled function prologue contains
32c9343637SVasily Gorbik  * only a single six byte instruction and looks like this:
33c9343637SVasily Gorbik  * >	brcl	0,0			# offset 0
34c9343637SVasily Gorbik  * To enable ftrace the code gets patched like above and afterwards looks
35c9343637SVasily Gorbik  * like this:
36c933146aSHeiko Carstens  * >	brasl	%r0,ftrace_caller	# offset 0
37c9343637SVasily Gorbik  *
38c9343637SVasily Gorbik  * The instruction will be patched by ftrace_make_call / ftrace_make_nop.
393d1e220dSHeiko Carstens  * The ftrace function gets called with a non-standard C function call ABI
403d1e220dSHeiko Carstens  * where r0 contains the return address. It is also expected that the called
413d1e220dSHeiko Carstens  * function only clobbers r0 and r1, but restores r2-r15.
42c933146aSHeiko Carstens  * For module code we can't directly jump to ftrace caller, but need a
43c933146aSHeiko Carstens  * trampoline (ftrace_plt), which clobbers also r1.
444cc9bed0SMartin Schwidefsky  */
454cc9bed0SMartin Schwidefsky 
46f8c26027SVasily Gorbik void *ftrace_func __read_mostly = ftrace_stub;
47de5012b4SIlya Leoshkevich struct ftrace_insn {
48de5012b4SIlya Leoshkevich 	u16 opc;
49de5012b4SIlya Leoshkevich 	s32 disp;
50de5012b4SIlya Leoshkevich } __packed;
51de5012b4SIlya Leoshkevich 
52de5012b4SIlya Leoshkevich #ifdef CONFIG_MODULES
53de5012b4SIlya Leoshkevich static char *ftrace_plt;
54de5012b4SIlya Leoshkevich #endif /* CONFIG_MODULES */
55de5012b4SIlya Leoshkevich 
ftrace_shared_hotpatch_trampoline(const char ** end)56de5012b4SIlya Leoshkevich static const char *ftrace_shared_hotpatch_trampoline(const char **end)
57de5012b4SIlya Leoshkevich {
58de5012b4SIlya Leoshkevich 	const char *tstart, *tend;
59de5012b4SIlya Leoshkevich 
60de5012b4SIlya Leoshkevich 	tstart = ftrace_shared_hotpatch_trampoline_br;
61de5012b4SIlya Leoshkevich 	tend = ftrace_shared_hotpatch_trampoline_br_end;
62de5012b4SIlya Leoshkevich #ifdef CONFIG_EXPOLINE
63de5012b4SIlya Leoshkevich 	if (!nospec_disable) {
64de5012b4SIlya Leoshkevich 		tstart = ftrace_shared_hotpatch_trampoline_exrl;
65de5012b4SIlya Leoshkevich 		tend = ftrace_shared_hotpatch_trampoline_exrl_end;
66de5012b4SIlya Leoshkevich 	}
67de5012b4SIlya Leoshkevich #endif /* CONFIG_EXPOLINE */
68de5012b4SIlya Leoshkevich 	if (end)
69de5012b4SIlya Leoshkevich 		*end = tend;
70de5012b4SIlya Leoshkevich 	return tstart;
71de5012b4SIlya Leoshkevich }
72de5012b4SIlya Leoshkevich 
ftrace_need_init_nop(void)73de5012b4SIlya Leoshkevich bool ftrace_need_init_nop(void)
74de5012b4SIlya Leoshkevich {
75b860b934SHeiko Carstens 	return true;
76de5012b4SIlya Leoshkevich }
77de5012b4SIlya Leoshkevich 
ftrace_init_nop(struct module * mod,struct dyn_ftrace * rec)78de5012b4SIlya Leoshkevich int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
79de5012b4SIlya Leoshkevich {
80de5012b4SIlya Leoshkevich 	static struct ftrace_hotpatch_trampoline *next_vmlinux_trampoline =
81de5012b4SIlya Leoshkevich 		__ftrace_hotpatch_trampolines_start;
82de5012b4SIlya Leoshkevich 	static const char orig[6] = { 0xc0, 0x04, 0x00, 0x00, 0x00, 0x00 };
83de5012b4SIlya Leoshkevich 	static struct ftrace_hotpatch_trampoline *trampoline;
84de5012b4SIlya Leoshkevich 	struct ftrace_hotpatch_trampoline **next_trampoline;
85de5012b4SIlya Leoshkevich 	struct ftrace_hotpatch_trampoline *trampolines_end;
86de5012b4SIlya Leoshkevich 	struct ftrace_hotpatch_trampoline tmp;
87de5012b4SIlya Leoshkevich 	struct ftrace_insn *insn;
88de5012b4SIlya Leoshkevich 	const char *shared;
89de5012b4SIlya Leoshkevich 	s32 disp;
90de5012b4SIlya Leoshkevich 
91de5012b4SIlya Leoshkevich 	BUILD_BUG_ON(sizeof(struct ftrace_hotpatch_trampoline) !=
92de5012b4SIlya Leoshkevich 		     SIZEOF_FTRACE_HOTPATCH_TRAMPOLINE);
93de5012b4SIlya Leoshkevich 
94de5012b4SIlya Leoshkevich 	next_trampoline = &next_vmlinux_trampoline;
95de5012b4SIlya Leoshkevich 	trampolines_end = __ftrace_hotpatch_trampolines_end;
96de5012b4SIlya Leoshkevich 	shared = ftrace_shared_hotpatch_trampoline(NULL);
97de5012b4SIlya Leoshkevich #ifdef CONFIG_MODULES
98de5012b4SIlya Leoshkevich 	if (mod) {
99de5012b4SIlya Leoshkevich 		next_trampoline = &mod->arch.next_trampoline;
100de5012b4SIlya Leoshkevich 		trampolines_end = mod->arch.trampolines_end;
101de5012b4SIlya Leoshkevich 		shared = ftrace_plt;
102de5012b4SIlya Leoshkevich 	}
103de5012b4SIlya Leoshkevich #endif
104de5012b4SIlya Leoshkevich 
105de5012b4SIlya Leoshkevich 	if (WARN_ON_ONCE(*next_trampoline >= trampolines_end))
106de5012b4SIlya Leoshkevich 		return -ENOMEM;
107de5012b4SIlya Leoshkevich 	trampoline = (*next_trampoline)++;
108de5012b4SIlya Leoshkevich 
109de5012b4SIlya Leoshkevich 	/* Check for the compiler-generated fentry nop (brcl 0, .). */
110de5012b4SIlya Leoshkevich 	if (WARN_ON_ONCE(memcmp((const void *)rec->ip, &orig, sizeof(orig))))
111de5012b4SIlya Leoshkevich 		return -EINVAL;
112de5012b4SIlya Leoshkevich 
113de5012b4SIlya Leoshkevich 	/* Generate the trampoline. */
114de5012b4SIlya Leoshkevich 	tmp.brasl_opc = 0xc015; /* brasl %r1, shared */
115de5012b4SIlya Leoshkevich 	tmp.brasl_disp = (shared - (const char *)&trampoline->brasl_opc) / 2;
116de5012b4SIlya Leoshkevich 	tmp.interceptor = FTRACE_ADDR;
117de5012b4SIlya Leoshkevich 	tmp.rest_of_intercepted_function = rec->ip + sizeof(struct ftrace_insn);
118de5012b4SIlya Leoshkevich 	s390_kernel_write(trampoline, &tmp, sizeof(tmp));
119de5012b4SIlya Leoshkevich 
120de5012b4SIlya Leoshkevich 	/* Generate a jump to the trampoline. */
121de5012b4SIlya Leoshkevich 	disp = ((char *)trampoline - (char *)rec->ip) / 2;
122de5012b4SIlya Leoshkevich 	insn = (struct ftrace_insn *)rec->ip;
123de5012b4SIlya Leoshkevich 	s390_kernel_write(&insn->disp, &disp, sizeof(disp));
124de5012b4SIlya Leoshkevich 
125de5012b4SIlya Leoshkevich 	return 0;
126de5012b4SIlya Leoshkevich }
1274cc9bed0SMartin Schwidefsky 
ftrace_get_trampoline(struct dyn_ftrace * rec)1289fa881f7SHeiko Carstens static struct ftrace_hotpatch_trampoline *ftrace_get_trampoline(struct dyn_ftrace *rec)
1299fa881f7SHeiko Carstens {
1309fa881f7SHeiko Carstens 	struct ftrace_hotpatch_trampoline *trampoline;
1319fa881f7SHeiko Carstens 	struct ftrace_insn insn;
1329fa881f7SHeiko Carstens 	s64 disp;
1339fa881f7SHeiko Carstens 	u16 opc;
1349fa881f7SHeiko Carstens 
1359fa881f7SHeiko Carstens 	if (copy_from_kernel_nofault(&insn, (void *)rec->ip, sizeof(insn)))
1369fa881f7SHeiko Carstens 		return ERR_PTR(-EFAULT);
1379fa881f7SHeiko Carstens 	disp = (s64)insn.disp * 2;
1389fa881f7SHeiko Carstens 	trampoline = (void *)(rec->ip + disp);
1399fa881f7SHeiko Carstens 	if (get_kernel_nofault(opc, &trampoline->brasl_opc))
1409fa881f7SHeiko Carstens 		return ERR_PTR(-EFAULT);
1419fa881f7SHeiko Carstens 	if (opc != 0xc015)
1429fa881f7SHeiko Carstens 		return ERR_PTR(-EINVAL);
1439fa881f7SHeiko Carstens 	return trampoline;
1449fa881f7SHeiko Carstens }
1459fa881f7SHeiko Carstens 
ftrace_modify_call(struct dyn_ftrace * rec,unsigned long old_addr,unsigned long addr)14610dec7dbSHeiko Carstens int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
14710dec7dbSHeiko Carstens 		       unsigned long addr)
14810dec7dbSHeiko Carstens {
1499fa881f7SHeiko Carstens 	struct ftrace_hotpatch_trampoline *trampoline;
1509fa881f7SHeiko Carstens 	u64 old;
1519fa881f7SHeiko Carstens 
1529fa881f7SHeiko Carstens 	trampoline = ftrace_get_trampoline(rec);
1539fa881f7SHeiko Carstens 	if (IS_ERR(trampoline))
1549fa881f7SHeiko Carstens 		return PTR_ERR(trampoline);
1559fa881f7SHeiko Carstens 	if (get_kernel_nofault(old, &trampoline->interceptor))
1569fa881f7SHeiko Carstens 		return -EFAULT;
1579fa881f7SHeiko Carstens 	if (old != old_addr)
1589fa881f7SHeiko Carstens 		return -EINVAL;
1599fa881f7SHeiko Carstens 	s390_kernel_write(&trampoline->interceptor, &addr, sizeof(addr));
16010dec7dbSHeiko Carstens 	return 0;
16110dec7dbSHeiko Carstens }
162dfd9f7abSHeiko Carstens 
ftrace_patch_branch_mask(void * addr,u16 expected,bool enable)16398c0d24dSSven Schnelle static int ftrace_patch_branch_mask(void *addr, u16 expected, bool enable)
164de5012b4SIlya Leoshkevich {
16598c0d24dSSven Schnelle 	u16 old;
16698c0d24dSSven Schnelle 	u8 op;
167de5012b4SIlya Leoshkevich 
16898c0d24dSSven Schnelle 	if (get_kernel_nofault(old, addr))
16998c0d24dSSven Schnelle 		return -EFAULT;
17098c0d24dSSven Schnelle 	if (old != expected)
17198c0d24dSSven Schnelle 		return -EINVAL;
17298c0d24dSSven Schnelle 	/* set mask field to all ones or zeroes */
17398c0d24dSSven Schnelle 	op = enable ? 0xf4 : 0x04;
17498c0d24dSSven Schnelle 	s390_kernel_write((char *)addr + 1, &op, sizeof(op));
17598c0d24dSSven Schnelle 	return 0;
176de5012b4SIlya Leoshkevich }
177de5012b4SIlya Leoshkevich 
ftrace_make_nop(struct module * mod,struct dyn_ftrace * rec,unsigned long addr)178dfd9f7abSHeiko Carstens int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
179dfd9f7abSHeiko Carstens 		    unsigned long addr)
180dfd9f7abSHeiko Carstens {
18198c0d24dSSven Schnelle 	/* Expect brcl 0xf,... */
18298c0d24dSSven Schnelle 	return ftrace_patch_branch_mask((void *)rec->ip, 0xc0f4, false);
183de5012b4SIlya Leoshkevich }
184de5012b4SIlya Leoshkevich 
ftrace_make_call(struct dyn_ftrace * rec,unsigned long addr)185dfd9f7abSHeiko Carstens int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
186dfd9f7abSHeiko Carstens {
1879fa881f7SHeiko Carstens 	struct ftrace_hotpatch_trampoline *trampoline;
1889fa881f7SHeiko Carstens 
1899fa881f7SHeiko Carstens 	trampoline = ftrace_get_trampoline(rec);
1909fa881f7SHeiko Carstens 	if (IS_ERR(trampoline))
1919fa881f7SHeiko Carstens 		return PTR_ERR(trampoline);
1929fa881f7SHeiko Carstens 	s390_kernel_write(&trampoline->interceptor, &addr, sizeof(addr));
19398c0d24dSSven Schnelle 	/* Expect brcl 0x0,... */
19498c0d24dSSven Schnelle 	return ftrace_patch_branch_mask((void *)rec->ip, 0xc004, true);
195de5012b4SIlya Leoshkevich }
196de5012b4SIlya Leoshkevich 
ftrace_update_ftrace_func(ftrace_func_t func)197dfd9f7abSHeiko Carstens int ftrace_update_ftrace_func(ftrace_func_t func)
198dfd9f7abSHeiko Carstens {
199f8c26027SVasily Gorbik 	ftrace_func = func;
200dfd9f7abSHeiko Carstens 	return 0;
201dfd9f7abSHeiko Carstens }
202dfd9f7abSHeiko Carstens 
arch_ftrace_update_code(int command)203de5012b4SIlya Leoshkevich void arch_ftrace_update_code(int command)
204de5012b4SIlya Leoshkevich {
205de5012b4SIlya Leoshkevich 	ftrace_modify_all_code(command);
206de5012b4SIlya Leoshkevich }
207de5012b4SIlya Leoshkevich 
ftrace_arch_code_modify_post_process(void)2083a2bfec0SLi kunyu void ftrace_arch_code_modify_post_process(void)
209de5012b4SIlya Leoshkevich {
210ae2b9a11SHeiko Carstens 	/*
211ae2b9a11SHeiko Carstens 	 * Flush any pre-fetched instructions on all
212ae2b9a11SHeiko Carstens 	 * CPUs to make the new code visible.
213ae2b9a11SHeiko Carstens 	 */
214ae2b9a11SHeiko Carstens 	text_poke_sync_lock();
215de5012b4SIlya Leoshkevich }
216de5012b4SIlya Leoshkevich 
217085b6ba0SHeiko Carstens #ifdef CONFIG_MODULES
218085b6ba0SHeiko Carstens 
ftrace_plt_init(void)219c933146aSHeiko Carstens static int __init ftrace_plt_init(void)
220c933146aSHeiko Carstens {
221de5012b4SIlya Leoshkevich 	const char *start, *end;
222c933146aSHeiko Carstens 
223de5012b4SIlya Leoshkevich 	ftrace_plt = module_alloc(PAGE_SIZE);
224c933146aSHeiko Carstens 	if (!ftrace_plt)
225c933146aSHeiko Carstens 		panic("cannot allocate ftrace plt\n");
226de5012b4SIlya Leoshkevich 
227de5012b4SIlya Leoshkevich 	start = ftrace_shared_hotpatch_trampoline(&end);
228de5012b4SIlya Leoshkevich 	memcpy(ftrace_plt, start, end - start);
2297c7ab788SHeiko Carstens 	set_memory_rox((unsigned long)ftrace_plt, 1);
230c933146aSHeiko Carstens 	return 0;
231c933146aSHeiko Carstens }
232c933146aSHeiko Carstens device_initcall(ftrace_plt_init);
233c933146aSHeiko Carstens 
234085b6ba0SHeiko Carstens #endif /* CONFIG_MODULES */
235085b6ba0SHeiko Carstens 
23688dbd203SHeiko Carstens #ifdef CONFIG_FUNCTION_GRAPH_TRACER
23788dbd203SHeiko Carstens /*
23888dbd203SHeiko Carstens  * Hook the return address and push it in the stack of return addresses
23988dbd203SHeiko Carstens  * in current thread info.
24088dbd203SHeiko Carstens  */
prepare_ftrace_return(unsigned long ra,unsigned long sp,unsigned long ip)241ec7bf478SMartin Schwidefsky unsigned long prepare_ftrace_return(unsigned long ra, unsigned long sp,
242ec7bf478SMartin Schwidefsky 				    unsigned long ip)
24388dbd203SHeiko Carstens {
2446ed15ea6SHeiko Carstens 	if (unlikely(ftrace_graph_is_dead()))
2456ed15ea6SHeiko Carstens 		goto out;
24688dbd203SHeiko Carstens 	if (unlikely(atomic_read(&current->tracing_graph_pause)))
24788dbd203SHeiko Carstens 		goto out;
2489cb1ccecSHeiko Carstens 	ip -= MCOUNT_INSN_SIZE;
249ec7bf478SMartin Schwidefsky 	if (!function_graph_enter(ra, ip, 0, (void *) sp))
250ec7bf478SMartin Schwidefsky 		ra = (unsigned long) return_to_handler;
25188dbd203SHeiko Carstens out:
252ec7bf478SMartin Schwidefsky 	return ra;
25388dbd203SHeiko Carstens }
2547a5388deSHeiko Carstens NOKPROBE_SYMBOL(prepare_ftrace_return);
2554cc9bed0SMartin Schwidefsky 
2564cc9bed0SMartin Schwidefsky /*
2574cc9bed0SMartin Schwidefsky  * Patch the kernel code at ftrace_graph_caller location. The instruction
2580cccdda8SHeiko Carstens  * there is branch relative on condition. To enable the ftrace graph code
2590cccdda8SHeiko Carstens  * block, we simply patch the mask field of the instruction to zero and
2600cccdda8SHeiko Carstens  * turn the instruction into a nop.
2610cccdda8SHeiko Carstens  * To disable the ftrace graph code the mask field will be patched to
2620cccdda8SHeiko Carstens  * all ones, which turns the instruction into an unconditional branch.
2634cc9bed0SMartin Schwidefsky  */
ftrace_enable_ftrace_graph_caller(void)2642481a87bSHeiko Carstens int ftrace_enable_ftrace_graph_caller(void)
2652481a87bSHeiko Carstens {
26698c0d24dSSven Schnelle 	int rc;
26798c0d24dSSven Schnelle 
26898c0d24dSSven Schnelle 	/* Expect brc 0xf,... */
26998c0d24dSSven Schnelle 	rc = ftrace_patch_branch_mask(ftrace_graph_caller, 0xa7f4, false);
27098c0d24dSSven Schnelle 	if (rc)
27198c0d24dSSven Schnelle 		return rc;
272e5873d6fSHeiko Carstens 	text_poke_sync_lock();
2738a5d8473SHeiko Carstens 	return 0;
2742481a87bSHeiko Carstens }
2752481a87bSHeiko Carstens 
ftrace_disable_ftrace_graph_caller(void)2762481a87bSHeiko Carstens int ftrace_disable_ftrace_graph_caller(void)
2772481a87bSHeiko Carstens {
27898c0d24dSSven Schnelle 	int rc;
27998c0d24dSSven Schnelle 
28098c0d24dSSven Schnelle 	/* Expect brc 0x0,... */
28198c0d24dSSven Schnelle 	rc = ftrace_patch_branch_mask(ftrace_graph_caller, 0xa704, true);
28298c0d24dSSven Schnelle 	if (rc)
28398c0d24dSSven Schnelle 		return rc;
284e5873d6fSHeiko Carstens 	text_poke_sync_lock();
2858a5d8473SHeiko Carstens 	return 0;
2862481a87bSHeiko Carstens }
2872481a87bSHeiko Carstens 
28888dbd203SHeiko Carstens #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
289657480d9SSven Schnelle 
290657480d9SSven Schnelle #ifdef CONFIG_KPROBES_ON_FTRACE
kprobe_ftrace_handler(unsigned long ip,unsigned long parent_ip,struct ftrace_ops * ops,struct ftrace_regs * fregs)291657480d9SSven Schnelle void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
292d19ad077SSteven Rostedt (VMware) 		struct ftrace_ops *ops, struct ftrace_regs *fregs)
293657480d9SSven Schnelle {
294657480d9SSven Schnelle 	struct kprobe_ctlblk *kcb;
295d19ad077SSteven Rostedt (VMware) 	struct pt_regs *regs;
296c536aa1cSSteven Rostedt (VMware) 	struct kprobe *p;
297c536aa1cSSteven Rostedt (VMware) 	int bit;
298657480d9SSven Schnelle 
299*ae0d1ea3SStephen Brennan 	if (unlikely(kprobe_ftrace_disabled))
300*ae0d1ea3SStephen Brennan 		return;
301*ae0d1ea3SStephen Brennan 
302773c1670SSteven Rostedt (VMware) 	bit = ftrace_test_recursion_trylock(ip, parent_ip);
303c536aa1cSSteven Rostedt (VMware) 	if (bit < 0)
304657480d9SSven Schnelle 		return;
305657480d9SSven Schnelle 
306d19ad077SSteven Rostedt (VMware) 	regs = ftrace_get_regs(fregs);
307c536aa1cSSteven Rostedt (VMware) 	p = get_kprobe((kprobe_opcode_t *)ip);
3081389f179SHeiko Carstens 	if (!regs || unlikely(!p) || kprobe_disabled(p))
309c536aa1cSSteven Rostedt (VMware) 		goto out;
310c536aa1cSSteven Rostedt (VMware) 
311657480d9SSven Schnelle 	if (kprobe_running()) {
312657480d9SSven Schnelle 		kprobes_inc_nmissed_count(p);
313c536aa1cSSteven Rostedt (VMware) 		goto out;
314657480d9SSven Schnelle 	}
315657480d9SSven Schnelle 
316657480d9SSven Schnelle 	__this_cpu_write(current_kprobe, p);
317657480d9SSven Schnelle 
318657480d9SSven Schnelle 	kcb = get_kprobe_ctlblk();
319657480d9SSven Schnelle 	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
320657480d9SSven Schnelle 
321657480d9SSven Schnelle 	instruction_pointer_set(regs, ip);
322657480d9SSven Schnelle 
323657480d9SSven Schnelle 	if (!p->pre_handler || !p->pre_handler(p, regs)) {
324657480d9SSven Schnelle 
325657480d9SSven Schnelle 		instruction_pointer_set(regs, ip + MCOUNT_INSN_SIZE);
326657480d9SSven Schnelle 
327657480d9SSven Schnelle 		if (unlikely(p->post_handler)) {
328657480d9SSven Schnelle 			kcb->kprobe_status = KPROBE_HIT_SSDONE;
329657480d9SSven Schnelle 			p->post_handler(p, regs, 0);
330657480d9SSven Schnelle 		}
331657480d9SSven Schnelle 	}
332657480d9SSven Schnelle 	__this_cpu_write(current_kprobe, NULL);
333c536aa1cSSteven Rostedt (VMware) out:
334c536aa1cSSteven Rostedt (VMware) 	ftrace_test_recursion_unlock(bit);
335657480d9SSven Schnelle }
336657480d9SSven Schnelle NOKPROBE_SYMBOL(kprobe_ftrace_handler);
337657480d9SSven Schnelle 
arch_prepare_kprobe_ftrace(struct kprobe * p)338657480d9SSven Schnelle int arch_prepare_kprobe_ftrace(struct kprobe *p)
339657480d9SSven Schnelle {
340657480d9SSven Schnelle 	p->ainsn.insn = NULL;
341657480d9SSven Schnelle 	return 0;
342657480d9SSven Schnelle }
343657480d9SSven Schnelle #endif
344