xref: /openbmc/linux/arch/x86/kernel/dumpstack_64.c (revision 5fe599e0)
16fcbede3SAlexander van Heukelum /*
26fcbede3SAlexander van Heukelum  *  Copyright (C) 1991, 1992  Linus Torvalds
36fcbede3SAlexander van Heukelum  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
46fcbede3SAlexander van Heukelum  */
56fcbede3SAlexander van Heukelum #include <linux/kallsyms.h>
66fcbede3SAlexander van Heukelum #include <linux/kprobes.h>
76fcbede3SAlexander van Heukelum #include <linux/uaccess.h>
86fcbede3SAlexander van Heukelum #include <linux/hardirq.h>
96fcbede3SAlexander van Heukelum #include <linux/kdebug.h>
10186f4360SPaul Gortmaker #include <linux/export.h>
116fcbede3SAlexander van Heukelum #include <linux/ptrace.h>
126fcbede3SAlexander van Heukelum #include <linux/kexec.h>
13b8030906SIngo Molnar #include <linux/sysfs.h>
146fcbede3SAlexander van Heukelum #include <linux/bug.h>
156fcbede3SAlexander van Heukelum #include <linux/nmi.h>
166fcbede3SAlexander van Heukelum 
176fcbede3SAlexander van Heukelum #include <asm/stacktrace.h>
186fcbede3SAlexander van Heukelum 
199c003907SJosh Poimboeuf static char *exception_stack_names[N_EXCEPTION_STACKS] = {
206fcbede3SAlexander van Heukelum 		[ DOUBLEFAULT_STACK-1	]	= "#DF",
219c003907SJosh Poimboeuf 		[ NMI_STACK-1		]	= "NMI",
229c003907SJosh Poimboeuf 		[ DEBUG_STACK-1		]	= "#DB",
236fcbede3SAlexander van Heukelum 		[ MCE_STACK-1		]	= "#MC",
249c003907SJosh Poimboeuf };
259c003907SJosh Poimboeuf 
269c003907SJosh Poimboeuf static unsigned long exception_stack_sizes[N_EXCEPTION_STACKS] = {
279c003907SJosh Poimboeuf 	[0 ... N_EXCEPTION_STACKS - 1]		= EXCEPTION_STKSZ,
289c003907SJosh Poimboeuf 	[DEBUG_STACK - 1]			= DEBUG_STKSZ
296fcbede3SAlexander van Heukelum };
300406ca6dSFrederic Weisbecker 
31cb76c939SJosh Poimboeuf void stack_type_str(enum stack_type type, const char **begin, const char **end)
320406ca6dSFrederic Weisbecker {
33cb76c939SJosh Poimboeuf 	BUILD_BUG_ON(N_EXCEPTION_STACKS != 4);
34cb76c939SJosh Poimboeuf 
35cb76c939SJosh Poimboeuf 	switch (type) {
36cb76c939SJosh Poimboeuf 	case STACK_TYPE_IRQ:
37cb76c939SJosh Poimboeuf 		*begin = "IRQ";
38cb76c939SJosh Poimboeuf 		*end   = "EOI";
39cb76c939SJosh Poimboeuf 		break;
40cb76c939SJosh Poimboeuf 	case STACK_TYPE_EXCEPTION ... STACK_TYPE_EXCEPTION_LAST:
41cb76c939SJosh Poimboeuf 		*begin = exception_stack_names[type - STACK_TYPE_EXCEPTION];
42cb76c939SJosh Poimboeuf 		*end   = "EOE";
43cb76c939SJosh Poimboeuf 		break;
44cb76c939SJosh Poimboeuf 	default:
45cb76c939SJosh Poimboeuf 		*begin = NULL;
46cb76c939SJosh Poimboeuf 		*end   = NULL;
47cb76c939SJosh Poimboeuf 	}
48cb76c939SJosh Poimboeuf }
49cb76c939SJosh Poimboeuf 
50cb76c939SJosh Poimboeuf static bool in_exception_stack(unsigned long *stack, struct stack_info *info,
51cb76c939SJosh Poimboeuf 			       unsigned long *visit_mask)
52cb76c939SJosh Poimboeuf {
53cb76c939SJosh Poimboeuf 	unsigned long *begin, *end;
54cb76c939SJosh Poimboeuf 	struct pt_regs *regs;
556fcbede3SAlexander van Heukelum 	unsigned k;
566fcbede3SAlexander van Heukelum 
579c003907SJosh Poimboeuf 	BUILD_BUG_ON(N_EXCEPTION_STACKS != 4);
589c003907SJosh Poimboeuf 
596fcbede3SAlexander van Heukelum 	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
60cb76c939SJosh Poimboeuf 		end   = (unsigned long *)raw_cpu_ptr(&orig_ist)->ist[k];
61cb76c939SJosh Poimboeuf 		begin = end - (exception_stack_sizes[k] / sizeof(long));
62cb76c939SJosh Poimboeuf 		regs  = (struct pt_regs *)end - 1;
639c003907SJosh Poimboeuf 
649c003907SJosh Poimboeuf 		if (stack < begin || stack >= end)
656fcbede3SAlexander van Heukelum 			continue;
669c003907SJosh Poimboeuf 
676fcbede3SAlexander van Heukelum 		/*
68cb76c939SJosh Poimboeuf 		 * Make sure we don't iterate through an exception stack more
69cb76c939SJosh Poimboeuf 		 * than once.  If it comes up a second time then there's
70cb76c939SJosh Poimboeuf 		 * something wrong going on - just break out and report an
71cb76c939SJosh Poimboeuf 		 * unknown stack type.
726fcbede3SAlexander van Heukelum 		 */
73cb76c939SJosh Poimboeuf 		if (*visit_mask & (1U << k))
746fcbede3SAlexander van Heukelum 			break;
75cb76c939SJosh Poimboeuf 		*visit_mask |= 1U << k;
766fcbede3SAlexander van Heukelum 
77cb76c939SJosh Poimboeuf 		info->type	= STACK_TYPE_EXCEPTION + k;
78cb76c939SJosh Poimboeuf 		info->begin	= begin;
79cb76c939SJosh Poimboeuf 		info->end	= end;
80cb76c939SJosh Poimboeuf 		info->next_sp	= (unsigned long *)regs->sp;
81cb76c939SJosh Poimboeuf 
82cb76c939SJosh Poimboeuf 		return true;
836fcbede3SAlexander van Heukelum 	}
849c003907SJosh Poimboeuf 
85cb76c939SJosh Poimboeuf 	return false;
866fcbede3SAlexander van Heukelum }
876fcbede3SAlexander van Heukelum 
88cb76c939SJosh Poimboeuf static bool in_irq_stack(unsigned long *stack, struct stack_info *info)
89af2d8289SFrederic Weisbecker {
90cb76c939SJosh Poimboeuf 	unsigned long *end   = (unsigned long *)this_cpu_read(irq_stack_ptr);
91cb76c939SJosh Poimboeuf 	unsigned long *begin = end - (IRQ_STACK_SIZE / sizeof(long));
92cb76c939SJosh Poimboeuf 
935fe599e0SJosh Poimboeuf 	/*
945fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
955fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
965fe599e0SJosh Poimboeuf 	 */
975fe599e0SJosh Poimboeuf 	if (stack < begin || stack > end)
98cb76c939SJosh Poimboeuf 		return false;
99cb76c939SJosh Poimboeuf 
100cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_IRQ;
101cb76c939SJosh Poimboeuf 	info->begin	= begin;
102cb76c939SJosh Poimboeuf 	info->end	= end;
103cb76c939SJosh Poimboeuf 
104cb76c939SJosh Poimboeuf 	/*
105cb76c939SJosh Poimboeuf 	 * The next stack pointer is the first thing pushed by the entry code
106cb76c939SJosh Poimboeuf 	 * after switching to the irq stack.
107cb76c939SJosh Poimboeuf 	 */
108cb76c939SJosh Poimboeuf 	info->next_sp = (unsigned long *)*(end - 1);
109cb76c939SJosh Poimboeuf 
110cb76c939SJosh Poimboeuf 	return true;
111af2d8289SFrederic Weisbecker }
112af2d8289SFrederic Weisbecker 
113cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
114cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
1152223f6f6SSteven Rostedt {
116cb76c939SJosh Poimboeuf 	if (!stack)
117cb76c939SJosh Poimboeuf 		goto unknown;
1182223f6f6SSteven Rostedt 
119cb76c939SJosh Poimboeuf 	task = task ? : current;
1202223f6f6SSteven Rostedt 
121cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
122cb76c939SJosh Poimboeuf 		return 0;
1232223f6f6SSteven Rostedt 
124cb76c939SJosh Poimboeuf 	if (task != current)
125cb76c939SJosh Poimboeuf 		goto unknown;
1262223f6f6SSteven Rostedt 
127cb76c939SJosh Poimboeuf 	if (in_exception_stack(stack, info, visit_mask))
128cb76c939SJosh Poimboeuf 		return 0;
1292223f6f6SSteven Rostedt 
130cb76c939SJosh Poimboeuf 	if (in_irq_stack(stack, info))
131cb76c939SJosh Poimboeuf 		return 0;
1322223f6f6SSteven Rostedt 
133cb76c939SJosh Poimboeuf 	return 0;
134cb76c939SJosh Poimboeuf 
135cb76c939SJosh Poimboeuf unknown:
136cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
137cb76c939SJosh Poimboeuf 	return -EINVAL;
1382223f6f6SSteven Rostedt }
1392223f6f6SSteven Rostedt 
140af2d8289SFrederic Weisbecker /*
1416fcbede3SAlexander van Heukelum  * x86-64 can have up to three kernel stacks:
1426fcbede3SAlexander van Heukelum  * process stack
1436fcbede3SAlexander van Heukelum  * interrupt stack
1446fcbede3SAlexander van Heukelum  * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
1456fcbede3SAlexander van Heukelum  */
1466fcbede3SAlexander van Heukelum 
147e8e999cfSNamhyung Kim void dump_trace(struct task_struct *task, struct pt_regs *regs,
148e8e999cfSNamhyung Kim 		unsigned long *stack, unsigned long bp,
1496fcbede3SAlexander van Heukelum 		const struct stacktrace_ops *ops, void *data)
1506fcbede3SAlexander van Heukelum {
151cb76c939SJosh Poimboeuf 	unsigned long visit_mask = 0;
152cb76c939SJosh Poimboeuf 	struct stack_info info;
1532223f6f6SSteven Rostedt 	int graph = 0;
1542223f6f6SSteven Rostedt 	int done = 0;
1556fcbede3SAlexander van Heukelum 
1564b8afafbSJosh Poimboeuf 	task = task ? : current;
1574b8afafbSJosh Poimboeuf 	stack = stack ? : get_stack_pointer(task, regs);
1584b8afafbSJosh Poimboeuf 	bp = bp ? : (unsigned long)get_frame_pointer(task, regs);
1596fcbede3SAlexander van Heukelum 
1606fcbede3SAlexander van Heukelum 	/*
1616fcbede3SAlexander van Heukelum 	 * Print function call entries in all stacks, starting at the
1626fcbede3SAlexander van Heukelum 	 * current stack address. If the stacks consist of nested
1636fcbede3SAlexander van Heukelum 	 * exceptions
1646fcbede3SAlexander van Heukelum 	 */
1652223f6f6SSteven Rostedt 	while (!done) {
166cb76c939SJosh Poimboeuf 		const char *begin_str, *end_str;
1676fcbede3SAlexander van Heukelum 
168cb76c939SJosh Poimboeuf 		get_stack_info(stack, task, &info, &visit_mask);
1692223f6f6SSteven Rostedt 
1702223f6f6SSteven Rostedt 		/* Default finish unless specified to continue */
1712223f6f6SSteven Rostedt 		done = 1;
1722223f6f6SSteven Rostedt 
173cb76c939SJosh Poimboeuf 		switch (info.type) {
1742223f6f6SSteven Rostedt 
1752223f6f6SSteven Rostedt 		/* Break out early if we are on the thread stack */
176cb76c939SJosh Poimboeuf 		case STACK_TYPE_TASK:
1772223f6f6SSteven Rostedt 			break;
1782223f6f6SSteven Rostedt 
179cb76c939SJosh Poimboeuf 		case STACK_TYPE_IRQ:
180cb76c939SJosh Poimboeuf 		case STACK_TYPE_EXCEPTION ... STACK_TYPE_EXCEPTION_LAST:
1812223f6f6SSteven Rostedt 
182cb76c939SJosh Poimboeuf 			stack_type_str(info.type, &begin_str, &end_str);
183cb76c939SJosh Poimboeuf 
184cb76c939SJosh Poimboeuf 			if (ops->stack(data, begin_str) < 0)
1856fcbede3SAlexander van Heukelum 				break;
1866fcbede3SAlexander van Heukelum 
187da01e18aSLinus Torvalds 			bp = ops->walk_stack(task, stack, bp, ops,
188cb76c939SJosh Poimboeuf 					     data, &info, &graph);
189cb76c939SJosh Poimboeuf 
190cb76c939SJosh Poimboeuf 			ops->stack(data, end_str);
191cb76c939SJosh Poimboeuf 
192cb76c939SJosh Poimboeuf 			stack = info.next_sp;
1932223f6f6SSteven Rostedt 			done = 0;
1942223f6f6SSteven Rostedt 			break;
1956fcbede3SAlexander van Heukelum 
196cb76c939SJosh Poimboeuf 		default:
1972223f6f6SSteven Rostedt 			ops->stack(data, "UNK");
1982223f6f6SSteven Rostedt 			break;
1992223f6f6SSteven Rostedt 		}
2006fcbede3SAlexander van Heukelum 	}
2016fcbede3SAlexander van Heukelum 
2026fcbede3SAlexander van Heukelum 	/*
2036fcbede3SAlexander van Heukelum 	 * This handles the process stack:
2046fcbede3SAlexander van Heukelum 	 */
205cb76c939SJosh Poimboeuf 	bp = ops->walk_stack(task, stack, bp, ops, data, &info, &graph);
2066fcbede3SAlexander van Heukelum }
2076fcbede3SAlexander van Heukelum EXPORT_SYMBOL(dump_trace);
2086fcbede3SAlexander van Heukelum 
209878719e8SNeil Horman void
2106fcbede3SAlexander van Heukelum show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
211e8e999cfSNamhyung Kim 		   unsigned long *sp, unsigned long bp, char *log_lvl)
2126fcbede3SAlexander van Heukelum {
21367f2de0bSIngo Molnar 	unsigned long *irq_stack_end;
21467f2de0bSIngo Molnar 	unsigned long *irq_stack;
2156fcbede3SAlexander van Heukelum 	unsigned long *stack;
2166fcbede3SAlexander van Heukelum 	int i;
21767f2de0bSIngo Molnar 
218cfeeed27SJosh Poimboeuf 	irq_stack_end = (unsigned long *)this_cpu_read(irq_stack_ptr);
2194950d6d4SJosh Poimboeuf 	irq_stack     = irq_stack_end - (IRQ_STACK_SIZE / sizeof(long));
2206fcbede3SAlexander van Heukelum 
2214b8afafbSJosh Poimboeuf 	sp = sp ? : get_stack_pointer(task, regs);
2226fcbede3SAlexander van Heukelum 
2236fcbede3SAlexander van Heukelum 	stack = sp;
2246fcbede3SAlexander van Heukelum 	for (i = 0; i < kstack_depth_to_print; i++) {
22598f30b12SAndy Lutomirski 		unsigned long word;
22698f30b12SAndy Lutomirski 
22726f80bd6SBrian Gerst 		if (stack >= irq_stack && stack <= irq_stack_end) {
22826f80bd6SBrian Gerst 			if (stack == irq_stack_end) {
22926f80bd6SBrian Gerst 				stack = (unsigned long *) (irq_stack_end[-1]);
230c767a54bSJoe Perches 				pr_cont(" <EOI> ");
2316fcbede3SAlexander van Heukelum 			}
2326fcbede3SAlexander van Heukelum 		} else {
23304769ae3SAdrien Schildknecht 		if (kstack_end(stack))
2346fcbede3SAlexander van Heukelum 			break;
2356fcbede3SAlexander van Heukelum 		}
23698f30b12SAndy Lutomirski 
23798f30b12SAndy Lutomirski 		if (probe_kernel_address(stack, word))
23898f30b12SAndy Lutomirski 			break;
23998f30b12SAndy Lutomirski 
2401fc7f61cSAdrien Schildknecht 		if ((i % STACKSLOTS_PER_LINE) == 0) {
2411fc7f61cSAdrien Schildknecht 			if (i != 0)
242c767a54bSJoe Perches 				pr_cont("\n");
24398f30b12SAndy Lutomirski 			printk("%s %016lx", log_lvl, word);
2441fc7f61cSAdrien Schildknecht 		} else
24598f30b12SAndy Lutomirski 			pr_cont(" %016lx", word);
24698f30b12SAndy Lutomirski 
24798f30b12SAndy Lutomirski 		stack++;
2486fcbede3SAlexander van Heukelum 		touch_nmi_watchdog();
2496fcbede3SAlexander van Heukelum 	}
25067f2de0bSIngo Molnar 
251c767a54bSJoe Perches 	pr_cont("\n");
252e8e999cfSNamhyung Kim 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
2536fcbede3SAlexander van Heukelum }
2546fcbede3SAlexander van Heukelum 
25557da8b96SJan Beulich void show_regs(struct pt_regs *regs)
2566fcbede3SAlexander van Heukelum {
2576fcbede3SAlexander van Heukelum 	int i;
2586fcbede3SAlexander van Heukelum 
259a43cb95dSTejun Heo 	show_regs_print_info(KERN_DEFAULT);
2606fcbede3SAlexander van Heukelum 	__show_regs(regs, 1);
2616fcbede3SAlexander van Heukelum 
2626fcbede3SAlexander van Heukelum 	/*
2636fcbede3SAlexander van Heukelum 	 * When in-kernel, we also print out the stack and code at the
2646fcbede3SAlexander van Heukelum 	 * time of the fault..
2656fcbede3SAlexander van Heukelum 	 */
2666fcbede3SAlexander van Heukelum 	if (!user_mode(regs)) {
2676fcbede3SAlexander van Heukelum 		unsigned int code_prologue = code_bytes * 43 / 64;
2686fcbede3SAlexander van Heukelum 		unsigned int code_len = code_bytes;
2696fcbede3SAlexander van Heukelum 		unsigned char c;
2706fcbede3SAlexander van Heukelum 		u8 *ip;
2716fcbede3SAlexander van Heukelum 
272b0f4c4b3SPrarit Bhargava 		printk(KERN_DEFAULT "Stack:\n");
2735a8ff54cSJosh Poimboeuf 		show_stack_log_lvl(NULL, regs, NULL, 0, KERN_DEFAULT);
2746fcbede3SAlexander van Heukelum 
275b0f4c4b3SPrarit Bhargava 		printk(KERN_DEFAULT "Code: ");
2766fcbede3SAlexander van Heukelum 
2776fcbede3SAlexander van Heukelum 		ip = (u8 *)regs->ip - code_prologue;
2786fcbede3SAlexander van Heukelum 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
2798a541665SAlexander van Heukelum 			/* try starting at IP */
2806fcbede3SAlexander van Heukelum 			ip = (u8 *)regs->ip;
2816fcbede3SAlexander van Heukelum 			code_len = code_len - code_prologue + 1;
2826fcbede3SAlexander van Heukelum 		}
2836fcbede3SAlexander van Heukelum 		for (i = 0; i < code_len; i++, ip++) {
2846fcbede3SAlexander van Heukelum 			if (ip < (u8 *)PAGE_OFFSET ||
2856fcbede3SAlexander van Heukelum 					probe_kernel_address(ip, c)) {
286c767a54bSJoe Perches 				pr_cont(" Bad RIP value.");
2876fcbede3SAlexander van Heukelum 				break;
2886fcbede3SAlexander van Heukelum 			}
2896fcbede3SAlexander van Heukelum 			if (ip == (u8 *)regs->ip)
290c767a54bSJoe Perches 				pr_cont("<%02x> ", c);
2916fcbede3SAlexander van Heukelum 			else
292c767a54bSJoe Perches 				pr_cont("%02x ", c);
2936fcbede3SAlexander van Heukelum 		}
2946fcbede3SAlexander van Heukelum 	}
295c767a54bSJoe Perches 	pr_cont("\n");
2966fcbede3SAlexander van Heukelum }
2976fcbede3SAlexander van Heukelum 
2986fcbede3SAlexander van Heukelum int is_valid_bugaddr(unsigned long ip)
2996fcbede3SAlexander van Heukelum {
3006fcbede3SAlexander van Heukelum 	unsigned short ud2;
3016fcbede3SAlexander van Heukelum 
3026fcbede3SAlexander van Heukelum 	if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
3036fcbede3SAlexander van Heukelum 		return 0;
3046fcbede3SAlexander van Heukelum 
3056fcbede3SAlexander van Heukelum 	return ud2 == 0x0b0f;
3066fcbede3SAlexander van Heukelum }
307