xref: /openbmc/linux/samples/ftrace/ftrace-direct-multi-modify.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1e1067a07SJiri Olsa // SPDX-License-Identifier: GPL-2.0-only
2e1067a07SJiri Olsa #include <linux/module.h>
3e1067a07SJiri Olsa #include <linux/kthread.h>
4e1067a07SJiri Olsa #include <linux/ftrace.h>
58c3526fbSFlorent Revest #ifndef CONFIG_ARM64
6e1067a07SJiri Olsa #include <asm/asm-offsets.h>
78c3526fbSFlorent Revest #endif
8e1067a07SJiri Olsa 
90daf5cb2SJiri Olsa extern void my_direct_func1(unsigned long ip);
100daf5cb2SJiri Olsa extern void my_direct_func2(unsigned long ip);
110daf5cb2SJiri Olsa 
my_direct_func1(unsigned long ip)12e1067a07SJiri Olsa void my_direct_func1(unsigned long ip)
13e1067a07SJiri Olsa {
14e1067a07SJiri Olsa 	trace_printk("my direct func1 ip %lx\n", ip);
15e1067a07SJiri Olsa }
16e1067a07SJiri Olsa 
my_direct_func2(unsigned long ip)17e1067a07SJiri Olsa void my_direct_func2(unsigned long ip)
18e1067a07SJiri Olsa {
19e1067a07SJiri Olsa 	trace_printk("my direct func2 ip %lx\n", ip);
20e1067a07SJiri Olsa }
21e1067a07SJiri Olsa 
22e1067a07SJiri Olsa extern void my_tramp1(void *);
23e1067a07SJiri Olsa extern void my_tramp2(void *);
24e1067a07SJiri Olsa 
25e1067a07SJiri Olsa #ifdef CONFIG_X86_64
26e1067a07SJiri Olsa 
270aec21cfSPeter Zijlstra #include <asm/ibt.h>
2801678fbcSSong Shuai #include <asm/nospec-branch.h>
290aec21cfSPeter Zijlstra 
30e1067a07SJiri Olsa asm (
31e1067a07SJiri Olsa "	.pushsection    .text, \"ax\", @progbits\n"
32e1067a07SJiri Olsa "	.type		my_tramp1, @function\n"
33e1067a07SJiri Olsa "	.globl		my_tramp1\n"
34e1067a07SJiri Olsa "   my_tramp1:"
350aec21cfSPeter Zijlstra 	ASM_ENDBR
36e1067a07SJiri Olsa "	pushq %rbp\n"
37e1067a07SJiri Olsa "	movq %rsp, %rbp\n"
38ee3e2469SPeter Zijlstra 	CALL_DEPTH_ACCOUNT
39e1067a07SJiri Olsa "	pushq %rdi\n"
40e1067a07SJiri Olsa "	movq 8(%rbp), %rdi\n"
41e1067a07SJiri Olsa "	call my_direct_func1\n"
42e1067a07SJiri Olsa "	popq %rdi\n"
43e1067a07SJiri Olsa "	leave\n"
440aec21cfSPeter Zijlstra 	ASM_RET
45e1067a07SJiri Olsa "	.size		my_tramp1, .-my_tramp1\n"
460aec21cfSPeter Zijlstra 
47e1067a07SJiri Olsa "	.type		my_tramp2, @function\n"
48e1067a07SJiri Olsa "	.globl		my_tramp2\n"
49e1067a07SJiri Olsa "   my_tramp2:"
500aec21cfSPeter Zijlstra 	ASM_ENDBR
51e1067a07SJiri Olsa "	pushq %rbp\n"
52e1067a07SJiri Olsa "	movq %rsp, %rbp\n"
53ee3e2469SPeter Zijlstra 	CALL_DEPTH_ACCOUNT
54e1067a07SJiri Olsa "	pushq %rdi\n"
55e1067a07SJiri Olsa "	movq 8(%rbp), %rdi\n"
56e1067a07SJiri Olsa "	call my_direct_func2\n"
57e1067a07SJiri Olsa "	popq %rdi\n"
58e1067a07SJiri Olsa "	leave\n"
590aec21cfSPeter Zijlstra 	ASM_RET
60e1067a07SJiri Olsa "	.size		my_tramp2, .-my_tramp2\n"
61e1067a07SJiri Olsa "	.popsection\n"
62e1067a07SJiri Olsa );
63e1067a07SJiri Olsa 
64e1067a07SJiri Olsa #endif /* CONFIG_X86_64 */
65e1067a07SJiri Olsa 
66e1067a07SJiri Olsa #ifdef CONFIG_S390
67e1067a07SJiri Olsa 
68e1067a07SJiri Olsa asm (
69e1067a07SJiri Olsa "       .pushsection    .text, \"ax\", @progbits\n"
70e1067a07SJiri Olsa "       .type           my_tramp1, @function\n"
71e1067a07SJiri Olsa "       .globl          my_tramp1\n"
72e1067a07SJiri Olsa "   my_tramp1:"
73e1067a07SJiri Olsa "       lgr             %r1,%r15\n"
74e1067a07SJiri Olsa "       stmg            %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
75e1067a07SJiri Olsa "       stg             %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
76e1067a07SJiri Olsa "       aghi            %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
77e1067a07SJiri Olsa "       stg             %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
78e1067a07SJiri Olsa "       lgr             %r2,%r0\n"
79e1067a07SJiri Olsa "       brasl           %r14,my_direct_func1\n"
80e1067a07SJiri Olsa "       aghi            %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
81e1067a07SJiri Olsa "       lmg             %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
82e1067a07SJiri Olsa "       lg              %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
83e1067a07SJiri Olsa "       lgr             %r1,%r0\n"
84e1067a07SJiri Olsa "       br              %r1\n"
85e1067a07SJiri Olsa "       .size           my_tramp1, .-my_tramp1\n"
86e1067a07SJiri Olsa "\n"
87e1067a07SJiri Olsa "       .type           my_tramp2, @function\n"
88e1067a07SJiri Olsa "       .globl          my_tramp2\n"
89e1067a07SJiri Olsa "   my_tramp2:"
90e1067a07SJiri Olsa "       lgr             %r1,%r15\n"
91e1067a07SJiri Olsa "       stmg            %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
92e1067a07SJiri Olsa "       stg             %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
93e1067a07SJiri Olsa "       aghi            %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
94e1067a07SJiri Olsa "       stg             %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
95e1067a07SJiri Olsa "       lgr             %r2,%r0\n"
96e1067a07SJiri Olsa "       brasl           %r14,my_direct_func2\n"
97e1067a07SJiri Olsa "       aghi            %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
98e1067a07SJiri Olsa "       lmg             %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
99e1067a07SJiri Olsa "       lg              %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
100e1067a07SJiri Olsa "       lgr             %r1,%r0\n"
101e1067a07SJiri Olsa "       br              %r1\n"
102e1067a07SJiri Olsa "       .size           my_tramp2, .-my_tramp2\n"
103e1067a07SJiri Olsa "       .popsection\n"
104e1067a07SJiri Olsa );
105e1067a07SJiri Olsa 
106e1067a07SJiri Olsa #endif /* CONFIG_S390 */
107e1067a07SJiri Olsa 
1088c3526fbSFlorent Revest #ifdef CONFIG_ARM64
1098c3526fbSFlorent Revest 
1108c3526fbSFlorent Revest asm (
1118c3526fbSFlorent Revest "	.pushsection    .text, \"ax\", @progbits\n"
1128c3526fbSFlorent Revest "	.type		my_tramp1, @function\n"
1138c3526fbSFlorent Revest "	.globl		my_tramp1\n"
1148c3526fbSFlorent Revest "   my_tramp1:"
115*e332938eSGONG, Ruiqi "	hint	34\n" // bti	c
1168c3526fbSFlorent Revest "	sub	sp, sp, #32\n"
1178c3526fbSFlorent Revest "	stp	x9, x30, [sp]\n"
1188c3526fbSFlorent Revest "	str	x0, [sp, #16]\n"
1198c3526fbSFlorent Revest "	mov	x0, x30\n"
1208c3526fbSFlorent Revest "	bl	my_direct_func1\n"
1218c3526fbSFlorent Revest "	ldp	x30, x9, [sp]\n"
1228c3526fbSFlorent Revest "	ldr	x0, [sp, #16]\n"
1238c3526fbSFlorent Revest "	add	sp, sp, #32\n"
1248c3526fbSFlorent Revest "	ret	x9\n"
1258c3526fbSFlorent Revest "	.size		my_tramp1, .-my_tramp1\n"
1268c3526fbSFlorent Revest 
1278c3526fbSFlorent Revest "	.type		my_tramp2, @function\n"
1288c3526fbSFlorent Revest "	.globl		my_tramp2\n"
1298c3526fbSFlorent Revest "   my_tramp2:"
130*e332938eSGONG, Ruiqi "	hint	34\n" // bti	c
1318c3526fbSFlorent Revest "	sub	sp, sp, #32\n"
1328c3526fbSFlorent Revest "	stp	x9, x30, [sp]\n"
1338c3526fbSFlorent Revest "	str	x0, [sp, #16]\n"
1348c3526fbSFlorent Revest "	mov	x0, x30\n"
1358c3526fbSFlorent Revest "	bl	my_direct_func2\n"
1368c3526fbSFlorent Revest "	ldp	x30, x9, [sp]\n"
1378c3526fbSFlorent Revest "	ldr	x0, [sp, #16]\n"
1388c3526fbSFlorent Revest "	add	sp, sp, #32\n"
1398c3526fbSFlorent Revest "	ret	x9\n"
1408c3526fbSFlorent Revest "	.size		my_tramp2, .-my_tramp2\n"
1418c3526fbSFlorent Revest "	.popsection\n"
1428c3526fbSFlorent Revest );
1438c3526fbSFlorent Revest 
1448c3526fbSFlorent Revest #endif /* CONFIG_ARM64 */
1458c3526fbSFlorent Revest 
14622f367a6SYouling Tang #ifdef CONFIG_LOONGARCH
14722f367a6SYouling Tang #include <asm/asm.h>
14822f367a6SYouling Tang 
14922f367a6SYouling Tang asm (
15022f367a6SYouling Tang "	.pushsection    .text, \"ax\", @progbits\n"
15122f367a6SYouling Tang "	.type		my_tramp1, @function\n"
15222f367a6SYouling Tang "	.globl		my_tramp1\n"
15322f367a6SYouling Tang "   my_tramp1:\n"
15422f367a6SYouling Tang "	addi.d	$sp, $sp, -32\n"
15522f367a6SYouling Tang "	st.d	$a0, $sp, 0\n"
15622f367a6SYouling Tang "	st.d	$t0, $sp, 8\n"
15722f367a6SYouling Tang "	st.d	$ra, $sp, 16\n"
15822f367a6SYouling Tang "	move	$a0, $t0\n"
15922f367a6SYouling Tang "	bl	my_direct_func1\n"
16022f367a6SYouling Tang "	ld.d	$a0, $sp, 0\n"
16122f367a6SYouling Tang "	ld.d	$t0, $sp, 8\n"
16222f367a6SYouling Tang "	ld.d	$ra, $sp, 16\n"
16322f367a6SYouling Tang "	addi.d	$sp, $sp, 32\n"
16422f367a6SYouling Tang "	jr	$t0\n"
16522f367a6SYouling Tang "	.size		my_tramp1, .-my_tramp1\n"
16622f367a6SYouling Tang 
16722f367a6SYouling Tang "	.type		my_tramp2, @function\n"
16822f367a6SYouling Tang "	.globl		my_tramp2\n"
16922f367a6SYouling Tang "   my_tramp2:\n"
17022f367a6SYouling Tang "	addi.d	$sp, $sp, -32\n"
17122f367a6SYouling Tang "	st.d	$a0, $sp, 0\n"
17222f367a6SYouling Tang "	st.d	$t0, $sp, 8\n"
17322f367a6SYouling Tang "	st.d	$ra, $sp, 16\n"
17422f367a6SYouling Tang "	move	$a0, $t0\n"
17522f367a6SYouling Tang "	bl	my_direct_func2\n"
17622f367a6SYouling Tang "	ld.d	$a0, $sp, 0\n"
17722f367a6SYouling Tang "	ld.d	$t0, $sp, 8\n"
17822f367a6SYouling Tang "	ld.d	$ra, $sp, 16\n"
17922f367a6SYouling Tang "	addi.d	$sp, $sp, 32\n"
18022f367a6SYouling Tang "	jr	$t0\n"
18122f367a6SYouling Tang "	.size		my_tramp2, .-my_tramp2\n"
18222f367a6SYouling Tang "	.popsection\n"
18322f367a6SYouling Tang );
18422f367a6SYouling Tang 
18522f367a6SYouling Tang #endif /* CONFIG_LOONGARCH */
18622f367a6SYouling Tang 
187e1067a07SJiri Olsa static unsigned long my_tramp = (unsigned long)my_tramp1;
188e1067a07SJiri Olsa static unsigned long tramps[2] = {
189e1067a07SJiri Olsa 	(unsigned long)my_tramp1,
190e1067a07SJiri Olsa 	(unsigned long)my_tramp2,
191e1067a07SJiri Olsa };
192e1067a07SJiri Olsa 
193e1067a07SJiri Olsa static struct ftrace_ops direct;
194e1067a07SJiri Olsa 
simple_thread(void * arg)195e1067a07SJiri Olsa static int simple_thread(void *arg)
196e1067a07SJiri Olsa {
197e1067a07SJiri Olsa 	static int t;
198e1067a07SJiri Olsa 	int ret = 0;
199e1067a07SJiri Olsa 
200e1067a07SJiri Olsa 	while (!kthread_should_stop()) {
201e1067a07SJiri Olsa 		set_current_state(TASK_INTERRUPTIBLE);
202e1067a07SJiri Olsa 		schedule_timeout(2 * HZ);
203e1067a07SJiri Olsa 
204e1067a07SJiri Olsa 		if (ret)
205e1067a07SJiri Olsa 			continue;
206e1067a07SJiri Olsa 		t ^= 1;
207da8bdfbdSFlorent Revest 		ret = modify_ftrace_direct(&direct, tramps[t]);
208e1067a07SJiri Olsa 		if (!ret)
209e1067a07SJiri Olsa 			my_tramp = tramps[t];
210e1067a07SJiri Olsa 		WARN_ON_ONCE(ret);
211e1067a07SJiri Olsa 	}
212e1067a07SJiri Olsa 
213e1067a07SJiri Olsa 	return 0;
214e1067a07SJiri Olsa }
215e1067a07SJiri Olsa 
216e1067a07SJiri Olsa static struct task_struct *simple_tsk;
217e1067a07SJiri Olsa 
ftrace_direct_multi_init(void)218e1067a07SJiri Olsa static int __init ftrace_direct_multi_init(void)
219e1067a07SJiri Olsa {
220e1067a07SJiri Olsa 	int ret;
221e1067a07SJiri Olsa 
222e1067a07SJiri Olsa 	ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);
223e1067a07SJiri Olsa 	ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0);
224e1067a07SJiri Olsa 
225da8bdfbdSFlorent Revest 	ret = register_ftrace_direct(&direct, my_tramp);
226e1067a07SJiri Olsa 
227e1067a07SJiri Olsa 	if (!ret)
228e1067a07SJiri Olsa 		simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn");
229e1067a07SJiri Olsa 	return ret;
230e1067a07SJiri Olsa }
231e1067a07SJiri Olsa 
ftrace_direct_multi_exit(void)232e1067a07SJiri Olsa static void __exit ftrace_direct_multi_exit(void)
233e1067a07SJiri Olsa {
234e1067a07SJiri Olsa 	kthread_stop(simple_tsk);
235da8bdfbdSFlorent Revest 	unregister_ftrace_direct(&direct, my_tramp, true);
236e1067a07SJiri Olsa }
237e1067a07SJiri Olsa 
238e1067a07SJiri Olsa module_init(ftrace_direct_multi_init);
239e1067a07SJiri Olsa module_exit(ftrace_direct_multi_exit);
240e1067a07SJiri Olsa 
241e1067a07SJiri Olsa MODULE_AUTHOR("Jiri Olsa");
242da8bdfbdSFlorent Revest MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct()");
243e1067a07SJiri Olsa MODULE_LICENSE("GPL");
244