aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2016-08-19 07:52:57 -0400
committerIngo Molnar <mingo@kernel.org>2016-08-24 06:15:14 -0400
commit9a7c348ba6a46f6270d4fe49577649dad5664fe7 (patch)
tree747a399fc9f6f3f1e234e27a164b9bb5e6ac015a
parentdaa460a88c09b26b68e8b017de589c217e901afb (diff)
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: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Steven 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.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--Documentation/trace/ftrace-design.txt11
-rw-r--r--arch/arm/kernel/ftrace.c2
-rw-r--r--arch/arm64/kernel/ftrace.c2
-rw-r--r--arch/blackfin/kernel/ftrace.c2
-rw-r--r--arch/microblaze/kernel/ftrace.c2
-rw-r--r--arch/mips/kernel/ftrace.c4
-rw-r--r--arch/parisc/kernel/ftrace.c2
-rw-r--r--arch/powerpc/kernel/ftrace.c3
-rw-r--r--arch/s390/kernel/ftrace.c3
-rw-r--r--arch/sh/kernel/ftrace.c2
-rw-r--r--arch/sparc/kernel/ftrace.c2
-rw-r--r--arch/tile/kernel/ftrace.c2
-rw-r--r--arch/x86/kernel/ftrace.c2
-rw-r--r--include/linux/ftrace.h5
-rw-r--r--kernel/trace/trace_functions_graph.c5
15 files changed, 34 insertions, 15 deletions
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt
index dd5f916b351d..a273dd0bbaaa 100644
--- a/Documentation/trace/ftrace-design.txt
+++ b/Documentation/trace/ftrace-design.txt
@@ -203,6 +203,17 @@ along to ftrace_push_return_trace() instead of a stub value of 0.
203 203
204Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer. 204Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer.
205 205
206HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
207--------------------------------
208
209An arch may pass in a pointer to the return address on the stack. This
210prevents potential stack unwinding issues where the unwinder gets out of
211sync with ret_stack and the wrong addresses are reported by
212ftrace_graph_ret_addr().
213
214Adding support for it is easy: just define the macro in asm/ftrace.h and
215pass the return address pointer as the 'retp' argument to
216ftrace_push_return_trace().
206 217
207HAVE_FTRACE_NMI_ENTER 218HAVE_FTRACE_NMI_ENTER
208--------------------- 219---------------------
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index 709ee1d6d4df..3f1759411d51 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -218,7 +218,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
218 } 218 }
219 219
220 err = ftrace_push_return_trace(old, self_addr, &trace.depth, 220 err = ftrace_push_return_trace(old, self_addr, &trace.depth,
221 frame_pointer); 221 frame_pointer, NULL);
222 if (err == -EBUSY) { 222 if (err == -EBUSY) {
223 *parent = old; 223 *parent = old;
224 return; 224 return;
diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c
index ebecf9aa33d1..40ad08ac569a 100644
--- a/arch/arm64/kernel/ftrace.c
+++ b/arch/arm64/kernel/ftrace.c
@@ -138,7 +138,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
138 return; 138 return;
139 139
140 err = ftrace_push_return_trace(old, self_addr, &trace.depth, 140 err = ftrace_push_return_trace(old, self_addr, &trace.depth,
141 frame_pointer); 141 frame_pointer, NULL);
142 if (err == -EBUSY) 142 if (err == -EBUSY)
143 return; 143 return;
144 else 144 else
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c
index 095de0fa044d..8dad7589b843 100644
--- a/arch/blackfin/kernel/ftrace.c
+++ b/arch/blackfin/kernel/ftrace.c
@@ -107,7 +107,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
107 return; 107 return;
108 108
109 if (ftrace_push_return_trace(*parent, self_addr, &trace.depth, 109 if (ftrace_push_return_trace(*parent, self_addr, &trace.depth,
110 frame_pointer) == -EBUSY) 110 frame_pointer, NULL) == -EBUSY)
111 return; 111 return;
112 112
113 trace.func = self_addr; 113 trace.func = self_addr;
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c
index fc7b48a52cd5..d57563c58a26 100644
--- a/arch/microblaze/kernel/ftrace.c
+++ b/arch/microblaze/kernel/ftrace.c
@@ -63,7 +63,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
63 return; 63 return;
64 } 64 }
65 65
66 err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0); 66 err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0, NULL);
67 if (err == -EBUSY) { 67 if (err == -EBUSY) {
68 *parent = old; 68 *parent = old;
69 return; 69 return;
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index 937c54bc8ccc..30a3b75e88eb 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -382,8 +382,8 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
382 if (unlikely(faulted)) 382 if (unlikely(faulted))
383 goto out; 383 goto out;
384 384
385 if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp) 385 if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp,
386 == -EBUSY) { 386 NULL) == -EBUSY) {
387 *parent_ra_addr = old_parent_ra; 387 *parent_ra_addr = old_parent_ra;
388 return; 388 return;
389 } 389 }
diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c
index a828a0adf52c..5a5506a35395 100644
--- a/arch/parisc/kernel/ftrace.c
+++ b/arch/parisc/kernel/ftrace.c
@@ -48,7 +48,7 @@ static void __hot prepare_ftrace_return(unsigned long *parent,
48 return; 48 return;
49 49
50 if (ftrace_push_return_trace(old, self_addr, &trace.depth, 50 if (ftrace_push_return_trace(old, self_addr, &trace.depth,
51 0 ) == -EBUSY) 51 0, NULL) == -EBUSY)
52 return; 52 return;
53 53
54 /* activate parisc_return_to_handler() as return point */ 54 /* activate parisc_return_to_handler() as return point */
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index cc52d9795f88..a95639b8d4ac 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -593,7 +593,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
593 if (!ftrace_graph_entry(&trace)) 593 if (!ftrace_graph_entry(&trace))
594 goto out; 594 goto out;
595 595
596 if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY) 596 if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
597 NULL) == -EBUSY)
597 goto out; 598 goto out;
598 599
599 parent = return_hooker; 600 parent = return_hooker;
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index 0f7bfeba6da6..60a8a4e207ed 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -209,7 +209,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
209 /* Only trace if the calling function expects to. */ 209 /* Only trace if the calling function expects to. */
210 if (!ftrace_graph_entry(&trace)) 210 if (!ftrace_graph_entry(&trace))
211 goto out; 211 goto out;
212 if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY) 212 if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
213 NULL) == -EBUSY)
213 goto out; 214 goto out;
214 parent = (unsigned long) return_to_handler; 215 parent = (unsigned long) return_to_handler;
215out: 216out:
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 38993e09ef03..95eccd49672f 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -382,7 +382,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
382 return; 382 return;
383 } 383 }
384 384
385 err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0); 385 err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0, NULL);
386 if (err == -EBUSY) { 386 if (err == -EBUSY) {
387 __raw_writel(old, parent); 387 __raw_writel(old, parent);
388 return; 388 return;
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c
index 0a2d2ddff543..6bcff698069b 100644
--- a/arch/sparc/kernel/ftrace.c
+++ b/arch/sparc/kernel/ftrace.c
@@ -131,7 +131,7 @@ unsigned long prepare_ftrace_return(unsigned long parent,
131 return parent + 8UL; 131 return parent + 8UL;
132 132
133 if (ftrace_push_return_trace(parent, self_addr, &trace.depth, 133 if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
134 frame_pointer) == -EBUSY) 134 frame_pointer, NULL) == -EBUSY)
135 return parent + 8UL; 135 return parent + 8UL;
136 136
137 trace.func = self_addr; 137 trace.func = self_addr;
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c
index 4a572088b270..b827a418b155 100644
--- a/arch/tile/kernel/ftrace.c
+++ b/arch/tile/kernel/ftrace.c
@@ -184,7 +184,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
184 *parent = return_hooker; 184 *parent = return_hooker;
185 185
186 err = ftrace_push_return_trace(old, self_addr, &trace.depth, 186 err = ftrace_push_return_trace(old, self_addr, &trace.depth,
187 frame_pointer); 187 frame_pointer, NULL);
188 if (err == -EBUSY) { 188 if (err == -EBUSY) {
189 *parent = old; 189 *parent = old;
190 return; 190 return;
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index d036cfb4495d..ae3b1fb2f582 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -1029,7 +1029,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
1029 } 1029 }
1030 1030
1031 if (ftrace_push_return_trace(old, self_addr, &trace.depth, 1031 if (ftrace_push_return_trace(old, self_addr, &trace.depth,
1032 frame_pointer) == -EBUSY) { 1032 frame_pointer, NULL) == -EBUSY) {
1033 *parent = old; 1033 *parent = old;
1034 return; 1034 return;
1035 } 1035 }
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 4ad9ccc60e38..483e02a50d37 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -798,6 +798,9 @@ struct ftrace_ret_stack {
798#ifdef HAVE_FUNCTION_GRAPH_FP_TEST 798#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
799 unsigned long fp; 799 unsigned long fp;
800#endif 800#endif
801#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
802 unsigned long *retp;
803#endif
801}; 804};
802 805
803/* 806/*
@@ -809,7 +812,7 @@ extern void return_to_handler(void);
809 812
810extern int 813extern int
811ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, 814ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
812 unsigned long frame_pointer); 815 unsigned long frame_pointer, unsigned long *retp);
813 816
814/* 817/*
815 * Sometimes we don't want to trace a function with the function 818 * Sometimes we don't want to trace a function with the function
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 0e03ed0eac68..f7212ec643e2 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -119,7 +119,7 @@ print_graph_duration(struct trace_array *tr, unsigned long long duration,
119/* Add a function return address to the trace stack on thread info.*/ 119/* Add a function return address to the trace stack on thread info.*/
120int 120int
121ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, 121ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
122 unsigned long frame_pointer) 122 unsigned long frame_pointer, unsigned long *retp)
123{ 123{
124 unsigned long long calltime; 124 unsigned long long calltime;
125 int index; 125 int index;
@@ -174,6 +174,9 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,
174#ifdef HAVE_FUNCTION_GRAPH_FP_TEST 174#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
175 current->ret_stack[index].fp = frame_pointer; 175 current->ret_stack[index].fp = frame_pointer;
176#endif 176#endif
177#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
178 current->ret_stack[index].retp = retp;
179#endif
177 *depth = current->curr_ret_stack; 180 *depth = current->curr_ret_stack;
178 181
179 return 0; 182 return 0;