Skip to content

Commit 878719e

Browse files
nhormanIngo Molnar
authored andcommitted
x86: unify appropriate bits from dumpstack_32 and dumpstack_64
Impact: cleanup As promised, now that dumpstack_32 and dumpstack_64 have so many bits in common, we should merge the in-sync bits into a common file, to prevent them from diverging again. This patch removes bits which are common between dumpstack_32.c and dumpstack_64.c and places them in a common dumpstack.c which is built for both 32 and 64 bit arches. Signed-off-by: Neil Horman <[email protected]> Acked-by: Alexander van Heukelum <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Makefile | 2 arch/x86/kernel/Makefile | 2 arch/x86/kernel/Makefile | 2 arch/x86/kernel/Makefile | 2 arch/x86/kernel/Makefile | 2 arch/x86/kernel/Makefile | 2 arch/x86/kernel/dumpstack.c | 319 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/dumpstack.h | 39 +++++ arch/x86/kernel/dumpstack_32.c | 294 ------------------------------------- arch/x86/kernel/dumpstack_64.c | 285 ------------------------------------ 5 files changed, 363 insertions(+), 576 deletions(-)
1 parent 871d377 commit 878719e

File tree

5 files changed

+363
-576
lines changed

5 files changed

+363
-576
lines changed

arch/x86/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ CFLAGS_tsc.o := $(nostackp)
2424

2525
obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
2626
obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
27-
obj-y += time_$(BITS).o ioport.o ldt.o
27+
obj-y += time_$(BITS).o ioport.o ldt.o dumpstack.o
2828
obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o
2929
obj-$(CONFIG_X86_VISWS) += visws_quirks.o
3030
obj-$(CONFIG_X86_32) += probe_roms_32.o

