aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2014-02-06 09:41:32 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2014-03-06 19:56:55 -0500
commit2223f6f6eeaad6ea0a3acd3f4bc1ae45e8117ddc (patch)
treea782943537fd1c0b63f45907ad88d2eb093745c4
parent198d208df4371734ac4728f69cb585c284d20a15 (diff)
x86: Clean up dumpstack_64.c code
The dump_trace() function in dumpstack_64.c is hard to follow. The test for exception stack is processed differently than the test for irq stack, and the normal stack is outside completely. By restructuring this code to have all the stacks determined by a single function that returns an enum of the following: STACK_IS_NORMAL STACK_IS_EXCEPTION STACK_IS_IRQ STACK_IS_UNKNOWN and has the logic of each within a switch statement. This should make the code much easier to read and understand. Link: http://lkml.kernel.org/r/20110806012354.684598995@goodmis.org Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Brian Gerst <brgerst@gmail.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Link: http://lkml.kernel.org/r/20140206144322.086050042@goodmis.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--arch/x86/kernel/dumpstack_64.c117
1 files changed, 83 insertions, 34 deletions
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index addb207dab92..346b1df2412e 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -104,6 +104,45 @@ in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
104 return (stack >= irq_stack && stack < irq_stack_end); 104 return (stack >= irq_stack && stack < irq_stack_end);
105} 105}
106 106
107static const unsigned long irq_stack_size =
108 (IRQ_STACK_SIZE - 64) / sizeof(unsigned long);
109
110enum stack_type {
111 STACK_IS_UNKNOWN,
112 STACK_IS_NORMAL,
113 STACK_IS_EXCEPTION,
114 STACK_IS_IRQ,
115};
116
117static enum stack_type
118analyze_stack(int cpu, struct task_struct *task,
119 unsigned long *stack, unsigned long **stack_end, char **id)
120{
121 unsigned long *irq_stack;
122 unsigned long addr;
123 unsigned used = 0;
124
125 addr = ((unsigned long)stack & (~(THREAD_SIZE - 1)));
126 if ((unsigned long)task_stack_page(task) == addr)
127 return STACK_IS_NORMAL;
128
129 *stack_end = in_exception_stack(cpu, (unsigned long)stack,
130 &used, id);
131 if (*stack_end)
132 return STACK_IS_EXCEPTION;
133
134 *stack_end = (unsigned long *)per_cpu(irq_stack_ptr, cpu);
135 if (!*stack_end)
136 return STACK_IS_UNKNOWN;
137
138 irq_stack = *stack_end - irq_stack_size;
139
140 if (in_irq_stack(stack, irq_stack, *stack_end))
141 return STACK_IS_IRQ;
142
143 return STACK_IS_UNKNOWN;
144}
145
107/* 146/*
108 * x86-64 can have up to three kernel stacks: 147 * x86-64 can have up to three kernel stacks:
109 * process stack 148 * process stack
@@ -116,12 +155,11 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
116 const struct stacktrace_ops *ops, void *data) 155 const struct stacktrace_ops *ops, void *data)
117{ 156{
118 const unsigned cpu = get_cpu(); 157 const unsigned cpu = get_cpu();
119 unsigned long *irq_stack_end =
120 (unsigned long *)per_cpu(irq_stack_ptr, cpu);
121 unsigned used = 0;
122 struct thread_info *tinfo; 158 struct thread_info *tinfo;
123 int graph = 0; 159 unsigned long *irq_stack;
124 unsigned long dummy; 160 unsigned long dummy;
161 int graph = 0;
162 int done = 0;
125 163
126 if (!task) 164 if (!task)
127 task = current; 165 task = current;
@@ -143,49 +181,60 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
143 * exceptions 181 * exceptions
144 */ 182 */
145 tinfo = task_thread_info(task); 183 tinfo = task_thread_info(task);
146 for (;;) { 184 while (!done) {
185 unsigned long *stack_end;
186 enum stack_type stype;
147 char *id; 187 char *id;
148 unsigned long *estack_end;
149 estack_end = in_exception_stack(cpu, (unsigned long)stack,
150 &used, &id);
151 188
152 if (estack_end) { 189 stype = analyze_stack(cpu, task, stack, &stack_end, &id);
190
191 /* Default finish unless specified to continue */
192 done = 1;
193
194 switch (stype) {
195
196 /* Break out early if we are on the thread stack */
197 case STACK_IS_NORMAL:
198 break;
199
200 case STACK_IS_EXCEPTION:
201
153 if (ops->stack(data, id) < 0) 202 if (ops->stack(data, id) < 0)
154 break; 203 break;
155 204
156 bp = ops->walk_stack(tinfo, stack, bp, ops, 205 bp = ops->walk_stack(tinfo, stack, bp, ops,
157 data, estack_end, &graph); 206 data, stack_end, &graph);
158 ops->stack(data, "<EOE>"); 207 ops->stack(data, "<EOE>");
159 /* 208 /*
160 * We link to the next stack via the 209 * We link to the next stack via the
161 * second-to-last pointer (index -2 to end) in the 210 * second-to-last pointer (index -2 to end) in the
162 * exception stack: 211 * exception stack:
163 */ 212 */
164 stack = (unsigned long *) estack_end[-2]; 213 stack = (unsigned long *) stack_end[-2];
165 continue; 214 done = 0;
166 } 215 break;
167 if (irq_stack_end) { 216
168 unsigned long *irq_stack; 217 case STACK_IS_IRQ:
169 irq_stack = irq_stack_end - 218
170 (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack); 219 if (ops->stack(data, "IRQ") < 0)
171 220 break;
172 if (in_irq_stack(stack, irq_stack, irq_stack_end)) { 221 bp = ops->walk_stack(tinfo, stack, bp,
173 if (ops->stack(data, "IRQ") < 0) 222 ops, data, stack_end, &graph);
174 break; 223 /*
175 bp = ops->walk_stack(tinfo, stack, bp, 224 * We link to the next stack (which would be
176 ops, data, irq_stack_end, &graph); 225 * the process stack normally) the last
177 /* 226 * pointer (index -1 to end) in the IRQ stack:
178 * We link to the next stack (which would be 227 */
179 * the process stack normally) the last 228 stack = (unsigned long *) (stack_end[-1]);
180 * pointer (index -1 to end) in the IRQ stack: 229 irq_stack = stack_end - irq_stack_size;
181 */ 230 ops->stack(data, "EOI");
182 stack = (unsigned long *) (irq_stack_end[-1]); 231 done = 0;
183 irq_stack_end = NULL; 232 break;
184 ops->stack(data, "EOI"); 233
185 continue; 234 case STACK_IS_UNKNOWN:
186 } 235 ops->stack(data, "UNK");
236 break;
187 } 237 }
188 break;
189 } 238 }
190 239
191 /* 240 /*