aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2005-04-16 18:25:17 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:25:17 -0400
commit0a65800243742480b4b594b619b759749a3cfef4 (patch)
tree72f9a3b376c604e7619ef265c7dc351644f45359 /arch
parent635186447d0e6f3b35895fda993a266a1315d2a7 (diff)
[PATCH] x86_64: Rewrite exception stack backtracing
Exceptions and hardware interrupts can, to a certain degree, nest, so when attempting to follow the sequence of stacks used in order to dump their contents this has to be accounted for. Also, IST stacks have their tops stored in the TSS, so there's no need to add the stack size to get to their ends. Minor changes from AK. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86_64/kernel/traps.c147
1 files changed, 79 insertions, 68 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index f6ccf155e3e5..65a37f52c56e 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -120,95 +120,106 @@ int printk_address(unsigned long address)
120} 120}
121#endif 121#endif
122 122
123unsigned long *in_exception_stack(int cpu, unsigned long stack) 123static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
124{ 124 unsigned *usedp, const char **idp)
125 int k; 125{
126 static const char ids[N_EXCEPTION_STACKS][8] = {
127 [DEBUG_STACK - 1] = "#DB",
128 [NMI_STACK - 1] = "NMI",
129 [DOUBLEFAULT_STACK - 1] = "#DF",
130 [STACKFAULT_STACK - 1] = "#SS",
131 [MCE_STACK - 1] = "#MC",
132 };
133 unsigned k;
134
126 for (k = 0; k < N_EXCEPTION_STACKS; k++) { 135 for (k = 0; k < N_EXCEPTION_STACKS; k++) {
127 struct tss_struct *tss = &per_cpu(init_tss, cpu); 136 unsigned long end;
128 unsigned long start = tss->ist[k] - EXCEPTION_STKSZ;
129 137
130 if (stack >= start && stack < tss->ist[k]) 138 end = per_cpu(init_tss, cpu).ist[k];
131 return (unsigned long *)tss->ist[k]; 139 if (stack >= end)
140 continue;
141 if (stack >= end - EXCEPTION_STKSZ) {
142 if (*usedp & (1U << k))
143 break;
144 *usedp |= 1U << k;
145 *idp = ids[k];
146 return (unsigned long *)end;
147 }
132 } 148 }
133 return NULL; 149 return NULL;
134} 150}
135 151
136/* 152/*
137 * x86-64 can have upto three kernel stacks: 153 * x86-64 can have upto three kernel stacks:
138 * process stack 154 * process stack
139 * interrupt stack 155 * interrupt stack
140 * severe exception (double fault, nmi, stack fault) hardware stack 156 * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
141 * Check and process them in order.
142 */ 157 */
143 158
144void show_trace(unsigned long *stack) 159void show_trace(unsigned long *stack)
145{ 160{
146 unsigned long addr; 161 unsigned long addr;
147 unsigned long *irqstack, *irqstack_end, *estack_end; 162 const unsigned cpu = safe_smp_processor_id();
148 const int cpu = safe_smp_processor_id(); 163 unsigned long *irqstack_end = (unsigned long *)cpu_pda[cpu].irqstackptr;
149 int i; 164 int i;
165 unsigned used = 0;
150 166
151 printk("\nCall Trace:"); 167 printk("\nCall Trace:");
152 i = 0; 168
153 169#define HANDLE_STACK(cond) \
154 estack_end = in_exception_stack(cpu, (unsigned long)stack); 170 do while (cond) { \
155 if (estack_end) { 171 addr = *stack++; \
156 while (stack < estack_end) { 172 if (kernel_text_address(addr)) { \
157 addr = *stack++; 173 /* \
158 if (__kernel_text_address(addr)) { 174 * If the address is either in the text segment of the \
159 i += printk_address(addr); 175 * kernel, or in the region which contains vmalloc'ed \
160 i += printk(" "); 176 * memory, it *may* be the address of a calling \
161 if (i > 50) { 177 * routine; if so, print it so that someone tracing \
162 printk("\n"); 178 * down the cause of the crash will be able to figure \
163 i = 0; 179 * out the call path that was taken. \
164 } 180 */ \
165 } 181 i += printk_address(addr); \
182 if (i > 50) { \
183 printk("\n "); \
184 i = 0; \
185 } \
186 else \
187 i += printk(" "); \
188 } \
189 } while (0)
190
191 for(i = 0; ; ) {
192 const char *id;
193 unsigned long *estack_end;
194 estack_end = in_exception_stack(cpu, (unsigned long)stack,
195 &used, &id);
196
197 if (estack_end) {
198 i += printk(" <%s> ", id);
199 HANDLE_STACK (stack < estack_end);
200 i += printk(" <EOE> ");
201 stack = (unsigned long *) estack_end[-2];
202 continue;
166 } 203 }
167 i += printk(" <EOE> "); 204 if (irqstack_end) {
168 i += 7; 205 unsigned long *irqstack;
169 stack = (unsigned long *) estack_end[-2]; 206 irqstack = irqstack_end -
170 } 207 (IRQSTACKSIZE - 64) / sizeof(*irqstack);
171 208
172 irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr); 209 if (stack >= irqstack && stack < irqstack_end) {
173 irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE + 64); 210 i += printk(" <IRQ> ");
174 211 HANDLE_STACK (stack < irqstack_end);
175 if (stack >= irqstack && stack < irqstack_end) { 212 stack = (unsigned long *) (irqstack_end[-1]);
176 printk("<IRQ> "); 213 irqstack_end = NULL;
177 while (stack < irqstack_end) { 214 i += printk(" <EOI> ");
178 addr = *stack++; 215 continue;
179 /*
180 * If the address is either in the text segment of the
181 * kernel, or in the region which contains vmalloc'ed
182 * memory, it *may* be the address of a calling
183 * routine; if so, print it so that someone tracing
184 * down the cause of the crash will be able to figure
185 * out the call path that was taken.
186 */
187 if (__kernel_text_address(addr)) {
188 i += printk_address(addr);
189 i += printk(" ");
190 if (i > 50) {
191 printk("\n ");
192 i = 0;
193 }
194 } 216 }
195 }
196 stack = (unsigned long *) (irqstack_end[-1]);
197 printk(" <EOI> ");
198 i += 7;
199 }
200
201 while (((long) stack & (THREAD_SIZE-1)) != 0) {
202 addr = *stack++;
203 if (__kernel_text_address(addr)) {
204 i += printk_address(addr);
205 i += printk(" ");
206 if (i > 50) {
207 printk("\n ");
208 i = 0;
209 }
210 } 217 }
218 break;
211 } 219 }
220
221 HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0);
222#undef HANDLE_STACK
212 printk("\n"); 223 printk("\n");
213} 224}
214 225