Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/spinlock.h>
0003 #include <linux/hardirq.h>
0004 #include <linux/ftrace.h>
0005 #include <linux/percpu.h>
0006 #include <linux/init.h>
0007 #include <linux/list.h>
0008 #include <trace/syscall.h>
0009 
0010 #include <asm/ftrace.h>
0011 
0012 #ifdef CONFIG_DYNAMIC_FTRACE
0013 static const u32 ftrace_nop = 0x01000000;
0014 
0015 static u32 ftrace_call_replace(unsigned long ip, unsigned long addr)
0016 {
0017     u32 call;
0018     s32 off;
0019 
0020     off = ((s32)addr - (s32)ip);
0021     call = 0x40000000 | ((u32)off >> 2);
0022 
0023     return call;
0024 }
0025 
0026 static int ftrace_modify_code(unsigned long ip, u32 old, u32 new)
0027 {
0028     u32 replaced;
0029     int faulted;
0030 
0031     __asm__ __volatile__(
0032     "1: cas [%[ip]], %[old], %[new]\n"
0033     "   flush   %[ip]\n"
0034     "   mov 0, %[faulted]\n"
0035     "2:\n"
0036     "   .section .fixup,#alloc,#execinstr\n"
0037     "   .align  4\n"
0038     "3: sethi   %%hi(2b), %[faulted]\n"
0039     "   jmpl    %[faulted] + %%lo(2b), %%g0\n"
0040     "    mov    1, %[faulted]\n"
0041     "   .previous\n"
0042     "   .section __ex_table,\"a\"\n"
0043     "   .align  4\n"
0044     "   .word   1b, 3b\n"
0045     "   .previous\n"
0046     : "=r" (replaced), [faulted] "=r" (faulted)
0047     : [new] "0" (new), [old] "r" (old), [ip] "r" (ip)
0048     : "memory");
0049 
0050     if (replaced != old && replaced != new)
0051         faulted = 2;
0052 
0053     return faulted;
0054 }
0055 
0056 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr)
0057 {
0058     unsigned long ip = rec->ip;
0059     u32 old, new;
0060 
0061     old = ftrace_call_replace(ip, addr);
0062     new = ftrace_nop;
0063     return ftrace_modify_code(ip, old, new);
0064 }
0065 
0066 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
0067 {
0068     unsigned long ip = rec->ip;
0069     u32 old, new;
0070 
0071     old = ftrace_nop;
0072     new = ftrace_call_replace(ip, addr);
0073     return ftrace_modify_code(ip, old, new);
0074 }
0075 
0076 int ftrace_update_ftrace_func(ftrace_func_t func)
0077 {
0078     unsigned long ip = (unsigned long)(&ftrace_call);
0079     u32 old, new;
0080 
0081     old = *(u32 *) &ftrace_call;
0082     new = ftrace_call_replace(ip, (unsigned long)func);
0083     return ftrace_modify_code(ip, old, new);
0084 }
0085 #endif
0086 
0087 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
0088 
0089 #ifdef CONFIG_DYNAMIC_FTRACE
0090 extern void ftrace_graph_call(void);
0091 
0092 int ftrace_enable_ftrace_graph_caller(void)
0093 {
0094     unsigned long ip = (unsigned long)(&ftrace_graph_call);
0095     u32 old, new;
0096 
0097     old = *(u32 *) &ftrace_graph_call;
0098     new = ftrace_call_replace(ip, (unsigned long) &ftrace_graph_caller);
0099     return ftrace_modify_code(ip, old, new);
0100 }
0101 
0102 int ftrace_disable_ftrace_graph_caller(void)
0103 {
0104     unsigned long ip = (unsigned long)(&ftrace_graph_call);
0105     u32 old, new;
0106 
0107     old = *(u32 *) &ftrace_graph_call;
0108     new = ftrace_call_replace(ip, (unsigned long) &ftrace_stub);
0109 
0110     return ftrace_modify_code(ip, old, new);
0111 }
0112 
0113 #endif /* !CONFIG_DYNAMIC_FTRACE */
0114 
0115 /*
0116  * Hook the return address and push it in the stack of return addrs
0117  * in current thread info.
0118  */
0119 unsigned long prepare_ftrace_return(unsigned long parent,
0120                     unsigned long self_addr,
0121                     unsigned long frame_pointer)
0122 {
0123     unsigned long return_hooker = (unsigned long) &return_to_handler;
0124 
0125     if (unlikely(atomic_read(&current->tracing_graph_pause)))
0126         return parent + 8UL;
0127 
0128     if (function_graph_enter(parent, self_addr, frame_pointer, NULL))
0129         return parent + 8UL;
0130 
0131     return return_hooker;
0132 }
0133 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */