Commit 9a7c348b authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Ingo Molnar

ftrace: Add return address pointer to ftrace_ret_stack

Storing this value will help prevent unwinders from getting out of sync
with the function graph tracer ret_stack.  Now instead of needing a
stateful iterator, they can compare the return address pointer to find
the right ret_stack entry.

Note that an array of 50 ftrace_ret_stack structs is allocated for every
task.  So when an arch implements this, it will add either 200 or 400
bytes of memory usage per task (depending on whether it's a 32-bit or
64-bit platform).
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Acked-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Byungchul Park <byungchul.park@lge.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nilay Vaish <nilayvaish@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/a95cfcc39e8f26b89a430c56926af0bb217bc0a1.1471607358.git.jpoimboe@redhat.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent daa460a8
...@@ -203,6 +203,17 @@ along to ftrace_push_return_trace() instead of a stub value of 0. ...@@ -203,6 +203,17 @@ along to ftrace_push_return_trace() instead of a stub value of 0.
Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer. Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer.
HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
--------------------------------
An arch may pass in a pointer to the return address on the stack. This
prevents potential stack unwinding issues where the unwinder gets out of
sync with ret_stack and the wrong addresses are reported by
ftrace_graph_ret_addr().
Adding support for it is easy: just define the macro in asm/ftrace.h and
pass the return address pointer as the 'retp' argument to
ftrace_push_return_trace().
HAVE_FTRACE_NMI_ENTER HAVE_FTRACE_NMI_ENTER
--------------------- ---------------------
......
...@@ -218,7 +218,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ...@@ -218,7 +218,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
} }
err = ftrace_push_return_trace(old, self_addr, &trace.depth, err = ftrace_push_return_trace(old, self_addr, &trace.depth,
frame_pointer); frame_pointer, NULL);
if (err == -EBUSY) { if (err == -EBUSY) {
*parent = old; *parent = old;
return; return;
......
...@@ -138,7 +138,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ...@@ -138,7 +138,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
return; return;
err = ftrace_push_return_trace(old, self_addr, &trace.depth, err = ftrace_push_return_trace(old, self_addr, &trace.depth,
frame_pointer); frame_pointer, NULL);
if (err == -EBUSY) if (err == -EBUSY)
return; return;
else else
......
...@@ -107,7 +107,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ...@@ -107,7 +107,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
return; return;
if (ftrace_push_return_trace(*parent, self_addr, &trace.depth, if (ftrace_push_return_trace(*parent, self_addr, &trace.depth,
frame_pointer) == -EBUSY) frame_pointer, NULL) == -EBUSY)
return; return;
trace.func = self_addr; trace.func = self_addr;
......
...@@ -63,7 +63,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) ...@@ -63,7 +63,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
return; return;
} }
err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0); err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0, NULL);
if (err == -EBUSY) { if (err == -EBUSY) {
*parent = old; *parent = old;
return; return;
......
...@@ -382,8 +382,8 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra, ...@@ -382,8 +382,8 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
if (unlikely(faulted)) if (unlikely(faulted))
goto out; goto out;
if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp) if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp,
== -EBUSY) { NULL) == -EBUSY) {
*parent_ra_addr = old_parent_ra; *parent_ra_addr = old_parent_ra;
return; return;
} }
......
...@@ -48,7 +48,7 @@ static void __hot prepare_ftrace_return(unsigned long *parent, ...@@ -48,7 +48,7 @@ static void __hot prepare_ftrace_return(unsigned long *parent,
return; return;
if (ftrace_push_return_trace(old, self_addr, &trace.depth, if (ftrace_push_return_trace(old, self_addr, &trace.depth,
0 ) == -EBUSY) 0, NULL) == -EBUSY)
return; return;
/* activate parisc_return_to_handler() as return point */ /* activate parisc_return_to_handler() as return point */
......
...@@ -593,7 +593,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip) ...@@ -593,7 +593,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
if (!ftrace_graph_entry(&trace)) if (!ftrace_graph_entry(&trace))
goto out; goto out;
if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY) if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
NULL) == -EBUSY)
goto out; goto out;
parent = return_hooker; parent = return_hooker;
......
...@@ -209,7 +209,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip) ...@@ -209,7 +209,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
/* Only trace if the calling function expects to. */ /* Only trace if the calling function expects to. */
if (!ftrace_graph_entry(&trace)) if (!ftrace_graph_entry(&trace))
goto out; goto out;
if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY) if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
NULL) == -EBUSY)
goto out; goto out;
parent = (unsigned long) return_to_handler; parent = (unsigned long) return_to_handler;
out: out:
......
...@@ -382,7 +382,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) ...@@ -382,7 +382,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
return; return;
} }
err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0); err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0, NULL);
if (err == -EBUSY) { if (err == -EBUSY) {
__raw_writel(old, parent); __raw_writel(old, parent);
return; return;
......
...@@ -131,7 +131,7 @@ unsigned long prepare_ftrace_return(unsigned long parent, ...@@ -131,7 +131,7 @@ unsigned long prepare_ftrace_return(unsigned long parent,
return parent + 8UL; return parent + 8UL;
if (ftrace_push_return_trace(parent, self_addr, &trace.depth, if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
frame_pointer) == -EBUSY) frame_pointer, NULL) == -EBUSY)
return parent + 8UL; return parent + 8UL;
trace.func = self_addr; trace.func = self_addr;
......
...@@ -184,7 +184,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ...@@ -184,7 +184,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
*parent = return_hooker; *parent = return_hooker;
err = ftrace_push_return_trace(old, self_addr, &trace.depth, err = ftrace_push_return_trace(old, self_addr, &trace.depth,
frame_pointer); frame_pointer, NULL);
if (err == -EBUSY) { if (err == -EBUSY) {
*parent = old; *parent = old;
return; return;
......
...@@ -1029,7 +1029,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, ...@@ -1029,7 +1029,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
} }
if (ftrace_push_return_trace(old, self_addr, &trace.depth, if (ftrace_push_return_trace(old, self_addr, &trace.depth,
frame_pointer) == -EBUSY) { frame_pointer, NULL) == -EBUSY) {
*parent = old; *parent = old;
return; return;
} }
......
...@@ -798,6 +798,9 @@ struct ftrace_ret_stack { ...@@ -798,6 +798,9 @@ struct ftrace_ret_stack {
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST #ifdef HAVE_FUNCTION_GRAPH_FP_TEST
unsigned long fp; unsigned long fp;
#endif #endif
#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
unsigned long *retp;
#endif
}; };
/* /*
...@@ -809,7 +812,7 @@ extern void return_to_handler(void); ...@@ -809,7 +812,7 @@ extern void return_to_handler(void);
extern int extern int
ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
unsigned long frame_pointer); unsigned long frame_pointer, unsigned long *retp);
/* /*
* Sometimes we don't want to trace a function with the function * Sometimes we don't want to trace a function with the function
......
...@@ -119,7 +119,7 @@ print_graph_duration(struct trace_array *tr, unsigned long long duration, ...@@ -119,7 +119,7 @@ print_graph_duration(struct trace_array *tr, unsigned long long duration,
/* Add a function return address to the trace stack on thread info.*/ /* Add a function return address to the trace stack on thread info.*/
int int
ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
unsigned long frame_pointer) unsigned long frame_pointer, unsigned long *retp)
{ {
unsigned long long calltime; unsigned long long calltime;
int index; int index;
...@@ -173,6 +173,9 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, ...@@ -173,6 +173,9 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
current->ret_stack[index].subtime = 0; current->ret_stack[index].subtime = 0;
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST #ifdef HAVE_FUNCTION_GRAPH_FP_TEST
current->ret_stack[index].fp = frame_pointer; current->ret_stack[index].fp = frame_pointer;
#endif
#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
current->ret_stack[index].retp = retp;
#endif #endif
*depth = current->curr_ret_stack; *depth = current->curr_ret_stack;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment