2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
7 #include <asm/assembler.h>
8 #include <asm/ftrace.h>
9 #include <asm/unwind.h>
11 #include "entry-header.S"
14 * When compiling with -pg, gcc inserts a call to the mcount routine at the
15 * start of every function. In mcount, apart from the function's address (in
16 * lr), we need to get hold of the function's caller's address.
18 * Newer GCCs (4.4+) solve this problem by using a version of mcount with call
24 * With these compilers, frame pointers are not necessary.
26 * mcount can be thought of as a function called in the middle of a subroutine
27 * call. As such, it needs to be transparent for both the caller and the
28 * callee: the original lr needs to be restored when leaving mcount, and no
29 * registers should be clobbered. (In the __gnu_mcount_nc implementation, we
30 * clobber the ip register. This is OK because the ARM calling convention
31 * allows it to be clobbered in subroutines and doesn't use it to hold
34 * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}"
35 * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c).
38 .macro mcount_adjust_addr rd, rn
39 bic \rd, \rn, #1 @ clear the Thumb bit if present
40 sub \rd, \rd, #MCOUNT_INSN_SIZE
43 .macro __mcount suffix
45 ldr r0, =ftrace_trace_function
51 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
52 ldr r1, =ftrace_graph_return
55 bne ftrace_graph_caller\suffix
57 ldr r1, =ftrace_graph_entry
59 ldr r0, =ftrace_graph_entry_stub
61 bne ftrace_graph_caller\suffix
66 1: mcount_get_lr r1 @ lr of instrumented func
67 mcount_adjust_addr r0, lr @ instrumented function
73 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
75 .macro __ftrace_regs_caller
77 sub sp, sp, #8 @ space for PC and CPSR OLD_R0,
78 @ OLD_R0 will overwrite previous LR
80 add ip, sp, #12 @ move in IP the value of SP as it was
81 @ before the push {lr} of the mcount mechanism
83 str lr, [sp, #0] @ store LR instead of PC
85 ldr lr, [sp, #8] @ get previous LR
87 str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR
90 stmdb sp!, {r0-r11, lr}
92 @ stack content at this point:
93 @ 0 4 48 52 56 60 64 68 72
94 @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 |
96 mov r3, sp @ struct pt_regs*
98 ldr r2, =function_trace_op
99 ldr r2, [r2] @ pointer to the current
100 @ function tracing op
102 ldr r1, [sp, #S_LR] @ lr of instrumented func
104 ldr lr, [sp, #S_PC] @ get LR
106 mcount_adjust_addr r0, lr @ instrumented function
108 .globl ftrace_regs_call
112 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
113 .globl ftrace_graph_regs_call
114 ftrace_graph_regs_call:
119 ldmia sp!, {r0-r12} @ restore r0 through r12
120 ldr ip, [sp, #8] @ restore PC
121 ldr lr, [sp, #4] @ restore LR
122 ldr sp, [sp, #0] @ restore SP
126 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
127 .macro __ftrace_graph_regs_caller
129 sub r0, fp, #4 @ lr of instrumented routine (parent)
131 @ called from __ftrace_regs_caller
132 ldr r1, [sp, #S_PC] @ instrumented routine (func)
133 mcount_adjust_addr r1, r1
135 mov r2, fp @ frame pointer
136 bl prepare_ftrace_return
138 @ pop registers saved in ftrace_regs_caller
139 ldmia sp!, {r0-r12} @ restore r0 through r12
140 ldr ip, [sp, #8] @ restore PC
141 ldr lr, [sp, #4] @ restore LR
142 ldr sp, [sp, #0] @ restore SP
149 .macro __ftrace_caller suffix
152 mcount_get_lr r1 @ lr of instrumented func
153 mcount_adjust_addr r0, lr @ instrumented function
155 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
156 ldr r2, =function_trace_op
157 ldr r2, [r2] @ pointer to the current
158 @ function tracing op
159 mov r3, #0 @ regs is NULL
162 .globl ftrace_call\suffix
166 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
167 .globl ftrace_graph_call\suffix
168 ftrace_graph_call\suffix:
175 .macro __ftrace_graph_caller
176 sub r0, fp, #4 @ &lr of instrumented routine (&parent)
177 #ifdef CONFIG_DYNAMIC_FTRACE
178 @ called from __ftrace_caller, saved in mcount_enter
179 ldr r1, [sp, #16] @ instrumented routine (func)
180 mcount_adjust_addr r1, r1
182 @ called from __mcount, untouched in lr
183 mcount_adjust_addr r1, lr @ instrumented routine (func)
185 mov r2, fp @ frame pointer
186 bl prepare_ftrace_return
196 * This pad compensates for the push {lr} at the call site. Note that we are
197 * unable to unwind through a function which does not otherwise save its lr.
200 stmdb sp!, {r0-r3, lr}
201 UNWIND(.save {r0-r3, lr})
204 .macro mcount_get_lr reg
209 ldmia sp!, {r0-r3, ip, lr}
213 ENTRY(__gnu_mcount_nc)
215 #ifdef CONFIG_DYNAMIC_FTRACE
223 ENDPROC(__gnu_mcount_nc)
225 #ifdef CONFIG_DYNAMIC_FTRACE
230 ENDPROC(ftrace_caller)
232 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
233 ENTRY(ftrace_regs_caller)
237 ENDPROC(ftrace_regs_caller)
242 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
243 ENTRY(ftrace_graph_caller)
245 __ftrace_graph_caller
247 ENDPROC(ftrace_graph_caller)
249 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
250 ENTRY(ftrace_graph_regs_caller)
252 __ftrace_graph_regs_caller
254 ENDPROC(ftrace_graph_regs_caller)
259 .purgem mcount_get_lr
262 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
263 .globl return_to_handler
266 mov r0, fp @ frame pointer
267 bl ftrace_return_to_handler
268 mov lr, r0 @ r0 has real ret addr