aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat)2013-03-13 20:25:35 -0500
committerGreg Kroah-Hartman2013-05-07 22:08:19 -0500
commit0b2efcddd7459f87f4b6dd69fba814fadd630f0e (patch)
tree12899e9933c403b366abc4f1ab8fdccb8242342f /kernel
parent4a13a00a69fe14edc29fc8eaf11e4ffb5d1b1200 (diff)
downloadkernel-audio-0b2efcddd7459f87f4b6dd69fba814fadd630f0e.tar.gz
kernel-audio-0b2efcddd7459f87f4b6dd69fba814fadd630f0e.tar.xz
kernel-audio-0b2efcddd7459f87f4b6dd69fba814fadd630f0e.zip
tracing: Fix stack tracer with fentry use
commit d4ecbfc49b4b1d4b597fb5ba9e4fa25d62f105c5 upstream. When gcc 4.6 on x86 is used, the function tracer will use the new option -mfentry which does a call to "fentry" at every function instead of "mcount". The significance of this is that fentry is called as the first operation of the function instead of the mcount usage of being called after the stack. This causes the stack tracer to show some bogus results for the size of the last function traced, as well as showing "ftrace_call" instead of the function. This is due to the stack frame not being set up by the function that is about to be traced. # cat stack_trace Depth Size Location (48 entries) ----- ---- -------- 0) 4824 216 ftrace_call+0x5/0x2f 1) 4608 112 ____cache_alloc+0xb7/0x22d 2) 4496 80 kmem_cache_alloc+0x63/0x12f The 216 size for ftrace_call includes both the ftrace_call stack (which includes the saving of registers it does), as well as the stack size of the parent. To fix this, if CC_USING_FENTRY is defined, then the stack_tracer will reserve the first item in stack_dump_trace[] array when calling save_stack_trace(), and it will fill it in with the parent ip. Then the code will look for the parent pointer on the stack and give the real size of the parent's stack pointer: # cat stack_trace Depth Size Location (14 entries) ----- ---- -------- 0) 2640 48 update_group_power+0x26/0x187 1) 2592 224 update_sd_lb_stats+0x2a5/0x4ac 2) 2368 160 find_busiest_group+0x31/0x1f1 3) 2208 256 load_balance+0xd9/0x662 I'm Cc'ing stable, although it's not urgent, as it only shows bogus size for item #0, the rest of the trace is legit. It should still be corrected in previous stable releases. Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace_stack.c33
1 files changed, 29 insertions, 4 deletions
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 856b407375f1..4370c8e8d274 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -20,13 +20,27 @@
20 20
21#define STACK_TRACE_ENTRIES 500 21#define STACK_TRACE_ENTRIES 500
22 22
23/*
24 * If fentry is used, then the function being traced will
25 * jump to fentry directly before it sets up its stack frame.
26 * We need to ignore that one and record the parent. Since
27 * the stack frame for the traced function wasn't set up yet,
28 * the stack_trace wont see the parent. That needs to be added
29 * manually to stack_dump_trace[] as the first element.
30 */
31#ifdef CC_USING_FENTRY
32# define add_func 1
33#else
34# define add_func 0
35#endif
36
23static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] = 37static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] =
24 { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX }; 38 { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX };
25static unsigned stack_dump_index[STACK_TRACE_ENTRIES]; 39static unsigned stack_dump_index[STACK_TRACE_ENTRIES];
26 40
27static struct stack_trace max_stack_trace = { 41static struct stack_trace max_stack_trace = {
28 .max_entries = STACK_TRACE_ENTRIES, 42 .max_entries = STACK_TRACE_ENTRIES - add_func,
29 .entries = stack_dump_trace, 43 .entries = &stack_dump_trace[add_func],
30}; 44};
31 45
32static unsigned long max_stack_size; 46static unsigned long max_stack_size;
@@ -40,7 +54,7 @@ int stack_tracer_enabled;
40static int last_stack_tracer_enabled; 54static int last_stack_tracer_enabled;
41 55
42static inline void 56static inline void
43check_stack(unsigned long *stack) 57check_stack(unsigned long ip, unsigned long *stack)
44{ 58{
45 unsigned long this_size, flags; 59 unsigned long this_size, flags;
46 unsigned long *p, *top, *start; 60 unsigned long *p, *top, *start;
@@ -71,6 +85,17 @@ check_stack(unsigned long *stack)
71 save_stack_trace(&max_stack_trace); 85 save_stack_trace(&max_stack_trace);
72 86
73 /* 87 /*
88 * When fentry is used, the traced function does not get
89 * its stack frame set up, and we lose the parent.
90 * Add that one in manally. We set up save_stack_trace()
91 * to not touch the first element in this case.
92 */
93 if (add_func) {
94 stack_dump_trace[0] = ip;
95 max_stack_trace.nr_entries++;
96 }
97
98 /*
74 * Now find where in the stack these are. 99 * Now find where in the stack these are.
75 */ 100 */
76 i = 0; 101 i = 0;
@@ -124,7 +149,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip,
124 if (per_cpu(trace_active, cpu)++ != 0) 149 if (per_cpu(trace_active, cpu)++ != 0)
125 goto out; 150 goto out;
126 151
127 check_stack(&stack); 152 check_stack(parent_ip, &stack);
128 153
129 out: 154 out:
130 per_cpu(trace_active, cpu)--; 155 per_cpu(trace_active, cpu)--;