| 1 | |
| 2 | #include <linux/module.h>
|
| 3 | #include <linux/kthread.h>
|
| 4 | #include <linux/ftrace.h>
|
| 5 | #if !defined(CONFIG_ARM64) && !defined(CONFIG_PPC32)
|
| 6 | #include <asm/asm-offsets.h>
|
| 7 | #endif
|
| 8 |
|
| 9 | extern void my_direct_func1(unsigned long ip);
|
| 10 | extern void my_direct_func2(unsigned long ip);
|
| 11 |
|
| 12 | void my_direct_func1(unsigned long ip)
|
| 13 | {
|
| 14 | trace_printk("my direct func1 ip %lx\n", ip);
|
| 15 | }
|
| 16 |
|
| 17 | void my_direct_func2(unsigned long ip)
|
| 18 | {
|
| 19 | trace_printk("my direct func2 ip %lx\n", ip);
|
| 20 | }
|
| 21 |
|
| 22 | extern void my_tramp1(void *);
|
| 23 | extern void my_tramp2(void *);
|
| 24 |
|
| 25 | #ifdef CONFIG_RISCV
|
| 26 | #include <asm/asm.h>
|
| 27 |
|
| 28 | asm (
|
| 29 | " .pushsection .text, \"ax\", @progbits\n"
|
| 30 | " .type my_tramp1, @function\n"
|
| 31 | " .globl my_tramp1\n"
|
| 32 | " my_tramp1:\n"
|
| 33 | " addi sp,sp,-3*"SZREG"\n"
|
| 34 | " "REG_S" a0,0*"SZREG"(sp)\n"
|
| 35 | " "REG_S" t0,1*"SZREG"(sp)\n"
|
| 36 | " "REG_S" ra,2*"SZREG"(sp)\n"
|
| 37 | " mv a0,t0\n"
|
| 38 | " call my_direct_func1\n"
|
| 39 | " "REG_L" a0,0*"SZREG"(sp)\n"
|
| 40 | " "REG_L" t0,1*"SZREG"(sp)\n"
|
| 41 | " "REG_L" ra,2*"SZREG"(sp)\n"
|
| 42 | " addi sp,sp,3*"SZREG"\n"
|
| 43 | " jr t0\n"
|
| 44 | " .size my_tramp1, .-my_tramp1\n"
|
| 45 |
|
| 46 | " .type my_tramp2, @function\n"
|
| 47 | " .globl my_tramp2\n"
|
| 48 | " my_tramp2:\n"
|
| 49 | " addi sp,sp,-3*"SZREG"\n"
|
| 50 | " "REG_S" a0,0*"SZREG"(sp)\n"
|
| 51 | " "REG_S" t0,1*"SZREG"(sp)\n"
|
| 52 | " "REG_S" ra,2*"SZREG"(sp)\n"
|
| 53 | " mv a0,t0\n"
|
| 54 | " call my_direct_func2\n"
|
| 55 | " "REG_L" a0,0*"SZREG"(sp)\n"
|
| 56 | " "REG_L" t0,1*"SZREG"(sp)\n"
|
| 57 | " "REG_L" ra,2*"SZREG"(sp)\n"
|
| 58 | " addi sp,sp,3*"SZREG"\n"
|
| 59 | " jr t0\n"
|
| 60 | " .size my_tramp2, .-my_tramp2\n"
|
| 61 | " .popsection\n"
|
| 62 | );
|
| 63 |
|
| 64 | #endif
|
| 65 |
|
| 66 | #ifdef CONFIG_X86_64
|
| 67 |
|
| 68 | #include <asm/ibt.h>
|
| 69 | #include <asm/nospec-branch.h>
|
| 70 |
|
| 71 | asm (
|
| 72 | " .pushsection .text, \"ax\", @progbits\n"
|
| 73 | " .type my_tramp1, @function\n"
|
| 74 | " .globl my_tramp1\n"
|
| 75 | " my_tramp1:"
|
| 76 | ASM_ENDBR
|
| 77 | " pushq %rbp\n"
|
| 78 | " movq %rsp, %rbp\n"
|
| 79 | CALL_DEPTH_ACCOUNT
|
| 80 | " pushq %rdi\n"
|
| 81 | " movq 8(%rbp), %rdi\n"
|
| 82 | " call my_direct_func1\n"
|
| 83 | " popq %rdi\n"
|
| 84 | " leave\n"
|
| 85 | ASM_RET
|
| 86 | " .size my_tramp1, .-my_tramp1\n"
|
| 87 |
|
| 88 | " .type my_tramp2, @function\n"
|
| 89 | " .globl my_tramp2\n"
|
| 90 | " my_tramp2:"
|
| 91 | ASM_ENDBR
|
| 92 | " pushq %rbp\n"
|
| 93 | " movq %rsp, %rbp\n"
|
| 94 | CALL_DEPTH_ACCOUNT
|
| 95 | " pushq %rdi\n"
|
| 96 | " movq 8(%rbp), %rdi\n"
|
| 97 | " call my_direct_func2\n"
|
| 98 | " popq %rdi\n"
|
| 99 | " leave\n"
|
| 100 | ASM_RET
|
| 101 | " .size my_tramp2, .-my_tramp2\n"
|
| 102 | " .popsection\n"
|
| 103 | );
|
| 104 |
|
| 105 | #endif
|
| 106 |
|
| 107 | #ifdef CONFIG_S390
|
| 108 |
|
| 109 | asm (
|
| 110 | " .pushsection .text, \"ax\", @progbits\n"
|
| 111 | " .type my_tramp1, @function\n"
|
| 112 | " .globl my_tramp1\n"
|
| 113 | " my_tramp1:"
|
| 114 | " lgr %r1,%r15\n"
|
| 115 | " stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
|
| 116 | " stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
|
| 117 | " aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
|
| 118 | " stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
|
| 119 | " lgr %r2,%r0\n"
|
| 120 | " brasl %r14,my_direct_func1\n"
|
| 121 | " aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
|
| 122 | " lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
|
| 123 | " lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
|
| 124 | " lgr %r1,%r0\n"
|
| 125 | " br %r1\n"
|
| 126 | " .size my_tramp1, .-my_tramp1\n"
|
| 127 | "\n"
|
| 128 | " .type my_tramp2, @function\n"
|
| 129 | " .globl my_tramp2\n"
|
| 130 | " my_tramp2:"
|
| 131 | " lgr %r1,%r15\n"
|
| 132 | " stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
|
| 133 | " stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
|
| 134 | " aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
|
| 135 | " stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
|
| 136 | " lgr %r2,%r0\n"
|
| 137 | " brasl %r14,my_direct_func2\n"
|
| 138 | " aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
|
| 139 | " lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
|
| 140 | " lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
|
| 141 | " lgr %r1,%r0\n"
|
| 142 | " br %r1\n"
|
| 143 | " .size my_tramp2, .-my_tramp2\n"
|
| 144 | " .popsection\n"
|
| 145 | );
|
| 146 |
|
| 147 | #endif
|
| 148 |
|
| 149 | #ifdef CONFIG_ARM64
|
| 150 |
|
| 151 | asm (
|
| 152 | " .pushsection .text, \"ax\", @progbits\n"
|
| 153 | " .type my_tramp1, @function\n"
|
| 154 | " .globl my_tramp1\n"
|
| 155 | " my_tramp1:"
|
| 156 | " hint 34\n" |
| 157 | " sub sp, sp, #32\n"
|
| 158 | " stp x9, x30, [sp]\n"
|
| 159 | " str x0, [sp, #16]\n"
|
| 160 | " mov x0, x30\n"
|
| 161 | " bl my_direct_func1\n"
|
| 162 | " ldp x30, x9, [sp]\n"
|
| 163 | " ldr x0, [sp, #16]\n"
|
| 164 | " add sp, sp, #32\n"
|
| 165 | " ret x9\n"
|
| 166 | " .size my_tramp1, .-my_tramp1\n"
|
| 167 |
|
| 168 | " .type my_tramp2, @function\n"
|
| 169 | " .globl my_tramp2\n"
|
| 170 | " my_tramp2:"
|
| 171 | " hint 34\n" |
| 172 | " sub sp, sp, #32\n"
|
| 173 | " stp x9, x30, [sp]\n"
|
| 174 | " str x0, [sp, #16]\n"
|
| 175 | " mov x0, x30\n"
|
| 176 | " bl my_direct_func2\n"
|
| 177 | " ldp x30, x9, [sp]\n"
|
| 178 | " ldr x0, [sp, #16]\n"
|
| 179 | " add sp, sp, #32\n"
|
| 180 | " ret x9\n"
|
| 181 | " .size my_tramp2, .-my_tramp2\n"
|
| 182 | " .popsection\n"
|
| 183 | );
|
| 184 |
|
| 185 | #endif
|
| 186 |
|
| 187 | #ifdef CONFIG_LOONGARCH
|
| 188 | #include <asm/asm.h>
|
| 189 |
|
| 190 | asm (
|
| 191 | " .pushsection .text, \"ax\", @progbits\n"
|
| 192 | " .type my_tramp1, @function\n"
|
| 193 | " .globl my_tramp1\n"
|
| 194 | " my_tramp1:\n"
|
| 195 | " addi.d $sp, $sp, -32\n"
|
| 196 | " st.d $a0, $sp, 0\n"
|
| 197 | " st.d $t0, $sp, 8\n"
|
| 198 | " st.d $ra, $sp, 16\n"
|
| 199 | " move $a0, $t0\n"
|
| 200 | " bl my_direct_func1\n"
|
| 201 | " ld.d $a0, $sp, 0\n"
|
| 202 | " ld.d $ra, $sp, 8\n"
|
| 203 | " ld.d $t0, $sp, 16\n"
|
| 204 | " addi.d $sp, $sp, 32\n"
|
| 205 | " jr $t0\n"
|
| 206 | " .size my_tramp1, .-my_tramp1\n"
|
| 207 |
|
| 208 | " .type my_tramp2, @function\n"
|
| 209 | " .globl my_tramp2\n"
|
| 210 | " my_tramp2:\n"
|
| 211 | " addi.d $sp, $sp, -32\n"
|
| 212 | " st.d $a0, $sp, 0\n"
|
| 213 | " st.d $t0, $sp, 8\n"
|
| 214 | " st.d $ra, $sp, 16\n"
|
| 215 | " move $a0, $t0\n"
|
| 216 | " bl my_direct_func2\n"
|
| 217 | " ld.d $a0, $sp, 0\n"
|
| 218 | " ld.d $ra, $sp, 8\n"
|
| 219 | " ld.d $t0, $sp, 16\n"
|
| 220 | " addi.d $sp, $sp, 32\n"
|
| 221 | " jr $t0\n"
|
| 222 | " .size my_tramp2, .-my_tramp2\n"
|
| 223 | " .popsection\n"
|
| 224 | );
|
| 225 |
|
| 226 | #endif
|
| 227 |
|
| 228 | #ifdef CONFIG_PPC
|
| 229 | #include <asm/ppc_asm.h>
|
| 230 |
|
| 231 | #ifdef CONFIG_PPC64
|
| 232 | #define STACK_FRAME_SIZE 48
|
| 233 | #else
|
| 234 | #define STACK_FRAME_SIZE 24
|
| 235 | #endif
|
| 236 |
|
| 237 | #if defined(CONFIG_PPC64_ELF_ABI_V2) && !defined(CONFIG_PPC_KERNEL_PCREL)
|
| 238 | #define PPC64_TOC_SAVE_AND_UPDATE \
|
| 239 | " std 2, 24(1)\n" \
|
| 240 | " bcl 20, 31, 1f\n" \
|
| 241 | " 1: mflr 12\n" \
|
| 242 | " ld 2, (99f - 1b)(12)\n"
|
| 243 | #define PPC64_TOC_RESTORE \
|
| 244 | " ld 2, 24(1)\n"
|
| 245 | #define PPC64_TOC \
|
| 246 | " 99: .quad .TOC.@tocbase\n"
|
| 247 | #else
|
| 248 | #define PPC64_TOC_SAVE_AND_UPDATE ""
|
| 249 | #define PPC64_TOC_RESTORE ""
|
| 250 | #define PPC64_TOC ""
|
| 251 | #endif
|
| 252 |
|
| 253 | #ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE
|
| 254 | #define PPC_FTRACE_RESTORE_LR \
|
| 255 | PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \
|
| 256 | " mtlr 0\n"
|
| 257 | #define PPC_FTRACE_RET \
|
| 258 | " blr\n"
|
| 259 | #define PPC_FTRACE_RECOVER_IP \
|
| 260 | " lwz 8, 4(3)\n" \
|
| 261 | " li 9, 6\n" \
|
| 262 | " slw 8, 8, 9\n" \
|
| 263 | " sraw 8, 8, 9\n" \
|
| 264 | " add 3, 3, 8\n" \
|
| 265 | " addi 3, 3, 4\n"
|
| 266 | #else
|
| 267 | #define PPC_FTRACE_RESTORE_LR \
|
| 268 | PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \
|
| 269 | " mtctr 0\n"
|
| 270 | #define PPC_FTRACE_RET \
|
| 271 | " mtlr 0\n" \
|
| 272 | " bctr\n"
|
| 273 | #define PPC_FTRACE_RECOVER_IP ""
|
| 274 | #endif
|
| 275 |
|
| 276 | asm (
|
| 277 | " .pushsection .text, \"ax\", @progbits\n"
|
| 278 | " .type my_tramp1, @function\n"
|
| 279 | " .globl my_tramp1\n"
|
| 280 | " my_tramp1:\n"
|
| 281 | PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n"
|
| 282 | PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n"
|
| 283 | " mflr 0\n"
|
| 284 | PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n"
|
| 285 | PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n"
|
| 286 | PPC64_TOC_SAVE_AND_UPDATE
|
| 287 | PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n"
|
| 288 | " mr 3, 0\n"
|
| 289 | PPC_FTRACE_RECOVER_IP
|
| 290 | " bl my_direct_func1\n"
|
| 291 | PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n"
|
| 292 | PPC64_TOC_RESTORE
|
| 293 | " addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n"
|
| 294 | PPC_FTRACE_RESTORE_LR
|
| 295 | " addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n"
|
| 296 | PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n"
|
| 297 | PPC_FTRACE_RET
|
| 298 | " .size my_tramp1, .-my_tramp1\n"
|
| 299 |
|
| 300 | " .type my_tramp2, @function\n"
|
| 301 | " .globl my_tramp2\n"
|
| 302 | " my_tramp2:\n"
|
| 303 | PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n"
|
| 304 | PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n"
|
| 305 | " mflr 0\n"
|
| 306 | PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n"
|
| 307 | PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n"
|
| 308 | PPC64_TOC_SAVE_AND_UPDATE
|
| 309 | PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n"
|
| 310 | " mr 3, 0\n"
|
| 311 | PPC_FTRACE_RECOVER_IP
|
| 312 | " bl my_direct_func2\n"
|
| 313 | PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n"
|
| 314 | PPC64_TOC_RESTORE
|
| 315 | " addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n"
|
| 316 | PPC_FTRACE_RESTORE_LR
|
| 317 | " addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n"
|
| 318 | PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n"
|
| 319 | PPC_FTRACE_RET
|
| 320 | PPC64_TOC
|
| 321 | " .size my_tramp2, .-my_tramp2\n"
|
| 322 | " .popsection\n"
|
| 323 | );
|
| 324 |
|
| 325 | #endif
|
| 326 |
|
| 327 | static unsigned long my_tramp = (unsigned long)my_tramp1;
|
| 328 | static unsigned long tramps[2] = {
|
| 329 | (unsigned long)my_tramp1,
|
| 330 | (unsigned long)my_tramp2,
|
| 331 | };
|
| 332 |
|
| 333 | static struct ftrace_ops direct;
|
| 334 |
|
| 335 | static int simple_thread(void *arg)
|
| 336 | {
|
| 337 | static int t;
|
| 338 | int ret = 0;
|
| 339 |
|
| 340 | while (!kthread_should_stop()) {
|
| 341 | set_current_state(TASK_INTERRUPTIBLE);
|
| 342 | schedule_timeout(2 * HZ);
|
| 343 |
|
| 344 | if (ret)
|
| 345 | continue;
|
| 346 | t ^= 1;
|
| 347 | ret = modify_ftrace_direct(&direct, tramps[t]);
|
| 348 | if (!ret)
|
| 349 | my_tramp = tramps[t];
|
| 350 | WARN_ON_ONCE(ret);
|
| 351 | }
|
| 352 |
|
| 353 | return 0;
|
| 354 | }
|
| 355 |
|
| 356 | static struct task_struct *simple_tsk;
|
| 357 |
|
| 358 | static int __init ftrace_direct_multi_init(void)
|
| 359 | {
|
| 360 | int ret;
|
| 361 |
|
| 362 | ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);
|
| 363 | ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0);
|
| 364 |
|
| 365 | ret = register_ftrace_direct(&direct, my_tramp);
|
| 366 |
|
| 367 | if (ret)
|
| 368 | return ret;
|
| 369 | simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn");
|
| 370 | if (IS_ERR(simple_tsk)) {
|
| 371 | unregister_ftrace_direct(&direct, my_tramp, true);
|
| 372 | return PTR_ERR(simple_tsk);
|
| 373 | }
|
| 374 |
|
| 375 | return 0;
|
| 376 | }
|
| 377 |
|
| 378 | static void __exit ftrace_direct_multi_exit(void)
|
| 379 | {
|
| 380 | kthread_stop(simple_tsk);
|
| 381 | unregister_ftrace_direct(&direct, my_tramp, true);
|
| 382 | }
|
| 383 |
|
| 384 | module_init(ftrace_direct_multi_init);
|
| 385 | module_exit(ftrace_direct_multi_exit);
|
| 386 |
|
| 387 | MODULE_AUTHOR("Jiri Olsa");
|
| 388 | MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct()");
|
| 389 | MODULE_LICENSE("GPL");
|