1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/module.h> 3 #include <linux/kthread.h> 4 #include <linux/ftrace.h> 5 6 void my_direct_func1(void) 7 { 8 trace_printk("my direct func1\n"); 9 } 10 11 void my_direct_func2(void) 12 { 13 trace_printk("my direct func2\n"); 14 } 15 16 extern void my_tramp1(void *); 17 extern void my_tramp2(void *); 18 19 static unsigned long my_ip = (unsigned long)schedule; 20 21 asm ( 22 " .pushsection .text, \"ax\", @progbits\n" 23 " .type my_tramp1, @function\n" 24 " my_tramp1:" 25 " pushq %rbp\n" 26 " movq %rsp, %rbp\n" 27 " call my_direct_func1\n" 28 " leave\n" 29 " .size my_tramp1, .-my_tramp1\n" 30 " ret\n" 31 " .type my_tramp2, @function\n" 32 " my_tramp2:" 33 " pushq %rbp\n" 34 " movq %rsp, %rbp\n" 35 " call my_direct_func2\n" 36 " leave\n" 37 " ret\n" 38 " .size my_tramp2, .-my_tramp2\n" 39 " .popsection\n" 40 ); 41 42 static unsigned long my_tramp = (unsigned long)my_tramp1; 43 static unsigned long tramps[2] = { 44 (unsigned long)my_tramp1, 45 (unsigned long)my_tramp2, 46 }; 47 48 static int simple_thread(void *arg) 49 { 50 static int t; 51 int ret = 0; 52 53 while (!kthread_should_stop()) { 54 set_current_state(TASK_INTERRUPTIBLE); 55 schedule_timeout(2 * HZ); 56 57 if (ret) 58 continue; 59 t ^= 1; 60 ret = modify_ftrace_direct(my_ip, my_tramp, tramps[t]); 61 if (!ret) 62 my_tramp = tramps[t]; 63 WARN_ON_ONCE(ret); 64 } 65 66 return 0; 67 } 68 69 static struct task_struct *simple_tsk; 70 71 static int __init ftrace_direct_init(void) 72 { 73 int ret; 74 75 ret = register_ftrace_direct(my_ip, my_tramp); 76 if (!ret) 77 simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn"); 78 return ret; 79 } 80 81 static void __exit ftrace_direct_exit(void) 82 { 83 kthread_stop(simple_tsk); 84 unregister_ftrace_direct(my_ip, my_tramp); 85 } 86 87 module_init(ftrace_direct_init); 88 module_exit(ftrace_direct_exit); 89 90 MODULE_AUTHOR("Steven Rostedt"); 91 MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct()"); 92 MODULE_LICENSE("GPL"); 93