16 #include <linux/module.h>
20 #include <linux/list.h>
22 #include <asm/cacheflush.h>
24 #include <asm/ftrace.h>
25 #include <asm/syscall.h>
28 #ifdef CONFIG_DYNAMIC_FTRACE
30 ftrace_call_replace(
unsigned long ip,
unsigned long addr,
int link)
34 addr = ppc_function_entry((
void *)addr);
43 ftrace_modify_code(
unsigned long ip,
unsigned int old,
unsigned int new)
45 unsigned int replaced;
75 static int test_24bit_addr(
unsigned long ip,
unsigned long addr)
84 static int is_bl_op(
unsigned int op)
86 return (op & 0xfc000003) == 0x48000001;
89 static unsigned long find_bl_target(
unsigned long ip,
unsigned int op)
93 offset = (op & 0x03fffffc);
95 if (offset & 0x02000000)
98 return ip + (
long)offset;
104 struct dyn_ftrace *rec,
unsigned long addr)
109 unsigned long ip = rec->ip;
124 tramp = find_bl_target(ip, op);
140 pr_devel(
"ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
148 pr_devel(
" %08x %08x", jmp[0], jmp[1]);
151 if (((jmp[0] & 0xffff0000) != 0x3d820000) ||
152 ((jmp[1] & 0xffff0000) != 0x398c0000) ||
153 (jmp[2] != 0xf8410028) ||
154 (jmp[3] != 0xe96c0020) ||
155 (jmp[4] != 0xe84c0028)) {
161 offset = ((unsigned)((
unsigned short)jmp[0]) << 16) +
162 (
int)((
short)jmp[1]);
167 tramp = mod->arch.toc + offset + 32;
175 pr_devel(
" %08x %08x\n", jmp[0], jmp[1]);
177 ptr = ((
unsigned long)jmp[0] << 32) + jmp[1];
180 if (ptr != ppc_function_entry((
void *)
addr)) {
193 if (op != 0xe8410028) {
221 __ftrace_make_nop(
struct module *mod,
222 struct dyn_ftrace *rec,
unsigned long addr)
226 unsigned long ip = rec->ip;
239 tramp = find_bl_target(ip, op);
249 pr_devel(
"ip:%lx jumps to %lx", ip, tramp);
257 pr_devel(
" %08x %08x ", jmp[0], jmp[1]);
260 if (((jmp[0] & 0xffff0000) != 0x3d800000) ||
261 ((jmp[1] & 0xffff0000) != 0x398c0000) ||
262 (jmp[2] != 0x7d8903a6) ||
263 (jmp[3] != 0x4e800420)) {
268 tramp = (jmp[1] & 0xffff) |
269 ((jmp[0] & 0xffff) << 16);
277 "Trampoline location %08lx does not match addr\n",
293 struct dyn_ftrace *rec,
unsigned long addr)
295 unsigned long ip = rec->ip;
296 unsigned int old,
new;
303 if (test_24bit_addr(ip, addr)) {
305 old = ftrace_call_replace(ip, addr, 1);
307 return ftrace_modify_code(ip, old,
new);
310 #ifdef CONFIG_MODULES
316 if (!rec->arch.mod) {
324 if (mod != rec->arch.mod) {
326 "Record mod %p not equal to passed in mod %p\n",
334 return __ftrace_make_nop(mod, rec, addr);
341 #ifdef CONFIG_MODULES
344 __ftrace_make_call(
struct dyn_ftrace *rec,
unsigned long addr)
347 unsigned long ip = rec->ip;
357 if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) &&
364 if (!rec->arch.mod->arch.tramp) {
380 pr_devel(
"write to %lx\n", rec->ip);
391 __ftrace_make_call(
struct dyn_ftrace *rec,
unsigned long addr)
394 unsigned long ip = rec->ip;
407 if (!rec->arch.mod->arch.tramp) {
420 pr_devel(
"write to %lx\n", rec->ip);
432 unsigned long ip = rec->ip;
433 unsigned int old,
new;
440 if (test_24bit_addr(ip, addr)) {
443 new = ftrace_call_replace(ip, addr, 1);
444 return ftrace_modify_code(ip, old,
new);
447 #ifdef CONFIG_MODULES
453 if (!rec->arch.mod) {
458 return __ftrace_make_call(rec, addr);
467 unsigned long ip = (
unsigned long)(&ftrace_call);
468 unsigned int old,
new;
471 old = *(
unsigned int *)&ftrace_call;
472 new = ftrace_call_replace(ip, (
unsigned long)func, 1);
473 ret = ftrace_modify_code(ip, old,
new);
478 static int __ftrace_replace_code(
struct dyn_ftrace *rec,
int enable)
480 unsigned long ftrace_addr = (
unsigned long)FTRACE_ADDR;
483 ret = ftrace_update_record(rec, enable);
486 case FTRACE_UPDATE_IGNORE:
488 case FTRACE_UPDATE_MAKE_CALL:
490 case FTRACE_UPDATE_MAKE_NOP:
497 void ftrace_replace_code(
int enable)
499 struct ftrace_rec_iter *iter;
500 struct dyn_ftrace *rec;
503 for (iter = ftrace_rec_iter_start(); iter;
504 iter = ftrace_rec_iter_next(iter)) {
505 rec = ftrace_rec_iter_record(iter);
506 ret = __ftrace_replace_code(rec, enable);
508 ftrace_bug(ret, rec->ip);
514 void arch_ftrace_update_code(
int command)
516 if (command & FTRACE_UPDATE_CALLS)
517 ftrace_replace_code(1);
518 else if (command & FTRACE_DISABLE_CALLS)
519 ftrace_replace_code(0);
521 if (command & FTRACE_UPDATE_TRACE_FUNC)
524 if (command & FTRACE_START_FUNC_RET)
525 ftrace_enable_ftrace_graph_caller();
526 else if (command & FTRACE_STOP_FUNC_RET)
527 ftrace_disable_ftrace_graph_caller();
533 unsigned long *
p =
data;
541 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
543 #ifdef CONFIG_DYNAMIC_FTRACE
544 extern void ftrace_graph_call(
void);
545 extern void ftrace_graph_stub(
void);
547 int ftrace_enable_ftrace_graph_caller(
void)
549 unsigned long ip = (
unsigned long)(&ftrace_graph_call);
550 unsigned long addr = (
unsigned long)(&ftrace_graph_caller);
551 unsigned long stub = (
unsigned long)(&ftrace_graph_stub);
552 unsigned int old,
new;
554 old = ftrace_call_replace(ip, stub, 0);
555 new = ftrace_call_replace(ip, addr, 0);
557 return ftrace_modify_code(ip, old,
new);
560 int ftrace_disable_ftrace_graph_caller(
void)
562 unsigned long ip = (
unsigned long)(&ftrace_graph_call);
563 unsigned long addr = (
unsigned long)(&ftrace_graph_caller);
564 unsigned long stub = (
unsigned long)(&ftrace_graph_stub);
565 unsigned int old,
new;
567 old = ftrace_call_replace(ip, addr, 0);
568 new = ftrace_call_replace(ip, stub, 0);
570 return ftrace_modify_code(ip, old,
new);
575 extern void mod_return_to_handler(
void);
582 void prepare_ftrace_return(
unsigned long *parent,
unsigned long self_addr)
595 return_hooker = (
unsigned long)&mod_return_to_handler;
598 return_hooker = ppc_function_entry((
void *)return_hooker);
606 "1: " PPC_LL "%[old], 0(%[parent])\n"
607 "2: " PPC_STL "%[return_hooker], 0(%[parent])\n"
608 " li %[faulted], 0\n"
611 ".section .fixup, \"ax\"\n"
612 "4: li %[faulted], 1\n"
616 ".section __ex_table,\"a\"\n"
622 : [old]
"=&r" (old), [faulted]
"=r" (faulted)
623 : [parent]
"r" (parent), [return_hooker]
"r" (return_hooker)
633 trace.func = self_addr;
637 if (!ftrace_graph_entry(&
trace)) {
647 #if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64)