root/arch/arm/kernel/entry-ftrace.S

/* [<][>][^][v][top][bottom][index][help] */
   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.  (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
  28  * parameters.)
  29  *
  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).
  32  */
  33 
  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
  37 .endm
  38 
  39 .macro __mcount suffix
  40         mcount_enter
  41         ldr     r0, =ftrace_trace_function
  42         ldr     r2, [r0]
  43         adr     r0, .Lftrace_stub
  44         cmp     r0, r2
  45         bne     1f
  46 
  47 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  48         ldr     r1, =ftrace_graph_return
  49         ldr     r2, [r1]
  50         cmp     r0, r2
  51         bne     ftrace_graph_caller\suffix
  52 
  53         ldr     r1, =ftrace_graph_entry
  54         ldr     r2, [r1]
  55         ldr     r0, =ftrace_graph_entry_stub
  56         cmp     r0, r2
  57         bne     ftrace_graph_caller\suffix
  58 #endif
  59 
  60         mcount_exit
  61 
  62 1:      mcount_get_lr   r1                      @ lr of instrumented func
  63         mcount_adjust_addr      r0, lr          @ instrumented function
  64         badr    lr, 2f
  65         mov     pc, r2
  66 2:      mcount_exit
  67 .endm
  68 
  69 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
  70 
  71 .macro __ftrace_regs_caller
  72 
  73         sub     sp, sp, #8      @ space for PC and CPSR OLD_R0,
  74                                 @ OLD_R0 will overwrite previous LR
  75 
  76         add     ip, sp, #12     @ move in IP the value of SP as it was
  77                                 @ before the push {lr} of the mcount mechanism
  78 
  79         str     lr, [sp, #0]    @ store LR instead of PC
  80 
  81         ldr     lr, [sp, #8]    @ get previous LR
  82 
  83         str     r0, [sp, #8]    @ write r0 as OLD_R0 over previous LR
  84 
  85         stmdb   sp!, {ip, lr}
  86         stmdb   sp!, {r0-r11, lr}
  87 
  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 |
  91 
  92         mov r3, sp                              @ struct pt_regs*
  93 
  94         ldr r2, =function_trace_op
  95         ldr r2, [r2]                            @ pointer to the current
  96                                                 @ function tracing op
  97 
  98         ldr     r1, [sp, #S_LR]                 @ lr of instrumented func
  99 
 100         ldr     lr, [sp, #S_PC]                 @ get LR
 101 
 102         mcount_adjust_addr      r0, lr          @ instrumented function
 103 
 104         .globl ftrace_regs_call
 105 ftrace_regs_call:
 106         bl      ftrace_stub
 107 
 108 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 109         .globl ftrace_graph_regs_call
 110 ftrace_graph_regs_call:
 111         mov     r0, r0
 112 #endif
 113 
 114         @ pop saved regs
 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
 119         mov     pc, ip                          @ return
 120 .endm
 121 
 122 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 123 .macro __ftrace_graph_regs_caller
 124 
 125         sub     r0, fp, #4              @ lr of instrumented routine (parent)
 126 
 127         @ called from __ftrace_regs_caller
 128         ldr     r1, [sp, #S_PC]         @ instrumented routine (func)
 129         mcount_adjust_addr      r1, r1
 130 
 131         mov     r2, fp                  @ frame pointer
 132         bl      prepare_ftrace_return
 133 
 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
 139         mov     pc, ip                          @ return
 140 
 141 .endm
 142 #endif
 143 #endif
 144 
 145 .macro __ftrace_caller suffix
 146         mcount_enter
 147 
 148         mcount_get_lr   r1                      @ lr of instrumented func
 149         mcount_adjust_addr      r0, lr          @ instrumented function
 150 
 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
 156 #endif
 157 
 158         .globl ftrace_call\suffix
 159 ftrace_call\suffix:
 160         bl      ftrace_stub
 161 
 162 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 163         .globl ftrace_graph_call\suffix
 164 ftrace_graph_call\suffix:
 165         mov     r0, r0
 166 #endif
 167 
 168         mcount_exit
 169 .endm
 170 
 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
 177 #else
 178         @ called from __mcount, untouched in lr
 179         mcount_adjust_addr      r1, lr  @ instrumented routine (func)
 180 #endif
 181         mov     r2, fp                  @ frame pointer
 182         bl      prepare_ftrace_return
 183         mcount_exit
 184 .endm
 185 
 186 /*
 187  * __gnu_mcount_nc
 188  */
 189 
 190 .macro mcount_enter
 191 /*
 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.
 194  */
 195  UNWIND(.pad    #4)
 196         stmdb   sp!, {r0-r3, lr}
 197  UNWIND(.save   {r0-r3, lr})
 198 .endm
 199 
 200 .macro mcount_get_lr reg
 201         ldr     \reg, [sp, #20]
 202 .endm
 203 
 204 .macro mcount_exit
 205         ldmia   sp!, {r0-r3, ip, lr}
 206         ret     ip
 207 .endm
 208 
 209 ENTRY(__gnu_mcount_nc)
 210 UNWIND(.fnstart)
 211 #ifdef CONFIG_DYNAMIC_FTRACE
 212         mov     ip, lr
 213         ldmia   sp!, {lr}
 214         ret     ip
 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         .globl return_to_handler
 260 return_to_handler:
 261         stmdb   sp!, {r0-r3}
 262         mov     r0, fp                  @ frame pointer
 263         bl      ftrace_return_to_handler
 264         mov     lr, r0                  @ r0 has real ret addr
 265         ldmia   sp!, {r0-r3}
 266         ret     lr
 267 #endif
 268 
 269 ENTRY(ftrace_stub)
 270 .Lftrace_stub:
 271         ret     lr
 272 ENDPROC(ftrace_stub)

/* [<][>][^][v][top][bottom][index][help] */