2 * Dynamic function tracer architecture backend.
4 * Copyright IBM Corp. 2009
6 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
10 #include <linux/uaccess.h>
11 #include <linux/ftrace.h>
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <asm/lowcore.h>
16 void ftrace_disable_code(void);
17 void ftrace_call_code(void);
18 void ftrace_nop_code(void);
20 #define FTRACE_INSN_SIZE 4
26 "ftrace_disable_code:\n"
29 " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
38 " j .+"__stringify(MCOUNT_INSN_SIZE)"\n");
43 " stg %r14,8(%r15)\n");
45 #else /* CONFIG_64BIT */
49 "ftrace_disable_code:\n"
51 " l %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
66 " j .+"__stringify(MCOUNT_INSN_SIZE)"\n");
71 " st %r14,4(%r15)\n");
73 #endif /* CONFIG_64BIT */
75 static int ftrace_modify_code(unsigned long ip,
76 void *old_code, int old_size,
77 void *new_code, int new_size)
79 unsigned char replaced[MCOUNT_INSN_SIZE];
82 * Note: Due to modules code can disappear and change.
83 * We need to protect against faulting as well as code
84 * changing. We do this by using the probe_kernel_*
86 * This however is just a simple sanity check.
88 if (probe_kernel_read(replaced, (void *)ip, old_size))
90 if (memcmp(replaced, old_code, old_size) != 0)
92 if (probe_kernel_write((void *)ip, new_code, new_size))
97 static int ftrace_make_initial_nop(struct module *mod, struct dyn_ftrace *rec,
100 return ftrace_modify_code(rec->ip,
101 ftrace_call_code, FTRACE_INSN_SIZE,
102 ftrace_disable_code, MCOUNT_INSN_SIZE);
105 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
108 if (addr == MCOUNT_ADDR)
109 return ftrace_make_initial_nop(mod, rec, addr);
110 return ftrace_modify_code(rec->ip,
111 ftrace_call_code, FTRACE_INSN_SIZE,
112 ftrace_nop_code, FTRACE_INSN_SIZE);
115 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
117 return ftrace_modify_code(rec->ip,
118 ftrace_nop_code, FTRACE_INSN_SIZE,
119 ftrace_call_code, FTRACE_INSN_SIZE);
122 int ftrace_update_ftrace_func(ftrace_func_t func)
124 ftrace_dyn_func = (unsigned long)func;
128 int __init ftrace_dyn_arch_init(void *data)
130 *(unsigned long *)data = 0;