arch/x86/kernel/dumpstack.c

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
/*
2+
* Copyright (C) 1991, 1992 Linus Torvalds
3+
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
4+
*/
5+
#include <linux/kallsyms.h>
6+
#include <linux/kprobes.h>
7+
#include <linux/uaccess.h>
8+
#include <linux/utsname.h>
9+
#include <linux/hardirq.h>
10+
#include <linux/kdebug.h>
11+
#include <linux/module.h>
12+
#include <linux/ptrace.h>
13+
#include <linux/kexec.h>
14+
#include <linux/bug.h>
15+
#include <linux/nmi.h>
16+
#include <linux/sysfs.h>
17+
18+
#include <asm/stacktrace.h>
19+
20+
#include "dumpstack.h"
21+
22+
int panic_on_unrecovered_nmi;
23+
unsigned int code_bytes = 64;
24+
int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
25+
static int die_counter;
26+
27+
void printk_address(unsigned long address, int reliable)
28+
{
29+
printk(" [<%p>] %s%pS\n", (void *) address,
30+
reliable ? "" : "? ", (void *) address);
31+
}
32+
33+
/*
34+
* x86-64 can have up to three kernel stacks:
35+
* process stack
36+
* interrupt stack
37+
* severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
38+
*/
39+
40+
static inline int valid_stack_ptr(struct thread_info *tinfo,
41+
void *p, unsigned int size, void *end)
42+
{
43+
void *t = tinfo;
44+
if (end) {
45+
if (p < end && p >= (end-THREAD_SIZE))
46+
return 1;
47+
else
48+
return 0;
49+
}
50+
return p > t && p < t + THREAD_SIZE - size;
51+
}
52+
53+
unsigned long
54+
print_context_stack(struct thread_info *tinfo,
55+
unsigned long *stack, unsigned long bp,
56+
const struct stacktrace_ops *ops, void *data,
57+
unsigned long *end)
58+
{
59+
struct stack_frame *frame = (struct stack_frame *)bp;
60+
61+
while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
62+
unsigned long addr;
63+
64+
addr = *stack;
65+
if (__kernel_text_address(addr)) {
66+
if ((unsigned long) stack == bp + sizeof(long)) {
67+
ops->address(data, addr, 1);
68+
frame = frame->next_frame;
69+
bp = (unsigned long) frame;
70+
} else {
71+
ops->address(data, addr, bp == 0);
72+
}
73+
}
74+
stack++;
75+
}
76+
return bp;
77+
}
78+
79+
80+
static void
81+
print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
82+
{
83+
printk(data);
84+
print_symbol(msg, symbol);
85+
printk("\n");
86+
}
87+
88+
static void print_trace_warning(void *data, char *msg)
89+
{
90+
printk("%s%s\n", (char *)data, msg);
91+
}
92+
93+
static int print_trace_stack(void *data, char *name)
94+
{
95+
printk("%s <%s> ", (char *)data, name);
96+
return 0;
97+
}
98+
99+
/*
100+
* Print one address/symbol entries per line.
101+
*/
102+
static void print_trace_address(void *data, unsigned long addr, int reliable)
103+
{
104+
touch_nmi_watchdog();
105+
printk(data);
106+
printk_address(addr, reliable);
107+
}
108+
109+
static const struct stacktrace_ops print_trace_ops = {
110+
.warning = print_trace_warning,
111+
.warning_symbol = print_trace_warning_symbol,
112+
.stack = print_trace_stack,
113+
.address = print_trace_address,
114+
};
115+
116+
void
117+
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
118+
unsigned long *stack, unsigned long bp, char *log_lvl)
119+
{
120+
printk("%sCall Trace:\n", log_lvl);
121+
dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
122+
}
123+
124+
void show_trace(struct task_struct *task, struct pt_regs *regs,
125+
unsigned long *stack, unsigned long bp)
126+
{
127+
show_trace_log_lvl(task, regs, stack, bp, "");
128+
}
129+
130+
void show_stack(struct task_struct *task, unsigned long *sp)
131+
{
132+
show_stack_log_lvl(task, NULL, sp, 0, "");
133+
}
134+
135+
/*
136+
* The architecture-independent dump_stack generator
137+
*/
138+
void dump_stack(void)
139+
{
140+
unsigned long bp = 0;
141+
unsigned long stack;
142+
143+
#ifdef CONFIG_FRAME_POINTER
144+
if (!bp)
145+
get_bp(bp);
146+
#endif
147+
148+
printk("Pid: %d, comm: %.20s %s %s %.*s\n",
149+
current->pid, current->comm, print_tainted(),
150+
init_utsname()->release,
151+
(int)strcspn(init_utsname()->version, " "),
152+
init_utsname()->version);
153+
show_trace(NULL, NULL, &stack, bp);
154+
}
155+
EXPORT_SYMBOL(dump_stack);
156+
157+
static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
158+
static int die_owner = -1;
159+
static unsigned int die_nest_count;
160+
161+
unsigned __kprobes long oops_begin(void)
162+
{
163+
int cpu;
164+
unsigned long flags;
165+
166+
oops_enter();
167+
168+
/* racy, but better than risking deadlock. */
169+
raw_local_irq_save(flags);
170+
cpu = smp_processor_id();
171+
if (!__raw_spin_trylock(&die_lock)) {
172+
if (cpu == die_owner)
173+
/* nested oops. should stop eventually */;
174+
else
175+
__raw_spin_lock(&die_lock);
176+
}
177+
die_nest_count++;
178+
die_owner = cpu;
179+
console_verbose();
180+
bust_spinlocks(1);
181+
return flags;
182+
}
183+
184+
void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
185+
{
186+
if (regs && kexec_should_crash(current))
187+
crash_kexec(regs);
188+
189+
bust_spinlocks(0);
190+
die_owner = -1;
191+
add_taint(TAINT_DIE);
192+
die_nest_count--;
193+
if (!die_nest_count)
194+
/* Nest count reaches zero, release the lock. */
195+
__raw_spin_unlock(&die_lock);
196+
raw_local_irq_restore(flags);
197+
oops_exit();
198+
199+
if (!signr)
200+
return;
201+
if (in_interrupt())
202+
panic("Fatal exception in interrupt");
203+
if (panic_on_oops)
204+
panic("Fatal exception");
205+
do_exit(signr);
206+
}
207+
208+
int __kprobes __die(const char *str, struct pt_regs *regs, long err)
209+
{
210+
#ifdef CONFIG_X86_32
211+
unsigned short ss;
212+
unsigned long sp;
213+
#endif
214+
printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
215+
#ifdef CONFIG_PREEMPT
216+
printk("PREEMPT ");
217+
#endif
218+
#ifdef CONFIG_SMP
219+
printk("SMP ");
220+
#endif
221+
#ifdef CONFIG_DEBUG_PAGEALLOC
222+
printk("DEBUG_PAGEALLOC");
223+
#endif
224+
printk("\n");
225+
sysfs_printk_last_file();
226+
if (notify_die(DIE_OOPS, str, regs, err,
227+
current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
228+
return 1;
229+
230+
show_registers(regs);
231+
#ifdef CONFIG_X86_32
232+
sp = (unsigned long) (&regs->sp);
233+
savesegment(ss, ss);
234+
if (user_mode(regs)) {
235+
sp = regs->sp;
236+
ss = regs->ss & 0xffff;
237+
}
238+
printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
239+
print_symbol("%s", regs->ip);
240+
printk(" SS:ESP %04x:%08lx\n", ss, sp);
241+
#else
242+
/* Executive summary in case the oops scrolled away */
243+
printk(KERN_ALERT "RIP ");
244+
printk_address(regs->ip, 1);
245+
printk(" RSP <%016lx>\n", regs->sp);
246+
#endif
247+
return 0;
248+
}
249+
250+
/*
251+
* This is gone through when something in the kernel has done something bad
252+
* and is about to be terminated:
253+
*/
254+
void die(const char *str, struct pt_regs *regs, long err)
255+
{
256+
unsigned long flags = oops_begin();
257+
int sig = SIGSEGV;
258+
259+
if (!user_mode_vm(regs))
260+
report_bug(regs->ip, regs);
261+
262+
if (__die(str, regs, err))
263+
sig = 0;
264+
oops_end(flags, regs, sig);
265+
}
266+
267+
void notrace __kprobes
268+
die_nmi(char *str, struct pt_regs *regs, int do_panic)
269+
{
270+
unsigned long flags;
271+
272+
if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
273+
return;
274+
275+
/*
276+
* We are in trouble anyway, lets at least try
277+
* to get a message out.
278+
*/
279+
flags = oops_begin();
280+
printk(KERN_EMERG "%s", str);
281+
printk(" on CPU%d, ip %08lx, registers:\n",
282+
smp_processor_id(), regs->ip);
283+
show_registers(regs);
284+
oops_end(flags, regs, 0);
285+
if (do_panic || panic_on_oops)
286+
panic("Non maskable interrupt");
287+
nmi_exit();
288+
local_irq_enable();
289+
do_exit(SIGBUS);
290+
}
291+
292+
static int __init oops_setup(char *s)
293+
{
294+
if (!s)
295+
return -EINVAL;
296+
if (!strcmp(s, "panic"))
297+
panic_on_oops = 1;
298+
return 0;
299+
}
300+
early_param("oops", oops_setup);
301+
302+
static int __init kstack_setup(char *s)
303+
{
304+
if (!s)
305+
return -EINVAL;
306+
kstack_depth_to_print = simple_strtoul(s, NULL, 0);
307+
return 0;
308+
}
309+
early_param("kstack", kstack_setup);
310+
311+
static int __init code_bytes_setup(char *s)
312+
{
313+
code_bytes = simple_strtoul(s, NULL, 0);
314+
if (code_bytes > 8192)
315+
code_bytes = 8192;
316+
317+
return 1;
318+
}
319+
__setup("code_bytes=", code_bytes_setup);

arch/x86/kernel/dumpstack.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (C) 1991, 1992 Linus Torvalds
3+
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
4+
*/
5+
6+
#ifndef DUMPSTACK_H
7+
#define DUMPSTACK_H
8+
9+
#ifdef CONFIG_X86_32
10+
#define STACKSLOTS_PER_LINE 8
11+
#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
12+
#else
13+
#define STACKSLOTS_PER_LINE 4
14+
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
15+
#endif
16+
17+
extern unsigned long
18+
print_context_stack(struct thread_info *tinfo,
19+
unsigned long *stack, unsigned long bp,
20+
const struct stacktrace_ops *ops, void *data,
21+
unsigned long *end);
22+
23+
extern void
24+
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
25+
unsigned long *stack, unsigned long bp, char *log_lvl);
26+
27+
extern void
28+
show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
29+
unsigned long *sp, unsigned long bp, char *log_lvl);
30+
31+
extern unsigned int code_bytes;
32+
extern int kstack_depth_to_print;
33+
34+
/* The form of the top of the frame on the stack */
35+
struct stack_frame {
36+
struct stack_frame *next_frame;
37+
unsigned long return_address;
38+
};
39+
#endif

0 commit comments

Comments
 (0)