diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-07-03 03:24:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-03 18:27:02 -0400 |
commit | c9ca1ba5bde45839cdc4f8ab93730cb68e6ee8a6 (patch) | |
tree | 8c1d73c012430a6d28e2602177116f684a6b8a8b /arch/x86_64/kernel/traps.c | |
parent | 3ac94932a2c859e8c57a8af091fa39334e1c3f23 (diff) |
[PATCH] lockdep: x86_64 document stack frame internals
Document stack frame nesting internals some more.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 02dc155da56f..79d05c482072 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -152,10 +152,22 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
152 | }; | 152 | }; |
153 | unsigned k; | 153 | unsigned k; |
154 | 154 | ||
155 | /* | ||
156 | * Iterate over all exception stacks, and figure out whether | ||
157 | * 'stack' is in one of them: | ||
158 | */ | ||
155 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { | 159 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { |
156 | unsigned long end; | 160 | unsigned long end; |
157 | 161 | ||
162 | /* | ||
163 | * set 'end' to the end of the exception stack. | ||
164 | */ | ||
158 | switch (k + 1) { | 165 | switch (k + 1) { |
166 | /* | ||
167 | * TODO: this block is not needed i think, because | ||
168 | * setup64.c:cpu_init() sets up t->ist[DEBUG_STACK] | ||
169 | * properly too. | ||
170 | */ | ||
159 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | 171 | #if DEBUG_STKSZ > EXCEPTION_STKSZ |
160 | case DEBUG_STACK: | 172 | case DEBUG_STACK: |
161 | end = cpu_pda(cpu)->debugstack + DEBUG_STKSZ; | 173 | end = cpu_pda(cpu)->debugstack + DEBUG_STKSZ; |
@@ -165,19 +177,43 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
165 | end = per_cpu(init_tss, cpu).ist[k]; | 177 | end = per_cpu(init_tss, cpu).ist[k]; |
166 | break; | 178 | break; |
167 | } | 179 | } |
180 | /* | ||
181 | * Is 'stack' above this exception frame's end? | ||
182 | * If yes then skip to the next frame. | ||
183 | */ | ||
168 | if (stack >= end) | 184 | if (stack >= end) |
169 | continue; | 185 | continue; |
186 | /* | ||
187 | * Is 'stack' above this exception frame's start address? | ||
188 | * If yes then we found the right frame. | ||
189 | */ | ||
170 | if (stack >= end - EXCEPTION_STKSZ) { | 190 | if (stack >= end - EXCEPTION_STKSZ) { |
191 | /* | ||
192 | * Make sure we only iterate through an exception | ||
193 | * stack once. If it comes up for the second time | ||
194 | * then there's something wrong going on - just | ||
195 | * break out and return NULL: | ||
196 | */ | ||
171 | if (*usedp & (1U << k)) | 197 | if (*usedp & (1U << k)) |
172 | break; | 198 | break; |
173 | *usedp |= 1U << k; | 199 | *usedp |= 1U << k; |
174 | *idp = ids[k]; | 200 | *idp = ids[k]; |
175 | return (unsigned long *)end; | 201 | return (unsigned long *)end; |
176 | } | 202 | } |
203 | /* | ||
204 | * If this is a debug stack, and if it has a larger size than | ||
205 | * the usual exception stacks, then 'stack' might still | ||
206 | * be within the lower portion of the debug stack: | ||
207 | */ | ||
177 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | 208 | #if DEBUG_STKSZ > EXCEPTION_STKSZ |
178 | if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) { | 209 | if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) { |
179 | unsigned j = N_EXCEPTION_STACKS - 1; | 210 | unsigned j = N_EXCEPTION_STACKS - 1; |
180 | 211 | ||
212 | /* | ||
213 | * Black magic. A large debug stack is composed of | ||
214 | * multiple exception stack entries, which we | ||
215 | * iterate through now. Dont look: | ||
216 | */ | ||
181 | do { | 217 | do { |
182 | ++j; | 218 | ++j; |
183 | end -= EXCEPTION_STKSZ; | 219 | end -= EXCEPTION_STKSZ; |
@@ -247,6 +283,11 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
247 | } | 283 | } |
248 | } | 284 | } |
249 | 285 | ||
286 | /* | ||
287 | * Print function call entries within a stack. 'cond' is the | ||
288 | * "end of stackframe" condition, that the 'stack++' | ||
289 | * iteration will eventually trigger. | ||
290 | */ | ||
250 | #define HANDLE_STACK(cond) \ | 291 | #define HANDLE_STACK(cond) \ |
251 | do while (cond) { \ | 292 | do while (cond) { \ |
252 | unsigned long addr = *stack++; \ | 293 | unsigned long addr = *stack++; \ |
@@ -263,7 +304,12 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
263 | } \ | 304 | } \ |
264 | } while (0) | 305 | } while (0) |
265 | 306 | ||
266 | for( ; ; ) { | 307 | /* |
308 | * Print function call entries in all stacks, starting at the | ||
309 | * current stack address. If the stacks consist of nested | ||
310 | * exceptions | ||
311 | */ | ||
312 | for ( ; ; ) { | ||
267 | const char *id; | 313 | const char *id; |
268 | unsigned long *estack_end; | 314 | unsigned long *estack_end; |
269 | estack_end = in_exception_stack(cpu, (unsigned long)stack, | 315 | estack_end = in_exception_stack(cpu, (unsigned long)stack, |
@@ -273,6 +319,11 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
273 | printk(" <%s>", id); | 319 | printk(" <%s>", id); |
274 | HANDLE_STACK (stack < estack_end); | 320 | HANDLE_STACK (stack < estack_end); |
275 | printk(" <EOE>"); | 321 | printk(" <EOE>"); |
322 | /* | ||
323 | * We link to the next stack via the | ||
324 | * second-to-last pointer (index -2 to end) in the | ||
325 | * exception stack: | ||
326 | */ | ||
276 | stack = (unsigned long *) estack_end[-2]; | 327 | stack = (unsigned long *) estack_end[-2]; |
277 | continue; | 328 | continue; |
278 | } | 329 | } |
@@ -284,6 +335,11 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
284 | if (stack >= irqstack && stack < irqstack_end) { | 335 | if (stack >= irqstack && stack < irqstack_end) { |
285 | printk(" <IRQ>"); | 336 | printk(" <IRQ>"); |
286 | HANDLE_STACK (stack < irqstack_end); | 337 | HANDLE_STACK (stack < irqstack_end); |
338 | /* | ||
339 | * We link to the next stack (which would be | ||
340 | * the process stack normally) the last | ||
341 | * pointer (index -1 to end) in the IRQ stack: | ||
342 | */ | ||
287 | stack = (unsigned long *) (irqstack_end[-1]); | 343 | stack = (unsigned long *) (irqstack_end[-1]); |
288 | irqstack_end = NULL; | 344 | irqstack_end = NULL; |
289 | printk(" <EOI>"); | 345 | printk(" <EOI>"); |
@@ -293,6 +349,9 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
293 | break; | 349 | break; |
294 | } | 350 | } |
295 | 351 | ||
352 | /* | ||
353 | * This prints the process stack: | ||
354 | */ | ||
296 | HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); | 355 | HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); |
297 | #undef HANDLE_STACK | 356 | #undef HANDLE_STACK |
298 | 357 | ||