[PATCH] i386: multi-column stack backtraces
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>
This commit is contained in:
parent
b824eb605c
commit
4d7d8c82c1
2 changed files with 36 additions and 5 deletions
|
@ -31,6 +31,15 @@ config DEBUG_STACK_USAGE
|
||||||
|
|
||||||
This option will slow down process creation somewhat.
|
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"
|
comment "Page alloc debug is incompatible with Software Suspend on i386"
|
||||||
depends on DEBUG_KERNEL && SOFTWARE_SUSPEND
|
depends on DEBUG_KERNEL && SOFTWARE_SUSPEND
|
||||||
|
|
||||||
|
|
|
@ -112,12 +112,30 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
|
||||||
p < (void *)tinfo + THREAD_SIZE - 3;
|
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);
|
printk(" [<%08lx>] ", addr);
|
||||||
|
#else
|
||||||
|
printk(" <%08lx> ", addr);
|
||||||
|
#endif
|
||||||
print_symbol("%s", addr);
|
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,
|
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)
|
char *log_lvl)
|
||||||
{
|
{
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
int printed = 0; /* nr of entries already printed on current line */
|
||||||
|
|
||||||
#ifdef CONFIG_FRAME_POINTER
|
#ifdef CONFIG_FRAME_POINTER
|
||||||
while (valid_stack_ptr(tinfo, (void *)ebp)) {
|
while (valid_stack_ptr(tinfo, (void *)ebp)) {
|
||||||
addr = *(unsigned long *)(ebp + 4);
|
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;
|
ebp = *(unsigned long *)ebp;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
while (valid_stack_ptr(tinfo, stack)) {
|
while (valid_stack_ptr(tinfo, stack)) {
|
||||||
addr = *stack++;
|
addr = *stack++;
|
||||||
if (__kernel_text_address(addr))
|
if (__kernel_text_address(addr))
|
||||||
print_addr_and_symbol(addr, log_lvl);
|
printed = print_addr_and_symbol(addr, log_lvl, printed);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (printed)
|
||||||
|
printk("\n");
|
||||||
|
|
||||||
return ebp;
|
return ebp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue