Blame view

arch/x86/kernel/dumpstack.c 7.36 KB
878719e83   Neil Horman   x86: unify approp...
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   *  Copyright (C) 1991, 1992  Linus Torvalds
   *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
   */
  #include <linux/kallsyms.h>
  #include <linux/kprobes.h>
  #include <linux/uaccess.h>
  #include <linux/utsname.h>
  #include <linux/hardirq.h>
  #include <linux/kdebug.h>
  #include <linux/module.h>
  #include <linux/ptrace.h>
712406a6b   Steven Rostedt   tracing/function-...
13
  #include <linux/ftrace.h>
878719e83   Neil Horman   x86: unify approp...
14
15
16
17
18
19
  #include <linux/kexec.h>
  #include <linux/bug.h>
  #include <linux/nmi.h>
  #include <linux/sysfs.h>
  
  #include <asm/stacktrace.h>
878719e83   Neil Horman   x86: unify approp...
20
21
  
  int panic_on_unrecovered_nmi;
5211a242d   Kurt Garloff   x86: Add sysctl t...
22
  int panic_on_io_nmi;
878719e83   Neil Horman   x86: unify approp...
23
24
25
26
27
28
  unsigned int code_bytes = 64;
  int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
  static int die_counter;
  
  void printk_address(unsigned long address, int reliable)
  {
71f9e5980   Namhyung Kim   x86, dumpstack: U...
29
30
  	printk(" [<%p>] %s%pB
  ", (void *) address,
878719e83   Neil Horman   x86: unify approp...
31
32
  			reliable ? "" : "? ", (void *) address);
  }
7ee991fbc   Steven Rostedt   ftrace: print rea...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  static void
  print_ftrace_graph_addr(unsigned long addr, void *data,
  			const struct stacktrace_ops *ops,
  			struct thread_info *tinfo, int *graph)
  {
  	struct task_struct *task = tinfo->task;
  	unsigned long ret_addr;
  	int index = task->curr_ret_stack;
  
  	if (addr != (unsigned long)return_to_handler)
  		return;
  
  	if (!task->ret_stack || index < *graph)
  		return;
  
  	index -= *graph;
  	ret_addr = task->ret_stack[index].ret;
  
  	ops->address(data, ret_addr, 1);
  
  	(*graph)++;
  }
  #else
  static inline void
  print_ftrace_graph_addr(unsigned long addr, void *data,
  			const struct stacktrace_ops *ops,
  			struct thread_info *tinfo, int *graph)
  { }
  #endif
878719e83   Neil Horman   x86: unify approp...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  /*
   * x86-64 can have up to three kernel stacks:
   * process stack
   * interrupt stack
   * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
   */
  
  static inline int valid_stack_ptr(struct thread_info *tinfo,
  			void *p, unsigned int size, void *end)
  {
  	void *t = tinfo;
  	if (end) {
  		if (p < end && p >= (end-THREAD_SIZE))
  			return 1;
  		else
  			return 0;
  	}
  	return p > t && p < t + THREAD_SIZE - size;
  }
  
  unsigned long
  print_context_stack(struct thread_info *tinfo,
  		unsigned long *stack, unsigned long bp,
  		const struct stacktrace_ops *ops, void *data,
7ee991fbc   Steven Rostedt   ftrace: print rea...
87
  		unsigned long *end, int *graph)
878719e83   Neil Horman   x86: unify approp...
88
89
90
91
92
93
94
95
96
97
98
99
100
  {
  	struct stack_frame *frame = (struct stack_frame *)bp;
  
  	while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
  		unsigned long addr;
  
  		addr = *stack;
  		if (__kernel_text_address(addr)) {
  			if ((unsigned long) stack == bp + sizeof(long)) {
  				ops->address(data, addr, 1);
  				frame = frame->next_frame;
  				bp = (unsigned long) frame;
  			} else {
2c344e9d6   Arjan van de Ven   x86: don't preten...
101
  				ops->address(data, addr, 0);
878719e83   Neil Horman   x86: unify approp...
102
  			}
7ee991fbc   Steven Rostedt   ftrace: print rea...
103
  			print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
878719e83   Neil Horman   x86: unify approp...
104
105
106
107
108
  		}
  		stack++;
  	}
  	return bp;
  }
