.. | .. |
---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
---|
1 | 2 | /* |
---|
2 | 3 | * arch/arm64/kernel/entry-ftrace.S |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2013 Linaro Limited |
---|
5 | 6 | * Author: AKASHI Takahiro <takahiro.akashi@linaro.org> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License version 2 as |
---|
9 | | - * published by the Free Software Foundation. |
---|
10 | 7 | */ |
---|
11 | 8 | |
---|
12 | 9 | #include <linux/linkage.h> |
---|
| 10 | +#include <asm/asm-offsets.h> |
---|
13 | 11 | #include <asm/assembler.h> |
---|
14 | 12 | #include <asm/ftrace.h> |
---|
15 | 13 | #include <asm/insn.h> |
---|
| 14 | + |
---|
| 15 | +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
---|
| 16 | +/* |
---|
| 17 | + * Due to -fpatchable-function-entry=2, the compiler has placed two NOPs before |
---|
| 18 | + * the regular function prologue. For an enabled callsite, ftrace_init_nop() and |
---|
| 19 | + * ftrace_make_call() have patched those NOPs to: |
---|
| 20 | + * |
---|
| 21 | + * MOV X9, LR |
---|
| 22 | + * BL <entry> |
---|
| 23 | + * |
---|
| 24 | + * ... where <entry> is either ftrace_caller or ftrace_regs_caller. |
---|
| 25 | + * |
---|
| 26 | + * Each instrumented function follows the AAPCS, so here x0-x8 and x18-x30 are |
---|
| 27 | + * live (x18 holds the Shadow Call Stack pointer), and x9-x17 are safe to |
---|
| 28 | + * clobber. |
---|
| 29 | + * |
---|
| 30 | + * We save the callsite's context into a pt_regs before invoking any ftrace |
---|
| 31 | + * callbacks. So that we can get a sensible backtrace, we create a stack record |
---|
| 32 | + * for the callsite and the ftrace entry assembly. This is not sufficient for |
---|
| 33 | + * reliable stacktrace: until we create the callsite stack record, its caller |
---|
| 34 | + * is missing from the LR and existing chain of frame records. |
---|
| 35 | + */ |
---|
| 36 | + .macro ftrace_regs_entry, allregs=0 |
---|
| 37 | + /* Make room for pt_regs, plus a callee frame */ |
---|
| 38 | + sub sp, sp, #(S_FRAME_SIZE + 16) |
---|
| 39 | + |
---|
| 40 | + /* Save function arguments (and x9 for simplicity) */ |
---|
| 41 | + stp x0, x1, [sp, #S_X0] |
---|
| 42 | + stp x2, x3, [sp, #S_X2] |
---|
| 43 | + stp x4, x5, [sp, #S_X4] |
---|
| 44 | + stp x6, x7, [sp, #S_X6] |
---|
| 45 | + stp x8, x9, [sp, #S_X8] |
---|
| 46 | + |
---|
| 47 | + /* Optionally save the callee-saved registers, always save the FP */ |
---|
| 48 | + .if \allregs == 1 |
---|
| 49 | + stp x10, x11, [sp, #S_X10] |
---|
| 50 | + stp x12, x13, [sp, #S_X12] |
---|
| 51 | + stp x14, x15, [sp, #S_X14] |
---|
| 52 | + stp x16, x17, [sp, #S_X16] |
---|
| 53 | + stp x18, x19, [sp, #S_X18] |
---|
| 54 | + stp x20, x21, [sp, #S_X20] |
---|
| 55 | + stp x22, x23, [sp, #S_X22] |
---|
| 56 | + stp x24, x25, [sp, #S_X24] |
---|
| 57 | + stp x26, x27, [sp, #S_X26] |
---|
| 58 | + stp x28, x29, [sp, #S_X28] |
---|
| 59 | + .else |
---|
| 60 | + str x29, [sp, #S_FP] |
---|
| 61 | + .endif |
---|
| 62 | + |
---|
| 63 | + /* Save the callsite's SP and LR */ |
---|
| 64 | + add x10, sp, #(S_FRAME_SIZE + 16) |
---|
| 65 | + stp x9, x10, [sp, #S_LR] |
---|
| 66 | + |
---|
| 67 | + /* Save the PC after the ftrace callsite */ |
---|
| 68 | + str x30, [sp, #S_PC] |
---|
| 69 | + |
---|
| 70 | + /* Create a frame record for the callsite above pt_regs */ |
---|
| 71 | + stp x29, x9, [sp, #S_FRAME_SIZE] |
---|
| 72 | + add x29, sp, #S_FRAME_SIZE |
---|
| 73 | + |
---|
| 74 | + /* Create our frame record within pt_regs. */ |
---|
| 75 | + stp x29, x30, [sp, #S_STACKFRAME] |
---|
| 76 | + add x29, sp, #S_STACKFRAME |
---|
| 77 | + .endm |
---|
| 78 | + |
---|
| 79 | +SYM_CODE_START(ftrace_regs_caller) |
---|
| 80 | +#ifdef BTI_C |
---|
| 81 | + BTI_C |
---|
| 82 | +#endif |
---|
| 83 | + ftrace_regs_entry 1 |
---|
| 84 | + b ftrace_common |
---|
| 85 | +SYM_CODE_END(ftrace_regs_caller) |
---|
| 86 | + |
---|
| 87 | +SYM_CODE_START(ftrace_caller) |
---|
| 88 | +#ifdef BTI_C |
---|
| 89 | + BTI_C |
---|
| 90 | +#endif |
---|
| 91 | + ftrace_regs_entry 0 |
---|
| 92 | + b ftrace_common |
---|
| 93 | +SYM_CODE_END(ftrace_caller) |
---|
| 94 | + |
---|
| 95 | +SYM_CODE_START(ftrace_common) |
---|
| 96 | + sub x0, x30, #AARCH64_INSN_SIZE // ip (callsite's BL insn) |
---|
| 97 | + mov x1, x9 // parent_ip (callsite's LR) |
---|
| 98 | + ldr_l x2, function_trace_op // op |
---|
| 99 | + mov x3, sp // regs |
---|
| 100 | + |
---|
| 101 | +SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) |
---|
| 102 | + bl ftrace_stub |
---|
| 103 | + |
---|
| 104 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER |
---|
| 105 | +SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller(); |
---|
| 106 | + nop // If enabled, this will be replaced |
---|
| 107 | + // "b ftrace_graph_caller" |
---|
| 108 | +#endif |
---|
| 109 | + |
---|
| 110 | +/* |
---|
| 111 | + * At the callsite x0-x8 and x19-x30 were live. Any C code will have preserved |
---|
| 112 | + * x19-x29 per the AAPCS, and we created frame records upon entry, so we need |
---|
| 113 | + * to restore x0-x8, x29, and x30. |
---|
| 114 | + */ |
---|
| 115 | +ftrace_common_return: |
---|
| 116 | + /* Restore function arguments */ |
---|
| 117 | + ldp x0, x1, [sp] |
---|
| 118 | + ldp x2, x3, [sp, #S_X2] |
---|
| 119 | + ldp x4, x5, [sp, #S_X4] |
---|
| 120 | + ldp x6, x7, [sp, #S_X6] |
---|
| 121 | + ldr x8, [sp, #S_X8] |
---|
| 122 | + |
---|
| 123 | + /* Restore the callsite's FP, LR, PC */ |
---|
| 124 | + ldr x29, [sp, #S_FP] |
---|
| 125 | + ldr x30, [sp, #S_LR] |
---|
| 126 | + ldr x9, [sp, #S_PC] |
---|
| 127 | + |
---|
| 128 | + /* Restore the callsite's SP */ |
---|
| 129 | + add sp, sp, #S_FRAME_SIZE + 16 |
---|
| 130 | + |
---|
| 131 | + ret x9 |
---|
| 132 | +SYM_CODE_END(ftrace_common) |
---|
| 133 | + |
---|
| 134 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER |
---|
| 135 | +SYM_CODE_START(ftrace_graph_caller) |
---|
| 136 | + ldr x0, [sp, #S_PC] |
---|
| 137 | + sub x0, x0, #AARCH64_INSN_SIZE // ip (callsite's BL insn) |
---|
| 138 | + add x1, sp, #S_LR // parent_ip (callsite's LR) |
---|
| 139 | + ldr x2, [sp, #S_FRAME_SIZE] // parent fp (callsite's FP) |
---|
| 140 | + bl prepare_ftrace_return |
---|
| 141 | + b ftrace_common_return |
---|
| 142 | +SYM_CODE_END(ftrace_graph_caller) |
---|
| 143 | +#endif |
---|
| 144 | + |
---|
| 145 | +#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ |
---|
16 | 146 | |
---|
17 | 147 | /* |
---|
18 | 148 | * Gcc with -pg will put the following code in the beginning of each function: |
---|
.. | .. |
---|
95 | 225 | * - tracer function to probe instrumented function's entry, |
---|
96 | 226 | * - ftrace_graph_caller to set up an exit hook |
---|
97 | 227 | */ |
---|
98 | | -ENTRY(_mcount) |
---|
| 228 | +SYM_FUNC_START(_mcount) |
---|
99 | 229 | mcount_enter |
---|
100 | 230 | |
---|
101 | 231 | ldr_l x2, ftrace_trace_function |
---|
.. | .. |
---|
119 | 249 | b.ne ftrace_graph_caller // ftrace_graph_caller(); |
---|
120 | 250 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
---|
121 | 251 | mcount_exit |
---|
122 | | -ENDPROC(_mcount) |
---|
| 252 | +SYM_FUNC_END(_mcount) |
---|
| 253 | +EXPORT_SYMBOL(_mcount) |
---|
| 254 | +NOKPROBE(_mcount) |
---|
123 | 255 | |
---|
124 | 256 | #else /* CONFIG_DYNAMIC_FTRACE */ |
---|
125 | 257 | /* |
---|
.. | .. |
---|
128 | 260 | * and later on, NOP to branch to ftrace_caller() when enabled or branch to |
---|
129 | 261 | * NOP when disabled per-function base. |
---|
130 | 262 | */ |
---|
131 | | -ENTRY(_mcount) |
---|
| 263 | +SYM_FUNC_START(_mcount) |
---|
132 | 264 | ret |
---|
133 | | -ENDPROC(_mcount) |
---|
| 265 | +SYM_FUNC_END(_mcount) |
---|
| 266 | +EXPORT_SYMBOL(_mcount) |
---|
| 267 | +NOKPROBE(_mcount) |
---|
134 | 268 | |
---|
135 | 269 | /* |
---|
136 | 270 | * void ftrace_caller(unsigned long return_address) |
---|
.. | .. |
---|
141 | 275 | * - tracer function to probe instrumented function's entry, |
---|
142 | 276 | * - ftrace_graph_caller to set up an exit hook |
---|
143 | 277 | */ |
---|
144 | | -ENTRY(ftrace_caller) |
---|
| 278 | +SYM_FUNC_START(ftrace_caller) |
---|
145 | 279 | mcount_enter |
---|
146 | 280 | |
---|
147 | 281 | mcount_get_pc0 x0 // function's pc |
---|
148 | 282 | mcount_get_lr x1 // function's lr |
---|
149 | 283 | |
---|
150 | | - .global ftrace_call |
---|
151 | | -ftrace_call: // tracer(pc, lr); |
---|
| 284 | +SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) // tracer(pc, lr); |
---|
152 | 285 | nop // This will be replaced with "bl xxx" |
---|
153 | 286 | // where xxx can be any kind of tracer. |
---|
154 | 287 | |
---|
155 | 288 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
---|
156 | | - .global ftrace_graph_call |
---|
157 | | -ftrace_graph_call: // ftrace_graph_caller(); |
---|
| 289 | +SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller(); |
---|
158 | 290 | nop // If enabled, this will be replaced |
---|
159 | 291 | // "b ftrace_graph_caller" |
---|
160 | 292 | #endif |
---|
161 | 293 | |
---|
162 | 294 | mcount_exit |
---|
163 | | -ENDPROC(ftrace_caller) |
---|
| 295 | +SYM_FUNC_END(ftrace_caller) |
---|
164 | 296 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
---|
165 | 297 | |
---|
166 | | -ENTRY(ftrace_stub) |
---|
167 | | - ret |
---|
168 | | -ENDPROC(ftrace_stub) |
---|
169 | | - |
---|
170 | 298 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
---|
171 | | - /* save return value regs*/ |
---|
172 | | - .macro save_return_regs |
---|
173 | | - sub sp, sp, #64 |
---|
174 | | - stp x0, x1, [sp] |
---|
175 | | - stp x2, x3, [sp, #16] |
---|
176 | | - stp x4, x5, [sp, #32] |
---|
177 | | - stp x6, x7, [sp, #48] |
---|
178 | | - .endm |
---|
179 | | - |
---|
180 | | - /* restore return value regs*/ |
---|
181 | | - .macro restore_return_regs |
---|
182 | | - ldp x0, x1, [sp] |
---|
183 | | - ldp x2, x3, [sp, #16] |
---|
184 | | - ldp x4, x5, [sp, #32] |
---|
185 | | - ldp x6, x7, [sp, #48] |
---|
186 | | - add sp, sp, #64 |
---|
187 | | - .endm |
---|
188 | | - |
---|
189 | 299 | /* |
---|
190 | 300 | * void ftrace_graph_caller(void) |
---|
191 | 301 | * |
---|
.. | .. |
---|
195 | 305 | * the call stack in order to intercept instrumented function's return path |
---|
196 | 306 | * and run return_to_handler() later on its exit. |
---|
197 | 307 | */ |
---|
198 | | -ENTRY(ftrace_graph_caller) |
---|
199 | | - mcount_get_lr_addr x0 // pointer to function's saved lr |
---|
200 | | - mcount_get_pc x1 // function's pc |
---|
| 308 | +SYM_FUNC_START(ftrace_graph_caller) |
---|
| 309 | + mcount_get_pc x0 // function's pc |
---|
| 310 | + mcount_get_lr_addr x1 // pointer to function's saved lr |
---|
201 | 311 | mcount_get_parent_fp x2 // parent's fp |
---|
202 | | - bl prepare_ftrace_return // prepare_ftrace_return(&lr, pc, fp) |
---|
| 312 | + bl prepare_ftrace_return // prepare_ftrace_return(pc, &lr, fp) |
---|
203 | 313 | |
---|
204 | 314 | mcount_exit |
---|
205 | | -ENDPROC(ftrace_graph_caller) |
---|
| 315 | +SYM_FUNC_END(ftrace_graph_caller) |
---|
| 316 | +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
---|
| 317 | +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ |
---|
206 | 318 | |
---|
| 319 | +SYM_FUNC_START(ftrace_stub) |
---|
| 320 | + ret |
---|
| 321 | +SYM_FUNC_END(ftrace_stub) |
---|
| 322 | + |
---|
| 323 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER |
---|
207 | 324 | /* |
---|
208 | 325 | * void return_to_handler(void) |
---|
209 | 326 | * |
---|
210 | 327 | * Run ftrace_return_to_handler() before going back to parent. |
---|
211 | | - * @fp is checked against the value passed by ftrace_graph_caller() |
---|
212 | | - * only when HAVE_FUNCTION_GRAPH_FP_TEST is enabled. |
---|
| 328 | + * @fp is checked against the value passed by ftrace_graph_caller(). |
---|
213 | 329 | */ |
---|
214 | | -ENTRY(return_to_handler) |
---|
215 | | - save_return_regs |
---|
| 330 | +SYM_CODE_START(return_to_handler) |
---|
| 331 | + /* save return value regs */ |
---|
| 332 | + sub sp, sp, #64 |
---|
| 333 | + stp x0, x1, [sp] |
---|
| 334 | + stp x2, x3, [sp, #16] |
---|
| 335 | + stp x4, x5, [sp, #32] |
---|
| 336 | + stp x6, x7, [sp, #48] |
---|
| 337 | + |
---|
216 | 338 | mov x0, x29 // parent's fp |
---|
217 | 339 | bl ftrace_return_to_handler// addr = ftrace_return_to_hander(fp); |
---|
218 | 340 | mov x30, x0 // restore the original return address |
---|
219 | | - restore_return_regs |
---|
| 341 | + |
---|
| 342 | + /* restore return value regs */ |
---|
| 343 | + ldp x0, x1, [sp] |
---|
| 344 | + ldp x2, x3, [sp, #16] |
---|
| 345 | + ldp x4, x5, [sp, #32] |
---|
| 346 | + ldp x6, x7, [sp, #48] |
---|
| 347 | + add sp, sp, #64 |
---|
| 348 | + |
---|
220 | 349 | ret |
---|
221 | | -END(return_to_handler) |
---|
| 350 | +SYM_CODE_END(return_to_handler) |
---|
222 | 351 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
---|