diff options
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/Kconfig.debug | 9 | ||||
-rw-r--r-- | arch/i386/kernel/traps.c | 32 |
2 files changed, 36 insertions, 5 deletions
diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug index bf32ecc9ad04..00108ba9a78d 100644 --- a/arch/i386/Kconfig.debug +++ b/arch/i386/Kconfig.debug | |||
@@ -31,6 +31,15 @@ config DEBUG_STACK_USAGE | |||
31 | 31 | ||
32 | This option will slow down process creation somewhat. | 32 | This option will slow down process creation somewhat. |
33 | 33 | ||
34 | config STACK_BACKTRACE_COLS | ||
35 | int "Stack backtraces per line" if DEBUG_KERNEL | ||
36 | range 1 3 | ||
37 | default 2 | ||
38 | help | ||
39 | Selects how many stack backtrace entries per line to display. | ||
40 | |||
41 | This can save screen space when displaying traces. | ||
42 | |||
34 | comment "Page alloc debug is incompatible with Software Suspend on i386" | 43 | comment "Page alloc debug is incompatible with Software Suspend on i386" |
35 | depends on DEBUG_KERNEL && SOFTWARE_SUSPEND | 44 | depends on DEBUG_KERNEL && SOFTWARE_SUSPEND |
36 | 45 | ||
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index b814dbdcc91e..ee61988f61b5 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -112,12 +112,30 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) | |||
112 | p < (void *)tinfo + THREAD_SIZE - 3; | 112 | p < (void *)tinfo + THREAD_SIZE - 3; |
113 | } | 113 | } |
114 | 114 | ||
115 | static void print_addr_and_symbol(unsigned long addr, char *log_lvl) | 115 | /* |
116 | * Print CONFIG_STACK_BACKTRACE_COLS address/symbol entries per line. | ||
117 | */ | ||
118 | static inline int print_addr_and_symbol(unsigned long addr, char *log_lvl, | ||
119 | int printed) | ||
116 | { | 120 | { |
117 | printk(log_lvl); | 121 | if (!printed) |
122 | printk(log_lvl); | ||
123 | |||
124 | #if CONFIG_STACK_BACKTRACE_COLS == 1 | ||
118 | printk(" [<%08lx>] ", addr); | 125 | printk(" [<%08lx>] ", addr); |
126 | #else | ||
127 | printk(" <%08lx> ", addr); | ||
128 | #endif | ||
119 | print_symbol("%s", addr); | 129 | print_symbol("%s", addr); |
120 | printk("\n"); | 130 | |
131 | printed = (printed + 1) % CONFIG_STACK_BACKTRACE_COLS; | ||
132 | |||
133 | if (printed) | ||
134 | printk(" "); | ||
135 | else | ||
136 | printk("\n"); | ||
137 | |||
138 | return printed; | ||
121 | } | 139 | } |
122 | 140 | ||
123 | static inline unsigned long print_context_stack(struct thread_info *tinfo, | 141 | 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, | |||
125 | char *log_lvl) | 143 | char *log_lvl) |
126 | { | 144 | { |
127 | unsigned long addr; | 145 | unsigned long addr; |
146 | int printed = 0; /* nr of entries already printed on current line */ | ||
128 | 147 | ||
129 | #ifdef CONFIG_FRAME_POINTER | 148 | #ifdef CONFIG_FRAME_POINTER |
130 | while (valid_stack_ptr(tinfo, (void *)ebp)) { | 149 | while (valid_stack_ptr(tinfo, (void *)ebp)) { |
131 | addr = *(unsigned long *)(ebp + 4); | 150 | addr = *(unsigned long *)(ebp + 4); |
132 | print_addr_and_symbol(addr, log_lvl); | 151 | printed = print_addr_and_symbol(addr, log_lvl, printed); |
133 | ebp = *(unsigned long *)ebp; | 152 | ebp = *(unsigned long *)ebp; |
134 | } | 153 | } |
135 | #else | 154 | #else |
136 | while (valid_stack_ptr(tinfo, stack)) { | 155 | while (valid_stack_ptr(tinfo, stack)) { |
137 | addr = *stack++; | 156 | addr = *stack++; |
138 | if (__kernel_text_address(addr)) | 157 | if (__kernel_text_address(addr)) |
139 | print_addr_and_symbol(addr, log_lvl); | 158 | printed = print_addr_and_symbol(addr, log_lvl, printed); |
140 | } | 159 | } |
141 | #endif | 160 | #endif |
161 | if (printed) | ||
162 | printk("\n"); | ||
163 | |||
142 | return ebp; | 164 | return ebp; |
143 | } | 165 | } |
144 | 166 | ||