06d65bda7   Frederic Weisbecker   perf events, x86/...
109
110
111
112
113
114
115
116
117
118
119
120
121
  EXPORT_SYMBOL_GPL(print_context_stack);
  
  unsigned long
  print_context_stack_bp(struct thread_info *tinfo,
  		       unsigned long *stack, unsigned long bp,
  		       const struct stacktrace_ops *ops, void *data,
  		       unsigned long *end, int *graph)
  {
  	struct stack_frame *frame = (struct stack_frame *)bp;
  	unsigned long *ret_addr = &frame->return_address;
  
  	while (valid_stack_ptr(tinfo, ret_addr, sizeof(*ret_addr), end)) {
  		unsigned long addr = *ret_addr;
c2c5d45d4   Frederic Weisbecker   perf: Stop stack ...
122
123
124
125
126
127
128
  		if (!__kernel_text_address(addr))
  			break;
  
  		ops->address(data, addr, 1);
  		frame = frame->next_frame;
  		ret_addr = &frame->return_address;
  		print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
06d65bda7   Frederic Weisbecker   perf events, x86/...
129
  	}
c2c5d45d4   Frederic Weisbecker   perf: Stop stack ...
130

06d65bda7   Frederic Weisbecker   perf events, x86/...
131
132
133
  	return (unsigned long)frame;
  }
  EXPORT_SYMBOL_GPL(print_context_stack_bp);
878719e83   Neil Horman   x86: unify approp...
134

878719e83   Neil Horman   x86: unify approp...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  static int print_trace_stack(void *data, char *name)
  {
  	printk("%s <%s> ", (char *)data, name);
  	return 0;
  }
  
  /*
   * Print one address/symbol entries per line.
   */
  static void print_trace_address(void *data, unsigned long addr, int reliable)
  {
  	touch_nmi_watchdog();
  	printk(data);
  	printk_address(addr, reliable);
  }
  
  static const struct stacktrace_ops print_trace_ops = {
06d65bda7   Frederic Weisbecker   perf events, x86/...
152
153
  	.stack			= print_trace_stack,
  	.address		= print_trace_address,
61c1917f4   Frederic Weisbecker   perf events, x86/...
154
  	.walk_stack		= print_context_stack,
878719e83   Neil Horman   x86: unify approp...
155
156
157
158
  };
  
  void
  show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
159
  		unsigned long *stack, unsigned long bp, char *log_lvl)
