Commit 555f386c98cc93890f48fdea098936755270304b

Authored by Mike Frysinger
Committed by Steven Rostedt
1 parent 1f5a6b4541

ftrace: document function and function graph implementation

While implementing function tracer and function tracer graph support,
I found the exact arch implementation details to be a bit lacking
(and my x86 foo ain't great).  So after pounding out support for
the Blackfin arch, start documenting the requirements/details.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
LKML-Reference: <1252973415-21264-1-git-send-email-vapier@gentoo.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Showing 3 changed files with 252 additions and 3 deletions Side-by-side Diff

Documentation/trace/ftrace-design.txt
  1 + function tracer guts
  2 + ====================
  3 +
  4 +Introduction
  5 +------------
  6 +
  7 +Here we will cover the architecture pieces that the common function tracing
  8 +code relies on for proper functioning. Things are broken down into increasing
  9 +complexity so that you can start simple and at least get basic functionality.
  10 +
  11 +Note that this focuses on architecture implementation details only. If you
  12 +want more explanation of a feature in terms of common code, review the common
  13 +ftrace.txt file.
  14 +
  15 +
  16 +Prerequisites
  17 +-------------
  18 +
  19 +Ftrace relies on these features being implemented:
  20 + STACKTRACE_SUPPORT - implement save_stack_trace()
  21 + TRACE_IRQFLAGS_SUPPORT - implement include/asm/irqflags.h
  22 +
  23 +
  24 +HAVE_FUNCTION_TRACER
  25 +--------------------
  26 +
  27 +You will need to implement the mcount and the ftrace_stub functions.
  28 +
  29 +The exact mcount symbol name will depend on your toolchain. Some call it
  30 +"mcount", "_mcount", or even "__mcount". You can probably figure it out by
  31 +running something like:
  32 + $ echo 'main(){}' | gcc -x c -S -o - - -pg | grep mcount
  33 + call mcount
  34 +We'll make the assumption below that the symbol is "mcount" just to keep things
  35 +nice and simple in the examples.
  36 +
  37 +Keep in mind that the ABI that is in effect inside of the mcount function is
  38 +*highly* architecture/toolchain specific. We cannot help you in this regard,
  39 +sorry. Dig up some old documentation and/or find someone more familiar than
  40 +you to bang ideas off of. Typically, register usage (argument/scratch/etc...)
  41 +is a major issue at this point, especially in relation to the location of the
  42 +mcount call (before/after function prologue). You might also want to look at
  43 +how glibc has implemented the mcount function for your architecture. It might
  44 +be (semi-)relevant.
  45 +
  46 +The mcount function should check the function pointer ftrace_trace_function
  47 +to see if it is set to ftrace_stub. If it is, there is nothing for you to do,
  48 +so return immediately. If it isn't, then call that function in the same way
  49 +the mcount function normally calls __mcount_internal -- the first argument is
  50 +the "frompc" while the second argument is the "selfpc" (adjusted to remove the
  51 +size of the mcount call that is embedded in the function).
  52 +
  53 +For example, if the function foo() calls bar(), when the bar() function calls
  54 +mcount(), the arguments mcount() will pass to the tracer are:
  55 + "frompc" - the address bar() will use to return to foo()
  56 + "selfpc" - the address bar() (with _mcount() size adjustment)
  57 +
  58 +Also keep in mind that this mcount function will be called *a lot*, so
  59 +optimizing for the default case of no tracer will help the smooth running of
  60 +your system when tracing is disabled. So the start of the mcount function is
  61 +typically the bare min with checking things before returning. That also means
  62 +the code flow should usually kept linear (i.e. no branching in the nop case).
  63 +This is of course an optimization and not a hard requirement.
  64 +
  65 +Here is some pseudo code that should help (these functions should actually be
  66 +implemented in assembly):
  67 +
  68 +void ftrace_stub(void)
  69 +{
  70 + return;
  71 +}
  72 +
  73 +void mcount(void)
  74 +{
  75 + /* save any bare state needed in order to do initial checking */
  76 +
  77 + extern void (*ftrace_trace_function)(unsigned long, unsigned long);
  78 + if (ftrace_trace_function != ftrace_stub)
  79 + goto do_trace;
  80 +
  81 + /* restore any bare state */
  82 +
  83 + return;
  84 +
  85 +do_trace:
  86 +
  87 + /* save all state needed by the ABI (see paragraph above) */
  88 +
  89 + unsigned long frompc = ...;
  90 + unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE;
  91 + ftrace_trace_function(frompc, selfpc);
  92 +
  93 + /* restore all state needed by the ABI */
  94 +}
  95 +
  96 +Don't forget to export mcount for modules !
  97 +extern void mcount(void);
  98 +EXPORT_SYMBOL(mcount);
  99 +
  100 +
  101 +HAVE_FUNCTION_TRACE_MCOUNT_TEST
  102 +-------------------------------
  103 +
  104 +This is an optional optimization for the normal case when tracing is turned off
  105 +in the system. If you do not enable this Kconfig option, the common ftrace
  106 +code will take care of doing the checking for you.
  107 +
  108 +To support this feature, you only need to check the function_trace_stop
  109 +variable in the mcount function. If it is non-zero, there is no tracing to be
  110 +done at all, so you can return.
  111 +
  112 +This additional pseudo code would simply be:
  113 +void mcount(void)
  114 +{
  115 + /* save any bare state needed in order to do initial checking */
  116 +
  117 ++ if (function_trace_stop)
  118 ++ return;
  119 +
  120 + extern void (*ftrace_trace_function)(unsigned long, unsigned long);
  121 + if (ftrace_trace_function != ftrace_stub)
  122 +...
  123 +
  124 +
  125 +HAVE_FUNCTION_GRAPH_TRACER
  126 +--------------------------
  127 +
  128 +Deep breath ... time to do some real work. Here you will need to update the
  129 +mcount function to check ftrace graph function pointers, as well as implement
  130 +some functions to save (hijack) and restore the return address.
  131 +
  132 +The mcount function should check the function pointers ftrace_graph_return
  133 +(compare to ftrace_stub) and ftrace_graph_entry (compare to
  134 +ftrace_graph_entry_stub). If either of those are not set to the relevant stub
  135 +function, call the arch-specific function ftrace_graph_caller which in turn
  136 +calls the arch-specific function prepare_ftrace_return. Neither of these
  137 +function names are strictly required, but you should use them anyways to stay
  138 +consistent across the architecture ports -- easier to compare & contrast
  139 +things.
  140 +
  141 +The arguments to prepare_ftrace_return are slightly different than what are
  142 +passed to ftrace_trace_function. The second argument "selfpc" is the same,
  143 +but the first argument should be a pointer to the "frompc". Typically this is
  144 +located on the stack. This allows the function to hijack the return address
  145 +temporarily to have it point to the arch-specific function return_to_handler.
  146 +That function will simply call the common ftrace_return_to_handler function and
  147 +that will return the original return address with which, you can return to the
  148 +original call site.
  149 +
  150 +Here is the updated mcount pseudo code:
  151 +void mcount(void)
  152 +{
  153 +...
  154 + if (ftrace_trace_function != ftrace_stub)
  155 + goto do_trace;
  156 +
  157 ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  158 ++ extern void (*ftrace_graph_return)(...);
  159 ++ extern void (*ftrace_graph_entry)(...);
  160 ++ if (ftrace_graph_return != ftrace_stub ||
  161 ++ ftrace_graph_entry != ftrace_graph_entry_stub)
  162 ++ ftrace_graph_caller();
  163 ++#endif
  164 +
  165 + /* restore any bare state */
  166 +...
  167 +
  168 +Here is the pseudo code for the new ftrace_graph_caller assembly function:
  169 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  170 +void ftrace_graph_caller(void)
  171 +{
  172 + /* save all state needed by the ABI */
  173 +
  174 + unsigned long *frompc = &...;
  175 + unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE;
  176 + prepare_ftrace_return(frompc, selfpc);
  177 +
  178 + /* restore all state needed by the ABI */
  179 +}
  180 +#endif
  181 +
  182 +For information on how to implement prepare_ftrace_return(), simply look at
  183 +the x86 version. The only architecture-specific piece in it is the setup of
  184 +the fault recovery table (the asm(...) code). The rest should be the same
  185 +across architectures.
  186 +
  187 +Here is the pseudo code for the new return_to_handler assembly function. Note
  188 +that the ABI that applies here is different from what applies to the mcount
  189 +code. Since you are returning from a function (after the epilogue), you might
  190 +be able to skimp on things saved/restored (usually just registers used to pass
  191 +return values).
  192 +
  193 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  194 +void return_to_handler(void)
  195 +{
  196 + /* save all state needed by the ABI (see paragraph above) */
  197 +
  198 + void (*original_return_point)(void) = ftrace_return_to_handler();
  199 +
  200 + /* restore all state needed by the ABI */
  201 +
  202 + /* this is usually either a return or a jump */
  203 + original_return_point();
  204 +}
  205 +#endif
  206 +
  207 +
  208 +HAVE_FTRACE_NMI_ENTER
  209 +---------------------
  210 +
  211 +If you can't trace NMI functions, then skip this option.
  212 +
  213 +<details to be filled>
  214 +
  215 +
  216 +HAVE_FTRACE_SYSCALLS
  217 +---------------------
  218 +
  219 +<details to be filled>
  220 +
  221 +
  222 +HAVE_FTRACE_MCOUNT_RECORD
  223 +-------------------------
  224 +
  225 +See scripts/recordmcount.pl for more info.
  226 +
  227 +<details to be filled>
  228 +
  229 +
  230 +HAVE_DYNAMIC_FTRACE
  231 +---------------------
  232 +
  233 +<details to be filled>
Documentation/trace/ftrace.txt
... ... @@ -26,6 +26,12 @@
26 26 means that the list of tracers can always grow).
27 27  
28 28  
  29 +Implementation Details
  30 +----------------------
  31 +
  32 +See ftrace-design.txt for details for arch porters and such.
  33 +
  34 +
29 35 The File System
30 36 ---------------
31 37  
kernel/trace/Kconfig
... ... @@ -11,12 +11,18 @@
11 11  
12 12 config HAVE_FTRACE_NMI_ENTER
13 13 bool
  14 + help
  15 + See Documentation/trace/ftrace-implementation.txt
14 16  
15 17 config HAVE_FUNCTION_TRACER
16 18 bool
  19 + help
  20 + See Documentation/trace/ftrace-implementation.txt
17 21  
18 22 config HAVE_FUNCTION_GRAPH_TRACER
19 23 bool
  24 + help
  25 + See Documentation/trace/ftrace-implementation.txt
20 26  
21 27 config HAVE_FUNCTION_GRAPH_FP_TEST
22 28 bool
23 29  
24 30  
25 31  
... ... @@ -28,21 +34,25 @@
28 34 config HAVE_FUNCTION_TRACE_MCOUNT_TEST
29 35 bool
30 36 help
31   - This gets selected when the arch tests the function_trace_stop
32   - variable at the mcount call site. Otherwise, this variable
33   - is tested by the called function.
  37 + See Documentation/trace/ftrace-implementation.txt
34 38  
35 39 config HAVE_DYNAMIC_FTRACE
36 40 bool
  41 + help
  42 + See Documentation/trace/ftrace-implementation.txt
37 43  
38 44 config HAVE_FTRACE_MCOUNT_RECORD
39 45 bool
  46 + help
  47 + See Documentation/trace/ftrace-implementation.txt
40 48  
41 49 config HAVE_HW_BRANCH_TRACER
42 50 bool
43 51  
44 52 config HAVE_SYSCALL_TRACEPOINTS
45 53 bool
  54 + help
  55 + See Documentation/trace/ftrace-implementation.txt
46 56  
47 57 config TRACER_MAX_TRACE
48 58 bool