[PATCH] i386: multi-column stack backtraces
authorChuck Ebbert <76306.1226@compuserve.com>
Thu, 23 Mar 2006 10:59:30 +0000 (02:59 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 23 Mar 2006 15:38:03 +0000 (07:38 -0800)
Print stack backtraces in multiple columns, saving screen space.  Number of
columns is configurable and defaults to one so behavior is
backwards-compatible.

Also removes the brackets around addresses when printing more
that one entry per line so they print as:
    <address>
instead of:
    [<address>]
This helps multiple entries fit better on one line.

Original idea by Dave Jones, taken from x86_64.

Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com>
Signed-off-by: Dave Jones <davej@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/Kconfig.debug
arch/i386/kernel/traps.c

index bf32ecc9ad04908bf20e6b1f76d3250a02aeada6..00108ba9a78dcef5629ead0e8bea35d0c08c9ea7 100644 (file)
@@ -31,6 +31,15 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
+config STACK_BACKTRACE_COLS
+       int "Stack backtraces per line" if DEBUG_KERNEL
+       range 1 3
+       default 2
+       help
+         Selects how many stack backtrace entries per line to display.
+
+         This can save screen space when displaying traces.
+
 comment "Page alloc debug is incompatible with Software Suspend on i386"
        depends on DEBUG_KERNEL && SOFTWARE_SUSPEND
 
index b814dbdcc91e58b06c140ff1a099f223c2212768..ee61988f61b5c33f81c9f4d1be68025d438312bf 100644 (file)
@@ -112,12 +112,30 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
                p < (void *)tinfo + THREAD_SIZE - 3;
 }
 
-static void print_addr_and_symbol(unsigned long addr, char *log_lvl)
+/*
+ * Print CONFIG_STACK_BACKTRACE_COLS address/symbol entries per line.
+ */
+static inline int print_addr_and_symbol(unsigned long addr, char *log_lvl,
+                                       int printed)
 {
-       printk(log_lvl);
+       if (!printed)
+               printk(log_lvl);
+
+#if CONFIG_STACK_BACKTRACE_COLS == 1
        printk(" [<%08lx>] ", addr);
+#else
+       printk(" <%08lx> ", addr);
+#endif
        print_symbol("%s", addr);
-       printk("\n");
+
+       printed = (printed + 1) % CONFIG_STACK_BACKTRACE_COLS;
+
+       if (printed)
+               printk("  ");
+       else
+               printk("\n");
+
+       return printed;
 }
 
 static inline unsigned long print_context_stack(struct thread_info *tinfo,
@@ -125,20 +143,24 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
                                char *log_lvl)
 {
        unsigned long addr;
+       int printed = 0; /* nr of entries already printed on current line */
 
 #ifdef CONFIG_FRAME_POINTER
        while (valid_stack_ptr(tinfo, (void *)ebp)) {
                addr = *(unsigned long *)(ebp + 4);
-               print_addr_and_symbol(addr, log_lvl);
+               printed = print_addr_and_symbol(addr, log_lvl, printed);
                ebp = *(unsigned long *)ebp;
        }
 #else
        while (valid_stack_ptr(tinfo, stack)) {
                addr = *stack++;
                if (__kernel_text_address(addr))
-                       print_addr_and_symbol(addr, log_lvl);
+                       printed = print_addr_and_symbol(addr, log_lvl, printed);
        }
 #endif
+       if (printed)
+               printk("\n");
+
        return ebp;
 }