16 #include <linux/string.h>
19 #include <linux/kernel.h>
20 #include <asm/ftrace.h>
21 #include <asm/cacheflush.h>
22 #include <asm/unistd.h>
25 #ifdef CONFIG_DYNAMIC_FTRACE
28 static unsigned char ftrace_nop[4];
47 static unsigned char *ftrace_nop_replace(
unsigned long ip)
53 static unsigned char *ftrace_call_replace(
unsigned long ip,
unsigned long addr)
62 return ftrace_replaced_code;
93 #define MOD_CODE_WRITE_FLAG (1 << 31)
95 static int mod_code_status;
96 static void *mod_code_ip;
97 static void *mod_code_newcode;
99 static unsigned nmi_wait_count;
102 int ftrace_arch_read_dyn_info(
char *
buf,
int size)
112 static void clear_mod_flag(
void)
117 int new = old & ~MOD_CODE_WRITE_FLAG;
126 static void ftrace_mod_code(
void)
142 void ftrace_nmi_enter(
void)
153 void ftrace_nmi_exit(
void)
160 static void wait_for_nmi_and_set_mod_flag(
void)
172 static void wait_for_nmi(
void)
185 do_ftrace_mod_code(
unsigned long ip,
void *new_code)
187 mod_code_ip = (
void *)ip;
188 mod_code_newcode = new_code;
193 wait_for_nmi_and_set_mod_flag();
206 return mod_code_status;
209 static int ftrace_modify_code(
unsigned long ip,
unsigned char *old_code,
210 unsigned char *new_code)
233 if (do_ftrace_mod_code(ip, new_code))
243 unsigned long ip = (
unsigned long)(&ftrace_call) + MCOUNT_INSN_OFFSET;
247 new = ftrace_call_replace(ip, (
unsigned long)func);
249 return ftrace_modify_code(ip, old,
new);
253 struct dyn_ftrace *rec,
unsigned long addr)
255 unsigned char *
new, *old;
256 unsigned long ip = rec->ip;
258 old = ftrace_call_replace(ip, addr);
259 new = ftrace_nop_replace(ip);
261 return ftrace_modify_code(rec->ip, old,
new);
266 unsigned char *
new, *old;
267 unsigned long ip = rec->ip;
269 old = ftrace_nop_replace(ip);
270 new = ftrace_call_replace(ip, addr);
272 return ftrace_modify_code(rec->ip, old,
new);
284 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
285 #ifdef CONFIG_DYNAMIC_FTRACE
286 extern void ftrace_graph_call(
void);
288 static int ftrace_mod(
unsigned long ip,
unsigned long old_addr,
289 unsigned long new_addr)
296 if (old_addr !=
__raw_readl((
unsigned long *)code))
303 int ftrace_enable_ftrace_graph_caller(
void)
305 unsigned long ip, old_addr, new_addr;
307 ip = (
unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET;
308 old_addr = (
unsigned long)(&skip_trace);
309 new_addr = (
unsigned long)(&ftrace_graph_caller);
311 return ftrace_mod(ip, old_addr, new_addr);
314 int ftrace_disable_ftrace_graph_caller(
void)
316 unsigned long ip, old_addr, new_addr;
318 ip = (
unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET;
319 old_addr = (
unsigned long)(&ftrace_graph_caller);
320 new_addr = (
unsigned long)(&skip_trace);
322 return ftrace_mod(ip, old_addr, new_addr);
343 void prepare_ftrace_return(
unsigned long *parent,
unsigned long self_addr)
365 ".section .fixup, \"ax\" \n\t"
373 ".section __ex_table,\"a\" \n\t"
377 :
"=&r" (old),
"=r" (faulted)
378 :
"r" (parent),
"r" (return_hooker)
393 trace.func = self_addr;
396 if (!ftrace_graph_entry(&
trace)) {