entry-ftrace.S 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * arch/arm64/kernel/entry-ftrace.S
  3. *
  4. * Copyright (C) 2013 Linaro Limited
  5. * 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. */
  11. #include <linux/linkage.h>
  12. #include <asm/ftrace.h>
  13. #include <asm/insn.h>
  14. /*
  15. * Gcc with -pg will put the following code in the beginning of each function:
  16. * mov x0, x30
  17. * bl _mcount
  18. * [function's body ...]
  19. * "bl _mcount" may be replaced to "bl ftrace_caller" or NOP if dynamic
  20. * ftrace is enabled.
  21. *
  22. * Please note that x0 as an argument will not be used here because we can
  23. * get lr(x30) of instrumented function at any time by winding up call stack
  24. * as long as the kernel is compiled without -fomit-frame-pointer.
  25. * (or CONFIG_FRAME_POINTER, this is forced on arm64)
  26. *
  27. * stack layout after mcount_enter in _mcount():
  28. *
  29. * current sp/fp => 0:+-----+
  30. * in _mcount() | x29 | -> instrumented function's fp
  31. * +-----+
  32. * | x30 | -> _mcount()'s lr (= instrumented function's pc)
  33. * old sp => +16:+-----+
  34. * when instrumented | |
  35. * function calls | ... |
  36. * _mcount() | |
  37. * | |
  38. * instrumented => +xx:+-----+
  39. * function's fp | x29 | -> parent's fp
  40. * +-----+
  41. * | x30 | -> instrumented function's lr (= parent's pc)
  42. * +-----+
  43. * | ... |
  44. */
  45. .macro mcount_enter
  46. stp x29, x30, [sp, #-16]!
  47. mov x29, sp
  48. .endm
  49. .macro mcount_exit
  50. ldp x29, x30, [sp], #16
  51. ret
  52. .endm
  53. .macro mcount_adjust_addr rd, rn
  54. sub \rd, \rn, #AARCH64_INSN_SIZE
  55. .endm
  56. /* for instrumented function's parent */
  57. .macro mcount_get_parent_fp reg
  58. ldr \reg, [x29]
  59. ldr \reg, [\reg]
  60. .endm
  61. /* for instrumented function */
  62. .macro mcount_get_pc0 reg
  63. mcount_adjust_addr \reg, x30
  64. .endm
  65. .macro mcount_get_pc reg
  66. ldr \reg, [x29, #8]
  67. mcount_adjust_addr \reg, \reg
  68. .endm
  69. .macro mcount_get_lr reg
  70. ldr \reg, [x29]
  71. ldr \reg, [\reg, #8]
  72. mcount_adjust_addr \reg, \reg
  73. .endm
  74. .macro mcount_get_lr_addr reg
  75. ldr \reg, [x29]
  76. add \reg, \reg, #8
  77. .endm
  78. #ifndef CONFIG_DYNAMIC_FTRACE
  79. /*
  80. * void _mcount(unsigned long return_address)
  81. * @return_address: return address to instrumented function
  82. *
  83. * This function makes calls, if enabled, to:
  84. * - tracer function to probe instrumented function's entry,
  85. * - ftrace_graph_caller to set up an exit hook
  86. */
  87. ENTRY(_mcount)
  88. mcount_enter
  89. adrp x0, ftrace_trace_function
  90. ldr x2, [x0, #:lo12:ftrace_trace_function]
  91. adr x0, ftrace_stub
  92. cmp x0, x2 // if (ftrace_trace_function
  93. b.eq skip_ftrace_call // != ftrace_stub) {
  94. mcount_get_pc x0 // function's pc
  95. mcount_get_lr x1 // function's lr (= parent's pc)
  96. blr x2 // (*ftrace_trace_function)(pc, lr);
  97. #ifndef CONFIG_FUNCTION_GRAPH_TRACER
  98. skip_ftrace_call: // return;
  99. mcount_exit // }
  100. #else
  101. mcount_exit // return;
  102. // }
  103. skip_ftrace_call:
  104. adrp x1, ftrace_graph_return
  105. ldr x2, [x1, #:lo12:ftrace_graph_return]
  106. cmp x0, x2 // if ((ftrace_graph_return
  107. b.ne ftrace_graph_caller // != ftrace_stub)
  108. adrp x1, ftrace_graph_entry // || (ftrace_graph_entry
  109. adrp x0, ftrace_graph_entry_stub // != ftrace_graph_entry_stub))
  110. ldr x2, [x1, #:lo12:ftrace_graph_entry]
  111. add x0, x0, #:lo12:ftrace_graph_entry_stub
  112. cmp x0, x2
  113. b.ne ftrace_graph_caller // ftrace_graph_caller();
  114. mcount_exit
  115. #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
  116. ENDPROC(_mcount)
  117. #else /* CONFIG_DYNAMIC_FTRACE */
  118. /*
  119. * _mcount() is used to build the kernel with -pg option, but all the branch
  120. * instructions to _mcount() are replaced to NOP initially at kernel start up,
  121. * and later on, NOP to branch to ftrace_caller() when enabled or branch to
  122. * NOP when disabled per-function base.
  123. */
  124. ENTRY(_mcount)
  125. ret
  126. ENDPROC(_mcount)
  127. /*
  128. * void ftrace_caller(unsigned long return_address)
  129. * @return_address: return address to instrumented function
  130. *
  131. * This function is a counterpart of _mcount() in 'static' ftrace, and
  132. * makes calls to:
  133. * - tracer function to probe instrumented function's entry,
  134. * - ftrace_graph_caller to set up an exit hook
  135. */
  136. ENTRY(ftrace_caller)
  137. mcount_enter
  138. mcount_get_pc0 x0 // function's pc
  139. mcount_get_lr x1 // function's lr
  140. .global ftrace_call
  141. ftrace_call: // tracer(pc, lr);
  142. nop // This will be replaced with "bl xxx"
  143. // where xxx can be any kind of tracer.
  144. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  145. .global ftrace_graph_call
  146. ftrace_graph_call: // ftrace_graph_caller();
  147. nop // If enabled, this will be replaced
  148. // "b ftrace_graph_caller"
  149. #endif
  150. mcount_exit
  151. ENDPROC(ftrace_caller)
  152. #endif /* CONFIG_DYNAMIC_FTRACE */
  153. ENTRY(ftrace_stub)
  154. ret
  155. ENDPROC(ftrace_stub)
  156. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  157. /*
  158. * void ftrace_graph_caller(void)
  159. *
  160. * Called from _mcount() or ftrace_caller() when function_graph tracer is
  161. * selected.
  162. * This function w/ prepare_ftrace_return() fakes link register's value on
  163. * the call stack in order to intercept instrumented function's return path
  164. * and run return_to_handler() later on its exit.
  165. */
  166. ENTRY(ftrace_graph_caller)
  167. mcount_get_lr_addr x0 // pointer to function's saved lr
  168. mcount_get_pc x1 // function's pc
  169. mcount_get_parent_fp x2 // parent's fp
  170. bl prepare_ftrace_return // prepare_ftrace_return(&lr, pc, fp)
  171. mcount_exit
  172. ENDPROC(ftrace_graph_caller)
  173. /*
  174. * void return_to_handler(void)
  175. *
  176. * Run ftrace_return_to_handler() before going back to parent.
  177. * @fp is checked against the value passed by ftrace_graph_caller()
  178. * only when CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST is enabled.
  179. */
  180. ENTRY(return_to_handler)
  181. str x0, [sp, #-16]!
  182. mov x0, x29 // parent's fp
  183. bl ftrace_return_to_handler// addr = ftrace_return_to_hander(fp);
  184. mov x30, x0 // restore the original return address
  185. ldr x0, [sp], #16
  186. ret
  187. END(return_to_handler)
  188. #endif /* CONFIG_FUNCTION_GRAPH_TRACER */