• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <asm/assembler.h>
4#include <asm/ftrace.h>
5#include <asm/unwind.h>
6
7#include "entry-header.S"
8
9/*
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.
13 *
14 * Newer GCCs (4.4+) solve this problem by using a version of mcount with call
15 * sites like:
16 *
17 *	push	{lr}
18 *	bl	__gnu_mcount_nc
19 *
20 * With these compilers, frame pointers are not necessary.
21 *
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.
26 *
27 * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}"
28 * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c).
29 */
30
31.macro mcount_adjust_addr rd, rn
32	bic	\rd, \rn, #1		@ clear the Thumb bit if present
33	sub	\rd, \rd, #MCOUNT_INSN_SIZE
34.endm
35
36.macro __mcount suffix
37	mcount_enter
38	ldr	r0, =ftrace_trace_function
39	ldr	r2, [r0]
40	adr	r0, .Lftrace_stub
41	cmp	r0, r2
42	bne	1f
43
44#ifdef CONFIG_FUNCTION_GRAPH_TRACER
45	ldr     r1, =ftrace_graph_return
46	ldr     r2, [r1]
47	cmp     r0, r2
48	bne     ftrace_graph_caller\suffix
49
50	ldr     r1, =ftrace_graph_entry
51	ldr     r2, [r1]
52	ldr     r0, =ftrace_graph_entry_stub
53	cmp     r0, r2
54	bne     ftrace_graph_caller\suffix
55#endif
56
57	mcount_exit
58
591: 	mcount_get_lr	r1			@ lr of instrumented func
60	mcount_adjust_addr	r0, lr		@ instrumented function
61	badr	lr, 2f
62	mov	pc, r2
632:	mcount_exit
64.endm
65
66#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
67
68.macro __ftrace_regs_caller
69
70	str	lr, [sp, #-8]!	@ store LR as PC and make space for CPSR/OLD_R0,
71				@ OLD_R0 will overwrite previous LR
72
73	ldr	lr, [sp, #8]    @ get previous LR
74
75	str	r0, [sp, #8]	@ write r0 as OLD_R0 over previous LR
76
77	str	lr, [sp, #-4]!	@ store previous LR as LR
78
79	add 	lr, sp, #16	@ move in LR the value of SP as it was
80				@ before the push {lr} of the mcount mechanism
81
82	push	{r0-r11, ip, lr}
83
84	@ stack content at this point:
85	@ 0  4          48   52       56            60   64    68       72
86	@ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 |
87
88	mov	r3, sp				@ struct pt_regs*
89
90	ldr r2, =function_trace_op
91	ldr r2, [r2]				@ pointer to the current
92						@ function tracing op
93
94	ldr	r1, [sp, #S_LR]			@ lr of instrumented func
95
96	ldr	lr, [sp, #S_PC]			@ get LR
97
98	mcount_adjust_addr	r0, lr		@ instrumented function
99
100	.globl ftrace_regs_call
101ftrace_regs_call:
102	bl	ftrace_stub
103
104#ifdef CONFIG_FUNCTION_GRAPH_TRACER
105	.globl ftrace_graph_regs_call
106ftrace_graph_regs_call:
107	mov	r0, r0
108#endif
109
110	@ pop saved regs
111	pop	{r0-r11, ip, lr}		@ restore r0 through r12
112	ldr	lr, [sp], #4			@ restore LR
113	ldr	pc, [sp], #12
114.endm
115
116#ifdef CONFIG_FUNCTION_GRAPH_TRACER
117.macro __ftrace_graph_regs_caller
118
119	sub     r0, fp, #4              @ lr of instrumented routine (parent)
120
121	@ called from __ftrace_regs_caller
122	ldr     r1, [sp, #S_PC]		@ instrumented routine (func)
123	mcount_adjust_addr	r1, r1
124
125	mov	r2, fp			@ frame pointer
126	bl	prepare_ftrace_return
127
128	@ pop registers saved in ftrace_regs_caller
129	pop	{r0-r11, ip, lr}		@ restore r0 through r12
130	ldr	lr, [sp], #4			@ restore LR
131	ldr	pc, [sp], #12
132
133.endm
134#endif
135#endif
136
137.macro __ftrace_caller suffix
138	mcount_enter
139
140	mcount_get_lr	r1			@ lr of instrumented func
141	mcount_adjust_addr	r0, lr		@ instrumented function
142
143#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
144	ldr r2, =function_trace_op
145	ldr r2, [r2]				@ pointer to the current
146						@ function tracing op
147	mov r3, #0				@ regs is NULL
148#endif
149
150	.globl ftrace_call\suffix
151ftrace_call\suffix:
152	bl	ftrace_stub
153
154#ifdef CONFIG_FUNCTION_GRAPH_TRACER
155	.globl ftrace_graph_call\suffix
156ftrace_graph_call\suffix:
157	mov	r0, r0
158#endif
159
160	mcount_exit
161.endm
162
163.macro __ftrace_graph_caller
164	sub	r0, fp, #4		@ &lr of instrumented routine (&parent)
165#ifdef CONFIG_DYNAMIC_FTRACE
166	@ called from __ftrace_caller, saved in mcount_enter
167	ldr	r1, [sp, #16]		@ instrumented routine (func)
168	mcount_adjust_addr	r1, r1
169#else
170	@ called from __mcount, untouched in lr
171	mcount_adjust_addr	r1, lr	@ instrumented routine (func)
172#endif
173	mov	r2, fp			@ frame pointer
174	bl	prepare_ftrace_return
175	mcount_exit
176.endm
177
178/*
179 * __gnu_mcount_nc
180 */
181
182.macro mcount_enter
183/*
184 * This pad compensates for the push {lr} at the call site.  Note that we are
185 * unable to unwind through a function which does not otherwise save its lr.
186 */
187 UNWIND(.pad	#4)
188	stmdb	sp!, {r0-r3, lr}
189 UNWIND(.save	{r0-r3, lr})
190.endm
191
192.macro mcount_get_lr reg
193	ldr	\reg, [sp, #20]
194.endm
195
196.macro mcount_exit
197	ldmia	sp!, {r0-r3}
198	ldr	lr, [sp, #4]
199	ldr	pc, [sp], #8
200.endm
201
202ENTRY(__gnu_mcount_nc)
203UNWIND(.fnstart)
204#ifdef CONFIG_DYNAMIC_FTRACE
205	push	{lr}
206	ldr	lr, [sp, #4]
207	ldr	pc, [sp], #8
208#else
209	__mcount
210#endif
211UNWIND(.fnend)
212ENDPROC(__gnu_mcount_nc)
213
214#ifdef CONFIG_DYNAMIC_FTRACE
215ENTRY(ftrace_caller)
216UNWIND(.fnstart)
217	__ftrace_caller
218UNWIND(.fnend)
219ENDPROC(ftrace_caller)
220
221#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
222ENTRY(ftrace_regs_caller)
223UNWIND(.fnstart)
224	__ftrace_regs_caller
225UNWIND(.fnend)
226ENDPROC(ftrace_regs_caller)
227#endif
228
229#endif
230
231#ifdef CONFIG_FUNCTION_GRAPH_TRACER
232ENTRY(ftrace_graph_caller)
233UNWIND(.fnstart)
234	__ftrace_graph_caller
235UNWIND(.fnend)
236ENDPROC(ftrace_graph_caller)
237
238#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
239ENTRY(ftrace_graph_regs_caller)
240UNWIND(.fnstart)
241	__ftrace_graph_regs_caller
242UNWIND(.fnend)
243ENDPROC(ftrace_graph_regs_caller)
244#endif
245#endif
246
247.purgem mcount_enter
248.purgem mcount_get_lr
249.purgem mcount_exit
250
251#ifdef CONFIG_FUNCTION_GRAPH_TRACER
252	.globl return_to_handler
253return_to_handler:
254	stmdb	sp!, {r0-r3}
255	mov	r0, fp			@ frame pointer
256	bl	ftrace_return_to_handler
257	mov	lr, r0			@ r0 has real ret addr
258	ldmia	sp!, {r0-r3}
259	ret	lr
260#endif
261
262ENTRY(ftrace_stub)
263.Lftrace_stub:
264	ret	lr
265ENDPROC(ftrace_stub)
266