aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/dumpstack_64.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index a071e6be177e..004b8aa6a35f 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -101,6 +101,35 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
101 return NULL; 101 return NULL;
102} 102}
103 103
104static inline int
105in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
106 unsigned long *irq_stack_end)
107{
108 return (stack >= irq_stack && stack < irq_stack_end);
109}
110
111/*
112 * We are returning from the irq stack and go to the previous one.
113 * If the previous stack is also in the irq stack, then bp in the first
114 * frame of the irq stack points to the previous, interrupted one.
115 * Otherwise we have another level of indirection: We first save
116 * the bp of the previous stack, then we switch the stack to the irq one
117 * and save a new bp that links to the previous one.
118 * (See save_args())
119 */
120static inline unsigned long
121fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
122 unsigned long *irq_stack, unsigned long *irq_stack_end)
123{
124#ifdef CONFIG_FRAME_POINTER
125 struct stack_frame *frame = (struct stack_frame *)bp;
126
127 if (!in_irq_stack(stack, irq_stack, irq_stack_end))
128 return (unsigned long)frame->next_frame;
129#endif
130 return bp;
131}
132
104/* 133/*
105 * x86-64 can have up to three kernel stacks: 134 * x86-64 can have up to three kernel stacks:
106 * process stack 135 * process stack
@@ -173,7 +202,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
173 irq_stack = irq_stack_end - 202 irq_stack = irq_stack_end -
174 (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack); 203 (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack);
175 204
176 if (stack >= irq_stack && stack < irq_stack_end) { 205 if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
177 if (ops->stack(data, "IRQ") < 0) 206 if (ops->stack(data, "IRQ") < 0)
178 break; 207 break;
179 bp = print_context_stack(tinfo, stack, bp, 208 bp = print_context_stack(tinfo, stack, bp,
@@ -184,6 +213,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
184 * pointer (index -1 to end) in the IRQ stack: 213 * pointer (index -1 to end) in the IRQ stack:
185 */ 214 */
186 stack = (unsigned long *) (irq_stack_end[-1]); 215 stack = (unsigned long *) (irq_stack_end[-1]);
216 bp = fixup_bp_irq_link(bp, stack, irq_stack,
217 irq_stack_end);
187 irq_stack_end = NULL; 218 irq_stack_end = NULL;
188 ops->stack(data, "EOI"); 219 ops->stack(data, "EOI");
189 continue; 220 continue;