2 * Code for tracing calls in Linux kernel.
3 * Copyright (C) 2009 Helge Deller <deller@gmx.de>
5 * based on code for x86 which is:
6 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
8 * future possible enhancements:
9 * - add CONFIG_DYNAMIC_FTRACE
10 * - add CONFIG_STACK_TRACER
13 #include <linux/init.h>
14 #include <linux/ftrace.h>
16 #include <asm/sections.h>
17 #include <asm/ftrace.h>
21 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
23 /* Add a function return address to the trace stack on thread info.*/
24 static int push_return_trace(unsigned long ret
, unsigned long long time
,
25 unsigned long func
, int *depth
)
29 if (!current
->ret_stack
)
32 /* The return trace stack is full */
33 if (current
->curr_ret_stack
== FTRACE_RETFUNC_DEPTH
- 1) {
34 atomic_inc(¤t
->trace_overrun
);
38 index
= ++current
->curr_ret_stack
;
40 current
->ret_stack
[index
].ret
= ret
;
41 current
->ret_stack
[index
].func
= func
;
42 current
->ret_stack
[index
].calltime
= time
;
48 /* Retrieve a function return address to the trace stack on thread info.*/
49 static void pop_return_trace(struct ftrace_graph_ret
*trace
, unsigned long *ret
)
53 index
= current
->curr_ret_stack
;
55 if (unlikely(index
< 0)) {
58 /* Might as well panic, otherwise we have no where to go */
59 *ret
= (unsigned long)
60 dereference_function_descriptor(&panic
);
64 *ret
= current
->ret_stack
[index
].ret
;
65 trace
->func
= current
->ret_stack
[index
].func
;
66 trace
->calltime
= current
->ret_stack
[index
].calltime
;
67 trace
->overrun
= atomic_read(¤t
->trace_overrun
);
70 current
->curr_ret_stack
--;
75 * Send the trace to the ring-buffer.
76 * @return the original return address.
78 unsigned long ftrace_return_to_handler(unsigned long retval0
,
79 unsigned long retval1
)
81 struct ftrace_graph_ret trace
;
84 pop_return_trace(&trace
, &ret
);
85 trace
.rettime
= cpu_clock(raw_smp_processor_id());
86 ftrace_graph_return(&trace
);
91 /* Might as well panic. What else to do? */
93 dereference_function_descriptor(&panic
);
96 /* HACK: we hand over the old functions' return values
97 in %r23 and %r24. Assembly in entry.S will take care
98 and move those to their final registers %ret0 and %ret1 */
99 asm( "copy %0, %%r23 \n\t"
100 "copy %1, %%r24 \n" : : "r" (retval0
), "r" (retval1
) );
106 * Hook the return address and push it in the stack of return addrs
107 * in current thread info.
109 void prepare_ftrace_return(unsigned long *parent
, unsigned long self_addr
)
112 unsigned long long calltime
;
113 struct ftrace_graph_ent trace
;
115 if (unlikely(atomic_read(¤t
->tracing_graph_pause
)))
119 *parent
= (unsigned long)
120 dereference_function_descriptor(&return_to_handler
);
122 if (unlikely(!__kernel_text_address(old
))) {
129 calltime
= cpu_clock(raw_smp_processor_id());
131 if (push_return_trace(old
, calltime
,
132 self_addr
, &trace
.depth
) == -EBUSY
) {
137 trace
.func
= self_addr
;
139 /* Only trace if the calling function expects to */
140 if (!ftrace_graph_entry(&trace
)) {
141 current
->curr_ret_stack
--;
146 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
149 void ftrace_function_trampoline(unsigned long parent
,
150 unsigned long self_addr
,
151 unsigned long org_sp_gr3
)
153 extern ftrace_func_t ftrace_trace_function
;
155 if (function_trace_stop
)
158 if (ftrace_trace_function
!= ftrace_stub
) {
159 ftrace_trace_function(parent
, self_addr
);
162 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
163 if (ftrace_graph_entry
&& ftrace_graph_return
) {
165 unsigned long *parent_rp
;
167 asm volatile ("copy %%r30, %0" : "=r"(sp
));
168 /* sanity check: is stack pointer which we got from
169 assembler function in entry.S in a reasonable
170 range compared to current stack pointer? */
171 if ((sp
- org_sp_gr3
) > 0x400)
174 /* calculate pointer to %rp in stack */
175 parent_rp
= (unsigned long *) org_sp_gr3
- 0x10;
176 /* sanity check: parent_rp should hold parent */
177 if (*parent_rp
!= parent
)
180 prepare_ftrace_return(parent_rp
, self_addr
);