aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
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