1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <asm/assembler.h>
4 #include <asm/ftrace.h>
5 #include <asm/unwind.h>
7 #include "entry-header.S"
10 * When compiling with -pg, gcc inserts a call to the mcount routine at the
11 * start of every function. In mcount, apart from the function's address (in
12 * lr), we need to get hold of the function's caller's address.
14 * Newer GCCs (4.4+) solve this problem by using a version of mcount with call
20 * With these compilers, frame pointers are not necessary.
22 * mcount can be thought of as a function called in the middle of a subroutine
23 * call. As such, it needs to be transparent for both the caller and the
24 * callee: the original lr needs to be restored when leaving mcount, and no
25 * registers should be clobbered. (In the __gnu_mcount_nc implementation, we
26 * clobber the ip register. This is OK because the ARM calling convention
27 * allows it to be clobbered in subroutines and doesn't use it to hold
30 * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}"
31 * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c).
34 .macro mcount_adjust_addr rd, rn
35 bic \rd, \rn, #1 @ clear the Thumb bit if present
36 sub \rd, \rd, #MCOUNT_INSN_SIZE
39 .macro __mcount suffix
41 ldr r0, =ftrace_trace_function
47 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
48 ldr r1, =ftrace_graph_return
51 bne ftrace_graph_caller\suffix
53 ldr r1, =ftrace_graph_entry
55 ldr r0, =ftrace_graph_entry_stub
57 bne ftrace_graph_caller\suffix
62 1: mcount_get_lr r1 @ lr of instrumented func
63 mcount_adjust_addr r0, lr @ instrumented function
69 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
71 .macro __ftrace_regs_caller
73 sub sp, sp, #8 @ space for PC and CPSR OLD_R0,
74 @ OLD_R0 will overwrite previous LR
76 add ip, sp, #12 @ move in IP the value of SP as it was
77 @ before the push {lr} of the mcount mechanism
79 str lr, [sp, #0] @ store LR instead of PC
81 ldr lr, [sp, #8] @ get previous LR
83 str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR
86 stmdb sp!, {r0-r11, lr}
88 @ stack content at this point:
89 @ 0 4 48 52 56 60 64 68 72
90 @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 |
92 mov r3, sp @ struct pt_regs*
94 ldr r2, =function_trace_op
95 ldr r2, [r2] @ pointer to the current
98 ldr r1, [sp, #S_LR] @ lr of instrumented func
100 ldr lr, [sp, #S_PC] @ get LR
102 mcount_adjust_addr r0, lr @ instrumented function
104 .globl ftrace_regs_call
108 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
109 .globl ftrace_graph_regs_call
110 ftrace_graph_regs_call:
115 ldmia sp!, {r0-r12} @ restore r0 through r12
116 ldr ip, [sp, #8] @ restore PC
117 ldr lr, [sp, #4] @ restore LR
118 ldr sp, [sp, #0] @ restore SP
122 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
123 .macro __ftrace_graph_regs_caller
125 sub r0, fp, #4 @ lr of instrumented routine (parent)
127 @ called from __ftrace_regs_caller
128 ldr r1, [sp, #S_PC] @ instrumented routine (func)
129 mcount_adjust_addr r1, r1
131 mov r2, fp @ frame pointer
132 bl prepare_ftrace_return
134 @ pop registers saved in ftrace_regs_caller
135 ldmia sp!, {r0-r12} @ restore r0 through r12
136 ldr ip, [sp, #8] @ restore PC
137 ldr lr, [sp, #4] @ restore LR
138 ldr sp, [sp, #0] @ restore SP
145 .macro __ftrace_caller suffix
148 mcount_get_lr r1 @ lr of instrumented func
149 mcount_adjust_addr r0, lr @ instrumented function
151 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
152 ldr r2, =function_trace_op
153 ldr r2, [r2] @ pointer to the current
154 @ function tracing op
155 mov r3, #0 @ regs is NULL
158 .globl ftrace_call\suffix
162 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
163 .globl ftrace_graph_call\suffix
164 ftrace_graph_call\suffix:
171 .macro __ftrace_graph_caller
172 sub r0, fp, #4 @ &lr of instrumented routine (&parent)
173 #ifdef CONFIG_DYNAMIC_FTRACE
174 @ called from __ftrace_caller, saved in mcount_enter
175 ldr r1, [sp, #16] @ instrumented routine (func)
176 mcount_adjust_addr r1, r1
178 @ called from __mcount, untouched in lr
179 mcount_adjust_addr r1, lr @ instrumented routine (func)
181 mov r2, fp @ frame pointer
182 bl prepare_ftrace_return
192 * This pad compensates for the push {lr} at the call site. Note that we are
193 * unable to unwind through a function which does not otherwise save its lr.
196 stmdb sp!, {r0-r3, lr}
197 UNWIND(.save {r0-r3, lr})
200 .macro mcount_get_lr reg
205 ldmia sp!, {r0-r3, ip, lr}
209 ENTRY(__gnu_mcount_nc)
211 #ifdef CONFIG_DYNAMIC_FTRACE
219 ENDPROC(__gnu_mcount_nc)
221 #ifdef CONFIG_DYNAMIC_FTRACE
226 ENDPROC(ftrace_caller)
228 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
229 ENTRY(ftrace_regs_caller)
233 ENDPROC(ftrace_regs_caller)
238 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
239 ENTRY(ftrace_graph_caller)
241 __ftrace_graph_caller
243 ENDPROC(ftrace_graph_caller)
245 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
246 ENTRY(ftrace_graph_regs_caller)
248 __ftrace_graph_regs_caller
250 ENDPROC(ftrace_graph_regs_caller)
255 .purgem mcount_get_lr
258 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
259 .globl return_to_handler
262 mov r0, fp @ frame pointer
263 bl ftrace_return_to_handler
264 mov lr, r0 @ r0 has real ret addr