aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-10-14 15:19:04 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-10-14 15:19:04 -0400
commitdabe98c972091818762e02841ab1f982e573e7d0 (patch)
tree3770c66ab60cc34225158e87a6532afa5704806c /arch
parent45123f7e74e004848da765f3182cd401a38d354d (diff)
arch/tile: prevent corrupt top frame from causing backtracer runaway
The backtracer will normally cut itself off after 100 frames anyway, but it's messy. With this change we notice that the frame being reported is the same as the last one, and cut off the dump with a message similar to what gdb displays in the same circumstance. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/tile/kernel/stack.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index ea2e0ce28380..0d54106be3d6 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -30,6 +30,10 @@
30#include <arch/abi.h> 30#include <arch/abi.h>
31#include <arch/interrupts.h> 31#include <arch/interrupts.h>
32 32
33#define KBT_ONGOING 0 /* Backtrace still ongoing */
34#define KBT_DONE 1 /* Backtrace cleanly completed */
35#define KBT_RUNNING 2 /* Can't run backtrace on a running task */
36#define KBT_LOOP 3 /* Backtrace entered a loop */
33 37
34/* Is address on the specified kernel stack? */ 38/* Is address on the specified kernel stack? */
35static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp) 39static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
@@ -207,11 +211,11 @@ static int KBacktraceIterator_next_item_inclusive(
207 for (;;) { 211 for (;;) {
208 do { 212 do {
209 if (!KBacktraceIterator_is_sigreturn(kbt)) 213 if (!KBacktraceIterator_is_sigreturn(kbt))
210 return 1; 214 return KBT_ONGOING;
211 } while (backtrace_next(&kbt->it)); 215 } while (backtrace_next(&kbt->it));
212 216
213 if (!KBacktraceIterator_restart(kbt)) 217 if (!KBacktraceIterator_restart(kbt))
214 return 0; 218 return KBT_DONE;
215 } 219 }
216} 220}
217 221
@@ -264,7 +268,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
264 kbt->pgtable = NULL; 268 kbt->pgtable = NULL;
265 kbt->verbose = 0; /* override in caller if desired */ 269 kbt->verbose = 0; /* override in caller if desired */
266 kbt->profile = 0; /* override in caller if desired */ 270 kbt->profile = 0; /* override in caller if desired */
267 kbt->end = 0; 271 kbt->end = KBT_ONGOING;
268 kbt->new_context = 0; 272 kbt->new_context = 0;
269 if (is_current) { 273 if (is_current) {
270 HV_PhysAddr pgdir_pa = hv_inquire_context().page_table; 274 HV_PhysAddr pgdir_pa = hv_inquire_context().page_table;
@@ -290,7 +294,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
290 if (regs == NULL) { 294 if (regs == NULL) {
291 if (is_current || t->state == TASK_RUNNING) { 295 if (is_current || t->state == TASK_RUNNING) {
292 /* Can't do this; we need registers */ 296 /* Can't do this; we need registers */
293 kbt->end = 1; 297 kbt->end = KBT_RUNNING;
294 return; 298 return;
295 } 299 }
296 pc = get_switch_to_pc(); 300 pc = get_switch_to_pc();
@@ -305,26 +309,29 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
305 } 309 }
306 310
307 backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52); 311 backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52);
308 kbt->end = !KBacktraceIterator_next_item_inclusive(kbt); 312 kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
309} 313}
310EXPORT_SYMBOL(KBacktraceIterator_init); 314EXPORT_SYMBOL(KBacktraceIterator_init);
311 315
312int KBacktraceIterator_end(struct KBacktraceIterator *kbt) 316int KBacktraceIterator_end(struct KBacktraceIterator *kbt)
313{ 317{
314 return kbt->end; 318 return kbt->end != KBT_ONGOING;
315} 319}
316EXPORT_SYMBOL(KBacktraceIterator_end); 320EXPORT_SYMBOL(KBacktraceIterator_end);
317 321
318void KBacktraceIterator_next(struct KBacktraceIterator *kbt) 322void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
319{ 323{
324 VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
320 kbt->new_context = 0; 325 kbt->new_context = 0;
321 if (!backtrace_next(&kbt->it) && 326 if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
322 !KBacktraceIterator_restart(kbt)) { 327 kbt->end = KBT_DONE;
323 kbt->end = 1; 328 return;
324 return; 329 }
325 } 330 kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
326 331 if (old_pc == kbt->it.pc && old_sp == kbt->it.sp) {
327 kbt->end = !KBacktraceIterator_next_item_inclusive(kbt); 332 /* Trapped in a loop; give up. */
333 kbt->end = KBT_LOOP;
334 }
328} 335}
329EXPORT_SYMBOL(KBacktraceIterator_next); 336EXPORT_SYMBOL(KBacktraceIterator_next);
330 337
@@ -387,6 +394,8 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
387 break; 394 break;
388 } 395 }
389 } 396 }
397 if (kbt->end == KBT_LOOP)
398 pr_err("Stack dump stopped; next frame identical to this one\n");
390 if (headers) 399 if (headers)
391 pr_err("Stack dump complete\n"); 400 pr_err("Stack dump complete\n");
392} 401}