Skip to content

Commit

Permalink
ftrace: Add return address pointer to ftrace_ret_stack
Browse files Browse the repository at this point in the history
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: Josh Poimboeuf <[email protected]>
Acked-by: Steven Rostedt <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Brian Gerst <[email protected]>
Cc: Byungchul Park <[email protected]>
Cc: Denys Vlasenko <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Nilay Vaish <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/a95cfcc39e8f26b89a430c56926af0bb217bc0a1.1471607358.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
jpoimboe authored and Ingo Molnar committed Aug 24, 2016
1 parent daa460a commit 9a7c348
Show file tree
Hide file tree
Showing 15 changed files with 34 additions and 15 deletions.
11 changes: 11 additions & 0 deletions Documentation/trace/ftrace-design.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

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
---------------------
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
frame_pointer);
frame_pointer, NULL);
if (err == -EBUSY) {
*parent = old;
return;
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
return;

err = ftrace_push_return_trace(old, self_addr, &trace.depth,
frame_pointer);
frame_pointer, NULL);
if (err == -EBUSY)
return;
else
Expand Down
2 changes: 1 addition & 1 deletion arch/blackfin/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
return;

if (ftrace_push_return_trace(*parent, self_addr, &trace.depth,
frame_pointer) == -EBUSY)
frame_pointer, NULL) == -EBUSY)
return;

trace.func = self_addr;
Expand Down
2 changes: 1 addition & 1 deletion arch/microblaze/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
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) {
*parent = old;
return;
Expand Down
4 changes: 2 additions & 2 deletions arch/mips/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
if (unlikely(faulted))
goto out;

if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp)
== -EBUSY) {
if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp,
NULL) == -EBUSY) {
*parent_ra_addr = old_parent_ra;
return;
}
Expand Down
2 changes: 1 addition & 1 deletion arch/parisc/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static void __hot prepare_ftrace_return(unsigned long *parent,
return;

if (ftrace_push_return_trace(old, self_addr, &trace.depth,
0 ) == -EBUSY)
0, NULL) == -EBUSY)
return;

/* activate parisc_return_to_handler() as return point */
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
if (!ftrace_graph_entry(&trace))
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;

parent = return_hooker;
Expand Down
3 changes: 2 additions & 1 deletion arch/s390/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
/* Only trace if the calling function expects to. */
if (!ftrace_graph_entry(&trace))
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;
parent = (unsigned long) return_to_handler;
out:
Expand Down
2 changes: 1 addition & 1 deletion arch/sh/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
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) {
__raw_writel(old, parent);
return;
Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ unsigned long prepare_ftrace_return(unsigned long parent,
return parent + 8UL;

if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
frame_pointer) == -EBUSY)
frame_pointer, NULL) == -EBUSY)
return parent + 8UL;

trace.func = self_addr;
Expand Down
2 changes: 1 addition & 1 deletion arch/tile/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
*parent = return_hooker;

err = ftrace_push_return_trace(old, self_addr, &trace.depth,
frame_pointer);
frame_pointer, NULL);
if (err == -EBUSY) {
*parent = old;
return;
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
frame_pointer) == -EBUSY) {
frame_pointer, NULL) == -EBUSY) {
*parent = old;
return;
}
Expand Down
5 changes: 4 additions & 1 deletion include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,9 @@ struct ftrace_ret_stack {
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
unsigned long fp;
#endif
#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
unsigned long *retp;
#endif
};

/*
Expand All @@ -809,7 +812,7 @@ extern void return_to_handler(void);

extern int
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
Expand Down
5 changes: 4 additions & 1 deletion kernel/trace/trace_functions_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.*/
int
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;
int index;
Expand Down Expand Up @@ -173,6 +173,9 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
current->ret_stack[index].subtime = 0;
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
current->ret_stack[index].fp = frame_pointer;
#endif
#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
current->ret_stack[index].retp = retp;
#endif
*depth = current->curr_ret_stack;

Expand Down

0 comments on commit 9a7c348

Please sign in to comment.