2 * Dynamic function tracing support.
4 * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com>
6 * For licencing details, see COPYING.
8 * Defines low-level handling of mcount calls when the kernel
9 * is compiled with the -pg flag. When using dynamic ftrace, the
10 * mcount call-sites get patched lazily with NOP till they are
11 * enabled. All code mutation routines here take effect atomically.
14 #include <linux/ftrace.h>
16 #include <asm/cacheflush.h>
17 #include <asm/ftrace.h>
20 #define BL_OPCODE 0xeb000000
21 #define BL_OFFSET_MASK 0x00ffffff
23 static unsigned long bl_insn
;
24 static const unsigned long NOP
= 0xe1a00000; /* mov r0, r0 */
26 unsigned char *ftrace_nop_replace(void)
31 /* construct a branch (BL) instruction to addr */
32 unsigned char *ftrace_call_replace(unsigned long pc
, unsigned long addr
)
36 offset
= (long)addr
- (long)(pc
+ PC_OFFSET
);
37 if (unlikely(offset
< -33554432 || offset
> 33554428)) {
38 /* Can't generate branches that far (from ARM ARM). Ftrace
39 * doesn't generate branches outside of kernel text.
44 offset
= (offset
>> 2) & BL_OFFSET_MASK
;
45 bl_insn
= BL_OPCODE
| offset
;
46 return (unsigned char *)&bl_insn
;
49 int ftrace_modify_code(unsigned long pc
, unsigned char *old_code
,
50 unsigned char *new_code
)
52 unsigned long err
= 0, replaced
= 0, old
, new;
54 old
= *(unsigned long *)old_code
;
55 new = *(unsigned long *)new_code
;
57 __asm__
__volatile__ (
60 "2: streq %3, [%2] \n"
65 ".pushsection .fixup, \"ax\"\n"
70 ".pushsection __ex_table, \"a\"\n"
75 : "=r"(err
), "=r"(replaced
)
76 : "r"(pc
), "r"(new), "r"(old
), "0"(err
), "1"(replaced
)
79 if (!err
&& (replaced
== old
))
80 flush_icache_range(pc
, pc
+ MCOUNT_INSN_SIZE
);
85 int ftrace_update_ftrace_func(ftrace_func_t func
)
88 unsigned long pc
, old
;
91 pc
= (unsigned long)&ftrace_call
;
92 memcpy(&old
, &ftrace_call
, MCOUNT_INSN_SIZE
);
93 new = ftrace_call_replace(pc
, (unsigned long)func
);
94 ret
= ftrace_modify_code(pc
, (unsigned char *)&old
, new);
98 /* run from ftrace_init with irqs disabled */
99 int __init
ftrace_dyn_arch_init(void *data
)
101 ftrace_mcount_set(data
);