diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 147 |
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 | ||
123 | unsigned long *in_exception_stack(int cpu, unsigned long stack) | 123 | static 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 | ||
144 | void show_trace(unsigned long *stack) | 159 | void 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 | ||