878719e83   Neil Horman   x86: unify approp...
160
161
162
  {
  	printk("%sCall Trace:
  ", log_lvl);
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
163
  	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
878719e83   Neil Horman   x86: unify approp...
164
165
166
  }
  
  void show_trace(struct task_struct *task, struct pt_regs *regs,
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
167
  		unsigned long *stack, unsigned long bp)
878719e83   Neil Horman   x86: unify approp...
168
  {
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
169
  	show_trace_log_lvl(task, regs, stack, bp, "");
878719e83   Neil Horman   x86: unify approp...
170
171
172
173
  }
  
  void show_stack(struct task_struct *task, unsigned long *sp)
  {
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
174
  	show_stack_log_lvl(task, NULL, sp, 0, "");
878719e83   Neil Horman   x86: unify approp...
175
176
177
178
179
180
181
  }
  
  /*
   * The architecture-independent dump_stack generator
   */
  void dump_stack(void)
  {
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
182
  	unsigned long bp;
878719e83   Neil Horman   x86: unify approp...
183
  	unsigned long stack;
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
184
  	bp = stack_frame(current, NULL);
878719e83   Neil Horman   x86: unify approp...
185
186
187
188
189
190
  	printk("Pid: %d, comm: %.20s %s %s %.*s
  ",
  		current->pid, current->comm, print_tainted(),
  		init_utsname()->release,
  		(int)strcspn(init_utsname()->version, " "),
  		init_utsname()->version);
e8e999cf3   Namhyung Kim   x86, dumpstack: C...
191
  	show_trace(NULL, NULL, &stack, bp);
878719e83   Neil Horman   x86: unify approp...
192
193
  }
  EXPORT_SYMBOL(dump_stack);
edc35bd72   Thomas Gleixner   locking: Rename _...
194
  static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
878719e83   Neil Horman   x86: unify approp...
195
196
197
198
199
200
201
202
203
204
205
206
207
  static int die_owner = -1;
  static unsigned int die_nest_count;
  
  unsigned __kprobes long oops_begin(void)
  {
  	int cpu;
  	unsigned long flags;
  
  	oops_enter();
  
  	/* racy, but better than risking deadlock. */
  	raw_local_irq_save(flags);
  	cpu = smp_processor_id();
0199c4e68   Thomas Gleixner   locking: Convert ...
208
  	if (!arch_spin_trylock(&die_lock)) {
878719e83   Neil Horman   x86: unify approp...
209
210
211
  		if (cpu == die_owner)
  			/* nested oops. should stop eventually */;
  		else
0199c4e68   Thomas Gleixner   locking: Convert ...
212
  			arch_spin_lock(&die_lock);
878719e83   Neil Horman   x86: unify approp...
213
214
215
216
217
218
219
  	}
  	die_nest_count++;
  	die_owner = cpu;
  	console_verbose();
  	bust_spinlocks(1);
  	return flags;
  }
81e88fdc4   Huang Ying   ACPI, APEI, Gener...
220
  EXPORT_SYMBOL_GPL(oops_begin);
878719e83   Neil Horman   x86: unify approp...
221
222
223
224
225
226
227
228
229
230
231
232
  
  void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
  {
  	if (regs && kexec_should_crash(current))
  		crash_kexec(regs);
  
  	bust_spinlocks(0);
  	die_owner = -1;
  	add_taint(TAINT_DIE);
  	die_nest_count--;
  	if (!die_nest_count)
  		/* Nest count reaches zero, release the lock. */
0199c4e68   Thomas Gleixner   locking: Convert ...
233
  		arch_spin_unlock(&die_lock);
878719e83   Neil Horman   x86: unify approp...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  	raw_local_irq_restore(flags);
  	oops_exit();
  
  	if (!signr)
  		return;
  	if (in_interrupt())
  		panic("Fatal exception in interrupt");
  	if (panic_on_oops)
  		panic("Fatal exception");
  	do_exit(signr);
  }
  
  int __kprobes __die(const char *str, struct pt_regs *regs, long err)
  {
  #ifdef CONFIG_X86_32
  	unsigned short ss;
  	unsigned long sp;
  #endif
  	printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
  #ifdef CONFIG_PREEMPT
  	printk("PREEMPT ");
  #endif
  #ifdef CONFIG_SMP
  	printk("SMP ");
  #endif
  #ifdef CONFIG_DEBUG_PAGEALLOC
  	printk("DEBUG_PAGEALLOC");
  #endif
  	printk("
  ");
878719e83   Neil Horman   x86: unify approp...
264
265
266
267
268
269
  	if (notify_die(DIE_OOPS, str, regs, err,
  			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
  		return 1;
  
  	show_registers(regs);
  #ifdef CONFIG_X86_32
a343c75d3   H. Peter Anvin   x86: use kernel_s...
270
  	if (user_mode_vm(regs)) {
878719e83   Neil Horman   x86: unify approp...
271
272
  		sp = regs->sp;
  		ss = regs->ss & 0xffff;
a343c75d3   H. Peter Anvin   x86: use kernel_s...
273
274
275
  	} else {
  		sp = kernel_stack_pointer(regs);
  		savesegment(ss, ss);
878719e83   Neil Horman   x86: unify approp...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  	}
  	printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
  	print_symbol("%s", regs->ip);
  	printk(" SS:ESP %04x:%08lx
  ", ss, sp);
  #else
  	/* Executive summary in case the oops scrolled away */
  	printk(KERN_ALERT "RIP ");
  	printk_address(regs->ip, 1);
  	printk(" RSP <%016lx>
  ", regs->sp);
  #endif
  	return 0;
  }
  
  /*
   * This is gone through when something in the kernel has done something bad
   * and is about to be terminated:
   */
  void die(const char *str, struct pt_regs *regs, long err)
  {
  	unsigned long flags = oops_begin();
  	int sig = SIGSEGV;
  
  	if (!user_mode_vm(regs))
  		report_bug(regs->ip, regs);
  
  	if (__die(str, regs, err))
  		sig = 0;
  	oops_end(flags, regs, sig);
  }
878719e83   Neil Horman   x86: unify approp...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  static int __init kstack_setup(char *s)
  {
  	if (!s)
  		return -EINVAL;
  	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
  	return 0;
  }
  early_param("kstack", kstack_setup);
  
  static int __init code_bytes_setup(char *s)
  {
  	code_bytes = simple_strtoul(s, NULL, 0);
  	if (code_bytes > 8192)
  		code_bytes = 8192;
  
  	return 1;
  }
  __setup("code_bytes=", code_bytes_setup);