xref: /openbmc/linux/arch/x86/kernel/dumpstack_32.c (revision 5fe599e02e41550c59831613a11c8ae057897c29)
12bc5f927SAlexander van Heukelum /*
22bc5f927SAlexander van Heukelum  *  Copyright (C) 1991, 1992  Linus Torvalds
32bc5f927SAlexander van Heukelum  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
42bc5f927SAlexander van Heukelum  */
52bc5f927SAlexander van Heukelum #include <linux/kallsyms.h>
62bc5f927SAlexander van Heukelum #include <linux/kprobes.h>
72bc5f927SAlexander van Heukelum #include <linux/uaccess.h>
82bc5f927SAlexander van Heukelum #include <linux/hardirq.h>
92bc5f927SAlexander van Heukelum #include <linux/kdebug.h>
10186f4360SPaul Gortmaker #include <linux/export.h>
112bc5f927SAlexander van Heukelum #include <linux/ptrace.h>
122bc5f927SAlexander van Heukelum #include <linux/kexec.h>
13b8030906SIngo Molnar #include <linux/sysfs.h>
142bc5f927SAlexander van Heukelum #include <linux/bug.h>
152bc5f927SAlexander van Heukelum #include <linux/nmi.h>
162bc5f927SAlexander van Heukelum 
172bc5f927SAlexander van Heukelum #include <asm/stacktrace.h>
182bc5f927SAlexander van Heukelum 
19cb76c939SJosh Poimboeuf void stack_type_str(enum stack_type type, const char **begin, const char **end)
20198d208dSSteven Rostedt {
21cb76c939SJosh Poimboeuf 	switch (type) {
22cb76c939SJosh Poimboeuf 	case STACK_TYPE_IRQ:
23cb76c939SJosh Poimboeuf 	case STACK_TYPE_SOFTIRQ:
24cb76c939SJosh Poimboeuf 		*begin = "IRQ";
25cb76c939SJosh Poimboeuf 		*end   = "EOI";
26cb76c939SJosh Poimboeuf 		break;
27cb76c939SJosh Poimboeuf 	default:
28cb76c939SJosh Poimboeuf 		*begin = NULL;
29cb76c939SJosh Poimboeuf 		*end   = NULL;
30cb76c939SJosh Poimboeuf 	}
31198d208dSSteven Rostedt }
32198d208dSSteven Rostedt 
33cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
34198d208dSSteven Rostedt {
35cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack);
36cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
37198d208dSSteven Rostedt 
38*5fe599e0SJosh Poimboeuf 	/*
39*5fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
40*5fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
41*5fe599e0SJosh Poimboeuf 	 */
42*5fe599e0SJosh Poimboeuf 	if (stack < begin || stack > end)
43cb76c939SJosh Poimboeuf 		return false;
44cb76c939SJosh Poimboeuf 
45cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_IRQ;
46cb76c939SJosh Poimboeuf 	info->begin	= begin;
47cb76c939SJosh Poimboeuf 	info->end	= end;
48cb76c939SJosh Poimboeuf 
49cb76c939SJosh Poimboeuf 	/*
50cb76c939SJosh Poimboeuf 	 * See irq_32.c -- the next stack pointer is stored at the beginning of
51cb76c939SJosh Poimboeuf 	 * the stack.
52cb76c939SJosh Poimboeuf 	 */
53cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
54cb76c939SJosh Poimboeuf 
55cb76c939SJosh Poimboeuf 	return true;
56198d208dSSteven Rostedt }
57198d208dSSteven Rostedt 
58cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
59198d208dSSteven Rostedt {
60cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack);
61cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
62198d208dSSteven Rostedt 
63*5fe599e0SJosh Poimboeuf 	/*
64*5fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
65*5fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
66*5fe599e0SJosh Poimboeuf 	 */
67*5fe599e0SJosh Poimboeuf 	if (stack < begin || stack > end)
68cb76c939SJosh Poimboeuf 		return false;
69cb76c939SJosh Poimboeuf 
70cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_SOFTIRQ;
71cb76c939SJosh Poimboeuf 	info->begin	= begin;
72cb76c939SJosh Poimboeuf 	info->end	= end;
73cb76c939SJosh Poimboeuf 
74cb76c939SJosh Poimboeuf 	/*
75cb76c939SJosh Poimboeuf 	 * The next stack pointer is stored at the beginning of the stack.
76cb76c939SJosh Poimboeuf 	 * See irq_32.c.
77cb76c939SJosh Poimboeuf 	 */
78cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
79cb76c939SJosh Poimboeuf 
80cb76c939SJosh Poimboeuf 	return true;
81cb76c939SJosh Poimboeuf }
82cb76c939SJosh Poimboeuf 
83cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
84cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
85cb76c939SJosh Poimboeuf {
86cb76c939SJosh Poimboeuf 	if (!stack)
87cb76c939SJosh Poimboeuf 		goto unknown;
88cb76c939SJosh Poimboeuf 
89cb76c939SJosh Poimboeuf 	task = task ? : current;
90cb76c939SJosh Poimboeuf 
91cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
92cb76c939SJosh Poimboeuf 		return 0;
93cb76c939SJosh Poimboeuf 
94cb76c939SJosh Poimboeuf 	if (task != current)
95cb76c939SJosh Poimboeuf 		goto unknown;
96cb76c939SJosh Poimboeuf 
97cb76c939SJosh Poimboeuf 	if (in_hardirq_stack(stack, info))
98cb76c939SJosh Poimboeuf 		return 0;
99cb76c939SJosh Poimboeuf 
100cb76c939SJosh Poimboeuf 	if (in_softirq_stack(stack, info))
101cb76c939SJosh Poimboeuf 		return 0;
102cb76c939SJosh Poimboeuf 
103cb76c939SJosh Poimboeuf unknown:
104cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
105cb76c939SJosh Poimboeuf 	return -EINVAL;
106198d208dSSteven Rostedt }
1070406ca6dSFrederic Weisbecker 
108e8e999cfSNamhyung Kim void dump_trace(struct task_struct *task, struct pt_regs *regs,
109e8e999cfSNamhyung Kim 		unsigned long *stack, unsigned long bp,
1102bc5f927SAlexander van Heukelum 		const struct stacktrace_ops *ops, void *data)
1112bc5f927SAlexander van Heukelum {
112cb76c939SJosh Poimboeuf 	unsigned long visit_mask = 0;
1137ee991fbSSteven Rostedt 	int graph = 0;
1147ee991fbSSteven Rostedt 
1154b8afafbSJosh Poimboeuf 	task = task ? : current;
1164b8afafbSJosh Poimboeuf 	stack = stack ? : get_stack_pointer(task, regs);
1174b8afafbSJosh Poimboeuf 	bp = bp ? : (unsigned long)get_frame_pointer(task, regs);
118e8e999cfSNamhyung Kim 
1192bc5f927SAlexander van Heukelum 	for (;;) {
120cb76c939SJosh Poimboeuf 		const char *begin_str, *end_str;
121cb76c939SJosh Poimboeuf 		struct stack_info info;
1222bc5f927SAlexander van Heukelum 
123cb76c939SJosh Poimboeuf 		if (get_stack_info(stack, task, &info, &visit_mask))
1240788aa6aSSteven Rostedt 			break;
1250788aa6aSSteven Rostedt 
126cb76c939SJosh Poimboeuf 		stack_type_str(info.type, &begin_str, &end_str);
127cb76c939SJosh Poimboeuf 
128cb76c939SJosh Poimboeuf 		if (begin_str && ops->stack(data, begin_str) < 0)
1292bc5f927SAlexander van Heukelum 			break;
1300788aa6aSSteven Rostedt 
131cb76c939SJosh Poimboeuf 		bp = ops->walk_stack(task, stack, bp, ops, data, &info, &graph);
132cb76c939SJosh Poimboeuf 
133cb76c939SJosh Poimboeuf 		if (end_str && ops->stack(data, end_str) < 0)
1342ac53721SAlexander van Heukelum 			break;
135cb76c939SJosh Poimboeuf 
136cb76c939SJosh Poimboeuf 		stack = info.next_sp;
137cb76c939SJosh Poimboeuf 
1382bc5f927SAlexander van Heukelum 		touch_nmi_watchdog();
1392bc5f927SAlexander van Heukelum 	}
1402bc5f927SAlexander van Heukelum }
1412bc5f927SAlexander van Heukelum EXPORT_SYMBOL(dump_trace);
1422bc5f927SAlexander van Heukelum 
143878719e8SNeil Horman void
1442bc5f927SAlexander van Heukelum show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
145e8e999cfSNamhyung Kim 		   unsigned long *sp, unsigned long bp, char *log_lvl)
1462bc5f927SAlexander van Heukelum {
1472bc5f927SAlexander van Heukelum 	unsigned long *stack;
1482bc5f927SAlexander van Heukelum 	int i;
1492bc5f927SAlexander van Heukelum 
1504b8afafbSJosh Poimboeuf 	sp = sp ? : get_stack_pointer(task, regs);
1512bc5f927SAlexander van Heukelum 
1522bc5f927SAlexander van Heukelum 	stack = sp;
1532bc5f927SAlexander van Heukelum 	for (i = 0; i < kstack_depth_to_print; i++) {
1542bc5f927SAlexander van Heukelum 		if (kstack_end(stack))
1552bc5f927SAlexander van Heukelum 			break;
1561fc7f61cSAdrien Schildknecht 		if ((i % STACKSLOTS_PER_LINE) == 0) {
1571fc7f61cSAdrien Schildknecht 			if (i != 0)
158c767a54bSJoe Perches 				pr_cont("\n");
1591fc7f61cSAdrien Schildknecht 			printk("%s %08lx", log_lvl, *stack++);
1601fc7f61cSAdrien Schildknecht 		} else
161c767a54bSJoe Perches 			pr_cont(" %08lx", *stack++);
162ca0a8164SAlexander van Heukelum 		touch_nmi_watchdog();
1632bc5f927SAlexander van Heukelum 	}
164c767a54bSJoe Perches 	pr_cont("\n");
165e8e999cfSNamhyung Kim 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
1662bc5f927SAlexander van Heukelum }
1672bc5f927SAlexander van Heukelum 
1682bc5f927SAlexander van Heukelum 
16957da8b96SJan Beulich void show_regs(struct pt_regs *regs)
1702bc5f927SAlexander van Heukelum {
1712bc5f927SAlexander van Heukelum 	int i;
1722bc5f927SAlexander van Heukelum 
173a43cb95dSTejun Heo 	show_regs_print_info(KERN_EMERG);
174f39b6f0eSAndy Lutomirski 	__show_regs(regs, !user_mode(regs));
1752bc5f927SAlexander van Heukelum 
1762bc5f927SAlexander van Heukelum 	/*
1772bc5f927SAlexander van Heukelum 	 * When in-kernel, we also print out the stack and code at the
1782bc5f927SAlexander van Heukelum 	 * time of the fault..
1792bc5f927SAlexander van Heukelum 	 */
180f39b6f0eSAndy Lutomirski 	if (!user_mode(regs)) {
1812bc5f927SAlexander van Heukelum 		unsigned int code_prologue = code_bytes * 43 / 64;
1822bc5f927SAlexander van Heukelum 		unsigned int code_len = code_bytes;
1832bc5f927SAlexander van Heukelum 		unsigned char c;
1842bc5f927SAlexander van Heukelum 		u8 *ip;
1852bc5f927SAlexander van Heukelum 
186c767a54bSJoe Perches 		pr_emerg("Stack:\n");
1875a8ff54cSJosh Poimboeuf 		show_stack_log_lvl(NULL, regs, NULL, 0, KERN_EMERG);
1882bc5f927SAlexander van Heukelum 
189c767a54bSJoe Perches 		pr_emerg("Code:");
1902bc5f927SAlexander van Heukelum 
1912bc5f927SAlexander van Heukelum 		ip = (u8 *)regs->ip - code_prologue;
1922bc5f927SAlexander van Heukelum 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
1938a541665SAlexander van Heukelum 			/* try starting at IP */
1942bc5f927SAlexander van Heukelum 			ip = (u8 *)regs->ip;
1952bc5f927SAlexander van Heukelum 			code_len = code_len - code_prologue + 1;
1962bc5f927SAlexander van Heukelum 		}
1972bc5f927SAlexander van Heukelum 		for (i = 0; i < code_len; i++, ip++) {
1982bc5f927SAlexander van Heukelum 			if (ip < (u8 *)PAGE_OFFSET ||
1992bc5f927SAlexander van Heukelum 					probe_kernel_address(ip, c)) {
200c767a54bSJoe Perches 				pr_cont("  Bad EIP value.");
2012bc5f927SAlexander van Heukelum 				break;
2022bc5f927SAlexander van Heukelum 			}
2032bc5f927SAlexander van Heukelum 			if (ip == (u8 *)regs->ip)
204c767a54bSJoe Perches 				pr_cont(" <%02x>", c);
2052bc5f927SAlexander van Heukelum 			else
206c767a54bSJoe Perches 				pr_cont(" %02x", c);
2072bc5f927SAlexander van Heukelum 		}
2082bc5f927SAlexander van Heukelum 	}
209c767a54bSJoe Perches 	pr_cont("\n");
2102bc5f927SAlexander van Heukelum }
2112bc5f927SAlexander van Heukelum 
2122bc5f927SAlexander van Heukelum int is_valid_bugaddr(unsigned long ip)
2132bc5f927SAlexander van Heukelum {
2142bc5f927SAlexander van Heukelum 	unsigned short ud2;
2152bc5f927SAlexander van Heukelum 
2162bc5f927SAlexander van Heukelum 	if (ip < PAGE_OFFSET)
2172bc5f927SAlexander van Heukelum 		return 0;
2182bc5f927SAlexander van Heukelum 	if (probe_kernel_address((unsigned short *)ip, ud2))
2192bc5f927SAlexander van Heukelum 		return 0;
2202bc5f927SAlexander van Heukelum 
2212bc5f927SAlexander van Heukelum 	return ud2 == 0x0b0f;
2222bc5f927SAlexander van Heukelum }
223