aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/dumpstack_64.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /arch/x86/kernel/dumpstack_64.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/x86/kernel/dumpstack_64.c')
-rw-r--r--arch/x86/kernel/dumpstack_64.c99
1 files changed, 69 insertions, 30 deletions
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index a071e6be177e..272c9f1f05f3 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -10,34 +10,31 @@
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/ptrace.h> 11#include <linux/ptrace.h>
12#include <linux/kexec.h> 12#include <linux/kexec.h>
13#include <linux/sysfs.h>
13#include <linux/bug.h> 14#include <linux/bug.h>
14#include <linux/nmi.h> 15#include <linux/nmi.h>
15#include <linux/sysfs.h>
16 16
17#include <asm/stacktrace.h> 17#include <asm/stacktrace.h>
18 18
19#include "dumpstack.h" 19#include "dumpstack.h"
20 20
21#define N_EXCEPTION_STACKS_END \
22 (N_EXCEPTION_STACKS + DEBUG_STKSZ/EXCEPTION_STKSZ - 2)
21 23
22static char x86_stack_ids[][8] = { 24static char x86_stack_ids[][8] = {
23 [DEBUG_STACK - 1] = "#DB", 25 [ DEBUG_STACK-1 ] = "#DB",
24 [NMI_STACK - 1] = "NMI", 26 [ NMI_STACK-1 ] = "NMI",
25 [DOUBLEFAULT_STACK - 1] = "#DF", 27 [ DOUBLEFAULT_STACK-1 ] = "#DF",
26 [STACKFAULT_STACK - 1] = "#SS", 28 [ STACKFAULT_STACK-1 ] = "#SS",
27 [MCE_STACK - 1] = "#MC", 29 [ MCE_STACK-1 ] = "#MC",
28#if DEBUG_STKSZ > EXCEPTION_STKSZ 30#if DEBUG_STKSZ > EXCEPTION_STKSZ
29 [N_EXCEPTION_STACKS ... 31 [ N_EXCEPTION_STACKS ...
30 N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" 32 N_EXCEPTION_STACKS_END ] = "#DB[?]"
31#endif 33#endif
32 }; 34};
33
34int x86_is_stack_id(int id, char *name)
35{
36 return x86_stack_ids[id - 1] == name;
37}
38 35
39static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, 36static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
40 unsigned *usedp, char **idp) 37 unsigned *usedp, char **idp)
41{ 38{
42 unsigned k; 39 unsigned k;
43 40
@@ -101,6 +98,41 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
101 return NULL; 98 return NULL;
102} 99}
103 100
101static inline int
102in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
103 unsigned long *irq_stack_end)
104{
105 return (stack >= irq_stack && stack < irq_stack_end);
106}
107
108/*
109 * We are returning from the irq stack and go to the previous one.
110 * If the previous stack is also in the irq stack, then bp in the first
111 * frame of the irq stack points to the previous, interrupted one.
112 * Otherwise we have another level of indirection: We first save
113 * the bp of the previous stack, then we switch the stack to the irq one
114 * and save a new bp that links to the previous one.
115 * (See save_args())
116 */
117static inline unsigned long
118fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
119 unsigned long *irq_stack, unsigned long *irq_stack_end)
120{
121#ifdef CONFIG_FRAME_POINTER
122 struct stack_frame *frame = (struct stack_frame *)bp;
123 unsigned long next;
124
125 if (!in_irq_stack(stack, irq_stack, irq_stack_end)) {
126 if (!probe_kernel_address(&frame->next_frame, next))
127 return next;
128 else
129 WARN_ONCE(1, "Perf: bad frame pointer = %p in "
130 "callchain\n", &frame->next_frame);
131 }
132#endif
133 return bp;
134}
135
104/* 136/*
105 * x86-64 can have up to three kernel stacks: 137 * x86-64 can have up to three kernel stacks:
106 * process stack 138 * process stack
@@ -157,8 +189,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
157 if (ops->stack(data, id) < 0) 189 if (ops->stack(data, id) < 0)
158 break; 190 break;
159 191
160 bp = print_context_stack(tinfo, stack, bp, ops, 192 bp = ops->walk_stack(tinfo, stack, bp, ops,
161 data, estack_end, &graph); 193 data, estack_end, &graph);
162 ops->stack(data, "<EOE>"); 194 ops->stack(data, "<EOE>");
163 /* 195 /*
164 * We link to the next stack via the 196 * We link to the next stack via the
@@ -173,10 +205,10 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
173 irq_stack = irq_stack_end - 205 irq_stack = irq_stack_end -
174 (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack); 206 (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack);
175 207
176 if (stack >= irq_stack && stack < irq_stack_end) { 208 if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
177 if (ops->stack(data, "IRQ") < 0) 209 if (ops->stack(data, "IRQ") < 0)
178 break; 210 break;
179 bp = print_context_stack(tinfo, stack, bp, 211 bp = ops->walk_stack(tinfo, stack, bp,
180 ops, data, irq_stack_end, &graph); 212 ops, data, irq_stack_end, &graph);
181 /* 213 /*
182 * We link to the next stack (which would be 214 * We link to the next stack (which would be
@@ -184,6 +216,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
184 * pointer (index -1 to end) in the IRQ stack: 216 * pointer (index -1 to end) in the IRQ stack:
185 */ 217 */
186 stack = (unsigned long *) (irq_stack_end[-1]); 218 stack = (unsigned long *) (irq_stack_end[-1]);
219 bp = fixup_bp_irq_link(bp, stack, irq_stack,
220 irq_stack_end);
187 irq_stack_end = NULL; 221 irq_stack_end = NULL;
188 ops->stack(data, "EOI"); 222 ops->stack(data, "EOI");
189 continue; 223 continue;
@@ -195,28 +229,31 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
195 /* 229 /*
196 * This handles the process stack: 230 * This handles the process stack:
197 */ 231 */
198 bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph); 232 bp = ops->walk_stack(tinfo, stack, bp, ops, data, NULL, &graph);
199 put_cpu(); 233 put_cpu();
200} 234}
201EXPORT_SYMBOL(dump_trace); 235EXPORT_SYMBOL(dump_trace);
202 236
203void 237void
204show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, 238show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
205 unsigned long *sp, unsigned long bp, char *log_lvl) 239 unsigned long *sp, unsigned long bp, char *log_lvl)
206{ 240{
241 unsigned long *irq_stack_end;
242 unsigned long *irq_stack;
207 unsigned long *stack; 243 unsigned long *stack;
244 int cpu;
208 int i; 245 int i;
209 const int cpu = smp_processor_id(); 246
210 unsigned long *irq_stack_end = 247 preempt_disable();
211 (unsigned long *)(per_cpu(irq_stack_ptr, cpu)); 248 cpu = smp_processor_id();
212 unsigned long *irq_stack = 249
213 (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE); 250 irq_stack_end = (unsigned long *)(per_cpu(irq_stack_ptr, cpu));
251 irq_stack = (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE);
214 252
215 /* 253 /*
216 * debugging aid: "show_stack(NULL, NULL);" prints the 254 * Debugging aid: "show_stack(NULL, NULL);" prints the
217 * back trace for this cpu. 255 * back trace for this cpu:
218 */ 256 */
219
220 if (sp == NULL) { 257 if (sp == NULL) {
221 if (task) 258 if (task)
222 sp = (unsigned long *)task->thread.sp; 259 sp = (unsigned long *)task->thread.sp;
@@ -240,6 +277,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
240 printk(" %016lx", *stack++); 277 printk(" %016lx", *stack++);
241 touch_nmi_watchdog(); 278 touch_nmi_watchdog();
242 } 279 }
280 preempt_enable();
281
243 printk("\n"); 282 printk("\n");
244 show_trace_log_lvl(task, regs, sp, bp, log_lvl); 283 show_trace_log_lvl(task, regs, sp, bp, log_lvl);
245} 284}
@@ -253,6 +292,7 @@ void show_registers(struct pt_regs *regs)
253 292
254 sp = regs->sp; 293 sp = regs->sp;
255 printk("CPU %d ", cpu); 294 printk("CPU %d ", cpu);
295 print_modules();
256 __show_regs(regs, 1); 296 __show_regs(regs, 1);
257 printk("Process %s (pid: %d, threadinfo %p, task %p)\n", 297 printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
258 cur->comm, cur->pid, task_thread_info(cur), cur); 298 cur->comm, cur->pid, task_thread_info(cur), cur);
@@ -303,4 +343,3 @@ int is_valid_bugaddr(unsigned long ip)
303 343
304 return ud2 == 0x0b0f; 344 return ud2 == 0x0b0f;
305} 345}
306