Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm/kernel/entry-ftrace.S
26292 views
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 "add sp, #4"
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_va r2, ftrace_trace_function
39
badr r0, .Lftrace_stub
40
cmp r0, r2
41
bne 1f
42
43
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
44
ldr_va r2, ftrace_graph_return
45
cmp r0, r2
46
bne ftrace_graph_caller\suffix
47
48
ldr_va r2, ftrace_graph_entry
49
mov_l r0, ftrace_graph_entry_stub
50
cmp r0, r2
51
bne ftrace_graph_caller\suffix
52
#endif
53
54
mcount_exit
55
56
1: mcount_get_lr r1 @ lr of instrumented func
57
mcount_adjust_addr r0, lr @ instrumented function
58
badr lr, 2f
59
mov pc, r2
60
2: mcount_exit
61
.endm
62
63
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
64
65
.macro __ftrace_regs_caller
66
67
str lr, [sp, #-8]! @ store LR as PC and make space for CPSR/OLD_R0,
68
@ OLD_R0 will overwrite previous LR
69
70
ldr lr, [sp, #8] @ get previous LR
71
72
str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR
73
74
str lr, [sp, #-4]! @ store previous LR as LR
75
76
add lr, sp, #16 @ move in LR the value of SP as it was
77
@ before the push {lr} of the mcount mechanism
78
79
push {r0-r11, ip, lr}
80
81
@ stack content at this point:
82
@ 0 4 48 52 56 60 64 68 72
83
@ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 |
84
85
mov r3, sp @ struct pt_regs*
86
87
ldr_va r2, function_trace_op @ pointer to the current
88
@ function tracing op
89
90
ldr r1, [sp, #S_LR] @ lr of instrumented func
91
92
ldr lr, [sp, #S_PC] @ get LR
93
94
mcount_adjust_addr r0, lr @ instrumented function
95
96
.globl ftrace_regs_call
97
ftrace_regs_call:
98
bl ftrace_stub
99
100
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
101
.globl ftrace_graph_regs_call
102
ftrace_graph_regs_call:
103
ARM( mov r0, r0 )
104
THUMB( nop.w )
105
#endif
106
107
@ pop saved regs
108
pop {r0-r11, ip, lr} @ restore r0 through r12
109
ldr lr, [sp], #4 @ restore LR
110
ldr pc, [sp], #12
111
.endm
112
113
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
114
.macro __ftrace_graph_regs_caller
115
116
#ifdef CONFIG_UNWINDER_FRAME_POINTER
117
sub r0, fp, #4 @ lr of instrumented routine (parent)
118
#else
119
add r0, sp, #S_LR
120
#endif
121
122
@ called from __ftrace_regs_caller
123
ldr r1, [sp, #S_PC] @ instrumented routine (func)
124
mcount_adjust_addr r1, r1
125
126
mov r2, fpreg @ frame pointer
127
add r3, sp, #PT_REGS_SIZE
128
bl prepare_ftrace_return
129
130
@ pop registers saved in ftrace_regs_caller
131
pop {r0-r11, ip, lr} @ restore r0 through r12
132
ldr lr, [sp], #4 @ restore LR
133
ldr pc, [sp], #12
134
135
.endm
136
#endif
137
#endif
138
139
.macro __ftrace_caller suffix
140
mcount_enter
141
142
mcount_get_lr r1 @ lr of instrumented func
143
mcount_adjust_addr r0, lr @ instrumented function
144
145
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
146
ldr_va r2, function_trace_op @ pointer to the current
147
@ function tracing op
148
mov r3, #0 @ regs is NULL
149
#endif
150
151
.globl ftrace_call\suffix
152
ftrace_call\suffix:
153
bl ftrace_stub
154
155
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
156
.globl ftrace_graph_call\suffix
157
ftrace_graph_call\suffix:
158
ARM( mov r0, r0 )
159
THUMB( nop.w )
160
#endif
161
162
mcount_exit
163
.endm
164
165
.macro __ftrace_graph_caller
166
#ifdef CONFIG_UNWINDER_FRAME_POINTER
167
sub r0, fp, #4 @ &lr of instrumented routine (&parent)
168
#else
169
add r0, sp, #20
170
#endif
171
#ifdef CONFIG_DYNAMIC_FTRACE
172
@ called from __ftrace_caller, saved in mcount_enter
173
ldr r1, [sp, #16] @ instrumented routine (func)
174
mcount_adjust_addr r1, r1
175
#else
176
@ called from __mcount, untouched in lr
177
mcount_adjust_addr r1, lr @ instrumented routine (func)
178
#endif
179
mov r2, fpreg @ frame pointer
180
add r3, sp, #24
181
bl prepare_ftrace_return
182
mcount_exit
183
.endm
184
185
/*
186
* __gnu_mcount_nc
187
*/
188
189
.macro mcount_enter
190
/*
191
* This pad compensates for the push {lr} at the call site. Note that we are
192
* unable to unwind through a function which does not otherwise save its lr.
193
*/
194
UNWIND(.pad #4)
195
stmdb sp!, {r0-r3, lr}
196
UNWIND(.save {r0-r3, lr})
197
.endm
198
199
.macro mcount_get_lr reg
200
ldr \reg, [sp, #20]
201
.endm
202
203
.macro mcount_exit
204
ldmia sp!, {r0-r3}
205
ldr lr, [sp, #4]
206
ldr pc, [sp], #8
207
.endm
208
209
ENTRY(__gnu_mcount_nc)
210
UNWIND(.fnstart)
211
#ifdef CONFIG_DYNAMIC_FTRACE
212
push {lr}
213
ldr lr, [sp, #4]
214
ldr pc, [sp], #8
215
#else
216
__mcount
217
#endif
218
UNWIND(.fnend)
219
ENDPROC(__gnu_mcount_nc)
220
221
#ifdef CONFIG_DYNAMIC_FTRACE
222
ENTRY(ftrace_caller)
223
UNWIND(.fnstart)
224
__ftrace_caller
225
UNWIND(.fnend)
226
ENDPROC(ftrace_caller)
227
228
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
229
ENTRY(ftrace_regs_caller)
230
UNWIND(.fnstart)
231
__ftrace_regs_caller
232
UNWIND(.fnend)
233
ENDPROC(ftrace_regs_caller)
234
#endif
235
236
#endif
237
238
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
239
ENTRY(ftrace_graph_caller)
240
UNWIND(.fnstart)
241
__ftrace_graph_caller
242
UNWIND(.fnend)
243
ENDPROC(ftrace_graph_caller)
244
245
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
246
ENTRY(ftrace_graph_regs_caller)
247
UNWIND(.fnstart)
248
__ftrace_graph_regs_caller
249
UNWIND(.fnend)
250
ENDPROC(ftrace_graph_regs_caller)
251
#endif
252
#endif
253
254
.purgem mcount_enter
255
.purgem mcount_get_lr
256
.purgem mcount_exit
257
258
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
259
ENTRY(return_to_handler)
260
stmdb sp!, {r0-r3}
261
add r0, sp, #16 @ sp at exit of instrumented routine
262
bl ftrace_return_to_handler
263
mov lr, r0 @ r0 has real ret addr
264
ldmia sp!, {r0-r3}
265
ret lr
266
ENDPROC(return_to_handler)
267
#endif
268
269
ENTRY(ftrace_stub)
270
.Lftrace_stub:
271
ret lr
272
ENDPROC(ftrace_stub)
273
274
ENTRY(ftrace_stub_graph)
275
ret lr
276
ENDPROC(ftrace_stub_graph)
277
278
#ifdef CONFIG_DYNAMIC_FTRACE
279
280
__INIT
281
282
.macro init_tramp, dst:req
283
ENTRY(\dst\()_from_init)
284
ldr pc, =\dst
285
ENDPROC(\dst\()_from_init)
286
.endm
287
288
init_tramp ftrace_caller
289
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
290
init_tramp ftrace_regs_caller
291
#endif
292
#endif
293
294